mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Compare commits
73
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d3e1bbfc6 | ||
|
|
738225d2a2 | ||
|
|
4be9b106f4 | ||
|
|
af4eeb09f4 | ||
|
|
15821498a3 | ||
|
|
54bdce6c46 | ||
|
|
433de0e67b | ||
|
|
30e5d8f91c | ||
|
|
506ea842b8 | ||
|
|
9adc1ad998 | ||
|
|
8d1877d26d | ||
|
|
d03989051a | ||
|
|
5da2ee8bf6 | ||
|
|
aa0aac2bfe | ||
|
|
ee098125e6 | ||
|
|
bada3ef31a | ||
|
|
00a805cc39 | ||
|
|
fd2c74727e | ||
|
|
ba64ed53c6 | ||
|
|
c61f57bd9b | ||
|
|
4d5593ebcb | ||
|
|
601fabf401 | ||
|
|
eb8ecb31f0 | ||
|
|
2801af552e | ||
|
|
ef30192b29 | ||
|
|
392ba66df3 | ||
|
|
d4dd5f07df | ||
|
|
db29feed11 | ||
|
|
1fc5f939bf | ||
|
|
9e0105caec | ||
|
|
0cc7fb4e39 | ||
|
|
db15679ec1 | ||
|
|
6a8a22aba2 | ||
|
|
9b654ff3f1 | ||
|
|
a67f4b8a8f | ||
|
|
673dea01af | ||
|
|
b44b6cebb8 | ||
|
|
8bc3dbd0aa | ||
|
|
b4176bb2d9 | ||
|
|
8b3e417872 | ||
|
|
b949189881 | ||
|
|
cc19490898 | ||
|
|
9fac0a8ecd | ||
|
|
346e5c6293 | ||
|
|
0bea84374e | ||
|
|
3d589bd78e | ||
|
|
e1c8bee1d1 | ||
|
|
ead2932316 | ||
|
|
bb55299ff6 | ||
|
|
2d4f62a5b6 | ||
|
|
03a7b017b6 | ||
|
|
edf8f2f086 | ||
|
|
78ed49c73d | ||
|
|
5697acabb3 | ||
|
|
09197e421c | ||
|
|
46afd90fdc | ||
|
|
80ba0a05d7 | ||
|
|
aab34bff20 | ||
|
|
ef325c1cde | ||
|
|
99a4ff1527 | ||
|
|
f2d1b09fc6 | ||
|
|
31970291bd | ||
|
|
0a758179c2 | ||
|
|
481e95d42d | ||
|
|
8f178a59ab | ||
|
|
a6d96f5f31 | ||
|
|
67f41d4de6 | ||
|
|
1d53b92731 | ||
|
|
42b2cbc7f5 | ||
|
|
04ace5df24 | ||
|
|
323944757d | ||
|
|
7d5a1c2e9e | ||
|
|
dc107f5044 |
+166
-27
@@ -9,11 +9,6 @@ on:
|
|||||||
# allows to manually trigger a build
|
# allows to manually trigger a build
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
build_all_languages:
|
|
||||||
description: build all languages
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
assemble_release:
|
assemble_release:
|
||||||
description: create release
|
description: create release
|
||||||
required: false
|
required: false
|
||||||
@@ -27,7 +22,6 @@ jobs:
|
|||||||
workflow_setup:
|
workflow_setup:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
languages_json_array: ${{ steps.global_vars.outputs.languages_json_array }}
|
|
||||||
assemble_release: ${{ steps.global_vars.outputs.assemble_release }}
|
assemble_release: ${{ steps.global_vars.outputs.assemble_release }}
|
||||||
steps:
|
steps:
|
||||||
- id: global_vars
|
- id: global_vars
|
||||||
@@ -37,15 +31,6 @@ jobs:
|
|||||||
|
|
||||||
full_release='${{ ( github.repository == '1dot13/source' && github.ref_name == 'master' ) || startsWith(github.ref, 'refs/tags/v') }}'
|
full_release='${{ ( github.repository == '1dot13/source' && github.ref_name == 'master' ) || startsWith(github.ref, 'refs/tags/v') }}'
|
||||||
|
|
||||||
if [[ '${{ inputs.build_all_languages }}' == 'true' || ( '${{ inputs.build_all_languages }}' == '' && "$full_release" == 'true' ) ]]
|
|
||||||
then
|
|
||||||
languages_json_array='["Chinese", "German", "English", "French", "Polish", "Italian", "Dutch", "Russian"]';
|
|
||||||
else
|
|
||||||
# English + some other language for compilation testing
|
|
||||||
languages_json_array='["German", "English"]'
|
|
||||||
fi
|
|
||||||
echo "languages_json_array=$languages_json_array" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
if [[ '${{ inputs.assemble_release }}' == 'true' || ( '${{ inputs.assemble_release }}' == '' && "$full_release" == 'true' ) ]]
|
if [[ '${{ inputs.assemble_release }}' == 'true' || ( '${{ inputs.assemble_release }}' == '' && "$full_release" == 'true' ) ]]
|
||||||
then
|
then
|
||||||
assemble_release='true'
|
assemble_release='true'
|
||||||
@@ -154,39 +139,193 @@ jobs:
|
|||||||
cat dist/versions.env
|
cat dist/versions.env
|
||||||
|
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: versions.env
|
name: versions.env
|
||||||
path: dist/
|
path: dist/
|
||||||
|
|
||||||
build:
|
# every executable contains all languages and picks one at runtime, so one build serves every package
|
||||||
|
compile:
|
||||||
needs: [ workflow_setup ]
|
needs: [ workflow_setup ]
|
||||||
|
runs-on: windows-latest # required for the MSVC toolchain
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: ${{ fromJson(needs.workflow_setup.outputs.languages_json_array) }}
|
application: [ja2, ja2mapeditor, ja2ub, ja2ubmapeditor]
|
||||||
uses: ./.github/workflows/build_language.yml
|
|
||||||
with:
|
steps:
|
||||||
language: ${{ matrix.language }}
|
- name: Checkout source
|
||||||
assemble: ${{ needs.workflow_setup.outputs.assemble_release == 'true' }}
|
uses: actions/checkout@v7
|
||||||
# at least English and some other lang have to work
|
|
||||||
continue-on-error: ${{ matrix.language != 'English' && matrix.language != 'German' }}
|
- name: Download versions.env
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: versions.env
|
||||||
|
path: artifacts
|
||||||
|
- name: Restore versions.env
|
||||||
|
shell: bash
|
||||||
|
run: cat artifacts/versions.env >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# TODO: Move this into CMake, just taking the GitHub Actions parameters as -D variables
|
||||||
|
- name: Update GameVersion.cpp
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
GAME_VERSION=$(echo "$GAME_VERSION" | tr -cd '[:print:]' | tr -d '"\\')
|
||||||
|
GAME_BUILD=$(echo "$GAME_BUILD_INFORMATION" | tr -cd '[:print:]' | tr -d '"\\')
|
||||||
|
sed -i "s|@Version@|${GAME_VERSION:0:15}|" Ja2/GameVersion.cpp
|
||||||
|
sed -i "s|@Build@|${GAME_BUILD:0:255}|" Ja2/GameVersion.cpp
|
||||||
|
cat Ja2/GameVersion.cpp
|
||||||
|
|
||||||
|
- name: Prepare build properties
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
touch CMakePresets.json
|
||||||
|
|
||||||
|
JA2Application=$(echo '${{ matrix.application }}' | tr '[:lower:]' '[:upper:]')
|
||||||
|
|
||||||
|
echo "
|
||||||
|
JA2Application=$JA2Application
|
||||||
|
" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: egor-tensin/vs-shell@v2
|
||||||
|
with:
|
||||||
|
arch: x86
|
||||||
|
- name: Prepare build
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DApplications="$Env:JA2Application"
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cmake --build build/ -- -v
|
||||||
|
- name: List build artifacts
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
find build/
|
||||||
|
|
||||||
|
- name: Upload
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.application }}
|
||||||
|
path: build/*.exe
|
||||||
|
|
||||||
|
# only the game data differs per language, every package gets the same executables
|
||||||
|
assemble:
|
||||||
|
needs: [ workflow_setup, compile ]
|
||||||
|
if: needs.workflow_setup.outputs.assemble_release == 'true'
|
||||||
|
runs-on: windows-latest # required for case-insensitive filesystem handling
|
||||||
|
# at least English has to work
|
||||||
|
continue-on-error: ${{ matrix.language != 'English' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [Chinese, German, English, French, Polish, Italian, Dutch, Russian]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download versions.env
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: versions.env
|
||||||
|
path: artifacts
|
||||||
|
- name: Restore versions.env
|
||||||
|
shell: bash
|
||||||
|
run: cat artifacts/versions.env >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Checkout gamedir
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
repository: ${{ env.GAMEDIR_REPOSITORY }}
|
||||||
|
ref: ${{ env.GAMEDIR_COMMIT_SHA }}
|
||||||
|
path: gamedir
|
||||||
|
|
||||||
|
- name: Checkout gamedir-languages
|
||||||
|
if: matrix.language != 'English'
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
repository: ${{ env.GAMEDIR_LANGUAGES_REPOSITORY }}
|
||||||
|
ref: ${{ env.GAMEDIR_LANGUAGES_COMMIT_SHA }}
|
||||||
|
path: gamedir-languages
|
||||||
|
|
||||||
|
- name: Copy gamedir-languages files to gamedir
|
||||||
|
if: matrix.language != 'English'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
cp -a gamedir-languages/${{ matrix.language }}_Version/* gamedir/
|
||||||
|
|
||||||
|
- name: Download applications
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
pattern: ja2*
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Copy application files to gamedir
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
for APP in ja2 ja2mapeditor ja2ub ja2ubmapeditor
|
||||||
|
do
|
||||||
|
mv artifacts/${APP}/*.exe gamedir/${APP}.exe
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Create version information file
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
# "-" separates words, "_" combines words, see double-click behavior
|
||||||
|
DIST_PREFIX='JA2_113'
|
||||||
|
DIST_NAME="${DIST_PREFIX}-${GAME_VERSION}-G${GAMEDIR_COMMIT_SHA:0:4}L${GAMEDIR_LANGUAGES_COMMIT_SHA:0:4}-${{ matrix.language }}"
|
||||||
|
echo "DIST_NAME=$DIST_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "If you encounter problems during gameplay, please provide the following version information:
|
||||||
|
Distribution Name: $DIST_NAME
|
||||||
|
Game Version: $GAME_VERSION
|
||||||
|
Language: ${{ matrix.language }}
|
||||||
|
Build Information: $GAME_BUILD_INFORMATION
|
||||||
|
Source Repository: $GITHUB_REPOSITORY
|
||||||
|
Source Commit SHA: $GITHUB_SHA
|
||||||
|
Source Commit Date: $SOURCE_COMMIT_DATETIME
|
||||||
|
Gamedir Repository: $GAMEDIR_REPOSITORY
|
||||||
|
Gamedir Commit SHA: $GAMEDIR_COMMIT_SHA
|
||||||
|
Gamedir Commit Date: $GAMEDIR_COMMIT_DATETIME
|
||||||
|
Gamedir Languages Repository: $GAMEDIR_LANGUAGES_REPOSITORY
|
||||||
|
Gamedir Languages Commit SHA: $GAMEDIR_LANGUAGES_COMMIT_SHA
|
||||||
|
Gamedir Languages Commit Date: $GAMEDIR_LANGUAGES_COMMIT_DATETIME
|
||||||
|
" > "gamedir/${DIST_PREFIX}-Version.txt"
|
||||||
|
cat "gamedir/${DIST_PREFIX}-Version.txt"
|
||||||
|
|
||||||
|
- name: Create release archive
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
mkdir dist/
|
||||||
|
cd gamedir/
|
||||||
|
7z a -bb -xr'!.*' "../dist/${DIST_NAME}.7z" .
|
||||||
|
|
||||||
|
- name: Upload
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.language }}_release
|
||||||
|
path: dist/
|
||||||
|
compression-level: 0
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: [ workflow_setup, build ]
|
needs: [ workflow_setup, assemble ]
|
||||||
if: needs.workflow_setup.outputs.assemble_release == 'true'
|
if: needs.workflow_setup.outputs.assemble_release == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
path: dist
|
path: dist
|
||||||
pattern: '*_release'
|
pattern: '*_release'
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
path: source
|
path: source
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|||||||
@@ -1,206 +0,0 @@
|
|||||||
name: build language
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
language:
|
|
||||||
description: 'any of Chinese German English French Polish Italian Dutch Russian'
|
|
||||||
required: true
|
|
||||||
default: 'English'
|
|
||||||
type: string
|
|
||||||
assemble:
|
|
||||||
description: 'assemble full package'
|
|
||||||
required: true
|
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
continue-on-error:
|
|
||||||
description: 'allows a language to fail, used when building all languages'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
compile:
|
|
||||||
runs-on: windows-latest # required for msbuild
|
|
||||||
continue-on-error: ${{ inputs.continue-on-error }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
application: [ja2, ja2mapeditor, ja2ub, ja2ubmapeditor]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout source
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Download versions.env
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: versions.env
|
|
||||||
path: artifacts
|
|
||||||
- name: Restore versions.env
|
|
||||||
shell: bash
|
|
||||||
run: cat artifacts/versions.env >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# TODO: Move this into CMake, just taking the GitHub Actions parameters as -D variables
|
|
||||||
- name: Update GameVersion.cpp
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
INPUTS_LANGUAGE=${{ inputs.language }}
|
|
||||||
GAME_VERSION=$(echo "$GAME_VERSION" | tr -cd '[:print:]' | tr -d '"\\')
|
|
||||||
GAME_BUILD="${INPUTS_LANGUAGE:0:2} $GAME_BUILD_INFORMATION"
|
|
||||||
GAME_BUILD=$(echo "$GAME_BUILD" | tr -cd '[:print:]' | tr -d '"\\')
|
|
||||||
sed -i "s|@Version@|${GAME_VERSION:0:15}|" Ja2/GameVersion.cpp
|
|
||||||
sed -i "s|@Build@|${GAME_BUILD:0:255}|" Ja2/GameVersion.cpp
|
|
||||||
cat Ja2/GameVersion.cpp
|
|
||||||
|
|
||||||
- name: Prepare build properties
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
touch CMakePresets.json
|
|
||||||
|
|
||||||
JA2Language=$(echo '${{ inputs.language }}' | tr '[:lower:]' '[:upper:]')
|
|
||||||
JA2Application=$(echo '${{ matrix.application }}' | tr '[:lower:]' '[:upper:]')
|
|
||||||
|
|
||||||
echo "
|
|
||||||
JA2Language=$JA2Language
|
|
||||||
JA2Application=$JA2Application
|
|
||||||
" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- uses: microsoft/setup-msbuild@v2
|
|
||||||
with:
|
|
||||||
msbuild-architecture: x86
|
|
||||||
- uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
with:
|
|
||||||
arch: x86
|
|
||||||
- name: Prepare build
|
|
||||||
run: |
|
|
||||||
cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLanguages="$Env:JA2Language" -DApplications="$Env:JA2Application"
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
cmake --build build/ -- -v
|
|
||||||
- name: List build artifacts
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
find build/
|
|
||||||
|
|
||||||
- name: Upload
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_${{ matrix.application }}
|
|
||||||
path: build/*.exe
|
|
||||||
|
|
||||||
assemble:
|
|
||||||
needs: [ compile ]
|
|
||||||
if: inputs.assemble
|
|
||||||
runs-on: windows-latest # required for case-insensitive filesystem handling
|
|
||||||
continue-on-error: ${{ inputs.continue-on-error }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Download versions.env
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: versions.env
|
|
||||||
path: artifacts
|
|
||||||
- name: Restore versions.env
|
|
||||||
shell: bash
|
|
||||||
run: cat artifacts/versions.env >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout gamedir
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ env.GAMEDIR_REPOSITORY }}
|
|
||||||
ref: ${{ env.GAMEDIR_COMMIT_SHA }}
|
|
||||||
path: gamedir
|
|
||||||
|
|
||||||
- name: Checkout gamedir-languages
|
|
||||||
if: inputs.language != 'English'
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ env.GAMEDIR_LANGUAGES_REPOSITORY }}
|
|
||||||
ref: ${{ env.GAMEDIR_LANGUAGES_COMMIT_SHA }}
|
|
||||||
path: gamedir-languages
|
|
||||||
|
|
||||||
- name: Copy gamedir-languages files to gamedir
|
|
||||||
if: inputs.language != 'English'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
cp -a gamedir-languages/${{ inputs.language }}_Version/* gamedir/
|
|
||||||
|
|
||||||
- name: Download ja2
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_ja2
|
|
||||||
path: artifacts/ja2
|
|
||||||
|
|
||||||
- name: Download ja2mapeditor
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_ja2mapeditor
|
|
||||||
path: artifacts/ja2mapeditor
|
|
||||||
|
|
||||||
- name: Download ja2ub
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_ja2ub
|
|
||||||
path: artifacts/ja2ub
|
|
||||||
|
|
||||||
- name: Download ja2ubmapeditor
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_ja2ubmapeditor
|
|
||||||
path: artifacts/ja2ubmapeditor
|
|
||||||
|
|
||||||
- name: Copy application files to gamedir
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
for APP in ja2 ja2mapeditor ja2ub ja2ubmapeditor
|
|
||||||
do
|
|
||||||
mv artifacts/${APP}/*.exe gamedir/${APP}.exe
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Create version information file
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
# "-" separates words, "_" combines words, see double-click behavior
|
|
||||||
DIST_PREFIX='JA2_113'
|
|
||||||
DIST_NAME="${DIST_PREFIX}-${GAME_VERSION}-G${GAMEDIR_COMMIT_SHA:0:4}L${GAMEDIR_LANGUAGES_COMMIT_SHA:0:4}-${{ inputs.language }}"
|
|
||||||
echo "DIST_NAME=$DIST_NAME" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo "If you encounter problems during gameplay, please provide the following version information:
|
|
||||||
Distribution Name: $DIST_NAME
|
|
||||||
Game Version: $GAME_VERSION
|
|
||||||
Language: ${{ inputs.language }}
|
|
||||||
Build Information: $GAME_BUILD_INFORMATION
|
|
||||||
Source Repository: $GITHUB_REPOSITORY
|
|
||||||
Source Commit SHA: $GITHUB_SHA
|
|
||||||
Source Commit Date: $SOURCE_COMMIT_DATETIME
|
|
||||||
Gamedir Repository: $GAMEDIR_REPOSITORY
|
|
||||||
Gamedir Commit SHA: $GAMEDIR_COMMIT_SHA
|
|
||||||
Gamedir Commit Date: $GAMEDIR_COMMIT_DATETIME
|
|
||||||
Gamedir Languages Repository: $GAMEDIR_LANGUAGES_REPOSITORY
|
|
||||||
Gamedir Languages Commit SHA: $GAMEDIR_LANGUAGES_COMMIT_SHA
|
|
||||||
Gamedir Languages Commit Date: $GAMEDIR_LANGUAGES_COMMIT_DATETIME
|
|
||||||
" > "gamedir/${DIST_PREFIX}-Version.txt"
|
|
||||||
cat "gamedir/${DIST_PREFIX}-Version.txt"
|
|
||||||
|
|
||||||
- name: Create release archive
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -eux
|
|
||||||
mkdir dist/
|
|
||||||
cd gamedir/
|
|
||||||
7z a -bb -xr'!.*' "../dist/${DIST_NAME}.7z" .
|
|
||||||
|
|
||||||
- name: Upload
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.language }}_release
|
|
||||||
path: dist/
|
|
||||||
compression-level: 0
|
|
||||||
+29
-27
@@ -27,7 +27,11 @@ if(ADDRESS_SANITIZER)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_compile_options("/wd4838")
|
# TODO: fix the warnings here and turn them on
|
||||||
|
# https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-c4000-through-c4199
|
||||||
|
add_compile_options("/wd4838") # silence implicit narrowing conversion warnings
|
||||||
|
# add_compile_options("/w14061")
|
||||||
|
# add_compile_options("/w14062")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# whether we are using MSBuild as a generator
|
# whether we are using MSBuild as a generator
|
||||||
@@ -102,15 +106,13 @@ foreach(lib IN LISTS Ja2_Libs)
|
|||||||
add_subdirectory(${lib})
|
add_subdirectory(${lib})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# language library relies on Application _and_ Language preprocessor definition. very bad.
|
# language library relies on Application preprocessor definition; compiled once per app
|
||||||
|
# with all 8 languages built in and selected at runtime (docs/plans/language-design.md).
|
||||||
add_subdirectory(i18n)
|
add_subdirectory(i18n)
|
||||||
|
|
||||||
# simple function to validate Languages and Application choices
|
# simple function to validate the Application choice
|
||||||
include(cmake/ValidateOptions.cmake)
|
include(cmake/ValidateOptions.cmake)
|
||||||
|
|
||||||
set(ValidLanguages CHINESE DUTCH ENGLISH FRENCH GERMAN ITALIAN POLISH RUSSIAN)
|
|
||||||
ValidateOptions("${ValidLanguages}" "Languages" "${Languages}" "LangTargets")
|
|
||||||
|
|
||||||
set(ValidApplications JA2 JA2MAPEDITOR JA2UB JA2UBMAPEDITOR)
|
set(ValidApplications JA2 JA2MAPEDITOR JA2UB JA2UBMAPEDITOR)
|
||||||
ValidateOptions("${ValidApplications}" "Applications" "${Applications}" "ApplicationTargets")
|
ValidateOptions("${ValidApplications}" "Applications" "${Applications}" "ApplicationTargets")
|
||||||
|
|
||||||
@@ -136,32 +138,32 @@ foreach(app IN LISTS ApplicationTargets)
|
|||||||
target_compile_definitions(${game_library} PRIVATE ${compilationFlags} ${debugFlags})
|
target_compile_definitions(${game_library} PRIVATE ${compilationFlags} ${debugFlags})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
foreach(lang IN LISTS LangTargets)
|
# executable for the application, e.g. JA2.exe
|
||||||
# executable for an application/language combination, e.g. JA2_ENGLISH.exe
|
set(exe ${app})
|
||||||
set(exe ${app}_${lang})
|
add_executable(${exe} WIN32
|
||||||
add_executable(${exe} WIN32
|
sgp/sgp.cpp
|
||||||
sgp/sgp.cpp
|
Ja2/Res/ja2.rc
|
||||||
Ja2/Res/ja2.rc
|
)
|
||||||
)
|
target_link_libraries(${exe} PRIVATE ${Ja2_Libraries} $<IF:${usingMsBuild},legacy_stdio_definitions.lib,>)
|
||||||
target_link_libraries(${exe} PRIVATE ${Ja2_Libraries} $<IF:${usingMsBuild},legacy_stdio_definitions.lib,>)
|
target_link_options(${exe} PRIVATE $<IF:${usingMsBuild},/SAFESEH:NO,>)
|
||||||
target_link_options(${exe} PRIVATE $<IF:${usingMsBuild},/SAFESEH:NO,>)
|
target_compile_definitions(${exe} PRIVATE ${compilationFlags} ${debugFlags})
|
||||||
target_compile_definitions(${exe} PRIVATE ${compilationFlags} ${debugFlags})
|
|
||||||
|
|
||||||
# language library for an application, e.g. JA2MAPEDITOR_ENGLISH_i18n
|
# language library for the application, e.g. JA2MAPEDITOR_i18n — one per app, all 8
|
||||||
set(language_library ${exe}_i18n)
|
# languages compiled in, selected at runtime by BindLanguageStrings
|
||||||
add_library(${language_library})
|
set(language_library ${exe}_i18n)
|
||||||
target_sources(${language_library} PRIVATE ${i18nSrc})
|
add_library(${language_library})
|
||||||
target_compile_definitions(${language_library} PRIVATE ${compilationFlags} ${debugFlags} ${lang})
|
target_sources(${language_library} PRIVATE ${i18nSrc})
|
||||||
target_link_libraries(${exe} PRIVATE ${language_library})
|
target_compile_definitions(${language_library} PRIVATE ${compilationFlags} ${debugFlags})
|
||||||
|
target_compile_options(${language_library} PRIVATE /w14062)
|
||||||
|
target_link_libraries(${exe} PRIVATE ${language_library})
|
||||||
|
|
||||||
# go through all game libraries again and link them to the app/language executable
|
# go through all game libraries again and link them to the app executable
|
||||||
foreach(lib IN LISTS Ja2_Libs)
|
foreach(lib IN LISTS Ja2_Libs)
|
||||||
target_link_libraries(${exe} PRIVATE ${app}_${lib})
|
target_link_libraries(${exe} PRIVATE ${app}_${lib})
|
||||||
endforeach()
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# for SGP only
|
# for SGP only
|
||||||
target_link_libraries(${app}_sgp PRIVATE "ddraw.lib" "${PROJECT_SOURCE_DIR}/fmodvc.lib")
|
target_link_libraries(${app}_sgp PRIVATE "ddraw.lib" "${PROJECT_SOURCE_DIR}/fmodvc.lib")
|
||||||
target_link_libraries(${app}_sgp PRIVATE libpng)
|
target_link_libraries(${app}_sgp PRIVATE libpng)
|
||||||
target_compile_definitions(${app}_sgp PRIVATE NO_ZLIB_COMPRESSION)
|
target_compile_definitions(${app}_sgp PRIVATE ${compilationFlags} ${debugFlags} NO_ZLIB_COMPRESSION)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ void IncreaseSelectionDensity();
|
|||||||
void DecreaseSelectionDensity();
|
void DecreaseSelectionDensity();
|
||||||
void RemoveCursors();
|
void RemoveCursors();
|
||||||
|
|
||||||
extern STR16 wszSelType[6];
|
extern STR16 *wszSelType;
|
||||||
|
|
||||||
extern BOOLEAN gfCurrentSelectionWithRightButton;
|
extern BOOLEAN gfCurrentSelectionWithRightButton;
|
||||||
|
|
||||||
@@ -40,4 +40,4 @@ extern BOOLEAN gfCurrentSelectionWithRightButton;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ extern UINT8 gubCurrMercMode, gubPrevMercMode;
|
|||||||
|
|
||||||
#define NUM_DIFF_LVLS 5
|
#define NUM_DIFF_LVLS 5
|
||||||
|
|
||||||
extern STR16 zDiffNames[NUM_DIFF_LVLS];
|
extern STR16 *zDiffNames;
|
||||||
extern INT16 sCurBaseDiff;
|
extern INT16 sCurBaseDiff;
|
||||||
extern INT16 gsSelectedMercID;
|
extern INT16 gsSelectedMercID;
|
||||||
extern INT32 gsSelectedMercGridNo;
|
extern INT32 gsSelectedMercGridNo;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ MOUSE_REGION popupRegion;
|
|||||||
UINT16 gusEntryHeight;
|
UINT16 gusEntryHeight;
|
||||||
BOOLEAN fWaitingForLButtonRelease = FALSE;
|
BOOLEAN fWaitingForLButtonRelease = FALSE;
|
||||||
|
|
||||||
extern CHAR16 gszScheduleActions[ NUM_SCHEDULE_ACTIONS ][20];
|
extern CHAR16 (*gszScheduleActions)[20]; // NUM_SCHEDULE_ACTIONS entries
|
||||||
|
|
||||||
//Finds the string for any popup menu in JA2 -- the strings are stored
|
//Finds the string for any popup menu in JA2 -- the strings are stored
|
||||||
//in different ways in each instance.
|
//in different ways in each instance.
|
||||||
|
|||||||
@@ -332,7 +332,6 @@ BOOLEAN LoadGameSettings()
|
|||||||
|
|
||||||
gGameSettings.fOptions[TOPTION_ALT_START_AIM] = iniReader.ReadBoolean("JA2 Game Settings", "TOPTION_ALT_START_AIM" , TRUE); // Start at max aiming level instead of default no aiming
|
gGameSettings.fOptions[TOPTION_ALT_START_AIM] = iniReader.ReadBoolean("JA2 Game Settings", "TOPTION_ALT_START_AIM" , TRUE); // Start at max aiming level instead of default no aiming
|
||||||
gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] = iniReader.ReadBoolean("JA2 Game Settings", "TOPTION_ALT_PATHFINDING" , FALSE); // A* pathfinding
|
gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] = iniReader.ReadBoolean("JA2 Game Settings", "TOPTION_ALT_PATHFINDING" , FALSE); // A* pathfinding
|
||||||
gGameSettings.fOptions[TOPTION_USE_LEGACY_TACTICALAI] = iniReader.ReadBoolean("JA2 Game Settings", "TOPTION_USE_LEGACY_TACTICALAI", FALSE); // A* pathfinding
|
|
||||||
gGameSettings.fOptions[TOPTION_MERCENARY_FORMATIONS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_MERCENARY_FORMATIONS" , FALSE ); // Flugente: mercenary formations
|
gGameSettings.fOptions[TOPTION_MERCENARY_FORMATIONS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_MERCENARY_FORMATIONS" , FALSE ); // Flugente: mercenary formations
|
||||||
gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SHOW_ENEMY_LOCATION" , FALSE); // sevenfm: show locations of known enemies
|
gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SHOW_ENEMY_LOCATION" , FALSE); // sevenfm: show locations of known enemies
|
||||||
gGameSettings.fOptions[TOPTION_REPORT_MISS_MARGIN] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_REPORT_MISS_MARGIN" , FALSE ); // HEADROCK HAM 4: Shot offset report
|
gGameSettings.fOptions[TOPTION_REPORT_MISS_MARGIN] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_REPORT_MISS_MARGIN" , FALSE ); // HEADROCK HAM 4: Shot offset report
|
||||||
@@ -617,7 +616,6 @@ BOOLEAN SaveGameSettings()
|
|||||||
settings << "TOPTION_SHOW_ENEMY_LOCATION = " << (gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] ? "TRUE" : "FALSE" ) << endl;
|
settings << "TOPTION_SHOW_ENEMY_LOCATION = " << (gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] ? "TRUE" : "FALSE" ) << endl;
|
||||||
settings << "TOPTION_ALT_START_AIM = " << (gGameSettings.fOptions[TOPTION_ALT_START_AIM] ? "TRUE" : "FALSE") << endl;
|
settings << "TOPTION_ALT_START_AIM = " << (gGameSettings.fOptions[TOPTION_ALT_START_AIM] ? "TRUE" : "FALSE") << endl;
|
||||||
settings << "TOPTION_ALT_PATHFINDING = " << (gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] ? "TRUE" : "FALSE") << endl;
|
settings << "TOPTION_ALT_PATHFINDING = " << (gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] ? "TRUE" : "FALSE") << endl;
|
||||||
settings << "TOPTION_USE_LEGACY_TACTICALAI = " << (gGameSettings.fOptions[TOPTION_USE_LEGACY_TACTICALAI] ? "TRUE" : "FALSE") << endl;
|
|
||||||
|
|
||||||
settings << "TOPTION_CHEAT_MODE_OPTIONS_HEADER = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] ? "TRUE" : "FALSE" ) << endl;
|
settings << "TOPTION_CHEAT_MODE_OPTIONS_HEADER = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] ? "TRUE" : "FALSE" ) << endl;
|
||||||
settings << "TOPTION_FORCE_BOBBY_RAY_SHIPMENTS = " << (gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] ? "TRUE" : "FALSE" ) << endl;
|
settings << "TOPTION_FORCE_BOBBY_RAY_SHIPMENTS = " << (gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] ? "TRUE" : "FALSE" ) << endl;
|
||||||
@@ -848,7 +846,6 @@ void InitGameSettings()
|
|||||||
gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] = FALSE; // sevenfm: show locations of known enemies
|
gGameSettings.fOptions[TOPTION_SHOW_ENEMY_LOCATION] = FALSE; // sevenfm: show locations of known enemies
|
||||||
gGameSettings.fOptions[TOPTION_ALT_START_AIM] = TRUE;
|
gGameSettings.fOptions[TOPTION_ALT_START_AIM] = TRUE;
|
||||||
gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] = FALSE;
|
gGameSettings.fOptions[TOPTION_ALT_PATHFINDING] = FALSE;
|
||||||
gGameSettings.fOptions[TOPTION_USE_LEGACY_TACTICALAI] = FALSE;
|
|
||||||
|
|
||||||
// arynn: Cheat/Debug Menu
|
// arynn: Cheat/Debug Menu
|
||||||
gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_HEADER ] = FALSE;
|
gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_HEADER ] = FALSE;
|
||||||
@@ -2752,6 +2749,7 @@ void LoadSkillTraitsExternalSettings()
|
|||||||
gSkillTraitValues.ubTERepairRobotPenaltyReduction = iniReader.ReadInteger("Technician","REPAIR_SPEED_ROBOT_PENALTY_REDUCTION", 30, 0, 100);
|
gSkillTraitValues.ubTERepairRobotPenaltyReduction = iniReader.ReadInteger("Technician","REPAIR_SPEED_ROBOT_PENALTY_REDUCTION", 30, 0, 100);
|
||||||
if (gSkillTraitValues.ubTETraitsNumToRepairRobot == 2) {gSkillTraitValues.ubTERepairRobotPenaltyReduction /= 2; }
|
if (gSkillTraitValues.ubTETraitsNumToRepairRobot == 2) {gSkillTraitValues.ubTERepairRobotPenaltyReduction /= 2; }
|
||||||
gSkillTraitValues.fTETraitsCanRestoreItemThreshold = iniReader.ReadBoolean( "Technician", "MERCS_CAN_DO_ADVANCED_REPAIRS", FALSE );
|
gSkillTraitValues.fTETraitsCanRestoreItemThreshold = iniReader.ReadBoolean( "Technician", "MERCS_CAN_DO_ADVANCED_REPAIRS", FALSE );
|
||||||
|
gSkillTraitValues.ubTechLevelNeededForAdvancedRepair = iniReader.ReadInteger("Technician", "TECH_LEVEL_NEEDED_FOR_ADVANCED_REPAIR", 2, 1, 2);
|
||||||
|
|
||||||
// DOCTOR
|
// DOCTOR
|
||||||
gSkillTraitValues.ubDONumberTraitsNeededForSurgery = iniReader.ReadInteger("Doctor","NUMBER_OF_TRAITS_NEEDED_FOR_SURGERY", 1, 0, 2);
|
gSkillTraitValues.ubDONumberTraitsNeededForSurgery = iniReader.ReadInteger("Doctor","NUMBER_OF_TRAITS_NEEDED_FOR_SURGERY", 1, 0, 2);
|
||||||
|
|||||||
+3
-1
@@ -8,8 +8,10 @@
|
|||||||
#include "Campaign Types.h"
|
#include "Campaign Types.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
#define GAME_INI_FILE "Ja2.ini"
|
#define GAME_INI_FILE "Ja2.ini"
|
||||||
|
|
||||||
|
constexpr std::string_view LANGUAGE_INI_FILE{"Language.ini"};
|
||||||
//If you add any options, MAKE sure you add the corresponding string to the Options Screen string array.
|
//If you add any options, MAKE sure you add the corresponding string to the Options Screen string array.
|
||||||
// look up : zOptionsScreenHelpText , zOptionsToggleText
|
// look up : zOptionsScreenHelpText , zOptionsToggleText
|
||||||
//Also, define its initialization and add its load/save to INI lines in : InitGameSettings() , SaveGameSettings() , LoadGameSettings()
|
//Also, define its initialization and add its load/save to INI lines in : InitGameSettings() , SaveGameSettings() , LoadGameSettings()
|
||||||
@@ -105,7 +107,6 @@ enum
|
|||||||
TOPTION_SHOW_ENEMY_LOCATION,
|
TOPTION_SHOW_ENEMY_LOCATION,
|
||||||
TOPTION_ALT_START_AIM,
|
TOPTION_ALT_START_AIM,
|
||||||
TOPTION_ALT_PATHFINDING,
|
TOPTION_ALT_PATHFINDING,
|
||||||
TOPTION_USE_LEGACY_TACTICALAI,
|
|
||||||
|
|
||||||
// arynn: Debug/Cheat
|
// arynn: Debug/Cheat
|
||||||
TOPTION_CHEAT_MODE_OPTIONS_HEADER,
|
TOPTION_CHEAT_MODE_OPTIONS_HEADER,
|
||||||
@@ -2146,6 +2147,7 @@ typedef struct
|
|||||||
UINT8 ubTERepairRobotPenaltyReduction;
|
UINT8 ubTERepairRobotPenaltyReduction;
|
||||||
UINT8 ubTETraitsNumToRepairRobot;
|
UINT8 ubTETraitsNumToRepairRobot;
|
||||||
BOOLEAN fTETraitsCanRestoreItemThreshold;
|
BOOLEAN fTETraitsCanRestoreItemThreshold;
|
||||||
|
UINT8 ubTechLevelNeededForAdvancedRepair; // if we have a high enough technician level, we can repair items above the normal threshold (1 for technician, 2 for engineer)
|
||||||
|
|
||||||
// DOCTOR
|
// DOCTOR
|
||||||
UINT8 ubDONumberTraitsNeededForSurgery;
|
UINT8 ubDONumberTraitsNeededForSurgery;
|
||||||
|
|||||||
+1
-1
@@ -174,7 +174,7 @@ private:
|
|||||||
|
|
||||||
static VideoPlayer s_VP(VideoPlayer::VT_SMK | VideoPlayer::VT_BINK);
|
static VideoPlayer s_VP(VideoPlayer::VT_SMK | VideoPlayer::VT_BINK);
|
||||||
|
|
||||||
extern STR16 gzIntroScreen[];
|
extern STR16* gzIntroScreen;
|
||||||
extern HVSURFACE ghFrameBuffer;
|
extern HVSURFACE ghFrameBuffer;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ extern BOOLEAN gfDontOverRideSaveBuffer; //this variable can be unset if u
|
|||||||
|
|
||||||
|
|
||||||
extern void HandleTacticalUILoseCursorFromOtherScreen( );
|
extern void HandleTacticalUILoseCursorFromOtherScreen( );
|
||||||
extern STR16 pUpdatePanelButtons[];
|
extern STR16* pUpdatePanelButtons;
|
||||||
|
|
||||||
|
|
||||||
#define NUM_CHAT_TOGGLES 2
|
#define NUM_CHAT_TOGGLES 2
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ BOOLEAN gfStartedFromMapScreen = FALSE;
|
|||||||
BOOLEAN fRestoreBackgroundForMessageBox = FALSE;
|
BOOLEAN fRestoreBackgroundForMessageBox = FALSE;
|
||||||
BOOLEAN gfDontOverRideSaveBuffer = TRUE; //this variable can be unset if ur in a non gamescreen and DONT want the msg box to use the save buffer
|
BOOLEAN gfDontOverRideSaveBuffer = TRUE; //this variable can be unset if ur in a non gamescreen and DONT want the msg box to use the save buffer
|
||||||
extern void HandleTacticalUILoseCursorFromOtherScreen( );
|
extern void HandleTacticalUILoseCursorFromOtherScreen( );
|
||||||
extern STR16 pUpdatePanelButtons[];
|
extern STR16* pUpdatePanelButtons;
|
||||||
|
|
||||||
CHAR16 gzUserDefinedButton1[ 128 ];
|
CHAR16 gzUserDefinedButton1[ 128 ];
|
||||||
CHAR16 gzUserDefinedButton2[ 128 ];
|
CHAR16 gzUserDefinedButton2[ 128 ];
|
||||||
|
|||||||
@@ -1822,7 +1822,7 @@ void HandleHighLightedText( BOOLEAN fHighLight )
|
|||||||
bLastRegion = -1;
|
bLastRegion = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bHighLight != -1 )
|
if( bHighLight != -1 && toggle_box_array[bHighLight] != -1)
|
||||||
{
|
{
|
||||||
if( bHighLight < OPT_FIRST_COLUMN_TOGGLE_CUT_OFF )
|
if( bHighLight < OPT_FIRST_COLUMN_TOGGLE_CUT_OFF )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1468,31 +1468,6 @@ BOOLEAN LoadMercBioInfo(UINT8 ubIndex, STR16 pInfoString, STR16 pAddInfo)
|
|||||||
//{
|
//{
|
||||||
// if( pInfoString[i] > 33 )
|
// if( pInfoString[i] > 33 )
|
||||||
// pInfoString[i] -= 1;
|
// pInfoString[i] -= 1;
|
||||||
// #ifdef POLISH
|
|
||||||
// switch( pInfoString[ i ] )
|
|
||||||
// {
|
|
||||||
// case 260: pInfoString[ i ] = 165; break;
|
|
||||||
// case 262: pInfoString[ i ] = 198; break;
|
|
||||||
// case 280: pInfoString[ i ] = 202; break;
|
|
||||||
// case 321: pInfoString[ i ] = 163; break;
|
|
||||||
// case 323: pInfoString[ i ] = 209; break;
|
|
||||||
// case 211: pInfoString[ i ] = 211; break;
|
|
||||||
|
|
||||||
// case 346: pInfoString[ i ] = 338; break;
|
|
||||||
// case 379: pInfoString[ i ] = 175; break;
|
|
||||||
// case 377: pInfoString[ i ] = 143; break;
|
|
||||||
// case 261: pInfoString[ i ] = 185; break;
|
|
||||||
// case 263: pInfoString[ i ] = 230; break;
|
|
||||||
// case 281: pInfoString[ i ] = 234; break;
|
|
||||||
|
|
||||||
// case 322: pInfoString[ i ] = 179; break;
|
|
||||||
// case 324: pInfoString[ i ] = 241; break;
|
|
||||||
// case 243: pInfoString[ i ] = 243; break;
|
|
||||||
// case 347: pInfoString[ i ] = 339; break;
|
|
||||||
// case 380: pInfoString[ i ] = 191; break;
|
|
||||||
// case 378: pInfoString[ i ] = 376; break;
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
DecodeString(pInfoString, SIZE_MERC_BIO_INFO);
|
DecodeString(pInfoString, SIZE_MERC_BIO_INFO);
|
||||||
@@ -1514,31 +1489,6 @@ BOOLEAN LoadMercBioInfo(UINT8 ubIndex, STR16 pInfoString, STR16 pAddInfo)
|
|||||||
//{
|
//{
|
||||||
// if( pAddInfo[i] > 33 )
|
// if( pAddInfo[i] > 33 )
|
||||||
// pAddInfo[i] -= 1;
|
// pAddInfo[i] -= 1;
|
||||||
// #ifdef POLISH
|
|
||||||
// switch( pAddInfo[ i ] )
|
|
||||||
// {
|
|
||||||
// case 260: pAddInfo[ i ] = 165; break;
|
|
||||||
// case 262: pAddInfo[ i ] = 198; break;
|
|
||||||
// case 280: pAddInfo[ i ] = 202; break;
|
|
||||||
// case 321: pAddInfo[ i ] = 163; break;
|
|
||||||
// case 323: pAddInfo[ i ] = 209; break;
|
|
||||||
// case 211: pAddInfo[ i ] = 211; break;
|
|
||||||
|
|
||||||
// case 346: pAddInfo[ i ] = 338; break;
|
|
||||||
// case 379: pAddInfo[ i ] = 175; break;
|
|
||||||
// case 377: pAddInfo[ i ] = 143; break;
|
|
||||||
// case 261: pAddInfo[ i ] = 185; break;
|
|
||||||
// case 263: pAddInfo[ i ] = 230; break;
|
|
||||||
// case 281: pAddInfo[ i ] = 234; break;
|
|
||||||
|
|
||||||
// case 322: pAddInfo[ i ] = 179; break;
|
|
||||||
// case 324: pAddInfo[ i ] = 241; break;
|
|
||||||
// case 243: pAddInfo[ i ] = 243; break;
|
|
||||||
// case 347: pAddInfo[ i ] = 339; break;
|
|
||||||
// case 380: pAddInfo[ i ] = 191; break;
|
|
||||||
// case 378: pAddInfo[ i ] = 376; break;
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
DecodeString(pAddInfo, SIZE_MERC_BIO_INFO);
|
DecodeString(pAddInfo, SIZE_MERC_BIO_INFO);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ extern INT32 iAddExplosives ;
|
|||||||
extern INT32 iAddMechanical ;
|
extern INT32 iAddMechanical ;
|
||||||
|
|
||||||
// pop up strings
|
// pop up strings
|
||||||
extern STR16 pImpPopUpStrings[];
|
extern STR16* pImpPopUpStrings;
|
||||||
|
|
||||||
//extern BOOLEAN fIMPCompletedFlag;
|
//extern BOOLEAN fIMPCompletedFlag;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ void RenderIMPPersonalityEntrance( void );
|
|||||||
void ExitIMPPersonalityEntrance( void );
|
void ExitIMPPersonalityEntrance( void );
|
||||||
void HandleIMPPersonalityEntrance( void );
|
void HandleIMPPersonalityEntrance( void );
|
||||||
|
|
||||||
STR16 pSkillTraitBeginIMPStrings[];
|
extern STR16* pSkillTraitBeginIMPStrings;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ void PrintImpText( void );
|
|||||||
void PrintIMPPersonalityQuizQuestionAndAnsers( void );
|
void PrintIMPPersonalityQuizQuestionAndAnsers( void );
|
||||||
|
|
||||||
// buttons text
|
// buttons text
|
||||||
extern STR16 pImpButtonText[];
|
extern STR16* pImpButtonText;
|
||||||
|
|
||||||
|
|
||||||
// extra strings not found in IMP Text Document
|
// extra strings not found in IMP Text Document
|
||||||
extern STR16 pExtraIMPStrings[];
|
extern STR16* pExtraIMPStrings;
|
||||||
|
|
||||||
extern STR16 pSkillTraitBeginIMPStrings[]; // added - SANDRO
|
extern STR16* pSkillTraitBeginIMPStrings; // added - SANDRO
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
IMP_HOME_1,
|
IMP_HOME_1,
|
||||||
@@ -145,4 +145,4 @@ enum{
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ set(ModularizedTacticalAISrc
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyAIPlanFactory.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyAIPlanFactory.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyCreaturePlan.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyCreaturePlan.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyZombiePlan.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/LegacyZombiePlan.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/BoxerPlan.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/CivilianPlan.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/RobotPlan.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/SoldierPlan.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/NullPlan.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/NullPlan.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/NullPlanFactory.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/NullPlanFactory.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/Plan.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/Plan.cpp"
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Plan.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
/**@class LegacyAIPlan
|
|
||||||
* @brief Component/Concrete Product. Wrapper/Re-Write of DecideAction()
|
|
||||||
*
|
|
||||||
* Wrapper around boxer related AI uplifted from original DecideAction() routines
|
|
||||||
*/
|
|
||||||
class LegacyAIBoxerPlan: public Plan
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
public:
|
|
||||||
LegacyAIBoxerPlan(SOLDIERTYPE* npc);
|
|
||||||
virtual void execute(PlanInputData& environment);
|
|
||||||
virtual bool done() const {return false;}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Plan.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
/**@class LegacyAIPlan
|
|
||||||
* @brief Component/Concrete Product. Wrapper/Re-Write of DecideAction()
|
|
||||||
*
|
|
||||||
* Wrapper around civilian/noncombatant related AI uplifted from original DecideAction() routines
|
|
||||||
*/
|
|
||||||
class CivilianPlan : public Plan
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
public:
|
|
||||||
CivilianPlan(SOLDIERTYPE* npc);
|
|
||||||
virtual void execute(PlanInputData& environment);
|
|
||||||
virtual bool done() const { return false; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Plan.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
/**@class LegacyAIPlan
|
|
||||||
* @brief Component/Concrete Product. Wrapper/Re-Write of DecideAction()
|
|
||||||
*
|
|
||||||
* Wrapper around robot related AI uplifted from original DecideAction() routines
|
|
||||||
*/
|
|
||||||
class RobotPlan : public Plan
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
public:
|
|
||||||
RobotPlan(SOLDIERTYPE* npc);
|
|
||||||
virtual void execute(PlanInputData& environment);
|
|
||||||
virtual bool done() const { return false; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Plan.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
/**@class LegacyAIPlan
|
|
||||||
* @brief Component/Concrete Product. Wrapper/Re-Write of DecideAction()
|
|
||||||
*
|
|
||||||
* Wrapper around soldier related AI uplifted from original DecideAction() routines
|
|
||||||
*/
|
|
||||||
class SoldierPlan : public Plan
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
public:
|
|
||||||
SoldierPlan(SOLDIERTYPE* npc);
|
|
||||||
virtual void execute(PlanInputData& environment);
|
|
||||||
virtual bool done() const { return false; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#include "../include/BoxerPlan.h"
|
|
||||||
#include "../../TacticalAI/ai.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
LegacyAIBoxerPlan::LegacyAIBoxerPlan(SOLDIERTYPE* npc)
|
|
||||||
: Plan(npc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LegacyAIBoxerPlan::execute(PlanInputData& environment)
|
|
||||||
{
|
|
||||||
switch (get_npc()->aiData.bAlertStatus)
|
|
||||||
{
|
|
||||||
case STATUS_GREEN:
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenBoxer(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_YELLOW:
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenBoxer(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_RED:
|
|
||||||
get_npc()->aiData.bAction = DecideActionBlackBoxer(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_BLACK:
|
|
||||||
get_npc()->aiData.bAction = DecideActionBlackBoxer(get_npc());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tactical
|
|
||||||
} // namespace AI
|
|
||||||
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#include "../include/CivilianPlan.h"
|
|
||||||
#include "../../TacticalAI/ai.h"
|
|
||||||
#include "NPC.h"
|
|
||||||
#include "Soldier Profile.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
CivilianPlan::CivilianPlan(SOLDIERTYPE* npc)
|
|
||||||
: Plan(npc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CivilianPlan::execute(PlanInputData& environment)
|
|
||||||
{
|
|
||||||
if ( !environment.turn_based() )
|
|
||||||
{
|
|
||||||
if ( (get_npc()->ubProfile != NO_PROFILE) && (gMercProfiles[get_npc()->ubProfile].ubMiscFlags3 & PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL) )
|
|
||||||
{
|
|
||||||
TriggerNPCWithGivenApproach(get_npc()->ubProfile, APPROACH_DONE_TRAVERSAL, FALSE);
|
|
||||||
gMercProfiles[get_npc()->ubProfile].ubMiscFlags3 &= (~PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL);
|
|
||||||
get_npc()->ubQuoteActionID = 0;
|
|
||||||
// wait a tiny bit
|
|
||||||
get_npc()->aiData.usActionData = 100;
|
|
||||||
get_npc()->aiData.bAction = AI_ACTION_WAIT;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (get_npc()->aiData.bAlertStatus)
|
|
||||||
{
|
|
||||||
case STATUS_GREEN:
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenCivilian(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_YELLOW:
|
|
||||||
get_npc()->aiData.bAction = DecideActionYellowCivilian(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_RED:
|
|
||||||
get_npc()->aiData.bAction = DecideActionRedCivilian(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_BLACK:
|
|
||||||
get_npc()->aiData.bAction = DecideActionBlackCivilian(get_npc());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tactical
|
|
||||||
} // namespace AI
|
|
||||||
|
|
||||||
@@ -7,10 +7,6 @@
|
|||||||
#include "../include/LegacyCreaturePlan.h"
|
#include "../include/LegacyCreaturePlan.h"
|
||||||
#include "../include/LegacyZombiePlan.h"
|
#include "../include/LegacyZombiePlan.h"
|
||||||
#include "../include/LegacyArmedVehiclePlan.h"
|
#include "../include/LegacyArmedVehiclePlan.h"
|
||||||
#include "../include/BoxerPlan.h"
|
|
||||||
#include "../include/CivilianPlan.h"
|
|
||||||
#include "../include/RobotPlan.h"
|
|
||||||
#include "../include/SoldierPlan.h"
|
|
||||||
#include "../include/CrowPlan.h"
|
#include "../include/CrowPlan.h"
|
||||||
#include "../include/PlanList.h"
|
#include "../include/PlanList.h"
|
||||||
|
|
||||||
@@ -18,7 +14,8 @@
|
|||||||
#include "../../Tactical/Soldier Control.h" // For SOLDIERTYPE definition
|
#include "../../Tactical/Soldier Control.h" // For SOLDIERTYPE definition
|
||||||
#include "../../Tactical/Animation Data.h" // For the definition of, wait for it... BLOODCAT!
|
#include "../../Tactical/Animation Data.h" // For the definition of, wait for it... BLOODCAT!
|
||||||
#include "Soldier macros.h"
|
#include "Soldier macros.h"
|
||||||
#include "ai.h"
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
namespace AI
|
namespace AI
|
||||||
@@ -46,11 +43,6 @@ namespace AI
|
|||||||
if(npc->IsZombie())
|
if(npc->IsZombie())
|
||||||
return new LegacyZombiePlan(npc);
|
return new LegacyZombiePlan(npc);
|
||||||
|
|
||||||
if (BOXER(npc)) { return new LegacyAIBoxerPlan(npc); }
|
|
||||||
if (IS_CIV_BODY_TYPE(npc)) { return new CivilianPlan(npc); }
|
|
||||||
if (ENEMYROBOT(npc)) { return new RobotPlan(npc); }
|
|
||||||
if (SoldierAI(npc)) { return new SoldierPlan(npc); }
|
|
||||||
|
|
||||||
return new LegacyAIPlan(npc); // no special plan for other cases yet, return default legacy AI wrapper
|
return new LegacyAIPlan(npc); // no special plan for other cases yet, return default legacy AI wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
#include "../include/RobotPlan.h"
|
|
||||||
#include "../../TacticalAI/ai.h"
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
RobotPlan::RobotPlan(SOLDIERTYPE* npc)
|
|
||||||
: Plan(npc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RobotPlan::execute(PlanInputData& environment)
|
|
||||||
{
|
|
||||||
switch (get_npc()->aiData.bAlertStatus)
|
|
||||||
{
|
|
||||||
case STATUS_GREEN:
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenRobot(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_YELLOW:
|
|
||||||
get_npc()->aiData.bAction = DecideActionYellowRobot(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_RED:
|
|
||||||
get_npc()->aiData.bAction = DecideActionRedRobot(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_BLACK:
|
|
||||||
get_npc()->aiData.bAction = DecideActionBlackRobot(get_npc());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tactical
|
|
||||||
} // namespace AI
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
#include "../include/SoldierPlan.h"
|
|
||||||
#include "../../TacticalAI/ai.h"
|
|
||||||
#include "../../TacticalAI/AIInternals.h" // ACTING_ON_SCHEDULE
|
|
||||||
#include "../../TacticalAI/NPC.h" // NPCReachedDestination
|
|
||||||
#include "../../Tactical/Dialogue Control.h" // DialogueQueueIsEmpty
|
|
||||||
#include "../../Utils/Font Control.h" // ScreenMsg about deadlock
|
|
||||||
#include "../../i18n/include/Text.h" // Sniper warning
|
|
||||||
#include "../../Utils/message.h" // ditto
|
|
||||||
|
|
||||||
namespace AI
|
|
||||||
{
|
|
||||||
namespace tactical
|
|
||||||
{
|
|
||||||
SoldierPlan::SoldierPlan(SOLDIERTYPE* npc)
|
|
||||||
: Plan(npc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SoldierPlan::execute(PlanInputData& environment)
|
|
||||||
{
|
|
||||||
if (!environment.turn_based())
|
|
||||||
{
|
|
||||||
if ((get_npc()->ubProfile != NO_PROFILE) && (gMercProfiles[get_npc()->ubProfile].ubMiscFlags3 & PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL))
|
|
||||||
{
|
|
||||||
TriggerNPCWithGivenApproach(get_npc()->ubProfile, APPROACH_DONE_TRAVERSAL, FALSE);
|
|
||||||
gMercProfiles[get_npc()->ubProfile].ubMiscFlags3 &= (~PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL);
|
|
||||||
get_npc()->ubQuoteActionID = 0;
|
|
||||||
// wait a tiny bit
|
|
||||||
get_npc()->aiData.usActionData = 100;
|
|
||||||
get_npc()->aiData.bAction = AI_ACTION_WAIT;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (get_npc()->bTeam == gbPlayerNum)
|
|
||||||
{
|
|
||||||
if (environment.get_tactical_status().fAutoBandageMode)
|
|
||||||
{
|
|
||||||
get_npc()->aiData.bAction = DecideAutoBandage(get_npc());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_npc()->bTeam != MILITIA_TEAM)
|
|
||||||
{
|
|
||||||
if (!sniperwarning && get_npc()->aiData.bOrders == SNIPER)
|
|
||||||
{
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_WATHCHOUTFORSNIPERS]);
|
|
||||||
sniperwarning = TRUE;
|
|
||||||
|
|
||||||
// Flugente: additional dialogue
|
|
||||||
AdditionalTacticalCharacterDialogue_AllInCurrentSector(NO_PROFILE, ADE_SNIPERWARNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!biggunwarning && FindRocketLauncherOrCannon(get_npc()) != NO_SLOT)
|
|
||||||
{
|
|
||||||
biggunwarning = TRUE;
|
|
||||||
//TODO: don't say this again after reloading a savegame
|
|
||||||
SayQuoteFromAnyBodyInSector(QUOTE_WEARY_SLASH_SUSPUCIOUS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get_npc()->aiData.fAIFlags &= (~AI_CAUTIOUS); // turn off cautious flag
|
|
||||||
// if status override is set, bypass RED/YELLOW and go directly to GREEN!
|
|
||||||
if ((get_npc()->aiData.bBypassToGreen) && (get_npc()->aiData.bAlertStatus < STATUS_BLACK))
|
|
||||||
{
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenSoldier(get_npc());
|
|
||||||
if (!gfTurnBasedAI)
|
|
||||||
{
|
|
||||||
// reset bypass now
|
|
||||||
get_npc()->aiData.bBypassToGreen = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (get_npc()->aiData.bAlertStatus)
|
|
||||||
{
|
|
||||||
case STATUS_GREEN:
|
|
||||||
get_npc()->aiData.bAction = DecideActionGreenSoldier(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_YELLOW:
|
|
||||||
get_npc()->aiData.bAction = DecideActionYellowSoldier(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_RED:
|
|
||||||
get_npc()->aiData.bAction = DecideActionRedSoldier(get_npc());
|
|
||||||
break;
|
|
||||||
case STATUS_BLACK:
|
|
||||||
//if ( gGameSettings.fOptions[TOPTION_USE_LEGACY_TACTICALAI] ) // Commented out for now since new AI is WIP
|
|
||||||
{
|
|
||||||
get_npc()->aiData.bAction = DecideActionBlackSoldier(get_npc());
|
|
||||||
}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// get_npc()->aiData.bAction = DecideActionBlackSoldierUtilityAI(get_npc());
|
|
||||||
//}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUGAIMSG("Deciding for guynum " << (int)get_npc()->ubID << " at gridno " << get_npc()->sGridNo << ", APs " << get_npc()->bActionPoints <<
|
|
||||||
", decided action: " << (int)get_npc()->aiData.bAction << ", data " << (int)get_npc()->aiData.usActionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tactical
|
|
||||||
} // namespace AI
|
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ REPAIR_PASS_SLOTS_TYPE gRepairPassSlotList[ NUM_REPAIR_PASS_TYPES ] =
|
|||||||
{ /* HEADROCK HAM B2.8: LBE Slot pass */ 0, 5, VESTPOCKPOS, LTHIGHPOCKPOS, RTHIGHPOCKPOS, CPACKPOCKPOS, BPACKPOCKPOS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
{ /* HEADROCK HAM B2.8: LBE Slot pass */ 0, 5, VESTPOCKPOS, LTHIGHPOCKPOS, RTHIGHPOCKPOS, CPACKPOCKPOS, BPACKPOCKPOS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
extern STR16 sRepairsDoneString[];
|
extern STR16* sRepairsDoneString;
|
||||||
|
|
||||||
// PopUp Box Handles
|
// PopUp Box Handles
|
||||||
INT32 ghAssignmentBox = -1;
|
INT32 ghAssignmentBox = -1;
|
||||||
@@ -4948,7 +4948,7 @@ static void CollectRepairableItems(SOLDIERTYPE* pRepairSoldier, SOLDIERTYPE* pSo
|
|||||||
// Check for attachments (are there stackable items that can take attachments though?)
|
// Check for attachments (are there stackable items that can take attachments though?)
|
||||||
UINT8 attachmentIndex = 0;
|
UINT8 attachmentIndex = 0;
|
||||||
for (attachmentList::const_iterator iter = (*pObj)[stackIndex]->attachments.begin(); iter != (*pObj)[stackIndex]->attachments.end(); ++iter, ++attachmentIndex) {
|
for (attachmentList::const_iterator iter = (*pObj)[stackIndex]->attachments.begin(); iter != (*pObj)[stackIndex]->attachments.end(); ++iter, ++attachmentIndex) {
|
||||||
if (IsItemRepairable(pRepairSoldier, iter->usItem, (*iter)[attachmentIndex]->data.objectStatus, (*iter)[attachmentIndex]->data.sRepairThreshold )) {
|
if ( iter->exists() && IsItemRepairable(pRepairSoldier, iter->usItem, (*iter)[attachmentIndex]->data.objectStatus, (*iter)[attachmentIndex]->data.sRepairThreshold )) {
|
||||||
// Send the main item, not the attachment
|
// Send the main item, not the attachment
|
||||||
RepairItem item(pObj, pSoldier, (INVENTORY_SLOT) pocketIndex);
|
RepairItem item(pObj, pSoldier, (INVENTORY_SLOT) pocketIndex);
|
||||||
itemsToFix.push(item);
|
itemsToFix.push(item);
|
||||||
@@ -5081,7 +5081,7 @@ OBJECTTYPE* FindRepairableItemInSpecificPocket(SOLDIERTYPE * pSoldier, OBJECTTYP
|
|||||||
// have to check for attachments after...
|
// have to check for attachments after...
|
||||||
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
||||||
// if it's repairable and NEEDS repairing
|
// if it's repairable and NEEDS repairing
|
||||||
if ( IsItemRepairable( pSoldier, iter->usItem, (*iter)[subObject]->data.objectStatus, (*iter)[subObject]->data.sRepairThreshold ) && iter->exists() ) {
|
if ( iter->exists() && IsItemRepairable( pSoldier, iter->usItem, (*iter)[subObject]->data.objectStatus, (*iter)[subObject]->data.sRepairThreshold ) ) {
|
||||||
return( &(*iter) );
|
return( &(*iter) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5171,8 +5171,12 @@ BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE *
|
|||||||
INT16 threshold = 100;
|
INT16 threshold = 100;
|
||||||
if ( gGameExternalOptions.fAdvRepairSystem && (Item[pObj->usItem].usItemClass & (IC_WEAPON|IC_ARMOUR)) )
|
if ( gGameExternalOptions.fAdvRepairSystem && (Item[pObj->usItem].usItemClass & (IC_WEAPON|IC_ARMOUR)) )
|
||||||
{
|
{
|
||||||
if ( !gSkillTraitValues.fTETraitsCanRestoreItemThreshold || !HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ) )
|
if (gSkillTraitValues.fTETraitsCanRestoreItemThreshold && NUM_SKILL_TRAITS(pSoldier, TECHNICIAN_NT) >= gSkillTraitValues.ubTechLevelNeededForAdvancedRepair) // Greysa: added skill check for advanced repair. If we have a high enough technician level, we can repair items above the normal threshold (1 for technician, 2 for engineer)
|
||||||
{
|
{
|
||||||
|
threshold = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
threshold = (*pObj)[ubLoop]->data.sRepairThreshold;
|
threshold = (*pObj)[ubLoop]->data.sRepairThreshold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11085,7 +11089,8 @@ void DetermineWhichAssignmentMenusCanBeShown( void )
|
|||||||
CreateDestroyMouseRegionForFacilityMenu();
|
CreateDestroyMouseRegionForFacilityMenu();
|
||||||
CreateDestroyMouseRegionsForFacilityAssignmentMenu();
|
CreateDestroyMouseRegionsForFacilityAssignmentMenu();
|
||||||
|
|
||||||
if( ( ( gCharactersList[ bSelectedInfoChar ].usSolID->stats.bLife == 0 )||( gCharactersList[bSelectedInfoChar].usSolID->bAssignment == ASSIGNMENT_POW ) ) && ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) )
|
const auto selectedCharacter = gCharactersList[bSelectedInfoChar].usSolID;
|
||||||
|
if( selectedCharacter < NOBODY && ( (selectedCharacter->stats.bLife == 0 )||(selectedCharacter->bAssignment == ASSIGNMENT_POW ) ) && ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) )
|
||||||
{
|
{
|
||||||
// show basic assignment menu
|
// show basic assignment menu
|
||||||
ShowBox( ghRemoveMercAssignBox );
|
ShowBox( ghRemoveMercAssignBox );
|
||||||
|
|||||||
@@ -2481,6 +2481,12 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
|
|||||||
DeleteVideoObjectFromIndex( gpAR->iIndent );
|
DeleteVideoObjectFromIndex( gpAR->iIndent );
|
||||||
DeleteVideoSurfaceFromIndex( gpAR->iInterfaceBuffer );
|
DeleteVideoSurfaceFromIndex( gpAR->iInterfaceBuffer );
|
||||||
|
|
||||||
|
// Load necessary mapinfo to place corpses
|
||||||
|
CHAR8 bFilename[50];
|
||||||
|
INT32 worldRows, worldCols;
|
||||||
|
GetMapFileName(gpAR->ubSectorX, gpAR->ubSectorY, 0, bFilename, TRUE, TRUE);
|
||||||
|
LoadWorldInfoForAutoResolve(bFilename, worldRows, worldCols);
|
||||||
|
|
||||||
if( fDeleteForGood )
|
if( fDeleteForGood )
|
||||||
{ //Delete the soldier instances -- done when we are completely finished.
|
{ //Delete the soldier instances -- done when we are completely finished.
|
||||||
|
|
||||||
@@ -2519,7 +2525,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
|
|||||||
RemoveCharacterFromSquads( gpMercs[ i ].pSoldier );
|
RemoveCharacterFromSquads( gpMercs[ i ].pSoldier );
|
||||||
ChangeSoldiersAssignment( gpMercs[ i ].pSoldier, ASSIGNMENT_DEAD );
|
ChangeSoldiersAssignment( gpMercs[ i ].pSoldier, ASSIGNMENT_DEAD );
|
||||||
|
|
||||||
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpMercs[ i ].pSoldier, RandomGridNo(), ADD_DEAD_SOLDIER_TO_SWEETSPOT );
|
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpMercs[ i ].pSoldier, RandomGridNoUnloadedSector(worldRows, worldCols), ADD_DEAD_SOLDIER_TO_SWEETSPOT );
|
||||||
}
|
}
|
||||||
else if( gpAR->ubBattleStatus == BATTLE_SURRENDERED || gpAR->ubBattleStatus == BATTLE_CAPTURED )
|
else if( gpAR->ubBattleStatus == BATTLE_SURRENDERED || gpAR->ubBattleStatus == BATTLE_CAPTURED )
|
||||||
{
|
{
|
||||||
@@ -2624,7 +2630,8 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: drop sector equipment
|
// Flugente: drop sector equipment
|
||||||
gpCivs[ i ].pSoldier->DropSectorEquipment();
|
const auto gridno = RandomGridNoUnloadedSector(worldRows, worldCols);
|
||||||
|
gpCivs[ i ].pSoldier->DropSectorEquipment(gridno);
|
||||||
|
|
||||||
if( fDeleteForGood && gpCivs[ i ].pSoldier->stats.bLife < OKLIFE/2 )
|
if( fDeleteForGood && gpCivs[ i ].pSoldier->stats.bLife < OKLIFE/2 )
|
||||||
{
|
{
|
||||||
@@ -2649,7 +2656,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
|
|||||||
UpdateMilitia( militia );
|
UpdateMilitia( militia );
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpCivs[ i ].pSoldier, RandomGridNo(), ADD_DEAD_SOLDIER_TO_SWEETSPOT );
|
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpCivs[ i ].pSoldier, gridno, ADD_DEAD_SOLDIER_TO_SWEETSPOT );
|
||||||
StrategicRemoveMilitiaFromSector( gpCivs[ i ].pSoldier->sSectorX, gpCivs[ i ].pSoldier->sSectorY, ubCurrentRank, 1 );
|
StrategicRemoveMilitiaFromSector( gpCivs[ i ].pSoldier->sSectorX, gpCivs[ i ].pSoldier->sSectorY, ubCurrentRank, 1 );
|
||||||
|
|
||||||
if( ProcessLoyalty() )
|
if( ProcessLoyalty() )
|
||||||
@@ -2681,7 +2688,8 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
|
|||||||
TrackEnemiesKilled( ENEMY_KILLED_IN_AUTO_RESOLVE, gpEnemies[ i ].pSoldier->ubSoldierClass ); //add casualty to some statistic
|
TrackEnemiesKilled( ENEMY_KILLED_IN_AUTO_RESOLVE, gpEnemies[ i ].pSoldier->ubSoldierClass ); //add casualty to some statistic
|
||||||
if( ProcessLoyalty() )HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ENEMY_KILLED, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
|
if( ProcessLoyalty() )HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ENEMY_KILLED, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
|
||||||
ProcessQueenCmdImplicationsOfDeath( gpEnemies[ i ].pSoldier );
|
ProcessQueenCmdImplicationsOfDeath( gpEnemies[ i ].pSoldier );
|
||||||
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpEnemies[ i ].pSoldier, RandomGridNo(), ADD_DEAD_SOLDIER_TO_SWEETSPOT );
|
const auto gridno = RandomGridNoUnloadedSector(worldRows, worldCols);
|
||||||
|
AddDeadSoldierToUnLoadedSector( gpAR->ubSectorX, gpAR->ubSectorY, 0, gpEnemies[ i ].pSoldier, gridno, ADD_DEAD_SOLDIER_TO_SWEETSPOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6007,7 +6015,7 @@ void AutoResolveMilitiaDropAndPromote()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: drop sector equipment
|
// Flugente: drop sector equipment
|
||||||
gpCivs[i].pSoldier->DropSectorEquipment( );
|
gpCivs[i].pSoldier->DropSectorEquipment( NOWHERE );
|
||||||
|
|
||||||
if ( gpCivs[i].pSoldier->stats.bLife < OKLIFE / 2 )
|
if ( gpCivs[i].pSoldier->stats.bLife < OKLIFE / 2 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -249,10 +249,6 @@ void AdvanceClock( UINT8 ubWarpCode )
|
|||||||
guiDay = ( guiGameClock / NUM_SEC_IN_DAY );
|
guiDay = ( guiGameClock / NUM_SEC_IN_DAY );
|
||||||
guiHour = ( guiGameClock - ( guiDay * NUM_SEC_IN_DAY ) ) / NUM_SEC_IN_HOUR;
|
guiHour = ( guiGameClock - ( guiDay * NUM_SEC_IN_DAY ) ) / NUM_SEC_IN_HOUR;
|
||||||
guiMin = ( guiGameClock - ( ( guiDay * NUM_SEC_IN_DAY ) + ( guiHour * NUM_SEC_IN_HOUR ) ) ) / NUM_SEC_IN_MIN;
|
guiMin = ( guiGameClock - ( ( guiDay * NUM_SEC_IN_DAY ) + ( guiHour * NUM_SEC_IN_HOUR ) ) ) / NUM_SEC_IN_MIN;
|
||||||
|
|
||||||
uiHourLua = guiHour;
|
|
||||||
uiDayLua = guiDay;
|
|
||||||
uiMinLua = guiMin;
|
|
||||||
|
|
||||||
swprintf( WORLDTIMESTR, L"%s %d, %02d:%02d", gpGameClockString[ STR_GAMECLOCK_DAY_NAME ], guiDay, guiHour, guiMin );
|
swprintf( WORLDTIMESTR, L"%s %d, %02d:%02d", gpGameClockString[ STR_GAMECLOCK_DAY_NAME ], guiDay, guiHour, guiMin );
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,6 @@ CHAR16 zString[128];
|
|||||||
|
|
||||||
HourlyDrugUpdate();
|
HourlyDrugUpdate();
|
||||||
|
|
||||||
RebelCommand::HourlyUpdate();
|
|
||||||
|
|
||||||
// WANNE: This check should avoid the resaving of a loaded auto-save game, when entering tactical
|
// WANNE: This check should avoid the resaving of a loaded auto-save game, when entering tactical
|
||||||
BOOLEAN doAutoSave = TRUE;
|
BOOLEAN doAutoSave = TRUE;
|
||||||
@@ -169,6 +168,10 @@ CHAR16 zString[128];
|
|||||||
|
|
||||||
if (doAutoSave)
|
if (doAutoSave)
|
||||||
{
|
{
|
||||||
|
// We're also using the doAutoSave check to prevent RebelCommand::DailyUpdate() from running a second time when loading an autosave at 00:00
|
||||||
|
RebelCommand::HourlyUpdate();
|
||||||
|
|
||||||
|
|
||||||
if ( AutoSaveToSlot[1] == FALSE && AutoSaveToSlot[2] == FALSE && AutoSaveToSlot[3] == FALSE && AutoSaveToSlot[4] == FALSE )
|
if ( AutoSaveToSlot[1] == FALSE && AutoSaveToSlot[2] == FALSE && AutoSaveToSlot[3] == FALSE && AutoSaveToSlot[4] == FALSE )
|
||||||
AutoSaveToSlot[0] = TRUE;
|
AutoSaveToSlot[0] = TRUE;
|
||||||
|
|
||||||
|
|||||||
@@ -859,6 +859,7 @@ static int l_PlayerTeamFull(lua_State* L);
|
|||||||
|
|
||||||
static int l_ProfilesStrategicInsertionData(lua_State* L);
|
static int l_ProfilesStrategicInsertionData(lua_State* L);
|
||||||
|
|
||||||
|
static int l_HealBoxers(lua_State* L);
|
||||||
static int l_ResetBoxers(lua_State* L);
|
static int l_ResetBoxers(lua_State* L);
|
||||||
|
|
||||||
static int l_AddVolunteers(lua_State* L);
|
static int l_AddVolunteers(lua_State* L);
|
||||||
@@ -912,9 +913,6 @@ static int l_SetIntelAndQuestMapDataForSector(lua_State* L);
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
UINT16 idProfil;
|
UINT16 idProfil;
|
||||||
UINT32 uiHourLua;
|
|
||||||
UINT32 uiDayLua;
|
|
||||||
UINT32 uiMinLua;
|
|
||||||
|
|
||||||
UINT16 PROFILLUA_sSectorX;
|
UINT16 PROFILLUA_sSectorX;
|
||||||
UINT16 PROFILLUA_sSectorY;
|
UINT16 PROFILLUA_sSectorY;
|
||||||
@@ -1189,6 +1187,7 @@ static void IniFunction(lua_State* L, BOOLEAN bQuests)
|
|||||||
lua_register(L, "TacticalCharacterDialogueWithSpecialEvent", l_TacticalCharacterDialogueWithSpecialEvent);
|
lua_register(L, "TacticalCharacterDialogueWithSpecialEvent", l_TacticalCharacterDialogueWithSpecialEvent);
|
||||||
lua_register(L, "SetSalary", l_MercSalary);
|
lua_register(L, "SetSalary", l_MercSalary);
|
||||||
lua_register(L, "SetProfileStrategicInsertionData", l_ProfilesStrategicInsertionData);
|
lua_register(L, "SetProfileStrategicInsertionData", l_ProfilesStrategicInsertionData);
|
||||||
|
lua_register(L, "HealBoxers", l_HealBoxers);
|
||||||
|
|
||||||
//Get merc
|
//Get merc
|
||||||
lua_register(L, "GetDirection", l_GetDirection); //new
|
lua_register(L, "GetDirection", l_GetDirection); //new
|
||||||
@@ -9315,6 +9314,27 @@ static int l_ResetBoxers(lua_State* L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// heal boxers back to max health in case the player stays in sector while the boxers are resting
|
||||||
|
static int l_HealBoxers(lua_State* L)
|
||||||
|
{
|
||||||
|
for (UINT8 i = 0; i < NUM_BOXERS; ++i)
|
||||||
|
{
|
||||||
|
// Get breath back
|
||||||
|
gubBoxerID[i]->bBreath = gubBoxerID[i]->bBreathMax;
|
||||||
|
gubBoxerID[i]->sBreathRed = 0;
|
||||||
|
// Get life back
|
||||||
|
gubBoxerID[i]->stats.bLife = gubBoxerID[i]->stats.bLifeMax;
|
||||||
|
gubBoxerID[i]->bBleeding = 0;
|
||||||
|
// erase insta-healable injury
|
||||||
|
gubBoxerID[i]->iHealableInjury = 0;
|
||||||
|
|
||||||
|
DebugQuestInfo(String("Lua: healed gubBoxerID[%d] %d back to full health", i, gubBoxerID[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Set character to sector Y
|
//Set character to sector Y
|
||||||
static int l_SetCharacterSectorY(lua_State* L)
|
static int l_SetCharacterSectorY(lua_State* L)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ typedef struct
|
|||||||
|
|
||||||
extern ACTION_ITEM_VALUES ActionItemsValues[500];
|
extern ACTION_ITEM_VALUES ActionItemsValues[500];
|
||||||
|
|
||||||
extern UINT32 uiHourLua;
|
|
||||||
extern UINT32 uiDayLua;
|
|
||||||
extern UINT32 uiMinLua;
|
|
||||||
extern UINT16 PROFILLUA_sSectorX;
|
extern UINT16 PROFILLUA_sSectorX;
|
||||||
extern UINT16 PROFILLUA_sSectorY;
|
extern UINT16 PROFILLUA_sSectorY;
|
||||||
extern UINT8 PROFILLUA_bSectorZ;
|
extern UINT8 PROFILLUA_bSectorZ;
|
||||||
|
|||||||
+10
-9
@@ -510,15 +510,6 @@ void IniGlobalGameSetting(lua_State *L)
|
|||||||
lua_pushinteger(L, gubBoxingMatchesWon);
|
lua_pushinteger(L, gubBoxingMatchesWon);
|
||||||
lua_setglobal(L, "gubBoxingMatchesWon");
|
lua_setglobal(L, "gubBoxingMatchesWon");
|
||||||
|
|
||||||
lua_pushinteger(L, uiHourLua);
|
|
||||||
lua_setglobal(L, "cHour");
|
|
||||||
|
|
||||||
lua_pushinteger(L, uiDayLua);
|
|
||||||
lua_setglobal(L, "cDay");
|
|
||||||
|
|
||||||
lua_pushinteger(L, uiMinLua);
|
|
||||||
lua_setglobal(L, "cMin");
|
|
||||||
|
|
||||||
lua_pushinteger(L, gbPlayerNum);
|
lua_pushinteger(L, gbPlayerNum);
|
||||||
lua_setglobal(L, "gbPlayerNum");
|
lua_setglobal(L, "gbPlayerNum");
|
||||||
|
|
||||||
@@ -590,6 +581,16 @@ void IniGlobalGameSetting(lua_State *L)
|
|||||||
lua_pushinteger(L, guiMin);
|
lua_pushinteger(L, guiMin);
|
||||||
lua_setglobal(L, "guiMin");
|
lua_setglobal(L, "guiMin");
|
||||||
|
|
||||||
|
lua_pushinteger(L, guiDay);
|
||||||
|
lua_setglobal(L, "cDay");
|
||||||
|
|
||||||
|
lua_pushinteger(L, guiHour);
|
||||||
|
lua_setglobal(L, "cHour");
|
||||||
|
|
||||||
|
lua_pushinteger(L, guiMin);
|
||||||
|
lua_setglobal(L, "cMin");
|
||||||
|
|
||||||
|
|
||||||
lua_pushinteger(L, guiCurrentScreen);
|
lua_pushinteger(L, guiCurrentScreen);
|
||||||
lua_setglobal(L, "guiCurrentScreen");
|
lua_setglobal(L, "guiCurrentScreen");
|
||||||
|
|
||||||
|
|||||||
@@ -1133,8 +1133,12 @@ void SaveSeenAndUnseenItems( void )
|
|||||||
if(pipl->fExists && pipl->object.ubNumberOfObjects)
|
if(pipl->fExists && pipl->object.ubNumberOfObjects)
|
||||||
{
|
{
|
||||||
uiTotalNumberOfVisibleItems += pipl->object.ubNumberOfObjects;
|
uiTotalNumberOfVisibleItems += pipl->object.ubNumberOfObjects;
|
||||||
if(i > uiNumberOfSeenItems)
|
if (i > uiNumberOfSeenItems)
|
||||||
|
{
|
||||||
pInventoryPoolList[uiNumberOfSeenItems] = *pipl;
|
pInventoryPoolList[uiNumberOfSeenItems] = *pipl;
|
||||||
|
pipl->fExists = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
uiNumberOfSeenItems++;
|
uiNumberOfSeenItems++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6024,10 +6028,7 @@ void HandleItemCooldownFunctions( OBJECTTYPE* itemStack, INT32 deltaSeconds, BOO
|
|||||||
FLOAT newguntemperature = max(0.0f, guntemperature - tickspassed * cooldownfactor ); // ... calculate new temperature ...
|
FLOAT newguntemperature = max(0.0f, guntemperature - tickspassed * cooldownfactor ); // ... calculate new temperature ...
|
||||||
|
|
||||||
#if JA2TESTVERSION
|
#if JA2TESTVERSION
|
||||||
if (guntemperature != newguntemperature)
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", guntemperature, newguntemperature);
|
||||||
{
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", guntemperature, newguntemperature);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(*itemStack)[i]->data.bTemperature = newguntemperature; // ... set new temperature
|
(*itemStack)[i]->data.bTemperature = newguntemperature; // ... set new temperature
|
||||||
@@ -6047,10 +6048,7 @@ void HandleItemCooldownFunctions( OBJECTTYPE* itemStack, INT32 deltaSeconds, BOO
|
|||||||
(*iter)[i]->data.bTemperature = newtemperature; // ... set new temperature
|
(*iter)[i]->data.bTemperature = newtemperature; // ... set new temperature
|
||||||
|
|
||||||
#if JA2TESTVERSION
|
#if JA2TESTVERSION
|
||||||
if (temperature != newtemperature)
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", temperature, newtemperature);
|
||||||
{
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", temperature, newtemperature);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// we assume that there can exist only 1 underbarrel weapon per gun
|
// we assume that there can exist only 1 underbarrel weapon per gun
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ INT32 iHeightOfInitFastHelpText = 0;
|
|||||||
|
|
||||||
extern INT32 giMapContractButton;
|
extern INT32 giMapContractButton;
|
||||||
extern INT32 giCharInfoButton[];
|
extern INT32 giCharInfoButton[];
|
||||||
extern STR16 pUpdatePanelButtons[];
|
extern STR16* pUpdatePanelButtons;
|
||||||
|
|
||||||
// the list of soldiers that are moving
|
// the list of soldiers that are moving
|
||||||
SOLDIERTYPE * pSoldierMovingList[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
|
SOLDIERTYPE * pSoldierMovingList[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
|
||||||
|
|||||||
@@ -904,7 +904,16 @@ BOOLEAN BeginStrategicRemoveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fAddRehireButto
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!is_networked)
|
if (!is_networked)
|
||||||
|
{
|
||||||
|
#ifdef JA2UB
|
||||||
|
// Leave equipment to merc's current sector by default in UB
|
||||||
|
HandleLeavingOfEquipmentInCurrentSector(pSoldier->ubID);
|
||||||
|
StrategicRemoveMerc(pSoldier);
|
||||||
|
pLeaveSoldier = NULL;
|
||||||
|
#else
|
||||||
NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( pSoldier, fAddRehireButton );
|
NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( pSoldier, fAddRehireButton );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// WANNE - MP: Skip all the dialog boxes that appear. Just dismiss the merc
|
// WANNE - MP: Skip all the dialog boxes that appear. Just dismiss the merc
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ extern "C" {
|
|||||||
|
|
||||||
extern CHAR16 gzUserDefinedButton1[ 128 ];
|
extern CHAR16 gzUserDefinedButton1[ 128 ];
|
||||||
extern CHAR16 gzUserDefinedButton2[ 128 ];
|
extern CHAR16 gzUserDefinedButton2[ 128 ];
|
||||||
extern CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT];
|
extern CHAR16 (*pTownNames)[MAX_TOWN_NAME_LENGHT];
|
||||||
|
|
||||||
static size_t MAX_BUTTON_LENGTH = 60;
|
static size_t MAX_BUTTON_LENGTH = 60;
|
||||||
static size_t MAX_BODY_LENGTH = 450;
|
static size_t MAX_BODY_LENGTH = 450;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#define _QUEST_TEXT_H_
|
#define _QUEST_TEXT_H_
|
||||||
|
|
||||||
|
|
||||||
STR16 QuestDescText[];
|
extern STR16 *QuestDescText;
|
||||||
STR16 FactDescText[];
|
extern STR16 *FactDescText;
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class SOLDIERTYPE;
|
|||||||
|
|
||||||
|
|
||||||
#ifdef JA2EDITOR
|
#ifdef JA2EDITOR
|
||||||
extern CHAR16 gszScheduleActions[ NUM_SCHEDULE_ACTIONS ][20];
|
extern CHAR16 (*gszScheduleActions)[20]; // NUM_SCHEDULE_ACTIONS entries
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOLEAN GetEarliestMorningScheduleEvent( SCHEDULENODE *pSchedule, UINT32 * puiTime );
|
BOOLEAN GetEarliestMorningScheduleEvent( SCHEDULENODE *pSchedule, UINT32 * puiTime );
|
||||||
|
|||||||
@@ -4881,14 +4881,14 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
|
|||||||
}
|
}
|
||||||
|
|
||||||
// depending on which cities the player currently holds, we send out attack on multiple cities. We try to make these attacks occur simultaneously, so the player will have to fend off
|
// depending on which cities the player currently holds, we send out attack on multiple cities. We try to make these attacks occur simultaneously, so the player will have to fend off
|
||||||
// multiple gigantic attacks on different cities. Ideally, the attacks will be timed so well that the player cannot use a sqaud in both battles, even with use of the helicopter
|
// multiple gigantic attacks on different cities. Ideally, the attacks will be timed so well that the player cannot use a squad in both battles, even with use of the helicopter
|
||||||
// we first have to check which cities we have to attack. For that, we simply check wether there are troops in the target sector. If not, we will attack here
|
// we first have to check which cities we have to attack. For that, we simply check wether there are troops in the target sector. If not, we will attack here
|
||||||
BOOLEAN fAttack_Grumm = !(SectorInfo[ SEC_H3 ].ubNumTroops > 0);
|
BOOLEAN fAttack_Grumm = !(SectorInfo[ SEC_H3 ].ubNumTroops > 0);
|
||||||
BOOLEAN fAttack_Cambria = !(SectorInfo[ SEC_H8 ].ubNumTroops > 0);
|
BOOLEAN fAttack_Cambria = !(SectorInfo[ SEC_H8 ].ubNumTroops > 0);
|
||||||
BOOLEAN fCambriaSAMOccupied = !(SectorInfo[ SEC_I8 ].ubNumTroops > 0);
|
BOOLEAN fCambriaSAMOccupied = !(SectorInfo[ SEC_I8 ].ubNumTroops > 0);
|
||||||
BOOLEAN fAttack_Alma = !(SectorInfo[ SEC_I13 ].ubNumTroops > 0);
|
BOOLEAN fAttack_Alma = !(SectorInfo[ SEC_I13 ].ubNumTroops > 0);
|
||||||
BOOLEAN fAttack_Balime = !(SectorInfo[ SEC_L11 ].ubNumTroops > 0);
|
BOOLEAN fAttack_Balime = !(SectorInfo[ SEC_L11 ].ubNumTroops > 0);
|
||||||
BOOLEAN fAttack_Chitzena = !(SectorInfo[ SEC_L11 ].ubNumTroops > 0);
|
BOOLEAN fAttack_Chitzena = !(SectorInfo[ SEC_B2 ].ubNumTroops > 0);
|
||||||
|
|
||||||
ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + difficultyMod * 3);
|
ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + difficultyMod * 3);
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ INT16 sWorldSectorLocationOfFirstBattle = 0;
|
|||||||
// preprocess sector for mercs in it
|
// preprocess sector for mercs in it
|
||||||
extern BOOLEAN fSectorsWithSoldiers[ MAP_WORLD_X * MAP_WORLD_X ][ 4 ];
|
extern BOOLEAN fSectorsWithSoldiers[ MAP_WORLD_X * MAP_WORLD_X ][ 4 ];
|
||||||
|
|
||||||
extern CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT];
|
extern CHAR16 (*pTownNames)[MAX_TOWN_NAME_LENGHT];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-2
@@ -613,8 +613,8 @@ extern BOOLEAN gfAutoAIAware;
|
|||||||
extern void HandlePreBattleInterfaceStates();
|
extern void HandlePreBattleInterfaceStates();
|
||||||
|
|
||||||
// the title for the contract button on the character info panel in the upper left portion of the mapscreen
|
// the title for the contract button on the character info panel in the upper left portion of the mapscreen
|
||||||
extern STR16 pContractButtonString[];
|
extern STR16* pContractButtonString;
|
||||||
extern STR16 pBullseyeStrings[];
|
extern STR16* pBullseyeStrings;
|
||||||
|
|
||||||
extern OBJECTTYPE *gpItemDescObject;
|
extern OBJECTTYPE *gpItemDescObject;
|
||||||
|
|
||||||
@@ -8472,6 +8472,12 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent )
|
|||||||
if ( HandleNailsVestFetish( pSoldier, i, NOTHING ) )
|
if ( HandleNailsVestFetish( pSoldier, i, NOTHING ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// tais: never strip Madlab's robot of its installed components (ammo,
|
||||||
|
// targeting, chassis/armour, utility) - the player can't re-install them
|
||||||
|
// and the robot would be left defenceless. Only its cargo slot may be emptied.
|
||||||
|
if ( AM_A_ROBOT( pSoldier ) && i != ROBOT_INVENTORY_SLOT )
|
||||||
|
continue;
|
||||||
|
|
||||||
AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
||||||
DeleteObj(&pSoldier->inv[i]);
|
DeleteObj(&pSoldier->inv[i]);
|
||||||
}
|
}
|
||||||
@@ -12742,6 +12748,10 @@ void HandleShadingOfLinesForContractMenu( void )
|
|||||||
SOLDIERTYPE* pSoldier = gCharactersList[ bSelectedContractChar ].usSolID;
|
SOLDIERTYPE* pSoldier = gCharactersList[ bSelectedContractChar ].usSolID;
|
||||||
const bool multipleMercsSelected = (gSelectedSoldiers.size() > 0) ? true : false;
|
const bool multipleMercsSelected = (gSelectedSoldiers.size() > 0) ? true : false;
|
||||||
|
|
||||||
|
#ifdef JA2UB
|
||||||
|
// No contract renewal in UB
|
||||||
|
const bool atLeastOneAIMmerc = false;
|
||||||
|
#else
|
||||||
bool atLeastOneAIMmerc = false;
|
bool atLeastOneAIMmerc = false;
|
||||||
if (pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC)
|
if (pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC)
|
||||||
{
|
{
|
||||||
@@ -12759,6 +12769,7 @@ void HandleShadingOfLinesForContractMenu( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // JA2UB
|
||||||
|
|
||||||
// is guy in AIM? and well enough to talk and make such decisions?
|
// is guy in AIM? and well enough to talk and make such decisions?
|
||||||
if( (atLeastOneAIMmerc) && ( pSoldier->stats.bLife >= OKLIFE ) )
|
if( (atLeastOneAIMmerc) && ( pSoldier->stats.bLife >= OKLIFE ) )
|
||||||
@@ -15366,7 +15377,10 @@ BOOLEAN CanExtendContractForCharSlot( INT16 bCharNumber )
|
|||||||
|
|
||||||
// if a vehicle, in transit, or a POW
|
// if a vehicle, in transit, or a POW
|
||||||
if( /*( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ||*/
|
if( /*( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ||*/
|
||||||
|
#ifndef JA2UB
|
||||||
|
// Allow contract box in UB before helicopter ride, so mercs can be dismissed if player has hired more than 6 mercs
|
||||||
( pSoldier->bAssignment == IN_TRANSIT ) ||
|
( pSoldier->bAssignment == IN_TRANSIT ) ||
|
||||||
|
#endif
|
||||||
( pSoldier->bAssignment == ASSIGNMENT_POW ) )
|
( pSoldier->bAssignment == ASSIGNMENT_POW ) )
|
||||||
{
|
{
|
||||||
// can't extend contracts at this time
|
// can't extend contracts at this time
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ extern HVSURFACE ghFrameBuffer;
|
|||||||
extern BOOLEAN gfOverrideSector;
|
extern BOOLEAN gfOverrideSector;
|
||||||
|
|
||||||
extern BOOLEAN sBadSectorsList[WORLD_MAP_X][WORLD_MAP_X];
|
extern BOOLEAN sBadSectorsList[WORLD_MAP_X][WORLD_MAP_X];
|
||||||
extern STR16 pBullseyeStrings[];
|
extern STR16* pBullseyeStrings;
|
||||||
|
|
||||||
extern void HandleRPCDescription( );
|
extern void HandleRPCDescription( );
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,3 @@
|
|||||||
# priority (LOW,HIGH) and description
|
# priority (LOW,HIGH) and description
|
||||||
|
|
||||||
LOW readd the C4838 (https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4838) warning to CMakeLists.txt once they're all fixed in the code
|
LOW readd the C4838 (https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4838) warning to CMakeLists.txt once they're all fixed in the code
|
||||||
HIGH get rid of ENGLISH, GERMAN, etc preprocessor definitions completely. that way i18n can be built just once and language can be changed in the options screen pending game restart (hotloading will likely require more work)
|
|
||||||
|
|||||||
@@ -1423,7 +1423,7 @@ void AddObjectToArmsDealerInventory( UINT8 ubArmsDealer, OBJECTTYPE *pObject )
|
|||||||
for (attachmentList::iterator iter = seperateObject[0]->attachments.begin(); iter != seperateObject[0]->attachments.end();) {
|
for (attachmentList::iterator iter = seperateObject[0]->attachments.begin(); iter != seperateObject[0]->attachments.end();) {
|
||||||
// ARM: Note: this is only used for selling, not repairs, so attachmentes are seperated when sold to a dealer
|
// ARM: Note: this is only used for selling, not repairs, so attachmentes are seperated when sold to a dealer
|
||||||
// If the attachment is detachable
|
// If the attachment is detachable
|
||||||
if (! (Item[ iter->usItem ].inseparable ) && iter->exists())
|
if (! (iter->exists() && Item[ iter->usItem ].inseparable))
|
||||||
{
|
{
|
||||||
// add this particular attachment (they can't be imprinted, or themselves have attachments!)
|
// add this particular attachment (they can't be imprinted, or themselves have attachments!)
|
||||||
AddObjectToArmsDealerInventory( ubArmsDealer, &(*iter) );
|
AddObjectToArmsDealerInventory( ubArmsDealer, &(*iter) );
|
||||||
@@ -1931,7 +1931,7 @@ UINT32 CalculateObjectItemRepairTime( UINT8 ubArmsDealer, OBJECTTYPE *pItemObjec
|
|||||||
// add time to repair any attachments on it
|
// add time to repair any attachments on it
|
||||||
for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) {
|
||||||
// if damaged and repairable
|
// if damaged and repairable
|
||||||
if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) && iter->exists())
|
if ( iter->exists() && ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) )
|
||||||
{
|
{
|
||||||
//uiRepairTime += CalculateSimpleItemRepairTime( ubArmsDealer, iter->usItem, (*iter)[x]->data.objectStatus );
|
//uiRepairTime += CalculateSimpleItemRepairTime( ubArmsDealer, iter->usItem, (*iter)[x]->data.objectStatus );
|
||||||
uiRepairTime += CalculateObjectItemRepairTime( ubArmsDealer, &(*iter) );
|
uiRepairTime += CalculateObjectItemRepairTime( ubArmsDealer, &(*iter) );
|
||||||
@@ -1988,7 +1988,7 @@ UINT32 CalculateObjectItemRepairCost( UINT8 ubArmsDealer, OBJECTTYPE *pItemObjec
|
|||||||
// add cost of repairing any attachments on it
|
// add cost of repairing any attachments on it
|
||||||
for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) {
|
||||||
// if damaged and repairable
|
// if damaged and repairable
|
||||||
if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) && iter->exists())
|
if ( iter->exists() && ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) )
|
||||||
{
|
{
|
||||||
uiRepairCost += CalculateObjectItemRepairCost( ubArmsDealer, &(*iter));
|
uiRepairCost += CalculateObjectItemRepairCost( ubArmsDealer, &(*iter));
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-8
@@ -21,7 +21,6 @@
|
|||||||
#include "GameSettings.h" // added by SANDRO
|
#include "GameSettings.h" // added by SANDRO
|
||||||
#include <Font Control.h>
|
#include <Font Control.h>
|
||||||
#include <message.h>
|
#include <message.h>
|
||||||
#include "Soldier macros.h"
|
|
||||||
|
|
||||||
INT32 gsBoxerGridNo[ NUM_BOXERS ] = { 11393, 11233, 11073 };
|
INT32 gsBoxerGridNo[ NUM_BOXERS ] = { 11393, 11233, 11073 };
|
||||||
SoldierID gubBoxerID[ NUM_BOXERS ] = { NOBODY, NOBODY, NOBODY };
|
SoldierID gubBoxerID[ NUM_BOXERS ] = { NOBODY, NOBODY, NOBODY };
|
||||||
@@ -55,7 +54,7 @@ void ExitBoxing( void )
|
|||||||
|
|
||||||
if ( pSoldier != NULL )
|
if ( pSoldier != NULL )
|
||||||
{
|
{
|
||||||
if ( BOXER(pSoldier) && InARoom( pSoldier->sGridNo, &usRoom ) && usRoom == BOXING_RING )
|
if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) && InARoom( pSoldier->sGridNo, &usRoom ) && usRoom == BOXING_RING )
|
||||||
{
|
{
|
||||||
if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC )
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC )
|
||||||
{
|
{
|
||||||
@@ -239,7 +238,7 @@ static void CountPeopleInBoxingRingAndDoActions( void )
|
|||||||
{
|
{
|
||||||
++ubPlayersInRing;
|
++ubPlayersInRing;
|
||||||
|
|
||||||
if ( !pNonBoxingPlayer && !BOXER(pSoldier) )
|
if ( !pNonBoxingPlayer && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
pNonBoxingPlayer = pSoldier;
|
pNonBoxingPlayer = pSoldier;
|
||||||
}
|
}
|
||||||
@@ -291,7 +290,7 @@ static void CountPeopleInBoxingRingAndDoActions( void )
|
|||||||
// ladieees and gennleman, we have a fight!
|
// ladieees and gennleman, we have a fight!
|
||||||
for (uiLoop = 0; uiLoop < 2; ++uiLoop)
|
for (uiLoop = 0; uiLoop < 2; ++uiLoop)
|
||||||
{
|
{
|
||||||
if (!BOXER(pInRing[uiLoop]))
|
if (!(pInRing[uiLoop]->flags.uiStatusFlags & SOLDIER_BOXER))
|
||||||
{
|
{
|
||||||
// set as boxer!
|
// set as boxer!
|
||||||
pInRing[uiLoop]->flags.uiStatusFlags |= SOLDIER_BOXER;
|
pInRing[uiLoop]->flags.uiStatusFlags |= SOLDIER_BOXER;
|
||||||
@@ -454,11 +453,14 @@ BOOLEAN BoxerAvailable( void )
|
|||||||
return( FALSE );
|
return( FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE THIS IS NOW BROKEN BECAUSE NPC.C ASSUMES THAT BOXERSAVAILABLE < 3 IS A
|
|
||||||
// SEQUEL FIGHT. Maybe we could check Kingpin's location instead!
|
|
||||||
UINT8 BoxersAvailable( void )
|
UINT8 BoxersAvailable( void )
|
||||||
{
|
{
|
||||||
UINT8 ubCount = 0;
|
UINT8 ubCount = 0;
|
||||||
|
// Should also run CheckOnBoxers to make sure boxer IDs are set for this function similarly to BoxerAvailable
|
||||||
|
if (CheckOnBoxers() == FALSE)
|
||||||
|
{
|
||||||
|
return(ubCount);
|
||||||
|
}
|
||||||
|
|
||||||
for (UINT8 ubLoop = 0; ubLoop < NUM_BOXERS; ++ubLoop)
|
for (UINT8 ubLoop = 0; ubLoop < NUM_BOXERS; ++ubLoop)
|
||||||
{
|
{
|
||||||
@@ -512,7 +514,7 @@ void BoxingMovementCheck( SOLDIERTYPE * pSoldier )
|
|||||||
// someone moving in/into the ring
|
// someone moving in/into the ring
|
||||||
CountPeopleInBoxingRingAndDoActions();
|
CountPeopleInBoxingRingAndDoActions();
|
||||||
}
|
}
|
||||||
else if ( ( gTacticalStatus.bBoxingState == BOXING ) && BOXER(pSoldier) )
|
else if ( ( gTacticalStatus.bBoxingState == BOXING ) && ( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) )
|
||||||
{
|
{
|
||||||
// boxer stepped out of the ring!
|
// boxer stepped out of the ring!
|
||||||
BoxingPlayerDisqualified( pSoldier, BOXER_OUT_OF_RING );
|
BoxingPlayerDisqualified( pSoldier, BOXER_OUT_OF_RING );
|
||||||
@@ -562,7 +564,7 @@ void ClearAllBoxerFlags( void )
|
|||||||
{
|
{
|
||||||
for (UINT32 uiSlot = 0; uiSlot < guiNumMercSlots; ++uiSlot)
|
for (UINT32 uiSlot = 0; uiSlot < guiNumMercSlots; ++uiSlot)
|
||||||
{
|
{
|
||||||
if ( MercSlots[ uiSlot ] && BOXER(MercSlots[ uiSlot ]) )
|
if ( MercSlots[ uiSlot ] && MercSlots[ uiSlot ]->flags.uiStatusFlags & SOLDIER_BOXER )
|
||||||
{
|
{
|
||||||
// Flugente: nuke the entire opponent count, remove boxing flag, reevaluate opponent list
|
// Flugente: nuke the entire opponent count, remove boxing flag, reevaluate opponent list
|
||||||
DecayIndividualOpplist(MercSlots[uiSlot]);
|
DecayIndividualOpplist(MercSlots[uiSlot]);
|
||||||
|
|||||||
+412
-556
File diff suppressed because it is too large
Load Diff
@@ -758,29 +758,6 @@ void EatFromInventory( SOLDIERTYPE *pSoldier, BOOLEAN fcanteensonly )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrinkFromInventory(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
if ( !pSoldier )
|
|
||||||
return;
|
|
||||||
|
|
||||||
INT8 invsize = pSoldier->inv.size();
|
|
||||||
|
|
||||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop )
|
|
||||||
{
|
|
||||||
if ( pSoldier->inv[bLoop].exists() && ItemIsCanteen(pSoldier->inv[bLoop].usItem) )
|
|
||||||
{
|
|
||||||
OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]);
|
|
||||||
|
|
||||||
if ( pObj && TotalPoints(pObj) > 1 )
|
|
||||||
{
|
|
||||||
//ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_DRINKS], pSoldier->GetName());
|
|
||||||
ApplyConsumable(pSoldier, pObj, false, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HourlyFoodUpdate( void )
|
void HourlyFoodUpdate( void )
|
||||||
{
|
{
|
||||||
SoldierID bMercID, bLastTeamID;
|
SoldierID bMercID, bLastTeamID;
|
||||||
|
|||||||
@@ -108,6 +108,5 @@ void SoldierAutoFillCanteens(SOLDIERTYPE *pSoldier);
|
|||||||
BOOLEAN HasFoodInInventory( SOLDIERTYPE *pSoldier, BOOLEAN fCheckFood, BOOLEAN fCheckDrink );
|
BOOLEAN HasFoodInInventory( SOLDIERTYPE *pSoldier, BOOLEAN fCheckFood, BOOLEAN fCheckDrink );
|
||||||
|
|
||||||
void DrinkFromWaterTap( SOLDIERTYPE *pSoldier );
|
void DrinkFromWaterTap( SOLDIERTYPE *pSoldier );
|
||||||
void DrinkFromInventory(SOLDIERTYPE* pSoldier);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7035,7 +7035,7 @@ UINT8 StealItems(SOLDIERTYPE* pSoldier,SOLDIERTYPE* pOpponent, UINT8* ubIndexRet
|
|||||||
if ((pObject->exists() == true) && !ItemIsUndroppableByDefault(pObject->usItem)) // CHECK! Undroppable items cannot be stolen - SANDRO
|
if ((pObject->exists() == true) && !ItemIsUndroppableByDefault(pObject->usItem)) // CHECK! Undroppable items cannot be stolen - SANDRO
|
||||||
{
|
{
|
||||||
// Is the enemy collapsed
|
// Is the enemy collapsed
|
||||||
if ( pOpponent->stats.bLife < OKLIFE || pOpponent->bCollapsed )
|
if ( pOpponent->stats.bLife < OKLIFE || pOpponent->bCollapsed || (pOpponent->usSoldierFlagMask & SOLDIER_POW) )
|
||||||
{
|
{
|
||||||
// We can steal any of his items in the inventory
|
// We can steal any of his items in the inventory
|
||||||
fStealItem = TRUE;
|
fStealItem = TRUE;
|
||||||
|
|||||||
+2
-51
@@ -73,7 +73,7 @@
|
|||||||
#include "TeamTurns.h"
|
#include "TeamTurns.h"
|
||||||
#include "Map Screen Interface.h" // added by Flugente for SquadNames
|
#include "Map Screen Interface.h" // added by Flugente for SquadNames
|
||||||
#include "Keys.h" // added by silversurfer for door handling from the side
|
#include "Keys.h" // added by silversurfer for door handling from the side
|
||||||
#include "Cheats.h"
|
|
||||||
#include "AIInternals.h"
|
#include "AIInternals.h"
|
||||||
extern BOOLEAN gubWorldTileInLight[MAX_ALLOWED_WORLD_MAX];
|
extern BOOLEAN gubWorldTileInLight[MAX_ALLOWED_WORLD_MAX];
|
||||||
extern BOOLEAN gubIsCorpseThere[MAX_ALLOWED_WORLD_MAX];
|
extern BOOLEAN gubIsCorpseThere[MAX_ALLOWED_WORLD_MAX];
|
||||||
@@ -372,7 +372,7 @@ BOOLEAN gfDisplayTimerCursor = FALSE;
|
|||||||
UINT32 guiTimerCursorID = 0;
|
UINT32 guiTimerCursorID = 0;
|
||||||
UINT32 guiTimerLastUpdate = 0;
|
UINT32 guiTimerLastUpdate = 0;
|
||||||
UINT32 guiTimerCursorDelay = 0;
|
UINT32 guiTimerCursorDelay = 0;
|
||||||
UINT8 gRenderDebugInfoMode = DEBUG_OFF;
|
|
||||||
|
|
||||||
CHAR16 gzLocation[ 20 ];
|
CHAR16 gzLocation[ 20 ];
|
||||||
BOOLEAN gfLocation = FALSE;
|
BOOLEAN gfLocation = FALSE;
|
||||||
@@ -500,54 +500,6 @@ void GetMercOknoDirection( SoldierID ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pf
|
|||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
void HandleRenderDebugInfoModes()
|
|
||||||
{
|
|
||||||
if (DEBUG_CHEAT_LEVEL())
|
|
||||||
{
|
|
||||||
switch (gRenderDebugInfoMode)
|
|
||||||
{
|
|
||||||
case DEBUG_PATHFINDING:
|
|
||||||
// Nothing to do here, pathfinding info is filled in the pathing functions.
|
|
||||||
break;
|
|
||||||
case DEBUG_THREATVALUE:
|
|
||||||
break;
|
|
||||||
case DEBUG_COVERVALUE:
|
|
||||||
// Calculate cover values for pSoldier under cursor, or for currently selected merc, if nobody is under the cursor.
|
|
||||||
if (gTacticalStatus.Team[OUR_TEAM].bTeamActive)
|
|
||||||
{
|
|
||||||
static SOLDIERTYPE* previousSoldier = nullptr;
|
|
||||||
static INT32 previousLocation = NOWHERE;
|
|
||||||
static UINT8 previousStance = 0;
|
|
||||||
|
|
||||||
SoldierID usSoldierIndex = NOBODY;
|
|
||||||
UINT32 uiMercFlags;
|
|
||||||
FindSoldierFromMouse(&usSoldierIndex, &uiMercFlags);
|
|
||||||
if (usSoldierIndex == NOBODY)
|
|
||||||
{
|
|
||||||
usSoldierIndex = gusSelectedSoldier;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usSoldierIndex != NOBODY)
|
|
||||||
{
|
|
||||||
// Get Soldier
|
|
||||||
INT32 iPercentBetter;
|
|
||||||
SOLDIERTYPE* pSoldier;
|
|
||||||
GetSoldier(&pSoldier, usSoldierIndex);
|
|
||||||
if (previousSoldier != pSoldier || previousLocation != pSoldier->sGridNo || previousStance != gAnimControl[pSoldier->usAnimState].ubEndHeight)
|
|
||||||
{
|
|
||||||
FindBestNearbyCover(pSoldier, pSoldier->aiData.bAIMorale, &iPercentBetter, NOWHERE, false);
|
|
||||||
previousSoldier = pSoldier;
|
|
||||||
previousLocation = pSoldier->sGridNo;
|
|
||||||
previousStance = gAnimControl[pSoldier->usAnimState].ubEndHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: // off
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PreventFromTheFreezingBug(SOLDIERTYPE* pSoldier)
|
void PreventFromTheFreezingBug(SOLDIERTYPE* pSoldier)
|
||||||
{
|
{
|
||||||
@@ -721,7 +673,6 @@ UINT32 HandleTacticalUI( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleRenderDebugInfoModes();
|
|
||||||
// Check if current event has changed and clear event if so, to prepare it for execution
|
// Check if current event has changed and clear event if so, to prepare it for execution
|
||||||
// Clearing it does things like set first time flag, param variables, etc
|
// Clearing it does things like set first time flag, param variables, etc
|
||||||
if ( uiNewEvent != guiOldEvent )
|
if ( uiNewEvent != guiOldEvent )
|
||||||
|
|||||||
@@ -184,7 +184,6 @@ extern UINT32 guiCurrentEvent;
|
|||||||
extern INT16 gsSelectedLevel;
|
extern INT16 gsSelectedLevel;
|
||||||
extern BOOLEAN gfPlotNewMovement;
|
extern BOOLEAN gfPlotNewMovement;
|
||||||
extern UINT32 guiPendingOverrideEvent;
|
extern UINT32 guiPendingOverrideEvent;
|
||||||
extern UINT8 gRenderDebugInfoMode;
|
|
||||||
|
|
||||||
|
|
||||||
// GLOBALS
|
// GLOBALS
|
||||||
|
|||||||
@@ -10073,7 +10073,7 @@ void DrawArmorValues( OBJECTTYPE * gpItemDescObject )
|
|||||||
UINT16 iFinalProtectionValue = iProtectionValue;
|
UINT16 iFinalProtectionValue = iProtectionValue;
|
||||||
for (attachmentList::iterator iter = (*gpItemDescObject)[0]->attachments.begin(); iter != (*gpItemDescObject)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*gpItemDescObject)[0]->attachments.begin(); iter != (*gpItemDescObject)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (Item[ iter->usItem ].usItemClass == IC_ARMOUR)
|
if ( iter->exists() && Item[ iter->usItem ].usItemClass == IC_ARMOUR)
|
||||||
{
|
{
|
||||||
iFinalProtectionValue += Armour[Item[iter->usItem].ubClassIndex].ubProtection;
|
iFinalProtectionValue += Armour[Item[iter->usItem].ubClassIndex].ubProtection;
|
||||||
}
|
}
|
||||||
@@ -10099,7 +10099,7 @@ void DrawArmorValues( OBJECTTYPE * gpItemDescObject )
|
|||||||
UINT16 iComparedFinalProtectionValue = iComparedProtectionValue;
|
UINT16 iComparedFinalProtectionValue = iComparedProtectionValue;
|
||||||
for (attachmentList::iterator iter = (*gpComparedItemDescObject)[0]->attachments.begin(); iter != (*gpComparedItemDescObject)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*gpComparedItemDescObject)[0]->attachments.begin(); iter != (*gpComparedItemDescObject)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (Item[ iter->usItem ].usItemClass == IC_ARMOUR)
|
if ( iter->exists() && Item[ iter->usItem ].usItemClass == IC_ARMOUR)
|
||||||
{
|
{
|
||||||
iComparedFinalProtectionValue += Armour[Item[iter->usItem].ubClassIndex].ubProtection;
|
iComparedFinalProtectionValue += Armour[Item[iter->usItem].ubClassIndex].ubProtection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,13 +643,29 @@ void popupCallbackItem(INT16 itemId){
|
|||||||
i++;p++;
|
i++;p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJECTTYPE pObjTmp;
|
static OBJECTTYPE pObjTmp;
|
||||||
pObjTmp.initialize();
|
pObjTmp.initialize();
|
||||||
|
|
||||||
if( bestStack->RemoveObjectAtIndex(leastDamagedIndex, &pObjTmp) ){
|
if( bestStack->RemoveObjectAtIndex(leastDamagedIndex, &pObjTmp) ){
|
||||||
gpItemPointer = &pObjTmp; // pick up the object (or stack)
|
gpItemPointer = &pObjTmp; // pick up the object (or stack)
|
||||||
DoAttachment((UINT8)gubPopupStatusIndex, guiPopupItemPos); // try to attach it
|
DoAttachment((UINT8)gubPopupStatusIndex, guiPopupItemPos); // try to attach it
|
||||||
//gpItemPointer = NULL; // dont drop it!
|
|
||||||
|
// If attaching failed, change mouse cursor to item as we're still holding it
|
||||||
|
if ( gpItemPointer->exists() ) {
|
||||||
|
// Set mouse
|
||||||
|
guiExternVo = GetInterfaceGraphicForItem(&(Item[gpItemPointer->usItem]));
|
||||||
|
gusExternVoSubIndex = Item[gpItemPointer->usItem].ubGraphicNum;
|
||||||
|
|
||||||
|
MSYS_ChangeRegionCursor(&gMPanelRegion, EXTERN_CURSOR);
|
||||||
|
MSYS_SetCurrentCursor(EXTERN_CURSOR);
|
||||||
|
fMapInventoryItem = TRUE;
|
||||||
|
fTeamPanelDirty = TRUE;
|
||||||
|
|
||||||
|
//Dirty interface
|
||||||
|
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||||
|
|
||||||
|
UpdateItemHatches();
|
||||||
|
}
|
||||||
|
|
||||||
gItemDescAttachmentPopups[giActiveAttachmentPopup]->hide();
|
gItemDescAttachmentPopups[giActiveAttachmentPopup]->hide();
|
||||||
RenderItemDescriptionBox();
|
RenderItemDescriptionBox();
|
||||||
@@ -6060,7 +6076,8 @@ void ItemDescAmmoCallback(GUI_BUTTON *btn,INT32 reason)
|
|||||||
gfItemAmmoDown = FALSE;
|
gfItemAmmoDown = FALSE;
|
||||||
|
|
||||||
//CHRISL: We dont' want to be able to reload guns using the ammo crate from this function
|
//CHRISL: We dont' want to be able to reload guns using the ammo crate from this function
|
||||||
if((gpItemPointer != NULL && Magazine[Item[gpItemPointer->usItem].ubClassIndex].ubMagType >= AMMO_BOX) || !EnoughPoints(gpItemDescSoldier, APBPConstants[AP_RELOAD_GUN], 0, TRUE))//dnl ch65 040913
|
//Greysa: add check for ammo item
|
||||||
|
if( gpItemPointer != NULL && ( (Item[gpItemPointer->usItem].usItemClass != IC_AMMO || Magazine[Item[gpItemPointer->usItem].ubClassIndex].ubMagType >= AMMO_BOX) ) || !EnoughPoints(gpItemDescSoldier, APBPConstants[AP_RELOAD_GUN], 0, TRUE) )//dnl ch65 040913
|
||||||
{
|
{
|
||||||
fInterfacePanelDirty = DIRTYLEVEL2;
|
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||||
btn->uiFlags &= (~BUTTON_CLICKED_ON );
|
btn->uiFlags &= (~BUTTON_CLICKED_ON );
|
||||||
@@ -6083,7 +6100,8 @@ void ItemDescAmmoCallback(GUI_BUTTON *btn,INT32 reason)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//holding an item
|
//holding an item
|
||||||
if(Magazine[Item[gpItemPointer->usItem].ubClassIndex].ubCalibre == Weapon[Item[gpItemDescObject->usItem].ubClassIndex].ubCalibre)
|
//Greysa: add check for ammo item
|
||||||
|
if( Item[gpItemPointer->usItem].usItemClass == IC_AMMO && Magazine[Item[gpItemPointer->usItem].ubClassIndex].ubCalibre == Weapon[Item[gpItemDescObject->usItem].ubClassIndex].ubCalibre )
|
||||||
{
|
{
|
||||||
ReloadGun(gpItemDescSoldier, gpItemDescObject, gpItemPointer, ubStatusIndex);
|
ReloadGun(gpItemDescSoldier, gpItemDescObject, gpItemPointer, ubStatusIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6265,7 +6265,7 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier)
|
|||||||
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] >= gGameExternalOptions.usTurnsToUncover )
|
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] >= gGameExternalOptions.usTurnsToUncover )
|
||||||
{
|
{
|
||||||
// are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property
|
// are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property
|
||||||
if (ISVIP(pSoldier) && !pSoldier->bSectorZ )
|
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && !pSoldier->bSectorZ )
|
||||||
{
|
{
|
||||||
if ( PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )
|
if ( PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )
|
||||||
{
|
{
|
||||||
|
|||||||
+137
-104
@@ -1995,7 +1995,7 @@ OBJECTTYPE* FindAttachment( OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject )
|
|||||||
{
|
{
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
||||||
if (iter->usItem == usItem && iter->exists())
|
if ( iter->exists() && iter->usItem == usItem )
|
||||||
{
|
{
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
@@ -2008,7 +2008,7 @@ OBJECTTYPE* FindAttachmentByClass( OBJECTTYPE * pObj, UINT32 uiItemClass, UINT8
|
|||||||
{
|
{
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == uiItemClass && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].usItemClass == uiItemClass )
|
||||||
{
|
{
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
@@ -2021,7 +2021,7 @@ OBJECTTYPE* FindAttachmentByAttachmentClass( OBJECTTYPE * pObj, UINT32 uiAttachm
|
|||||||
{
|
{
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].attachmentclass == uiAttachmentClass && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].attachmentclass == uiAttachmentClass )
|
||||||
{
|
{
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
@@ -2139,7 +2139,7 @@ OBJECTTYPE* FindNonSmokeLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon
|
|||||||
|
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (ValidLaunchable( iter->usItem, usWeapon) && Explosive[Item[iter->usItem].ubClassIndex].ubType != EXPLOSV_SMOKE && iter->exists())
|
if ( iter->exists() && ValidLaunchable( iter->usItem, usWeapon) && Explosive[Item[iter->usItem].ubClassIndex].ubType != EXPLOSV_SMOKE )
|
||||||
{
|
{
|
||||||
return &(*iter);
|
return &(*iter);
|
||||||
}
|
}
|
||||||
@@ -2162,7 +2162,7 @@ BOOLEAN ItemHasAttachments( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 ite
|
|||||||
{
|
{
|
||||||
for(attachmentList::iterator att = (*pObj)[iter]->attachments.begin(); att != (*pObj)[iter]->attachments.end(); ++att)
|
for(attachmentList::iterator att = (*pObj)[iter]->attachments.begin(); att != (*pObj)[iter]->attachments.end(); ++att)
|
||||||
{
|
{
|
||||||
if ( att->usItem != 0 && !ItemIsHiddenAttachment(att->usItem) )
|
if ( att->exists() && att->usItem != 0 && !ItemIsHiddenAttachment(att->usItem) )
|
||||||
{
|
{
|
||||||
attachmentHidden = FALSE;
|
attachmentHidden = FALSE;
|
||||||
break;
|
break;
|
||||||
@@ -2178,7 +2178,7 @@ BOOLEAN ItemHasAttachments( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 ite
|
|||||||
{
|
{
|
||||||
for(attachmentList::iterator att = (*pObj)[iter]->attachments.begin(); att != (*pObj)[iter]->attachments.end(); ++att)
|
for(attachmentList::iterator att = (*pObj)[iter]->attachments.begin(); att != (*pObj)[iter]->attachments.end(); ++att)
|
||||||
{
|
{
|
||||||
if ( att->usItem != 0 && !ItemIsHiddenAttachment(att->usItem) )
|
if ( att->exists() && att->usItem != 0 && !ItemIsHiddenAttachment(att->usItem) )
|
||||||
{
|
{
|
||||||
attachmentHidden = FALSE;
|
attachmentHidden = FALSE;
|
||||||
break;
|
break;
|
||||||
@@ -3872,13 +3872,111 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier, bool aReloadEvenIfNotEmpty )
|
|||||||
{
|
{
|
||||||
OBJECTTYPE *pObj, *pObj2;
|
OBJECTTYPE *pObj, *pObj2;
|
||||||
INT8 bSlot;
|
INT8 bSlot;
|
||||||
INT16 bAPCost;
|
INT16 bAPCost;
|
||||||
BOOLEAN fRet = FALSE;
|
BOOLEAN fRet = FALSE;
|
||||||
|
|
||||||
CHECKF( pSoldier );
|
CHECKF( pSoldier );
|
||||||
|
|
||||||
// Flugente: check for underbarrel weapons and use that object if necessary
|
// Flugente: check for underbarrel weapons and use that object if necessary
|
||||||
pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) );
|
pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) );
|
||||||
|
pObj2 = NULL;
|
||||||
|
|
||||||
|
if (pSoldier->IsValidSecondHandShotForReloadingPurposes()) //check for valid second hand weapon for reloading purposes (something that doesn't use ammo)
|
||||||
|
{
|
||||||
|
pObj2 = pSoldier->GetUsedWeapon( &(pSoldier->inv[SECONDHANDPOS]) );
|
||||||
|
}
|
||||||
|
// Greysa: Check if weapon is jammed and unjam it first
|
||||||
|
if ((*pObj)[0]->data.gun.bGunAmmoStatus < 0 || ((pObj2 != NULL) && (*pObj2)[0]->data.gun.bGunAmmoStatus < 0))
|
||||||
|
{
|
||||||
|
if ((*pObj)[0]->data.gun.bGunAmmoStatus < 0)
|
||||||
|
{
|
||||||
|
//borrowed from Weapons.cpp
|
||||||
|
if (EnoughPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM], FALSE))
|
||||||
|
{
|
||||||
|
DeductPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM]);
|
||||||
|
|
||||||
|
INT8 bChanceMod;
|
||||||
|
|
||||||
|
if (Weapon[pObj->usItem].EasyUnjam)
|
||||||
|
bChanceMod = 100;
|
||||||
|
else
|
||||||
|
bChanceMod = (INT8)(GetReliability(pObj) * 4);
|
||||||
|
|
||||||
|
int iResult = SkillCheck(pSoldier, UNJAM_GUN_CHECK, bChanceMod);
|
||||||
|
|
||||||
|
if (iResult > 0)
|
||||||
|
{
|
||||||
|
// yay! unjammed the gun
|
||||||
|
(*pObj)[0]->data.gun.bGunAmmoStatus *= -1;
|
||||||
|
|
||||||
|
// MECHANICAL/DEXTERITY GAIN: Unjammed a gun
|
||||||
|
|
||||||
|
if (bChanceMod < 100) // don't give exp for unjamming an easily unjammable gun
|
||||||
|
{
|
||||||
|
StatChange(pSoldier, MECHANAMT, 5, FALSE);
|
||||||
|
StatChange(pSoldier, DEXTAMT, 5, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyMercPanelInterface(pSoldier, DIRTYLEVEL2);
|
||||||
|
PlayJA2Sample(Weapon[Item[pObj->usItem].ubClassIndex].ManualReloadSound, RATE_11025, SoundVolume(HIGHVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_UNJAMMED], pSoldier->GetName(), ItemNames[pObj->usItem]);
|
||||||
|
// merc voice feedback?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_FAILED_UNJAM], pSoldier->GetName(), ItemNames[pObj->usItem]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_NO_AP_NO_UNJAM], pSoldier->GetName(), ItemNames[pObj->usItem]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((pObj2 != NULL) && (*pObj2)[0]->data.gun.bGunAmmoStatus < 0)
|
||||||
|
{
|
||||||
|
if (EnoughPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM], FALSE))
|
||||||
|
{
|
||||||
|
DeductPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM]);
|
||||||
|
|
||||||
|
INT8 bChanceMod;
|
||||||
|
|
||||||
|
if (Weapon[pObj2->usItem].EasyUnjam)
|
||||||
|
bChanceMod = 100;
|
||||||
|
else
|
||||||
|
bChanceMod = (INT8)(GetReliability(pObj2) * 4);
|
||||||
|
|
||||||
|
int iResult = SkillCheck(pSoldier, UNJAM_GUN_CHECK, bChanceMod);
|
||||||
|
|
||||||
|
if (iResult > 0)
|
||||||
|
{
|
||||||
|
// yay! unjammed the gun
|
||||||
|
(*pObj2)[0]->data.gun.bGunAmmoStatus *= -1;
|
||||||
|
|
||||||
|
// MECHANICAL/DEXTERITY GAIN: Unjammed a gun
|
||||||
|
|
||||||
|
if (bChanceMod < 100) // don't give exp for unjamming an easily unjammable gun
|
||||||
|
{
|
||||||
|
StatChange(pSoldier, MECHANAMT, 5, FALSE);
|
||||||
|
StatChange(pSoldier, DEXTAMT, 5, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyMercPanelInterface(pSoldier, DIRTYLEVEL2);
|
||||||
|
PlayJA2Sample(Weapon[Item[pObj2->usItem].ubClassIndex].ManualReloadSound, RATE_11025, SoundVolume(HIGHVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_UNJAMMED], pSoldier->GetName(), ItemNames[pObj2->usItem]);
|
||||||
|
// merc voice feedback?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_FAILED_UNJAM], pSoldier->GetName(), ItemNames[pObj2->usItem]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_NO_AP_NO_UNJAM], pSoldier->GetName(), ItemNames[pObj2->usItem]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE; // Greysa: We want to skip reloading if we attempted to unjam, regardless of outcome. Return value doesn't seem to matter as there doesn't seem to be any actual checks on the returned value. I picked FALSE as actual reload hasn't occurred
|
||||||
|
}
|
||||||
|
|
||||||
//<SB> manual recharge
|
//<SB> manual recharge
|
||||||
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
||||||
@@ -3915,10 +4013,8 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier, bool aReloadEvenIfNotEmpty )
|
|||||||
|
|
||||||
PlayJA2Sample( Weapon[ Item[pObj->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
PlayJA2Sample( Weapon[ Item[pObj->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
||||||
|
|
||||||
if ( pSoldier->IsValidSecondHandShot( ) )
|
if (pObj2 != NULL)
|
||||||
{
|
{
|
||||||
pObj2 = &(pSoldier->inv[SECONDHANDPOS]);
|
|
||||||
|
|
||||||
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
||||||
{
|
{
|
||||||
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
||||||
@@ -3930,10 +4026,8 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier, bool aReloadEvenIfNotEmpty )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( pSoldier->IsValidSecondHandShot( ) )
|
if (pObj2 != NULL)
|
||||||
{
|
{
|
||||||
pObj2 = &(pSoldier->inv[SECONDHANDPOS]);
|
|
||||||
|
|
||||||
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
||||||
{
|
{
|
||||||
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
||||||
@@ -3989,21 +4083,19 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier, bool aReloadEvenIfNotEmpty )
|
|||||||
// if we are valid for two-pistol shooting (reloading) and we have enough APs still
|
// if we are valid for two-pistol shooting (reloading) and we have enough APs still
|
||||||
// then do a reload of both guns!
|
// then do a reload of both guns!
|
||||||
// Flugente: only reload if it's empty, or we really want to
|
// Flugente: only reload if it's empty, or we really want to
|
||||||
if ( pSoldier->IsValidSecondHandShotForReloadingPurposes()
|
if ( pObj2 != NULL && ( aReloadEvenIfNotEmpty || !EnoughAmmo( pSoldier, FALSE, SECONDHANDPOS ) ) )
|
||||||
&& ( aReloadEvenIfNotEmpty || !EnoughAmmo( pSoldier, FALSE, SECONDHANDPOS ) ) )
|
|
||||||
{
|
{
|
||||||
// Flugente: check for underbarrel weapons and use that object if necessary
|
// Flugente: check for underbarrel weapons and use that object if necessary
|
||||||
pObj = pSoldier->GetUsedWeapon( &( pSoldier->inv[SECONDHANDPOS] ) );
|
|
||||||
|
|
||||||
bSlot = FindAmmoToReload( pSoldier, SECONDHANDPOS, NO_SLOT );
|
bSlot = FindAmmoToReload( pSoldier, SECONDHANDPOS, NO_SLOT );
|
||||||
if ( bSlot != NO_SLOT )
|
if ( bSlot != NO_SLOT )
|
||||||
{
|
{
|
||||||
// ce would reload using this ammo!
|
// ce would reload using this ammo!
|
||||||
bAPCost = GetAPsToReloadGunWithAmmo( pSoldier, pObj, &( pSoldier->inv[bSlot] ) );
|
bAPCost = GetAPsToReloadGunWithAmmo( pSoldier, pObj2, &( pSoldier->inv[bSlot] ) );
|
||||||
if ( EnoughPoints( pSoldier, (INT16)bAPCost, 0, FALSE ) )
|
if ( EnoughPoints( pSoldier, (INT16)bAPCost, 0, FALSE ) )
|
||||||
{
|
{
|
||||||
// reload the 2nd gun too
|
// reload the 2nd gun too
|
||||||
fRet = ReloadGun( pSoldier, pObj, &( pSoldier->inv[bSlot] ) );
|
fRet = ReloadGun( pSoldier, pObj2, &( pSoldier->inv[bSlot] ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -5566,7 +5658,7 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac
|
|||||||
|
|
||||||
//Madd: if the attaching/merging item had any attachments on it, then try to move them to the first result
|
//Madd: if the attaching/merging item had any attachments on it, then try to move them to the first result
|
||||||
for (attachmentList::iterator iter = (*pAttachment)[0]->attachments.begin(); iter != (*pAttachment)[0]->attachments.end();) {
|
for (attachmentList::iterator iter = (*pAttachment)[0]->attachments.begin(); iter != (*pAttachment)[0]->attachments.end();) {
|
||||||
if( ValidItemAttachmentSlot(this, iter->usItem, TRUE, FALSE, subObject )){
|
if( iter->exists() && ValidItemAttachmentSlot(this, iter->usItem, TRUE, FALSE, subObject )){
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
||||||
@@ -5903,7 +5995,7 @@ void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
|
|
||||||
//Start by trying to re-attach inseperable items. They take precedence over items that can normally be removed
|
//Start by trying to re-attach inseperable items. They take precedence over items that can normally be removed
|
||||||
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
||||||
if(Item[iter->usItem].inseparable && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){
|
if( iter->exists() && Item[iter->usItem].inseparable && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){
|
if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){
|
||||||
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
|
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
|
||||||
@@ -5917,7 +6009,7 @@ void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
}
|
}
|
||||||
//Try to attach all the other attachments that didn't fit their current slot.
|
//Try to attach all the other attachments that didn't fit their current slot.
|
||||||
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
||||||
if(ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){
|
if( iter->exists() && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){
|
if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){
|
||||||
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
|
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
|
||||||
@@ -6093,7 +6185,7 @@ attachmentList ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
|
|
||||||
//First re-attach any slot-changing attachments.
|
//First re-attach any slot-changing attachments.
|
||||||
for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end();) {
|
for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end();) {
|
||||||
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex )){
|
if( iter->exists() && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex )){
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
||||||
@@ -6110,7 +6202,7 @@ attachmentList ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
|
|
||||||
//Time to re-attach the other attachments, if we can. I am the king of copy pasta.
|
//Time to re-attach the other attachments, if we can. I am the king of copy pasta.
|
||||||
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
|
||||||
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex)){
|
if( iter->exists() && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex)){
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
CreateItem(iter->usItem, (*iter)[0]->data.objectStatus, &tempAttachment);
|
||||||
@@ -6127,7 +6219,7 @@ attachmentList ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
|
|
||||||
//drop all items we couldn't re-attach.
|
//drop all items we couldn't re-attach.
|
||||||
for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end(); ++iter) {
|
for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end(); ++iter) {
|
||||||
if ( Item[iter->usItem].inseparable != 1)
|
if ( iter->exists() && Item[iter->usItem].inseparable != 1)
|
||||||
{//WarmSteel - Couldn't re-attach this item, try to drop it.
|
{//WarmSteel - Couldn't re-attach this item, try to drop it.
|
||||||
if (pSoldier) {
|
if (pSoldier) {
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
@@ -6145,7 +6237,7 @@ attachmentList ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
|
|||||||
}
|
}
|
||||||
//and the rest too
|
//and the rest too
|
||||||
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end(); ++iter) {
|
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end(); ++iter) {
|
||||||
if ( Item[iter->usItem].inseparable != 1)
|
if ( iter->exists() && Item[iter->usItem].inseparable != 1)
|
||||||
{//WarmSteel - Couldn't re-attach this item, try to drop it.
|
{//WarmSteel - Couldn't re-attach this item, try to drop it.
|
||||||
if (pSoldier) {
|
if (pSoldier) {
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
@@ -10330,7 +10422,7 @@ BOOLEAN NCTHIsScoped( OBJECTTYPE * pObj )
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( Item[iter->usItem].scopemagfactor > 1.0 && iter->exists() )
|
if ( iter->exists() && Item[iter->usItem].scopemagfactor > 1.0 )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10349,7 +10441,7 @@ BOOLEAN IsScoped( OBJECTTYPE * pObj )
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( Item[iter->usItem].aimbonus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].aimbonus > 0 )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10436,7 +10528,7 @@ INT16 GetBaseScopeAimBonus( OBJECTTYPE * pObj, INT32 iRange )
|
|||||||
//Search for the most powerful scope we can use.
|
//Search for the most powerful scope we can use.
|
||||||
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); iter++)
|
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); iter++)
|
||||||
{
|
{
|
||||||
if(Item[iter->usItem].aimbonus > bonus && iRange >= Item[iter->usItem].minrangeforaimbonus && iter->exists())
|
if( iter->exists() && Item[iter->usItem].aimbonus > bonus && iRange >= Item[iter->usItem].minrangeforaimbonus )
|
||||||
{
|
{
|
||||||
bonus = Item[iter->usItem].aimbonus;
|
bonus = Item[iter->usItem].aimbonus;
|
||||||
}
|
}
|
||||||
@@ -10514,7 +10606,7 @@ UINT32 FindRangeBonusAttachment( OBJECTTYPE * pObj )
|
|||||||
{
|
{
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].rangebonus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].rangebonus > 0 )
|
||||||
{
|
{
|
||||||
return( Item[iter->usItem].uiIndex );
|
return( Item[iter->usItem].uiIndex );
|
||||||
}
|
}
|
||||||
@@ -10535,7 +10627,7 @@ INT16 GetRangeBonus( OBJECTTYPE * pObj )
|
|||||||
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rangebonus;
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rangebonus;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( !ItemIsDuckbill(iter->usItem) || (ItemIsDuckbill(iter->usItem) && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ) && iter->exists())
|
if ( iter->exists() && !ItemIsDuckbill(iter->usItem) || (ItemIsDuckbill(iter->usItem) && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ) )
|
||||||
bonus += BonusReduce( Item[iter->usItem].rangebonus, (*iter)[0]->data.objectStatus );
|
bonus += BonusReduce( Item[iter->usItem].rangebonus, (*iter)[0]->data.objectStatus );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11961,7 +12053,7 @@ BOOLEAN HasThermalOptics( SOLDIERTYPE * pSoldier )
|
|||||||
OBJECTTYPE* pObj = &pSoldier->inv[HANDPOS];
|
OBJECTTYPE* pObj = &pSoldier->inv[HANDPOS];
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (ItemIsThermalOptics(iter->usItem) && iter->exists() )
|
if ( iter->exists() && ItemIsThermalOptics(iter->usItem) )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12018,7 +12110,7 @@ BOOLEAN IsDuckbill( OBJECTTYPE * pObj )
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (ItemIsDuckbill(iter->usItem) && iter->exists() )
|
if ( iter->exists() && ItemIsDuckbill(iter->usItem) )
|
||||||
{
|
{
|
||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
@@ -12069,7 +12161,7 @@ BOOLEAN IsDetonatorAttached( OBJECTTYPE * pObj )
|
|||||||
// return TRUE;
|
// return TRUE;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( IsAttachmentClass( iter->usItem, AC_DETONATOR ) && iter->exists() )
|
if ( iter->exists() && IsAttachmentClass( iter->usItem, AC_DETONATOR ) )
|
||||||
{
|
{
|
||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
@@ -12085,7 +12177,7 @@ BOOLEAN IsRemoteDetonatorAttached( OBJECTTYPE * pObj )
|
|||||||
// return TRUE;
|
// return TRUE;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( IsAttachmentClass( iter->usItem, AC_REMOTEDET ) && iter->exists() )
|
if ( iter->exists() && IsAttachmentClass( iter->usItem, AC_REMOTEDET ) )
|
||||||
{
|
{
|
||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
@@ -12357,7 +12449,7 @@ OBJECTTYPE* FindAttachedBatteries( OBJECTTYPE * pObj )
|
|||||||
{
|
{
|
||||||
if (pObj->exists() == true) {
|
if (pObj->exists() == true) {
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (ItemIsBatteries(iter->usItem) && iter->exists())
|
if ( iter->exists() && ItemIsBatteries(iter->usItem) )
|
||||||
{
|
{
|
||||||
return( &(*iter) );
|
return( &(*iter) );
|
||||||
}
|
}
|
||||||
@@ -12426,51 +12518,6 @@ INT8 FindCamoKit( SOLDIERTYPE * pSoldier )
|
|||||||
return( NO_SLOT );
|
return( NO_SLOT );
|
||||||
}
|
}
|
||||||
|
|
||||||
INT8 FindCanteen(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
const INT8 invsize = pSoldier->inv.size();
|
|
||||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop )
|
|
||||||
{
|
|
||||||
if ( pSoldier->inv[bLoop].exists() && ItemIsCanteen(pSoldier->inv[bLoop].usItem) )
|
|
||||||
{
|
|
||||||
OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]);
|
|
||||||
if ( pObj && TotalPoints(pObj) > 1 )
|
|
||||||
{
|
|
||||||
return(bLoop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(NO_SLOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
INT8 FindWirecutters(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
const INT8 invsize = pSoldier->inv.size();
|
|
||||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop )
|
|
||||||
{
|
|
||||||
if ( pSoldier->inv[bLoop].exists() && ItemIsWirecutters(pSoldier->inv[bLoop].usItem) )
|
|
||||||
{
|
|
||||||
return(bLoop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT8 FindTNT(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
const INT8 invsize = pSoldier->inv.size();
|
|
||||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop )
|
|
||||||
{
|
|
||||||
if ( pSoldier->inv[bLoop].exists() && ItemIsTNT(pSoldier->inv[bLoop].usItem) )
|
|
||||||
{
|
|
||||||
return(bLoop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//JMich_SkillModifiers: Adding a function to see if we have an item with disarm bonus
|
//JMich_SkillModifiers: Adding a function to see if we have an item with disarm bonus
|
||||||
INT8 FindDisarmKit( SOLDIERTYPE * pSoldier )
|
INT8 FindDisarmKit( SOLDIERTYPE * pSoldier )
|
||||||
{
|
{
|
||||||
@@ -12634,7 +12681,7 @@ INT16 GetCamoBonus( OBJECTTYPE * pObj )
|
|||||||
bonus = (Item[pObj->usItem].camobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
bonus = (Item[pObj->usItem].camobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (!ItemIsCamoKit(iter->usItem) && iter->exists())
|
if ( iter->exists() && !ItemIsCamoKit(iter->usItem) )
|
||||||
bonus += (INT16) (Item[iter->usItem].camobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
bonus += (INT16) (Item[iter->usItem].camobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12647,7 +12694,7 @@ INT16 GetUrbanCamoBonus( OBJECTTYPE * pObj )
|
|||||||
bonus = (Item[pObj->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
bonus = (Item[pObj->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (!ItemIsCamoKit(iter->usItem) && iter->exists())
|
if ( iter->exists() && !ItemIsCamoKit(iter->usItem) )
|
||||||
bonus += (INT16) (Item[iter->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
bonus += (INT16) (Item[iter->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12660,7 +12707,7 @@ INT16 GetDesertCamoBonus( OBJECTTYPE * pObj )
|
|||||||
bonus = (Item[pObj->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
bonus = (Item[pObj->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (!ItemIsCamoKit(iter->usItem) && iter->exists())
|
if ( iter->exists() && !ItemIsCamoKit(iter->usItem) )
|
||||||
bonus += (INT16) (Item[iter->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
bonus += (INT16) (Item[iter->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12673,7 +12720,7 @@ INT16 GetSnowCamoBonus( OBJECTTYPE * pObj )
|
|||||||
bonus = (Item[pObj->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
bonus = (Item[pObj->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (!ItemIsCamoKit(iter->usItem) && iter->exists())
|
if ( iter->exists() && !ItemIsCamoKit(iter->usItem) )
|
||||||
bonus += (INT16) (Item[iter->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
bonus += (INT16) (Item[iter->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13118,7 +13165,7 @@ OBJECTTYPE* FindNightGogglesInInv( SOLDIERTYPE * pSoldier, INT8 * bSlot, BOOLEAN
|
|||||||
if (searchAllInventory) {
|
if (searchAllInventory) {
|
||||||
for (UINT8 loop = 0; loop < pSoldier->inv[bLoop].ubNumberOfObjects; loop ++){
|
for (UINT8 loop = 0; loop < pSoldier->inv[bLoop].ubNumberOfObjects; loop ++){
|
||||||
for (attachmentList::iterator iter = pSoldier->inv[bLoop][loop]->attachments.begin(); iter != pSoldier->inv[bLoop][loop]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = pSoldier->inv[bLoop][loop]->attachments.begin(); iter != pSoldier->inv[bLoop][loop]->attachments.end(); ++iter) {
|
||||||
if ( Item[ iter->usItem ].cavevisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists() ) {
|
if ( iter->exists() && Item[ iter->usItem ].cavevisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE ) {
|
||||||
pGoggles = &(*iter);
|
pGoggles = &(*iter);
|
||||||
*bSlot = bLoop;
|
*bSlot = bLoop;
|
||||||
*isAttach = TRUE;
|
*isAttach = TRUE;
|
||||||
@@ -13176,7 +13223,7 @@ INT16 GetMinRangeForAimBonus( SOLDIERTYPE* pSoldier, OBJECTTYPE * pObj )
|
|||||||
attachmentList::iterator iterend = (*pObj)[0]->attachments.end();
|
attachmentList::iterator iterend = (*pObj)[0]->attachments.end();
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != iterend; ++iter)
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != iterend; ++iter)
|
||||||
{
|
{
|
||||||
if ( !gGameExternalOptions.fScopeModes || !IsAttachmentClass(iter->usItem, AC_SCOPE|AC_SIGHT|AC_IRONSIGHT ) )
|
if ( !gGameExternalOptions.fScopeModes || (iter->exists() && !IsAttachmentClass(iter->usItem, AC_SCOPE|AC_SIGHT|AC_IRONSIGHT )) )
|
||||||
bonus += Item[iter->usItem].minrangeforaimbonus;
|
bonus += Item[iter->usItem].minrangeforaimbonus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14094,7 +14141,7 @@ INT16 GetAverageBestLaserRange( OBJECTTYPE * pObj )
|
|||||||
}
|
}
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (Item[iter->usItem].bestlaserrange > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].bestlaserrange > 0 )
|
||||||
{
|
{
|
||||||
numModifiers++;
|
numModifiers++;
|
||||||
bonus += (FLOAT) Item[iter->usItem].bestlaserrange;
|
bonus += (FLOAT) Item[iter->usItem].bestlaserrange;
|
||||||
@@ -14120,7 +14167,7 @@ INT16 GetBestLaserRange( OBJECTTYPE * pObj )
|
|||||||
}
|
}
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (Item[iter->usItem].bestlaserrange > range && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].bestlaserrange > range )
|
||||||
{
|
{
|
||||||
range = Item[iter->usItem].bestlaserrange;
|
range = Item[iter->usItem].bestlaserrange;
|
||||||
}
|
}
|
||||||
@@ -15133,7 +15180,7 @@ BOOLEAN OBJECTTYPE::TransformObject( SOLDIERTYPE * pSoldier, UINT8 ubStatusIndex
|
|||||||
// I am the prince of copy pasta ;)
|
// I am the prince of copy pasta ;)
|
||||||
for (attachmentList::iterator iter = unattachableList.begin(); iter != unattachableList.end();)
|
for (attachmentList::iterator iter = unattachableList.begin(); iter != unattachableList.end();)
|
||||||
{
|
{
|
||||||
if( ValidItemAttachmentSlot(&gTempObject, iter->usItem, TRUE, FALSE, ubStatusIndex ))
|
if( iter->exists() && ValidItemAttachmentSlot(&gTempObject, iter->usItem, TRUE, FALSE, ubStatusIndex ))
|
||||||
{
|
{
|
||||||
//This seems to be rather valid. Can't be 100% sure though.
|
//This seems to be rather valid. Can't be 100% sure though.
|
||||||
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
OBJECTTYPE tempAttachment; // Madd: we must recreate the attachments because they may themselves have default inseparable attachments...
|
||||||
@@ -15821,7 +15868,7 @@ INT32 GetPercentRangeBonus( OBJECTTYPE * pObj )
|
|||||||
bonus = ( bonus * ( 100 + Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentrangebonus ) ) / 100;
|
bonus = ( bonus * ( 100 + Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentrangebonus ) ) / 100;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( !ItemIsDuckbill(iter->usItem) || (ItemIsDuckbill(iter->usItem) && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ))
|
if ( iter->exists() && !ItemIsDuckbill(iter->usItem) || (ItemIsDuckbill(iter->usItem) && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ))
|
||||||
bonus = ( bonus * ( 100 + BonusReduce( Item[iter->usItem].percentrangebonus, (*iter)[0]->data.objectStatus ) ) ) / 100;
|
bonus = ( bonus * ( 100 + BonusReduce( Item[iter->usItem].percentrangebonus, (*iter)[0]->data.objectStatus ) ) ) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16090,20 +16137,6 @@ BOOLEAN FindAttachmentRange(UINT16 usAttachment, UINT32* pStartIndex, UINT32* pE
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN ItemIsTNT(UINT16 usItem)
|
|
||||||
{
|
|
||||||
if ( Item[usItem].usItemClass == IC_BOMB &&
|
|
||||||
!ItemIsMine(usItem) &&
|
|
||||||
!ItemIsTripwire(usItem) &&
|
|
||||||
Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL &&
|
|
||||||
Explosive[Item[usItem].ubClassIndex].ubDamage > 40 &&
|
|
||||||
GetLauncherFromLaunchable(usItem) == NOTHING )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
// Item flagmask utility functions
|
// Item flagmask utility functions
|
||||||
// Just to improve readability
|
// Just to improve readability
|
||||||
|
|||||||
@@ -249,7 +249,6 @@ BOOLEAN ItemIsOnlyInDisease(UINT16 usItem);
|
|||||||
BOOLEAN ItemProvidesRobotCamo(UINT16 usItem);
|
BOOLEAN ItemProvidesRobotCamo(UINT16 usItem);
|
||||||
BOOLEAN ItemProvidesRobotNightvision(UINT16 usItem);
|
BOOLEAN ItemProvidesRobotNightvision(UINT16 usItem);
|
||||||
BOOLEAN ItemProvidesRobotLaserBonus(UINT16 usItem);
|
BOOLEAN ItemProvidesRobotLaserBonus(UINT16 usItem);
|
||||||
BOOLEAN ItemIsTNT(UINT16 usItem);
|
|
||||||
|
|
||||||
//Existing functions without header def's, added them here, just incase I'll need to call
|
//Existing functions without header def's, added them here, just incase I'll need to call
|
||||||
//them from the editor.
|
//them from the editor.
|
||||||
@@ -480,13 +479,9 @@ INT8 FindFirstAidKit( SOLDIERTYPE * pSoldier );
|
|||||||
INT8 FindDisarmKit( SOLDIERTYPE * pSoldier ); //JMich_SkillsModifiers: Added function to check for disarm bonus
|
INT8 FindDisarmKit( SOLDIERTYPE * pSoldier ); //JMich_SkillsModifiers: Added function to check for disarm bonus
|
||||||
INT8 FindLocksmithKit( SOLDIERTYPE * pSoldier );
|
INT8 FindLocksmithKit( SOLDIERTYPE * pSoldier );
|
||||||
INT8 FindCamoKit( SOLDIERTYPE * pSoldier );
|
INT8 FindCamoKit( SOLDIERTYPE * pSoldier );
|
||||||
INT8 FindCanteen(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 FindWalkman( SOLDIERTYPE * pSoldier );
|
INT8 FindWalkman( SOLDIERTYPE * pSoldier );
|
||||||
INT8 FindTrigger( SOLDIERTYPE * pSoldier );
|
INT8 FindTrigger( SOLDIERTYPE * pSoldier );
|
||||||
INT8 FindRemoteControl( SOLDIERTYPE * pSoldier );
|
INT8 FindRemoteControl( SOLDIERTYPE * pSoldier );
|
||||||
INT8 FindWirecutters(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 FindTNT(SOLDIERTYPE* pSoldier);
|
|
||||||
|
|
||||||
INT16 GetWornCamo( SOLDIERTYPE * pSoldier );
|
INT16 GetWornCamo( SOLDIERTYPE * pSoldier );
|
||||||
INT16 GetCamoBonus( OBJECTTYPE * pObj );
|
INT16 GetCamoBonus( OBJECTTYPE * pObj );
|
||||||
INT16 GetWornStealth( SOLDIERTYPE * pSoldier );
|
INT16 GetWornStealth( SOLDIERTYPE * pSoldier );
|
||||||
|
|||||||
+1
-2
@@ -167,7 +167,6 @@ extern BOOLEAN KeyExistsInInventory( SOLDIERTYPE *pSoldier, UINT8 ubKeyID );
|
|||||||
extern BOOLEAN KeyExistsInKeyRing( SOLDIERTYPE *pSoldier, UINT8 ubKeyID, UINT8 * pubPos );
|
extern BOOLEAN KeyExistsInKeyRing( SOLDIERTYPE *pSoldier, UINT8 ubKeyID, UINT8 * pubPos );
|
||||||
extern BOOLEAN SoldierHasKey( SOLDIERTYPE *pSoldier, UINT8 ubKeyID );
|
extern BOOLEAN SoldierHasKey( SOLDIERTYPE *pSoldier, UINT8 ubKeyID );
|
||||||
|
|
||||||
extern STR16 sKeyDescriptionStrings[];
|
|
||||||
/**********************************
|
/**********************************
|
||||||
* Door utils add by Kris Morness *
|
* Door utils add by Kris Morness *
|
||||||
**********************************/
|
**********************************/
|
||||||
@@ -281,4 +280,4 @@ void AttachStringToDoor( INT32 sGridNo );
|
|||||||
|
|
||||||
void DropKeysInKeyRing( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, INT8 bVisible, BOOLEAN fAddToDropList, INT32 iDropListSlot, BOOLEAN fUseUnLoaded );
|
void DropKeysInKeyRing( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, INT8 bVisible, BOOLEAN fAddToDropList, INT32 iDropListSlot, BOOLEAN fUseUnLoaded );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -171,7 +171,7 @@ INT32 GetSpreadPattern( OBJECTTYPE * pObj )
|
|||||||
//If there are attachments, check them. Stop on the first one with something defined.
|
//If there are attachments, check them. Stop on the first one with something defined.
|
||||||
//Dear God, I hate C++ iterators. What a fugly mess. //WarmSteel - I made it even messier ;3
|
//Dear God, I hate C++ iterators. What a fugly mess. //WarmSteel - I made it even messier ;3
|
||||||
for (attachmentList::iterator iter = pObj[0][0]->attachments.begin(); iter != pObj[0][0]->attachments.end(); ++iter){
|
for (attachmentList::iterator iter = pObj[0][0]->attachments.begin(); iter != pObj[0][0]->attachments.end(); ++iter){
|
||||||
if( (n=Item[ iter->usItem ].spreadPattern) && iter->exists()){
|
if( iter->exists() && (n=Item[ iter->usItem ].spreadPattern) ){
|
||||||
//An attachment has it, and it trumps everything, so return it's value.
|
//An attachment has it, and it trumps everything, so return it's value.
|
||||||
return n;}
|
return n;}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ namespace LogicalBodyTypes {
|
|||||||
data->filter = FilterDB::Instance().FindFilter(aFilter);
|
data->filter = FilterDB::Instance().FindFilter(aFilter);
|
||||||
if (data->filter == NULL) throw XMLParseException("Unknown filter specified!", name, data->pParser);
|
if (data->filter == NULL) throw XMLParseException("Unknown filter specified!", name, data->pParser);
|
||||||
}
|
}
|
||||||
if (aPalette != NULL && strcmp(aFilter, "") != 0 && strcmp(aFilter, "default") != 0) {
|
if (aPalette != NULL && strcmp(aPalette, "") != 0 && strcmp(aPalette, "default") != 0) {
|
||||||
data->paletteTable = PaletteDB::Instance().FindPaletteTable(aPalette);
|
data->paletteTable = PaletteDB::Instance().FindPaletteTable(aPalette);
|
||||||
if (data->paletteTable == NULL) throw XMLParseException("Unknown palette specified!", name, data->pParser);
|
if (data->paletteTable == NULL) throw XMLParseException("Unknown palette specified!", name, data->pParser);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ FLOAT gdMajorMapVersion = MAJOR_MAP_VERSION;
|
|||||||
BOOLEAN gfWorldLoaded;
|
BOOLEAN gfWorldLoaded;
|
||||||
|
|
||||||
MAPCREATE_STRUCT gMapInformation;
|
MAPCREATE_STRUCT gMapInformation;
|
||||||
|
MAPCREATE_STRUCT gMapInformationAutoResolve;
|
||||||
|
|
||||||
//CHRISL: MINOR_MAP_VERSION information moved to worlddef.h by ADB. We're using these values elsewhere and need them
|
//CHRISL: MINOR_MAP_VERSION information moved to worlddef.h by ADB. We're using these values elsewhere and need them
|
||||||
// in the header file
|
// in the header file
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern MAPCREATE_STRUCT gMapInformation;
|
extern MAPCREATE_STRUCT gMapInformation;
|
||||||
|
extern MAPCREATE_STRUCT gMapInformationAutoResolve;
|
||||||
|
|
||||||
void LoadMapInformation(INT8** hBuffer, FLOAT dMajorMapVersion);
|
void LoadMapInformation(INT8** hBuffer, FLOAT dMajorMapVersion);
|
||||||
void SaveMapInformation(HWFILE hFile, FLOAT dMajorMapVersion, UINT8 ubMinorMapVersion);
|
void SaveMapInformation(HWFILE hFile, FLOAT dMajorMapVersion, UINT8 ubMinorMapVersion);
|
||||||
|
|||||||
+16
-44
@@ -3026,7 +3026,7 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )
|
|||||||
|
|
||||||
// sevenfm: check all nearby enemy boxers for opportunity attack
|
// sevenfm: check all nearby enemy boxers for opportunity attack
|
||||||
if (IS_MERC_BODY_TYPE(pSoldier) &&
|
if (IS_MERC_BODY_TYPE(pSoldier) &&
|
||||||
BOXER(pSoldier) &&
|
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
gTacticalStatus.bBoxingState == BOXING &&
|
gTacticalStatus.bBoxingState == BOXING &&
|
||||||
pSoldier->aiData.bAlertStatus >= STATUS_RED)
|
pSoldier->aiData.bAlertStatus >= STATUS_RED)
|
||||||
{
|
{
|
||||||
@@ -3047,7 +3047,7 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )
|
|||||||
pOpponent->bCollapsed ||
|
pOpponent->bCollapsed ||
|
||||||
pOpponent->bBreathCollapsed ||
|
pOpponent->bBreathCollapsed ||
|
||||||
!IS_MERC_BODY_TYPE(pOpponent) ||
|
!IS_MERC_BODY_TYPE(pOpponent) ||
|
||||||
!BOXER(pOpponent) ||
|
!(pOpponent->flags.uiStatusFlags & SOLDIER_BOXER) ||
|
||||||
gAnimControl[pOpponent->usAnimState].ubEndHeight < ANIM_STAND ||
|
gAnimControl[pOpponent->usAnimState].ubEndHeight < ANIM_STAND ||
|
||||||
pOpponent->pathing.bLevel != pSoldier->pathing.bLevel ||
|
pOpponent->pathing.bLevel != pSoldier->pathing.bLevel ||
|
||||||
!SoldierToSoldierLineOfSightTest(pOpponent, pSoldier, TRUE, CALC_FROM_WANTED_DIR) ||
|
!SoldierToSoldierLineOfSightTest(pOpponent, pSoldier, TRUE, CALC_FROM_WANTED_DIR) ||
|
||||||
@@ -5031,11 +5031,11 @@ BOOLEAN NewOKDestination( SOLDIERTYPE * pCurrSoldier, INT32 sGridNo, BOOLEAN fPe
|
|||||||
BOOLEAN fOKCheckStruct;
|
BOOLEAN fOKCheckStruct;
|
||||||
|
|
||||||
// Allow civilians and NPCs with profile to go off screen, and also enemies if tactical retreat is enabled
|
// Allow civilians and NPCs with profile to go off screen, and also enemies if tactical retreat is enabled
|
||||||
const auto destinationOffscreen = !(GridNoOnVisibleWorldTile(sGridNo));
|
auto destinationOffscreen = !(GridNoOnVisibleWorldTile(sGridNo));
|
||||||
const auto hasProfile = pCurrSoldier->ubProfile != NO_PROFILE;
|
auto hasProfile = pCurrSoldier->ubProfile != NO_PROFILE;
|
||||||
const auto isCivilian = pCurrSoldier->bTeam == CIV_TEAM;
|
auto isCivilian = pCurrSoldier->bTeam == CIV_TEAM;
|
||||||
const auto isEnemy = pCurrSoldier->bTeam == ENEMY_TEAM;
|
auto isEnemy = pCurrSoldier->bTeam == ENEMY_TEAM;
|
||||||
const auto retreatAllowed = gGameExternalOptions.fAITacticalRetreat == TRUE;
|
auto retreatAllowed = gGameExternalOptions.fAITacticalRetreat == true;
|
||||||
|
|
||||||
if (destinationOffscreen && !(isCivilian || hasProfile || (isEnemy && retreatAllowed)))
|
if (destinationOffscreen && !(isCivilian || hasProfile || (isEnemy && retreatAllowed)))
|
||||||
{
|
{
|
||||||
@@ -5400,34 +5400,6 @@ BOOLEAN TeamMemberNear( INT8 bTeam, INT32 sGridNo, INT32 iRange )
|
|||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN NotDeafTeamMemberNear(INT8 bTeam, INT32 sGridNo, INT32 iRange)
|
|
||||||
{
|
|
||||||
for ( SoldierID pSoldier = gTacticalStatus.Team[bTeam].bFirstID; pSoldier <= gTacticalStatus.Team[bTeam].bLastID; ++pSoldier )
|
|
||||||
{
|
|
||||||
if ( pSoldier->bActive &&
|
|
||||||
pSoldier->bInSector &&
|
|
||||||
pSoldier->stats.bLife >= OKLIFE &&
|
|
||||||
pSoldier->bDeafenedCounter == 0 )
|
|
||||||
{
|
|
||||||
if ( PythSpacesAway(pSoldier->sGridNo, sGridNo) <= iRange )
|
|
||||||
{
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN PlayerCanHearNoise(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
if ( pSoldier &&
|
|
||||||
(pSoldier->bVisible == TRUE || NotDeafTeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE / 2) || NightLight() && !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && NotDeafTeamMemberNear(gbPlayerNum, pSoldier->sGridNo, TACTICAL_RANGE)) )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 FindAdjacentGridEx( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 *pubDirection, INT32 *psAdjustedGridNo, BOOLEAN fForceToPerson, BOOLEAN fDoor, bool allow_diagonal )
|
INT32 FindAdjacentGridEx( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 *pubDirection, INT32 *psAdjustedGridNo, BOOLEAN fForceToPerson, BOOLEAN fDoor, bool allow_diagonal )
|
||||||
{
|
{
|
||||||
// psAdjustedGridNo gets the original gridno or the new one if updated
|
// psAdjustedGridNo gets the original gridno or the new one if updated
|
||||||
@@ -6937,7 +6909,7 @@ BOOLEAN CheckForEndOfCombatMode( BOOLEAN fIncrementTurnsNotSeen )
|
|||||||
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
||||||
{
|
{
|
||||||
pTeamSoldier = MercSlots[ cnt ];
|
pTeamSoldier = MercSlots[ cnt ];
|
||||||
if ( pTeamSoldier && pTeamSoldier->stats.bLife >= OKLIFE && !pTeamSoldier->aiData.bNeutral )
|
if ( pTeamSoldier && pTeamSoldier->stats.bLife >= OKLIFE && !pTeamSoldier->aiData.bNeutral && !(pTeamSoldier->usSoldierFlagMask & SOLDIER_POW) )
|
||||||
{
|
{
|
||||||
if ( SoldierHasSeenEnemiesLastFewTurns( pTeamSoldier ) )
|
if ( SoldierHasSeenEnemiesLastFewTurns( pTeamSoldier ) )
|
||||||
{
|
{
|
||||||
@@ -7203,7 +7175,7 @@ static void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8
|
|||||||
//if ( pTeamSoldier->stats.bLife >= OKLIFE && pTeamSoldier->stats.bLife != 0 )
|
//if ( pTeamSoldier->stats.bLife >= OKLIFE && pTeamSoldier->stats.bLife != 0 )
|
||||||
{
|
{
|
||||||
// officers and generals are 'special' prisoners...
|
// officers and generals are 'special' prisoners...
|
||||||
if (ISVIP(pTeamSoldier))
|
if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP )
|
||||||
++sNumPrisoner[PRISONER_GENERAL];
|
++sNumPrisoner[PRISONER_GENERAL];
|
||||||
// downed pilots count as officers too, even though they are civilians. This makes capturing them more rewarding
|
// downed pilots count as officers too, even though they are civilians. This makes capturing them more rewarding
|
||||||
else if ( (pTeamSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER) || pTeamSoldier->ubCivilianGroup == DOWNEDPILOT_CIV_GROUP )
|
else if ( (pTeamSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER) || pTeamSoldier->ubCivilianGroup == DOWNEDPILOT_CIV_GROUP )
|
||||||
@@ -7232,7 +7204,7 @@ static void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: VIPs
|
// Flugente: VIPs
|
||||||
if (ISVIP(pTeamSoldier))
|
if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP )
|
||||||
DeleteVIP( pTeamSoldier->sSectorX, pTeamSoldier->sSectorY );
|
DeleteVIP( pTeamSoldier->sSectorX, pTeamSoldier->sSectorY );
|
||||||
|
|
||||||
// Flugente: turncoats
|
// Flugente: turncoats
|
||||||
@@ -9279,10 +9251,10 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
|
|||||||
if ( gTacticalStatus.bBoxingState == BOXING )
|
if ( gTacticalStatus.bBoxingState == BOXING )
|
||||||
{
|
{
|
||||||
// should have a check for "in boxing ring", no?
|
// should have a check for "in boxing ring", no?
|
||||||
if ( ( pSoldier->usAttackingWeapon != NOTHING && !ItemIsBrassKnuckles(pSoldier->usAttackingWeapon)) || !BOXER(pSoldier) || pSoldier->IsRiotShieldEquipped() )
|
if ( ( pSoldier->usAttackingWeapon != NOTHING && !ItemIsBrassKnuckles(pSoldier->usAttackingWeapon)) || !( pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ) || pSoldier->IsRiotShieldEquipped() )
|
||||||
{
|
{
|
||||||
// someone's cheating!
|
// someone's cheating!
|
||||||
if ( (Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_BLADE || Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_PUNCH) && BOXER(pTarget) )
|
if ( (Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_BLADE || Item[ pSoldier->usAttackingWeapon ].usItemClass == IC_PUNCH) && (pTarget->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
// knife or brass knuckles disqualify the player!
|
// knife or brass knuckles disqualify the player!
|
||||||
BoxingPlayerDisqualified( pSoldier, BAD_ATTACK );
|
BoxingPlayerDisqualified( pSoldier, BAD_ATTACK );
|
||||||
@@ -9293,7 +9265,7 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
|
|||||||
//gTacticalStatus.bBoxingState = NOT_BOXING;
|
//gTacticalStatus.bBoxingState = NOT_BOXING;
|
||||||
SetBoxingState( NOT_BOXING );
|
SetBoxingState( NOT_BOXING );
|
||||||
// if we are attacking a boxer we should set them to neutral (temporarily) so that the rest of the civgroup code works...
|
// if we are attacking a boxer we should set them to neutral (temporarily) so that the rest of the civgroup code works...
|
||||||
if ( (pTarget->bTeam == CIV_TEAM) && BOXER(pTarget) )
|
if ( (pTarget->bTeam == CIV_TEAM) && (pTarget->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
SetSoldierNeutral( pTarget );
|
SetSoldierNeutral( pTarget );
|
||||||
}
|
}
|
||||||
@@ -9440,7 +9412,7 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp
|
|||||||
//TriggerNPCWithIHateYouQuote( pTarget->ubProfile );
|
//TriggerNPCWithIHateYouQuote( pTarget->ubProfile );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( pTarget->ubCivilianGroup != NON_CIV_GROUP && !BOXER(pTarget) )
|
else if ( pTarget->ubCivilianGroup != NON_CIV_GROUP && !( pTarget->flags.uiStatusFlags & SOLDIER_BOXER ) )
|
||||||
{
|
{
|
||||||
// Firing at a civ in a civ group who isn't hostile... if anyone in that civ group can see this
|
// Firing at a civ in a civ group who isn't hostile... if anyone in that civ group can see this
|
||||||
// going on they should become hostile.
|
// going on they should become hostile.
|
||||||
@@ -10876,7 +10848,7 @@ static void TurnCoatAttemptMessageBoxCallBack( UINT8 ubExitValue )
|
|||||||
UINT8 approachchance = gusSelectedSoldier->GetTurncoatConvinctionChance( prisonerdialoguetargetID, approachselected );
|
UINT8 approachchance = gusSelectedSoldier->GetTurncoatConvinctionChance( prisonerdialoguetargetID, approachselected );
|
||||||
|
|
||||||
// you can never turn a VIP (though we don't tell the player if someone is a VIP, lest they have an exploit to find out)
|
// you can never turn a VIP (though we don't tell the player if someone is a VIP, lest they have an exploit to find out)
|
||||||
if (ISVIP(pSoldier))
|
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP )
|
||||||
approachchance = 0;
|
approachchance = 0;
|
||||||
|
|
||||||
// as using random numbers to pass the check would result in players savescumming, use a number based on the soldier's stats
|
// as using random numbers to pass the check would result in players savescumming, use a number based on the soldier's stats
|
||||||
@@ -11431,7 +11403,7 @@ void TeamDropAll(UINT8 bTeam, BOOLEAN fForce)
|
|||||||
// if soldier is in the current sector, drop all equipment (that has the TAKEN_BY_MILITIA-flag set)
|
// if soldier is in the current sector, drop all equipment (that has the TAKEN_BY_MILITIA-flag set)
|
||||||
if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) )
|
if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) )
|
||||||
{
|
{
|
||||||
pSoldier->DropSectorEquipment();
|
pSoldier->DropSectorEquipment( NOWHERE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -261,9 +261,6 @@ void SelectNextAvailSoldier( SOLDIERTYPE *pSoldier );
|
|||||||
BOOLEAN TeamMemberNear(INT8 bTeam, INT32 sGridNo, INT32 iRange);
|
BOOLEAN TeamMemberNear(INT8 bTeam, INT32 sGridNo, INT32 iRange);
|
||||||
BOOLEAN IsValidTargetMerc( SoldierID ubSoldierID );
|
BOOLEAN IsValidTargetMerc( SoldierID ubSoldierID );
|
||||||
|
|
||||||
BOOLEAN NotDeafTeamMemberNear(INT8 bTeam, INT32 sGridNo, INT32 iRange);
|
|
||||||
BOOLEAN PlayerCanHearNoise(SOLDIERTYPE* pSoldier);
|
|
||||||
|
|
||||||
// FUNCTIONS FOR MANIPULATING MERC SLOTS - A LIST OF ALL ACTIVE MERCS
|
// FUNCTIONS FOR MANIPULATING MERC SLOTS - A LIST OF ALL ACTIVE MERCS
|
||||||
INT32 GetFreeMercSlot( );
|
INT32 GetFreeMercSlot( );
|
||||||
INT32 AddMercSlot( SOLDIERTYPE *pSoldier );
|
INT32 AddMercSlot( SOLDIERTYPE *pSoldier );
|
||||||
@@ -436,3 +433,4 @@ BOOLEAN IsFreeSlotAvailable( int aTeam );
|
|||||||
void AttemptToCapturePlayerSoldiers();
|
void AttemptToCapturePlayerSoldiers();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+100
-36
@@ -36,9 +36,6 @@
|
|||||||
#include "BinaryHeap.hpp"
|
#include "BinaryHeap.hpp"
|
||||||
#include "opplist.h"
|
#include "opplist.h"
|
||||||
#include "Weapons.h"
|
#include "Weapons.h"
|
||||||
#include "renderworld.h"
|
|
||||||
#include "Cheats.h"
|
|
||||||
#include "Handle UI.h"
|
|
||||||
|
|
||||||
//forward declarations of common classes to eliminate includes
|
//forward declarations of common classes to eliminate includes
|
||||||
class OBJECTTYPE;
|
class OBJECTTYPE;
|
||||||
@@ -59,8 +56,19 @@ extern BOOLEAN InGasSpot(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel);
|
|||||||
// skiplist has extra level of pointers every 4 elements, so a level 5is optimized for
|
// skiplist has extra level of pointers every 4 elements, so a level 5is optimized for
|
||||||
// 4 to the power of 5 elements, or 2 to the power of 10, 1024
|
// 4 to the power of 5 elements, or 2 to the power of 10, 1024
|
||||||
|
|
||||||
|
//#define PATHAI_VISIBLE_DEBUG
|
||||||
|
|
||||||
//#define PATHAI_SKIPLIST_DEBUG
|
//#define PATHAI_SKIPLIST_DEBUG
|
||||||
|
|
||||||
|
#ifdef PATHAI_VISIBLE_DEBUG
|
||||||
|
#include "video.h"
|
||||||
|
|
||||||
|
//extern INT16 gsCoverValue[WORLD_MAX];
|
||||||
|
extern INT16 * gsCoverValue;
|
||||||
|
BOOLEAN gfDisplayCoverValues = TRUE;
|
||||||
|
BOOLEAN gfDrawPathPoints = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOLEAN gfPlotPathToExitGrid = FALSE;
|
BOOLEAN gfPlotPathToExitGrid = FALSE;
|
||||||
BOOLEAN gfRecalculatingExistingPathCost = FALSE;
|
BOOLEAN gfRecalculatingExistingPathCost = FALSE;
|
||||||
UINT8 gubGlobalPathFlags = 0;
|
UINT8 gubGlobalPathFlags = 0;
|
||||||
@@ -605,12 +613,15 @@ int AStarPathfinder::GetPath(SOLDIERTYPE *s ,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
|
||||||
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
ResetDebugInfoValues();
|
memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
|
||||||
gRenderDebugInfoValues[ StartNode ] = 0;
|
|
||||||
PATHAI_VISIBLE_DEBUG_Counter = 1;
|
|
||||||
}
|
}
|
||||||
|
gsCoverValue[ StartNode ] = 0;
|
||||||
|
PATHAI_VISIBLE_DEBUG_Counter = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
//init other private data, mostly flags
|
//init other private data, mostly flags
|
||||||
endDir = lastDir = direction = startDir = 0;
|
endDir = lastDir = direction = startDir = 0;
|
||||||
@@ -775,10 +786,12 @@ int AStarPathfinder::GetPath(SOLDIERTYPE *s ,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
SetRenderFlags( RENDER_FLAG_FULL );
|
SetRenderFlags( RENDER_FLAG_FULL );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Count the number of steps, but keep it less than the max path length.
|
// Count the number of steps, but keep it less than the max path length.
|
||||||
// Adjust the parent until it begins at the tail end of the max path length (or the dest if reachable)
|
// Adjust the parent until it begins at the tail end of the max path length (or the dest if reachable)
|
||||||
@@ -861,10 +874,12 @@ int AStarPathfinder::GetPath(SOLDIERTYPE *s ,
|
|||||||
sizePath = giPathDataSize;
|
sizePath = giPathDataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
SetRenderFlags( RENDER_FLAG_FULL );
|
SetRenderFlags( RENDER_FLAG_FULL );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef COUNT_PATHS
|
#ifdef COUNT_PATHS
|
||||||
guiSuccessfulPathChecks++;
|
guiSuccessfulPathChecks++;
|
||||||
@@ -976,13 +991,15 @@ void AStarPathfinder::ExecuteAStarLogic()
|
|||||||
SetAStarStatus(ParentNode, AStar_Closed);
|
SetAStarStatus(ParentNode, AStar_Closed);
|
||||||
//ClosedList.push_back(ParentNode);
|
//ClosedList.push_back(ParentNode);
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
if (gRenderDebugInfoValues[ParentNode] > 0)
|
if (gsCoverValue[ ParentNode ] > 0)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[ParentNode] *= -1;
|
gsCoverValue[ ParentNode ] *= -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Shouldn't G and AP be the same thing?
|
// Shouldn't G and AP be the same thing?
|
||||||
INT16 baseGCost = GetAStarG(ParentNode);
|
INT16 baseGCost = GetAStarG(ParentNode);
|
||||||
@@ -1065,7 +1082,7 @@ void AStarPathfinder::ExecuteAStarLogic()
|
|||||||
gpWorldLevelData[ CurrentNode ].ubExtFlags[0] |= MAPELEMENT_EXT_CLIMBPOINT;
|
gpWorldLevelData[ CurrentNode ].ubExtFlags[0] |= MAPELEMENT_EXT_CLIMBPOINT;
|
||||||
gpWorldLevelData[ ParentNode ].ubExtFlags[1] |= MAPELEMENT_EXT_CLIMBPOINT;
|
gpWorldLevelData[ ParentNode ].ubExtFlags[1] |= MAPELEMENT_EXT_CLIMBPOINT;
|
||||||
#ifdef ROOF_DEBUG
|
#ifdef ROOF_DEBUG
|
||||||
gRenderDebugInfoValues[CurrentNode] = 1;
|
gsCoverValue[CurrentNode] = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1163,13 +1180,26 @@ void AStarPathfinder::ExecuteAStarLogic()
|
|||||||
int AStarH = CalcH();
|
int AStarH = CalcH();
|
||||||
int AStarF = (AStarG + extraGCoverCost) + AStarH;
|
int AStarF = (AStarG + extraGCoverCost) + AStarH;
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
if (gRenderDebugInfoValues[CurrentNode] == 0x7FFFFFFF)
|
if (gsCoverValue[CurrentNode] == 0x7F7F)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[CurrentNode] = (INT16) AStarF;
|
//gsCoverValue[CurrentNode] = PATHAI_VISIBLE_DEBUG_Counter++;
|
||||||
|
gsCoverValue[CurrentNode] = (INT16) AStarF;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
else if (gsCoverValue[CurrentNodeIndex] >= 0)
|
||||||
|
{
|
||||||
|
gsCoverValue[CurrentNodeIndex]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gsCoverValue[CurrentNodeIndex]--;
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//insert this node onto the heap
|
//insert this node onto the heap
|
||||||
if (GetAStarStatus(CurrentNode) == AStar_Init)
|
if (GetAStarStatus(CurrentNode) == AStar_Init)
|
||||||
@@ -1350,7 +1380,7 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: dragging someone
|
// Flugente: dragging someone
|
||||||
if ( pSoldier->IsDragging( false ) )
|
if ( pSoldier->IsDragging() )
|
||||||
{
|
{
|
||||||
movementAPCost *= gItemSettings.fDragAPCostModifier;
|
movementAPCost *= gItemSettings.fDragAPCostModifier;
|
||||||
}
|
}
|
||||||
@@ -2220,7 +2250,9 @@ INT32 FindBestPath(SOLDIERTYPE *s , INT32 sDestination, INT8 bLevel, INT16 usMov
|
|||||||
CHAR8 zTempString[1000], zTS[50];
|
CHAR8 zTempString[1000], zTS[50];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PATHAI_VISIBLE_DEBUG
|
||||||
UINT16 usCounter = 0;
|
UINT16 usCounter = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
fVehicle = FALSE;
|
fVehicle = FALSE;
|
||||||
iOriginationX = iOriginationY = 0;
|
iOriginationX = iOriginationY = 0;
|
||||||
@@ -2470,10 +2502,12 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
|||||||
memset( pathQ, 0, iMaxPathQ * sizeof( path_t ) );
|
memset( pathQ, 0, iMaxPathQ * sizeof( path_t ) );
|
||||||
memset( trailTree, 0, iMaxTrailTree * sizeof( trail_t ) );
|
memset( trailTree, 0, iMaxTrailTree * sizeof( trail_t ) );
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
ResetDebugInfoValues();
|
memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bSkipListLevel = 1;
|
bSkipListLevel = 1;
|
||||||
iSkipListSize = 0;
|
iSkipListSize = 0;
|
||||||
@@ -2585,13 +2619,15 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
|||||||
// remember the cost used to get here...
|
// remember the cost used to get here...
|
||||||
prevCost = gubWorldMovementCosts[ trailTree[ sCurPathNdx ].sGridNo ][ trailTree[ sCurPathNdx ].stepDir ][ bLevel ];
|
prevCost = gubWorldMovementCosts[ trailTree[ sCurPathNdx ].sGridNo ][ trailTree[ sCurPathNdx ].stepDir ][ bLevel ];
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
{
|
{
|
||||||
if (gRenderDebugInfoValues[ curLoc ] > 0)
|
if (gsCoverValue[ curLoc ] > 0)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[ curLoc ] *= -1;
|
gsCoverValue[ curLoc ] *= -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (fTurnSlow)
|
if (fTurnSlow)
|
||||||
@@ -3517,13 +3553,27 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
|||||||
// costs less than the best so far to the same location?
|
// costs less than the best so far to the same location?
|
||||||
if (trailCostUsed[newLoc] != gubGlobalPathCount || newTotCost < trailCost[newLoc])
|
if (trailCostUsed[newLoc] != gubGlobalPathCount || newTotCost < trailCost[newLoc])
|
||||||
{
|
{
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
|
||||||
{
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
if (gRenderDebugInfoValues[newLoc] == 0x7FFFFFFF)
|
|
||||||
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
|
{
|
||||||
|
if (gsCoverValue[newLoc] == 0x7F7F)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[newLoc] = usCounter++;
|
gsCoverValue[newLoc] = usCounter++;
|
||||||
}
|
}
|
||||||
}
|
/*
|
||||||
|
else if (gsCoverValue[newLoc] >= 0)
|
||||||
|
{
|
||||||
|
gsCoverValue[newLoc]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gsCoverValue[newLoc]--;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//NEWQUENODE;
|
//NEWQUENODE;
|
||||||
{
|
{
|
||||||
@@ -3766,13 +3816,20 @@ ENDOFLOOP:
|
|||||||
while (pathQNotEmpty && pathNotYetFound);
|
while (pathQNotEmpty && pathNotYetFound);
|
||||||
|
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
{
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
if ( guiCurrentScreen == GAME_SCREEN )
|
|
||||||
{
|
{
|
||||||
InvalidateRegion(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
|
SetRenderFlags( RENDER_FLAG_FULL );
|
||||||
|
if ( guiCurrentScreen == GAME_SCREEN )
|
||||||
|
{
|
||||||
|
RenderWorld();
|
||||||
|
RenderCoverDebug( );
|
||||||
|
InvalidateScreen( );
|
||||||
|
EndFrameBufferRender();
|
||||||
|
RefreshScreen( NULL );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// work finished. Did we find a path?
|
// work finished. Did we find a path?
|
||||||
@@ -3827,10 +3884,17 @@ ENDOFLOOP:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_PATHFINDING && DEBUG_CHEAT_LEVEL())
|
#if defined( PATHAI_VISIBLE_DEBUG )
|
||||||
{
|
if (gfDisplayCoverValues && gfDrawPathPoints)
|
||||||
InvalidateRegion(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
|
{
|
||||||
}
|
SetRenderFlags( RENDER_FLAG_FULL );
|
||||||
|
RenderWorld();
|
||||||
|
RenderCoverDebug( );
|
||||||
|
InvalidateScreen( );
|
||||||
|
EndFrameBufferRender();
|
||||||
|
RefreshScreen( NULL );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// return path length : serves as a "successful" flag and a path length counter
|
// return path length : serves as a "successful" flag and a path length counter
|
||||||
|
|||||||
@@ -713,6 +713,10 @@ void RemoveCorpse( INT32 iCorpseID )
|
|||||||
DeleteAniTile( gRottingCorpse[ iCorpseID ].pAniTile );
|
DeleteAniTile( gRottingCorpse[ iCorpseID ].pAniTile );
|
||||||
|
|
||||||
FreeCorpsePalettes( &( gRottingCorpse[ iCorpseID ] ) );
|
FreeCorpsePalettes( &( gRottingCorpse[ iCorpseID ] ) );
|
||||||
|
|
||||||
|
const auto sGridNo = gRottingCorpse[iCorpseID].def.sGridNo;
|
||||||
|
auto pStructure = FindLastStructure(sGridNo, STRUCTURE_CORPSE);
|
||||||
|
DeleteStructureFromWorld(pStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN CreateCorpsePalette( ROTTING_CORPSE *pCorpse )
|
BOOLEAN CreateCorpsePalette( ROTTING_CORPSE *pCorpse )
|
||||||
@@ -1062,7 +1066,7 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
|
|||||||
DropKeysInKeyRing( pSoldier, pSoldier->sGridNo, pSoldier->pathing.bLevel, bVisible, FALSE, 0, FALSE );
|
DropKeysInKeyRing( pSoldier, pSoldier->sGridNo, pSoldier->pathing.bLevel, bVisible, FALSE, 0, FALSE );
|
||||||
|
|
||||||
// Flugente: even if we forbid militia from dropping their equipment, they will still drop what they took via sector inventory (this functions only drops what they took)
|
// Flugente: even if we forbid militia from dropping their equipment, they will still drop what they took via sector inventory (this functions only drops what they took)
|
||||||
pSoldier->DropSectorEquipment();
|
pSoldier->DropSectorEquipment( NOWHERE );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make team look for items
|
// Make team look for items
|
||||||
@@ -1108,7 +1112,8 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
|
|||||||
iCorpseID = AddRottingCorpse( &Corpse );
|
iCorpseID = AddRottingCorpse( &Corpse );
|
||||||
|
|
||||||
// If this is our guy......make visible...
|
// If this is our guy......make visible...
|
||||||
if ( iCorpseID != -1 && pSoldier->bTeam == OUR_TEAM || gbPublicOpplist[OUR_TEAM][pSoldier->ubID] == SEEN_CURRENTLY )
|
//if ( pSoldier->bTeam == gbPlayerNum )
|
||||||
|
if ( iCorpseID != -1 )
|
||||||
{
|
{
|
||||||
MakeCorpseVisible( pSoldier, &( gRottingCorpse[ iCorpseID ] ) );
|
MakeCorpseVisible( pSoldier, &( gRottingCorpse[ iCorpseID ] ) );
|
||||||
}
|
}
|
||||||
@@ -1770,10 +1775,10 @@ BOOLEAN IsValidDecapitationCorpse( ROTTING_CORPSE *pCorpse )
|
|||||||
|
|
||||||
ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo, INT8 bLevel )
|
ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo, INT8 bLevel )
|
||||||
{
|
{
|
||||||
STRUCTURE *pStructure, *pBaseStructure;
|
STRUCTURE *pStructure, *pBaseStructure;
|
||||||
INT32 sBaseGridNo;
|
INT32 sBaseGridNo;
|
||||||
|
|
||||||
pStructure = FindStructure( sGridNo, STRUCTURE_CORPSE );
|
pStructure = FindLastStructure( sGridNo, STRUCTURE_CORPSE );
|
||||||
|
|
||||||
if ( pStructure != NULL )
|
if ( pStructure != NULL )
|
||||||
{
|
{
|
||||||
@@ -2535,9 +2540,6 @@ void LookForAndMayCommentOnSeeingCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, U
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pCorpse->fActivated && pCorpse->def.bVisible != 1)
|
|
||||||
pCorpse->def.bVisible = 1;
|
|
||||||
|
|
||||||
if ( pCorpse->def.ubType != ROTTING_STAGE2 )
|
if ( pCorpse->def.ubType != ROTTING_STAGE2 )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3031,7 +3031,7 @@ BOOLEAN RepairIsDone(DEALER_SPECIAL_ITEM* pSpecial)
|
|||||||
|
|
||||||
// max condition of all permanent attachments on it
|
// max condition of all permanent attachments on it
|
||||||
for (attachmentList::iterator iter = RepairItem.ItemObject[0]->attachments.begin(); iter != RepairItem.ItemObject[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = RepairItem.ItemObject[0]->attachments.begin(); iter != RepairItem.ItemObject[0]->attachments.end(); ++iter) {
|
||||||
if ( CanDealerRepairItem( gbSelectedArmsDealerID, iter->usItem ) && iter->exists())
|
if ( iter->exists() && CanDealerRepairItem( gbSelectedArmsDealerID, iter->usItem ) )
|
||||||
{
|
{
|
||||||
// fix it up
|
// fix it up
|
||||||
(*iter)[0]->data.objectStatus = 100;
|
(*iter)[0]->data.objectStatus = 100;
|
||||||
|
|||||||
@@ -4223,7 +4223,7 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: VIPs
|
// Flugente: VIPs
|
||||||
if (ISVIP(pSoldier))
|
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP )
|
||||||
{
|
{
|
||||||
DeleteVIP( pSoldier->sSectorX, pSoldier->sSectorY );
|
DeleteVIP( pSoldier->sSectorX, pSoldier->sSectorY );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9046,7 +9046,7 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flugente: drag people
|
// Flugente: drag people
|
||||||
if ( pSoldier->IsDragging( false ) )
|
if ( pSoldier->IsDragging() )
|
||||||
{
|
{
|
||||||
pSoldier->sAniDelay = gItemSettings.fDragAPCostModifier * pSoldier->sAniDelay;
|
pSoldier->sAniDelay = gItemSettings.fDragAPCostModifier * pSoldier->sAniDelay;
|
||||||
}
|
}
|
||||||
@@ -9700,85 +9700,6 @@ void SOLDIERTYPE::BeginSoldierClimbWallUp( void )
|
|||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void SOLDIERTYPE::BeginSoldierJumpWindowAI(void)
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("check if we can jump through window"));
|
|
||||||
|
|
||||||
//UINT8 ubDirection = this->aiData.usActionData;
|
|
||||||
UINT8 ubDirection = this->ubDirection;
|
|
||||||
|
|
||||||
INT32 sWindowGridNo = this->sGridNo;
|
|
||||||
if ( ubDirection == NORTH || ubDirection == WEST )
|
|
||||||
sWindowGridNo = NewGridNo(this->sGridNo, (UINT16)DirectionInc((UINT8)ubDirection));
|
|
||||||
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("sWindowGridNo %d direction %d", sWindowGridNo, ubDirection));
|
|
||||||
|
|
||||||
if (//CheckWindow(this->sGridNo, ubDirection, gGameExternalOptions.fCanJumpThroughClosedWindows) &&
|
|
||||||
IsJumpableWindowPresentAtGridNo(sWindowGridNo, ubDirection, gGameExternalOptions.fCanJumpThroughClosedWindows) &&
|
|
||||||
//FindWindowJumpDirection(this, this->sGridNo, bDirection, &bDirection) &&
|
|
||||||
this->pathing.bLevel == 0 &&
|
|
||||||
(ubDirection == NORTH || ubDirection == EAST || ubDirection == SOUTH || ubDirection == WEST) )
|
|
||||||
{
|
|
||||||
// Flugente: if we are jumping through an intact window, smash it during our animation
|
|
||||||
if ( gGameExternalOptions.fCanJumpThroughClosedWindows )
|
|
||||||
{
|
|
||||||
// is there really an intact window that we jump through?
|
|
||||||
if ( IsJumpableWindowPresentAtGridNo(sWindowGridNo, ubDirection, TRUE) && !IsJumpableWindowPresentAtGridNo(sWindowGridNo, ubDirection, FALSE) )
|
|
||||||
{
|
|
||||||
STRUCTURE* pStructure = FindStructure(sWindowGridNo, STRUCTURE_WALLNWINDOW);
|
|
||||||
if ( pStructure && !(pStructure->fFlags & STRUCTURE_OPEN) )
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("jumping through closed window, damage soldier"));
|
|
||||||
// intact window found. Smash it!
|
|
||||||
WindowHit(sWindowGridNo, pStructure->usStructureID, (ubDirection == SOUTH || ubDirection == EAST), TRUE, PlayerCanHearNoise(this));
|
|
||||||
|
|
||||||
// we get a bit of damage for jumping through a window
|
|
||||||
this->SoldierTakeDamage(0, 2 + 2 * Random(4), 0, 1000, TAKE_DAMAGE_ELECTRICITY, NOBODY, sWindowGridNo, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->sTempNewGridNo = NewGridNo(this->sGridNo, (UINT16)DirectionInc(ubDirection));
|
|
||||||
this->flags.fDontChargeTurningAPs = TRUE;
|
|
||||||
EVENT_InternalSetSoldierDesiredDirection(this, ubDirection, FALSE, this->usAnimState);
|
|
||||||
this->flags.fTurningUntilDone = TRUE;
|
|
||||||
// ATE: Reset flag to go back to prone...
|
|
||||||
|
|
||||||
// Flugente: In case an animation is missing (civilian bodytypes), we TELEPORT instead
|
|
||||||
if ( IsAnimationValidForBodyType(this, JUMPWINDOWS) == FALSE )
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("teleport soldier to %d", this->sTempNewGridNo));
|
|
||||||
|
|
||||||
// sevenfm: deduct APs for jumping
|
|
||||||
if ( UsingNewInventorySystem() && FindBackpackOnSoldier(this) != ITEM_NOT_FOUND )
|
|
||||||
DeductPoints(this, GetAPsToJumpThroughWindows(this, TRUE), GetBPsToJumpThroughWindows(this, TRUE), SP_MOVEMENT_INTERRUPT);
|
|
||||||
else
|
|
||||||
DeductPoints(this, GetAPsToJumpThroughWindows(this, FALSE), GetBPsToJumpThroughWindows(this, FALSE), SP_MOVEMENT_INTERRUPT);
|
|
||||||
|
|
||||||
TeleportSoldier(this, this->sTempNewGridNo, TRUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("start jumping"));
|
|
||||||
this->flags.bTurningFromPronePosition = TURNING_FROM_PRONE_OFF;
|
|
||||||
this->EVENT_InitNewSoldierAnim(JUMPWINDOWS, 0, FALSE);
|
|
||||||
//this->usPendingAnimation = JUMPWINDOWS;
|
|
||||||
//EndAIGuysTurn(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flugente: should be fixed now, re-enable if not
|
|
||||||
// Flugente: if an AI guy, end turn (weird endless clock syndrome)
|
|
||||||
//if ( this->bTeam != OUR_TEAM )
|
|
||||||
//EndAIGuysTurn( this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ScreenMsg(FONT_LTRED, MSG_INTERFACE, L"[%d] %s cannot jump", this->ubID, this->GetName());
|
|
||||||
DebugAI(AI_MSG_INFO, this, String("CancelAIAction: cannot jump"));
|
|
||||||
CancelAIAction(this, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier )
|
UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier )
|
||||||
{
|
{
|
||||||
UINT32 uiChance;
|
UINT32 uiChance;
|
||||||
@@ -9932,7 +9853,7 @@ void SOLDIERTYPE::BeginSoldierGetup( void )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->bTurnsCollapsed++;
|
this->bTurnsCollapsed++;
|
||||||
if ( (gTacticalStatus.bBoxingState == BOXING) && (BOXER(this)) )
|
if ( (gTacticalStatus.bBoxingState == BOXING) && (this->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
if ( this->bTurnsCollapsed > 1 )
|
if ( this->bTurnsCollapsed > 1 )
|
||||||
{
|
{
|
||||||
@@ -11595,7 +11516,7 @@ void SOLDIERTYPE::MoveMerc( FLOAT dMovementChange, FLOAT dAngle, BOOLEAN fCheckR
|
|||||||
|
|
||||||
// Flugente: as we move a tile, we would now be too far away to drag someone.
|
// Flugente: as we move a tile, we would now be too far away to drag someone.
|
||||||
// So remember whether we were dragging (we have to set our position now, otherwise the person we drag woul soon occupy our gridno).
|
// So remember whether we were dragging (we have to set our position now, otherwise the person we drag woul soon occupy our gridno).
|
||||||
BOOLEAN currentlydragging = this->IsDragging();
|
BOOLEAN currentlydragging = this->IsDragging(true);
|
||||||
INT32 sOldGridNo = this->sGridNo;
|
INT32 sOldGridNo = this->sGridNo;
|
||||||
|
|
||||||
// OK, set new position
|
// OK, set new position
|
||||||
@@ -14747,7 +14668,7 @@ void SOLDIERTYPE::SoldierInventoryCoolDown( void )
|
|||||||
attachmentList::iterator iterend = (*pObj)[0]->attachments.end( );
|
attachmentList::iterator iterend = (*pObj)[0]->attachments.end( );
|
||||||
for ( attachmentList::iterator iter = (*pObj)[0]->attachments.begin( ); iter != iterend; ++iter )
|
for ( attachmentList::iterator iter = (*pObj)[0]->attachments.begin( ); iter != iterend; ++iter )
|
||||||
{
|
{
|
||||||
if ( Item[iter->usItem].usFlashLightRange )
|
if ( iter->exists() && Item[iter->usItem].usFlashLightRange )
|
||||||
flashlightfound = TRUE;
|
flashlightfound = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16897,7 +16818,7 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SOLDIERTYPE::DropSectorEquipment( )
|
void SOLDIERTYPE::DropSectorEquipment( INT32 UnloadedSectorGridNo)
|
||||||
{
|
{
|
||||||
// not if we already dropped the gear
|
// not if we already dropped the gear
|
||||||
if ( this->usSoldierFlagMask & SOLDIER_EQUIPMENT_DROPPED )
|
if ( this->usSoldierFlagMask & SOLDIER_EQUIPMENT_DROPPED )
|
||||||
@@ -16966,7 +16887,7 @@ void SOLDIERTYPE::DropSectorEquipment( )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddItemsToUnLoadedSector( this->sSectorX, this->sSectorY, this->bSectorZ, RandomGridNo( ), counter, pObject, 0, WORLD_ITEM_REACHABLE, 0, 1, FALSE );
|
AddItemsToUnLoadedSector( this->sSectorX, this->sSectorY, this->bSectorZ, UnloadedSectorGridNo, counter, pObject, 0, WORLD_ITEM_REACHABLE, 0, 1, FALSE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19125,7 +19046,7 @@ BOOLEAN SOLDIERTYPE::IsJamming( )
|
|||||||
{
|
{
|
||||||
if ( CanUseRadio( FALSE ) )
|
if ( CanUseRadio( FALSE ) )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
// if we cannot use the radio, remove that flag while we're at it
|
// if we cannot use the radio, remove that flag hile we're at it
|
||||||
else
|
else
|
||||||
usSoldierFlagMask &= ~SOLDIER_RADIO_OPERATOR_JAMMING;
|
usSoldierFlagMask &= ~SOLDIER_RADIO_OPERATOR_JAMMING;
|
||||||
}
|
}
|
||||||
@@ -24305,7 +24226,7 @@ BOOLEAN SOLDIERTYPE::CanBreakWindow(void)
|
|||||||
|
|
||||||
BOOLEAN SOLDIERTYPE::CanStartDrag(void)
|
BOOLEAN SOLDIERTYPE::CanStartDrag(void)
|
||||||
{
|
{
|
||||||
if (!this->IsDragging(false) && this->CanDragInPrinciple())
|
if (!this->IsDragging() && this->CanDragInPrinciple())
|
||||||
{
|
{
|
||||||
INT32 sNewGridNo = NewGridNo(this->sGridNo, DirectionInc(this->ubDirection));
|
INT32 sNewGridNo = NewGridNo(this->sGridNo, DirectionInc(this->ubDirection));
|
||||||
|
|
||||||
@@ -26376,13 +26297,3 @@ void SOLDIERTYPE::InitializeExtraData(void)
|
|||||||
|
|
||||||
this->delayedDamageFunction = nullptr;
|
this->delayedDamageFunction = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 SOLDIERTYPE::AnimHeight(void) const
|
|
||||||
{
|
|
||||||
return gAnimControl[this->usAnimState].ubHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 SOLDIERTYPE::AnimEndHeight(void) const
|
|
||||||
{
|
|
||||||
return gAnimControl[this->usAnimState].ubEndHeight;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1788,13 +1788,10 @@ public:
|
|||||||
void ChangeToFallbackAnimation( UINT8 fallBackDirection );
|
void ChangeToFallbackAnimation( UINT8 fallBackDirection );
|
||||||
|
|
||||||
// sevenfm
|
// sevenfm
|
||||||
void BeginSoldierJumpWindowAI(void);
|
|
||||||
void BreakWindow(void);
|
void BreakWindow(void);
|
||||||
BOOLEAN CanBreakWindow(void);
|
BOOLEAN CanBreakWindow(void);
|
||||||
BOOLEAN CanStartDrag(void);
|
BOOLEAN CanStartDrag(void);
|
||||||
void StartDrag(void);
|
void StartDrag(void);
|
||||||
UINT8 AnimHeight(void) const;
|
|
||||||
UINT8 AnimEndHeight(void) const;
|
|
||||||
|
|
||||||
void UpdateRobotControllerGivenController( void );
|
void UpdateRobotControllerGivenController( void );
|
||||||
void UpdateRobotControllerGivenRobot( void );
|
void UpdateRobotControllerGivenRobot( void );
|
||||||
@@ -1919,7 +1916,7 @@ public:
|
|||||||
void CancelMultiTurnAction(BOOLEAN fFinished);
|
void CancelMultiTurnAction(BOOLEAN fFinished);
|
||||||
BOOLEAN UpdateMultiTurnAction();
|
BOOLEAN UpdateMultiTurnAction();
|
||||||
|
|
||||||
void DropSectorEquipment();
|
void DropSectorEquipment( INT32 UnloadedSectorGridNo);
|
||||||
|
|
||||||
// sevenfm: Take new bomb with id = usItem from iventory to HANDPOS
|
// sevenfm: Take new bomb with id = usItem from iventory to HANDPOS
|
||||||
void TakeNewBombFromInventory(UINT16 usItem);
|
void TakeNewBombFromInventory(UINT16 usItem);
|
||||||
@@ -2059,7 +2056,7 @@ public:
|
|||||||
BOOLEAN CanDragPerson(SoldierID usID, BOOLEAN fCheckStance = FALSE);
|
BOOLEAN CanDragPerson(SoldierID usID, BOOLEAN fCheckStance = FALSE);
|
||||||
BOOLEAN CanDragCorpse(UINT16 usCorpseNum, BOOLEAN fCheckStance = FALSE);
|
BOOLEAN CanDragCorpse(UINT16 usCorpseNum, BOOLEAN fCheckStance = FALSE);
|
||||||
BOOLEAN CanDragStructure(INT32 sGridNo, BOOLEAN fCheckStance = FALSE);
|
BOOLEAN CanDragStructure(INT32 sGridNo, BOOLEAN fCheckStance = FALSE);
|
||||||
BOOLEAN IsDragging(bool aStopIfConditionNotSatisfied = true);
|
BOOLEAN IsDragging(bool aStopIfConditionNotSatisfied = false);
|
||||||
void SetDragOrderPerson( SoldierID usID );
|
void SetDragOrderPerson( SoldierID usID );
|
||||||
void SetDragOrderCorpse( UINT32 uiCorpseID );
|
void SetDragOrderCorpse( UINT32 uiCorpseID );
|
||||||
void SetDragOrderStructure( INT32 sGridNo );
|
void SetDragOrderStructure( INT32 sGridNo );
|
||||||
|
|||||||
@@ -37,10 +37,8 @@
|
|||||||
#define TANK( p ) (p->ubBodyType == TANK_NE || p->ubBodyType == TANK_NW )
|
#define TANK( p ) (p->ubBodyType == TANK_NE || p->ubBodyType == TANK_NW )
|
||||||
#define ENEMYROBOT( p ) (p->ubBodyType == ROBOTNOWEAPON && p->bTeam == ENEMY_TEAM)
|
#define ENEMYROBOT( p ) (p->ubBodyType == ROBOTNOWEAPON && p->bTeam == ENEMY_TEAM)
|
||||||
#define ARMED_VEHICLE( p ) ( TANK( p ) || COMBAT_JEEP(p) )
|
#define ARMED_VEHICLE( p ) ( TANK( p ) || COMBAT_JEEP(p) )
|
||||||
#define BOXER( p ) ( p->flags.uiStatusFlags & SOLDIER_BOXER )
|
|
||||||
#define ISVIP( p ) ( p->usSoldierFlagMask & SOLDIER_VIP )
|
|
||||||
|
|
||||||
//#define OK_ENTERABLE_VEHICLE( p ) ( ( p->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !TANK( p ) && p->stats.bLife >= OKLIFE )
|
//#define OK_ENTERABLE_VEHICLE( p ) ( ( p->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !TANK( p ) && p->stats.bLife >= OKLIFE )
|
||||||
#define OK_ENTERABLE_VEHICLE( p ) ( ( p->flags.uiStatusFlags & SOLDIER_VEHICLE ) && (!ARMED_VEHICLE( p ) || !(p->flags.uiStatusFlags & SOLDIER_ENEMY) ) && p->stats.bLife >= OKLIFE )
|
#define OK_ENTERABLE_VEHICLE( p ) ( ( p->flags.uiStatusFlags & SOLDIER_VEHICLE ) && (!ARMED_VEHICLE( p ) || !(p->flags.uiStatusFlags & SOLDIER_ENEMY) ) && p->stats.bLife >= OKLIFE )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier )
|
|||||||
{
|
{
|
||||||
OBJECTTYPE* pObject = &(gusSelectedSoldier->inv[HANDPOS]);
|
OBJECTTYPE* pObject = &(gusSelectedSoldier->inv[HANDPOS]);
|
||||||
for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) {
|
||||||
if ( Item[iter->usItem].visionrangebonus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].visionrangebonus > 0 )
|
||||||
{
|
{
|
||||||
fMercIsUsingScope = TRUE;
|
fMercIsUsingScope = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1218,9 +1218,10 @@ void EndInterrupt( BOOLEAN fMarkInterruptOccurred )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ubInterruptedSoldier = LATEST_INTERRUPT_GUY;
|
ubInterruptedSoldier = LATEST_INTERRUPT_GUY;
|
||||||
pSoldier = ubInterruptedSoldier;
|
|
||||||
|
|
||||||
DebugMsg( TOPIC_JA2INTERRUPT, DBG_LEVEL_3, String("INTERRUPT: interrupt over, soldier %d's team %d regains control", ubInterruptedSoldier, pSoldier->bTeam ) );
|
DebugMsg( TOPIC_JA2INTERRUPT, DBG_LEVEL_3, String("INTERRUPT: interrupt over, %d's team regains control", ubInterruptedSoldier ) );
|
||||||
|
|
||||||
|
pSoldier = ubInterruptedSoldier;
|
||||||
|
|
||||||
for ( SoldierID id = 0; id < MAX_NUM_SOLDIERS; ++id)
|
for ( SoldierID id = 0; id < MAX_NUM_SOLDIERS; ++id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1684,24 +1684,6 @@ void ItemCreationCallBack( UINT8 ubResult )
|
|||||||
memset(gszMsgBoxInputString,0,sizeof(gszMsgBoxInputString));
|
memset(gszMsgBoxInputString,0,sizeof(gszMsgBoxInputString));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CycleThroughTileDebugInfo()
|
|
||||||
{
|
|
||||||
const STR16 modeStrings[] =
|
|
||||||
{
|
|
||||||
L"Debug draw mode: Pathfinding",
|
|
||||||
L"Debug drawmode: Threat values",
|
|
||||||
L"Debug drawmode: Cover values",
|
|
||||||
L"Debug drawmode: Off",
|
|
||||||
};
|
|
||||||
|
|
||||||
gRenderDebugInfoMode += 1;
|
|
||||||
if (gRenderDebugInfoMode > DEBUG_OFF)
|
|
||||||
{
|
|
||||||
gRenderDebugInfoMode = 0;
|
|
||||||
}
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, modeStrings[gRenderDebugInfoMode]);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern BOOLEAN gfDisableRegionActive;
|
extern BOOLEAN gfDisableRegionActive;
|
||||||
extern BOOLEAN gfUserTurnRegionActive;
|
extern BOOLEAN gfUserTurnRegionActive;
|
||||||
|
|
||||||
@@ -2239,7 +2221,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
|
|||||||
// sevenfm: also stop dragging
|
// sevenfm: also stop dragging
|
||||||
if (gusSelectedSoldier != NOBODY &&
|
if (gusSelectedSoldier != NOBODY &&
|
||||||
gusSelectedSoldier &&
|
gusSelectedSoldier &&
|
||||||
gusSelectedSoldier->IsDragging(false))
|
gusSelectedSoldier->IsDragging())
|
||||||
{
|
{
|
||||||
gusSelectedSoldier->CancelDrag();
|
gusSelectedSoldier->CancelDrag();
|
||||||
DirtyMercPanelInterface(gusSelectedSoldier, DIRTYLEVEL2);
|
DirtyMercPanelInterface(gusSelectedSoldier, DIRTYLEVEL2);
|
||||||
@@ -4321,21 +4303,25 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
|
|||||||
|
|
||||||
// Make auto reload with magazines from sector inventory
|
// Make auto reload with magazines from sector inventory
|
||||||
case 'R':
|
case 'R':
|
||||||
HandleTBReloadAll();
|
if (fAlt && gusSelectedSoldier != NOBODY ) // Greysa: Moved here from 'r' to retain all functionality during testing.
|
||||||
|
{
|
||||||
|
if (CHEATER_CHEAT_LEVEL())
|
||||||
|
{
|
||||||
|
ReloadWeapon(gusSelectedSoldier, gusSelectedSoldier->ubAttackingHand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleTBReloadAll();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if( gusSelectedSoldier != NOBODY )
|
if( gusSelectedSoldier != NOBODY )
|
||||||
{
|
{
|
||||||
if( fAlt ) //reload selected merc's weapon
|
if( fAlt )
|
||||||
{
|
{
|
||||||
if ( CHEATER_CHEAT_LEVEL( ) )
|
HandleTBReload();
|
||||||
{
|
}
|
||||||
ReloadWeapon( gusSelectedSoldier, gusSelectedSoldier->ubAttackingHand );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
HandleTBReload();
|
|
||||||
}
|
|
||||||
else if( fCtrl )
|
else if( fCtrl )
|
||||||
{
|
{
|
||||||
if ( INFORMATION_CHEAT_LEVEL( ) )
|
if ( INFORMATION_CHEAT_LEVEL( ) )
|
||||||
@@ -4770,13 +4756,6 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Z':
|
case 'Z':
|
||||||
if (fCtrl)
|
|
||||||
{
|
|
||||||
if (DEBUG_CHEAT_LEVEL())
|
|
||||||
{
|
|
||||||
CycleThroughTileDebugInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6791,7 +6770,7 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
|
|||||||
pObj = &(pTeamSoldier->inv[gear]);
|
pObj = &(pTeamSoldier->inv[gear]);
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists())
|
if ( iter->exists() && Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
|
||||||
{
|
{
|
||||||
pGoggles = &(*iter);
|
pGoggles = &(*iter);
|
||||||
bestBonus = Item[ iter->usItem ].nightvisionrangebonus;
|
bestBonus = Item[ iter->usItem ].nightvisionrangebonus;
|
||||||
@@ -6839,7 +6818,7 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision)
|
|||||||
pObj = &(pTeamSoldier->inv[gear]);
|
pObj = &(pTeamSoldier->inv[gear]);
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists())
|
if ( iter->exists() && Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE )
|
||||||
{
|
{
|
||||||
pGoggles = &(*iter);
|
pGoggles = &(*iter);
|
||||||
bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus;
|
bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus;
|
||||||
|
|||||||
@@ -2081,7 +2081,7 @@ UINT8 HandleNonActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEA
|
|||||||
//sevenfm this should be checked only for guns because we can throw items with attached explosives
|
//sevenfm this should be checked only for guns because we can throw items with attached explosives
|
||||||
if(Item[pObj->usItem].usItemClass & IC_WEAPON )
|
if(Item[pObj->usItem].usItemClass & IC_WEAPON )
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV && iter->exists())
|
if ( iter->exists() && Item[ iter->usItem ].usItemClass & IC_EXPLOSV )
|
||||||
{
|
{
|
||||||
pObject = &(*iter);
|
pObject = &(*iter);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+23
-25
@@ -1036,7 +1036,7 @@ INT32 EffectiveArmour( OBJECTTYPE * pObj )
|
|||||||
iValue = iValue * (*pObj)[0]->data.objectStatus * Armour[ Item[pObj->usItem].ubClassIndex ].ubCoverage / 10000;
|
iValue = iValue * (*pObj)[0]->data.objectStatus * Armour[ Item[pObj->usItem].ubClassIndex ].ubCoverage / 10000;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
INT32 iValue2;
|
INT32 iValue2;
|
||||||
|
|
||||||
@@ -1062,7 +1062,7 @@ INT32 EffectiveArmourLBE( OBJECTTYPE * pObj )
|
|||||||
iValue = 0;
|
iValue = 0;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
INT32 iValue2;
|
INT32 iValue2;
|
||||||
|
|
||||||
@@ -1088,7 +1088,7 @@ INT32 ExplosiveEffectiveArmourLBE( OBJECTTYPE * pObj )
|
|||||||
iValue = 0;
|
iValue = 0;
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
INT32 iValue2;
|
INT32 iValue2;
|
||||||
|
|
||||||
@@ -1214,7 +1214,7 @@ INT32 ExplosiveEffectiveArmour( OBJECTTYPE * pObj )
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
INT32 iValue2;
|
INT32 iValue2;
|
||||||
|
|
||||||
@@ -1295,7 +1295,7 @@ INT16 FireEffectiveArmour( OBJECTTYPE * pObj )
|
|||||||
|
|
||||||
for ( attachmentList::iterator iter = ( *pObj )[0]->attachments.begin(); iter != ( *pObj )[0]->attachments.end(); ++iter )
|
for ( attachmentList::iterator iter = ( *pObj )[0]->attachments.begin(); iter != ( *pObj )[0]->attachments.end(); ++iter )
|
||||||
{
|
{
|
||||||
if ( Item[iter->usItem].usItemClass == IC_ARMOUR && ( *iter )[0]->data.objectStatus > 0 && iter->exists() )
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && ( *iter )[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
iValue += Item[iter->usItem].sFireResistance * ( *iter )[0]->data.objectStatus / 100;
|
iValue += Item[iter->usItem].sFireResistance * ( *iter )[0]->data.objectStatus / 100;
|
||||||
}
|
}
|
||||||
@@ -2560,7 +2560,7 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
|
|||||||
{
|
{
|
||||||
for (attachmentList::iterator iter = (*pObjAttHand)[0]->attachments.begin(); iter != (*pObjAttHand)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObjAttHand)[0]->attachments.begin(); iter != (*pObjAttHand)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (ItemHasHiddenMuzzleFlash(iter->usItem))
|
if ( iter->exists() && ItemHasHiddenMuzzleFlash(iter->usItem))
|
||||||
{
|
{
|
||||||
OBJECTTYPE* pA= &(*iter);
|
OBJECTTYPE* pA= &(*iter);
|
||||||
if ( (*pA)[0]->data.objectStatus >=USABLE)
|
if ( (*pA)[0]->data.objectStatus >=USABLE)
|
||||||
@@ -3346,7 +3346,7 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
|
|||||||
{
|
{
|
||||||
for (attachmentList::iterator iter = (*pObjUsed)[0]->attachments.begin(); iter != (*pObjUsed)[0]->attachments.end(); ++iter)
|
for (attachmentList::iterator iter = (*pObjUsed)[0]->attachments.begin(); iter != (*pObjUsed)[0]->attachments.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (ItemHasHiddenMuzzleFlash(iter->usItem))
|
if ( iter->exists() && ItemHasHiddenMuzzleFlash(iter->usItem))
|
||||||
{
|
{
|
||||||
OBJECTTYPE* pA= &(*iter);
|
OBJECTTYPE* pA= &(*iter);
|
||||||
if ( (*pA)[0]->data.objectStatus >=USABLE)
|
if ( (*pA)[0]->data.objectStatus >=USABLE)
|
||||||
@@ -4233,7 +4233,7 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
|||||||
// give bonus for surprise, but not so much as struggle would still occur
|
// give bonus for surprise, but not so much as struggle would still occur
|
||||||
iHitChance = CalcChanceToSteal( pSoldier, pTargetSoldier, pSoldier->aiData.bAimTime ) + 20;
|
iHitChance = CalcChanceToSteal( pSoldier, pTargetSoldier, pSoldier->aiData.bAimTime ) + 20;
|
||||||
}
|
}
|
||||||
else if ( pTargetSoldier->stats.bLife < OKLIFE || pTargetSoldier->bCollapsed )
|
else if (pTargetSoldier->stats.bLife < OKLIFE || pTargetSoldier->bCollapsed || pTargetSoldier->usSoldierFlagMask & SOLDIER_POW)
|
||||||
{
|
{
|
||||||
iHitChance = 100;
|
iHitChance = 100;
|
||||||
fSoldierCollapsed = TRUE;
|
fSoldierCollapsed = TRUE;
|
||||||
@@ -4257,10 +4257,10 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
|||||||
|
|
||||||
// sevenfm: bonus for boxers for attack from the back
|
// sevenfm: bonus for boxers for attack from the back
|
||||||
if (iHitChance < 100 &&
|
if (iHitChance < 100 &&
|
||||||
BOXER(pSoldier) &&
|
(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
!pSoldier->bBlindedCounter &&
|
!pSoldier->bBlindedCounter &&
|
||||||
gAnimControl[pTargetSoldier->usAnimState].ubEndHeight > ANIM_PRONE &&
|
gAnimControl[pTargetSoldier->usAnimState].ubEndHeight > ANIM_PRONE &&
|
||||||
BOXER(pTargetSoldier) &&
|
(pTargetSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
pTargetSoldier->usSoldierFlagMask2 & SOLDIER_BACK_ATTACK)
|
pTargetSoldier->usSoldierFlagMask2 & SOLDIER_BACK_ATTACK)
|
||||||
{
|
{
|
||||||
iHitChance += (100 - iHitChance) / 2;
|
iHitChance += (100 - iHitChance) / 2;
|
||||||
@@ -4876,7 +4876,7 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea
|
|||||||
if (pTargetSoldier->bActionPoints > 0 &&
|
if (pTargetSoldier->bActionPoints > 0 &&
|
||||||
gGameOptions.fNewTraitSystem &&
|
gGameOptions.fNewTraitSystem &&
|
||||||
gTacticalStatus.bBoxingState == BOXING &&
|
gTacticalStatus.bBoxingState == BOXING &&
|
||||||
BOXER(pTargetSoldier) &&
|
(pTargetSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
Chance(ubCounterattackChance) &&
|
Chance(ubCounterattackChance) &&
|
||||||
IS_MERC_BODY_TYPE(pSoldier) &&
|
IS_MERC_BODY_TYPE(pSoldier) &&
|
||||||
IS_MERC_BODY_TYPE(pTargetSoldier) &&
|
IS_MERC_BODY_TYPE(pTargetSoldier) &&
|
||||||
@@ -5111,7 +5111,7 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
|
|||||||
pObj = &(pSoldier->inv[HANDPOS]);
|
pObj = &(pSoldier->inv[HANDPOS]);
|
||||||
attachmentList::iterator iter;
|
attachmentList::iterator iter;
|
||||||
for (iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
for (iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
||||||
if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV && iter->exists())
|
if ( iter->exists() && Item[ iter->usItem ].usItemClass & IC_EXPLOSV )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -6089,7 +6089,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, Sol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, BOOLEAN fLargeForce, BOOLEAN fSound)
|
void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, BOOLEAN fLargeForce )
|
||||||
{
|
{
|
||||||
STRUCTURE * pWallAndWindow;
|
STRUCTURE * pWallAndWindow;
|
||||||
DB_STRUCTURE * pWallAndWindowInDB;
|
DB_STRUCTURE * pWallAndWindowInDB;
|
||||||
@@ -6210,12 +6210,10 @@ void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, B
|
|||||||
|
|
||||||
pNode = CreateAnimationTile( &AniParams );
|
pNode = CreateAnimationTile( &AniParams );
|
||||||
//ddd window{
|
//ddd window{
|
||||||
CompileWorldMovementCosts();
|
CompileWorldMovementCosts();
|
||||||
//ddd window}
|
//ddd window}
|
||||||
if ( fSound )
|
PlayJA2Sample( GLASS_SHATTER1 + Random(2), RATE_11025, MIDVOLUME, 1, SoundDir( sGridNo ) );
|
||||||
{
|
|
||||||
PlayJA2Sample(GLASS_SHATTER1 + Random(2), RATE_11025, MIDVOLUME, 1, SoundDir(sGridNo));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7995,7 +7993,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 i
|
|||||||
if (iSlot == VESTPOS && pVestPack->exists() == true)
|
if (iSlot == VESTPOS && pVestPack->exists() == true)
|
||||||
{
|
{
|
||||||
for (attachmentList::iterator iter = (*pVestPack)[0]->attachments.begin(); iter != (*pVestPack)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pVestPack)[0]->attachments.begin(); iter != (*pVestPack)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
INT32 protection = ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit );
|
INT32 protection = ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit );
|
||||||
|
|
||||||
@@ -8027,7 +8025,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 i
|
|||||||
if (pArmour->exists() == true)
|
if (pArmour->exists() == true)
|
||||||
{
|
{
|
||||||
for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists())
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
// bullet got through jacket; apply ceramic plate armour
|
// bullet got through jacket; apply ceramic plate armour
|
||||||
INT32 protection = ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit );
|
INT32 protection = ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit );
|
||||||
@@ -8073,7 +8071,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 i
|
|||||||
{
|
{
|
||||||
//Madd: put any attachments that someone might have added to the armour in the merc's inventory
|
//Madd: put any attachments that someone might have added to the armour in the merc's inventory
|
||||||
for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) {
|
||||||
if ( !AutoPlaceObject( pTarget, &(*iter), FALSE ) && iter->exists())
|
if ( iter->exists() && !AutoPlaceObject( pTarget, &(*iter), FALSE ) )
|
||||||
{ // put it on the ground
|
{ // put it on the ground
|
||||||
AddItemToPool( pTarget->sGridNo, &(*iter), 1, pTarget->pathing.bLevel, 0 , -1 );
|
AddItemToPool( pTarget->sGridNo, &(*iter), 1, pTarget->pathing.bLevel, 0 , -1 );
|
||||||
}
|
}
|
||||||
@@ -9725,7 +9723,7 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
|
|||||||
{
|
{
|
||||||
// Changed from DG by CJC to give higher chances of hitting with a stab or punch
|
// Changed from DG by CJC to give higher chances of hitting with a stab or punch
|
||||||
// sevenfm: lowered chance for boxers
|
// sevenfm: lowered chance for boxers
|
||||||
if (BOXER(pAttacker))
|
if (pAttacker->flags.uiStatusFlags & SOLDIER_BOXER)
|
||||||
iChance = 50 + (iAttRating - iDefRating) / 3;
|
iChance = 50 + (iAttRating - iDefRating) / 3;
|
||||||
else
|
else
|
||||||
iChance = 67 + (iAttRating - iDefRating) / 3;
|
iChance = 67 + (iAttRating - iDefRating) / 3;
|
||||||
@@ -9780,8 +9778,8 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
|
|||||||
|
|
||||||
// sevenfm: bonus for boxers for attacking from the back
|
// sevenfm: bonus for boxers for attacking from the back
|
||||||
if (ubMode == HTH_MODE_PUNCH &&
|
if (ubMode == HTH_MODE_PUNCH &&
|
||||||
BOXER(pAttacker) &&
|
(pAttacker->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
BOXER(pDefender) &&
|
(pDefender->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
iChance < 100 &&
|
iChance < 100 &&
|
||||||
!pAttacker->bBlindedCounter &&
|
!pAttacker->bBlindedCounter &&
|
||||||
gAnimControl[pDefender->usAnimState].ubEndHeight > ANIM_PRONE &&
|
gAnimControl[pDefender->usAnimState].ubEndHeight > ANIM_PRONE &&
|
||||||
|
|||||||
+1
-1
@@ -456,7 +456,7 @@ INT16 ArmourVersusFirePercent( SOLDIERTYPE * pSoldier );
|
|||||||
extern BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
|
extern BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
|
||||||
extern void WeaponHit( SoldierID usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 usDirection, INT16 sXPos, INT16 sYPos, INT16 sZPos, INT16 sRange, SoldierID ubAttackerID, BOOLEAN fHit, UINT8 ubSpecial, UINT8 ubHitLocation );
|
extern void WeaponHit( SoldierID usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 usDirection, INT16 sXPos, INT16 sYPos, INT16 sZPos, INT16 sRange, SoldierID ubAttackerID, BOOLEAN fHit, UINT8 ubSpecial, UINT8 ubHitLocation );
|
||||||
extern void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, SoldierID ubAttackerID, UINT16 sXPos, INT16 sYPos, INT16 sZPos, UINT16 usStructureID, INT32 iImpact, BOOLEAN fStopped );
|
extern void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, SoldierID ubAttackerID, UINT16 sXPos, INT16 sYPos, INT16 sZPos, UINT16 usStructureID, INT32 iImpact, BOOLEAN fStopped );
|
||||||
void WindowHit(INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, BOOLEAN fLargeForce, BOOLEAN fSound = TRUE);
|
extern void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, BOOLEAN fLargeForce );
|
||||||
// HEADROCK HAM 5.1: Moved to Bullets.h
|
// HEADROCK HAM 5.1: Moved to Bullets.h
|
||||||
extern BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
extern BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||||
extern void ShotMiss( SoldierID ubAttackerID, INT32 iBullet );
|
extern void ShotMiss( SoldierID ubAttackerID, INT32 iBullet );
|
||||||
|
|||||||
@@ -1180,7 +1180,7 @@ profileEndElementHandle(void *userData, const XML_Char *name)
|
|||||||
#include <vfs/Core/vfs_file_raii.h> // added by Flugente for vfs-stuff
|
#include <vfs/Core/vfs_file_raii.h> // added by Flugente for vfs-stuff
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
extern STR16 gzMercSkillTextNew[];
|
extern STR16* gzMercSkillTextNew;
|
||||||
|
|
||||||
void AnalyzeProfiles()
|
void AnalyzeProfiles()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "Overhead.h"
|
#include "Overhead.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "Points.h"
|
#include "Points.h"
|
||||||
#include "ai.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
@@ -190,6 +190,7 @@ typedef enum
|
|||||||
|
|
||||||
INT16 AdvanceToFiringRange( SOLDIERTYPE * pSoldier, INT16 sClosestOpponent );
|
INT16 AdvanceToFiringRange( SOLDIERTYPE * pSoldier, INT16 sClosestOpponent );
|
||||||
|
|
||||||
|
BOOLEAN AimingGun(SOLDIERTYPE *pSoldier);
|
||||||
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot);
|
void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot);
|
||||||
void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAttack);
|
void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAttack);
|
||||||
void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow);
|
void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow);
|
||||||
@@ -222,6 +223,7 @@ INT8 ArmedVehicleDecideAction( SOLDIERTYPE* pSoldier );
|
|||||||
// a variant of ClosestSeenOpponent(...), that allows to find enemies on a roof
|
// a variant of ClosestSeenOpponent(...), that allows to find enemies on a roof
|
||||||
INT32 ClosestSeenOpponentWithRoof(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
INT32 ClosestSeenOpponentWithRoof(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
||||||
|
|
||||||
|
INT8 CrowDecideAction( SOLDIERTYPE * pSoldier );
|
||||||
void DecideAlertStatus( SOLDIERTYPE *pSoldier );
|
void DecideAlertStatus( SOLDIERTYPE *pSoldier );
|
||||||
INT8 DecideAutoBandage( SOLDIERTYPE * pSoldier );
|
INT8 DecideAutoBandage( SOLDIERTYPE * pSoldier );
|
||||||
UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction );
|
UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction );
|
||||||
@@ -239,12 +241,9 @@ INT32 GetInterveningClimbingLocation( SOLDIERTYPE * pSoldier, INT32 sDestGridNo,
|
|||||||
UINT8 GetTraversalQuoteActionID( INT8 bDirection );
|
UINT8 GetTraversalQuoteActionID( INT8 bDirection );
|
||||||
INT32 GoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT8 bAction);
|
INT32 GoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT8 bAction);
|
||||||
|
|
||||||
ActionType HeadForTheStairCase( SOLDIERTYPE * pSoldier );
|
INT8 HeadForTheStairCase( SOLDIERTYPE * pSoldier );
|
||||||
|
|
||||||
BOOLEAN InSmoke(INT32 sGridNo, INT8 bLevel);
|
BOOLEAN InSmoke(INT32 sGridNo, INT8 bLevel);
|
||||||
BOOLEAN InSmoke(SOLDIERTYPE* pSoldier, INT32 sGridNo);
|
|
||||||
BOOLEAN InTearGas(SOLDIERTYPE* pSoldier, INT32 sGridNo);
|
|
||||||
BOOLEAN InMustardGas(SOLDIERTYPE* pSoldier, INT32 sGridNo);
|
|
||||||
BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||||
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||||
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include "opplist.h"
|
#include "opplist.h"
|
||||||
#include "Interface.h"
|
#include "Interface.h"
|
||||||
#include "Tactical Save.h"
|
#include "Tactical Save.h"
|
||||||
#include <Soldier macros.h>
|
|
||||||
|
|
||||||
#define AI_LIST_SIZE TOTAL_SOLDIERS
|
#define AI_LIST_SIZE TOTAL_SOLDIERS
|
||||||
|
|
||||||
@@ -181,7 +180,7 @@ BOOLEAN InsertIntoAIList( SoldierID ubID, INT8 bPriority )
|
|||||||
|
|
||||||
BOOLEAN SatisfiesAIListConditions( SOLDIERTYPE * pSoldier, UINT16 * pubDoneCount, BOOLEAN fDoRandomChecks )
|
BOOLEAN SatisfiesAIListConditions( SOLDIERTYPE * pSoldier, UINT16 * pubDoneCount, BOOLEAN fDoRandomChecks )
|
||||||
{
|
{
|
||||||
if ( (gTacticalStatus.bBoxingState == BOXING) && !BOXER(pSoldier) )
|
if ( (gTacticalStatus.bBoxingState == BOXING) && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
return( FALSE );
|
return( FALSE );
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-333
@@ -49,7 +49,6 @@
|
|||||||
#include "Soldier Functions.h" // added by SANDRO
|
#include "Soldier Functions.h" // added by SANDRO
|
||||||
#include "Text.h" // sevenfm
|
#include "Text.h" // sevenfm
|
||||||
#include "english.h" // sevenfm: for ESC key
|
#include "english.h" // sevenfm: for ESC key
|
||||||
#include "Food.h"
|
|
||||||
|
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
// needed to use the modularized tactical AI:
|
// needed to use the modularized tactical AI:
|
||||||
@@ -207,96 +206,18 @@ STR szAction[] = {
|
|||||||
"AI_ACTION_STOP_MEDIC"
|
"AI_ACTION_STOP_MEDIC"
|
||||||
};
|
};
|
||||||
|
|
||||||
STR16 wszAction[] = {
|
|
||||||
L"AI_ACTION_NONE",
|
|
||||||
|
|
||||||
L"AI_ACTION_RANDOM_PATROL",
|
|
||||||
L"AI_ACTION_SEEK_FRIEND",
|
|
||||||
L"AI_ACTION_SEEK_OPPONENT",
|
|
||||||
L"AI_ACTION_TAKE_COVER",
|
|
||||||
L"AI_ACTION_GET_CLOSER",
|
|
||||||
|
|
||||||
L"AI_ACTION_POINT_PATROL",
|
|
||||||
L"AI_ACTION_LEAVE_WATER_GAS",
|
|
||||||
L"AI_ACTION_SEEK_NOISE",
|
|
||||||
L"AI_ACTION_ESCORTED_MOVE",
|
|
||||||
L"AI_ACTION_RUN_AWAY",
|
|
||||||
|
|
||||||
L"AI_ACTION_KNIFE_MOVE",
|
|
||||||
L"AI_ACTION_APPROACH_MERC",
|
|
||||||
L"AI_ACTION_TRACK",
|
|
||||||
L"AI_ACTION_EAT",
|
|
||||||
L"AI_ACTION_PICKUP_ITEM",
|
|
||||||
|
|
||||||
L"AI_ACTION_SCHEDULE_MOVE",
|
|
||||||
L"AI_ACTION_WALK",
|
|
||||||
L"AI_ACTION_RUN",
|
|
||||||
L"AI_ACTION_WITHDRAW",
|
|
||||||
L"AI_ACTION_FLANK_LEFT",
|
|
||||||
L"AI_ACTION_FLANK_RIGHT",
|
|
||||||
L"AI_ACTION_MOVE_TO_CLIMB",
|
|
||||||
|
|
||||||
L"AI_ACTION_CHANGE_FACING",
|
|
||||||
|
|
||||||
L"AI_ACTION_CHANGE_STANCE",
|
|
||||||
|
|
||||||
L"AI_ACTION_YELLOW_ALERT",
|
|
||||||
L"AI_ACTION_RED_ALERT",
|
|
||||||
L"AI_ACTION_CREATURE_CALL",
|
|
||||||
L"AI_ACTION_PULL_TRIGGER",
|
|
||||||
|
|
||||||
L"AI_ACTION_USE_DETONATOR",
|
|
||||||
L"AI_ACTION_FIRE_GUN",
|
|
||||||
L"AI_ACTION_TOSS_PROJECTILE",
|
|
||||||
L"AI_ACTION_KNIFE_STAB",
|
|
||||||
L"AI_ACTION_THROW_KNIFE",
|
|
||||||
|
|
||||||
L"AI_ACTION_GIVE_AID",
|
|
||||||
L"AI_ACTION_WAIT",
|
|
||||||
L"AI_ACTION_PENDING_ACTION",
|
|
||||||
L"AI_ACTION_DROP_ITEM",
|
|
||||||
L"AI_ACTION_COWER",
|
|
||||||
|
|
||||||
L"AI_ACTION_STOP_COWERING",
|
|
||||||
L"AI_ACTION_OPEN_OR_CLOSE_DOOR",
|
|
||||||
L"AI_ACTION_UNLOCK_DOOR",
|
|
||||||
L"AI_ACTION_LOCK_DOOR",
|
|
||||||
L"AI_ACTION_LOWER_GUN",
|
|
||||||
|
|
||||||
L"AI_ACTION_ABSOLUTELY_NONE",
|
|
||||||
L"AI_ACTION_CLIMB_ROOF",
|
|
||||||
L"AI_ACTION_END_TURN",
|
|
||||||
L"AI_ACTION_END_COWER_AND_MOVE",
|
|
||||||
L"AI_ACTION_TRAVERSE_DOWN",
|
|
||||||
L"AI_ACTION_OFFER_SURRENDER",
|
|
||||||
L"AI_ACTION_RAISE_GUN",
|
|
||||||
L"AI_ACTION_STEAL_MOVE",
|
|
||||||
|
|
||||||
L"AI_ACTION_RELOAD_GUN",
|
|
||||||
|
|
||||||
L"AI_ACTION_JUMP_WINDOW",
|
|
||||||
L"AI_ACTION_FREE_PRISONER",
|
|
||||||
L"AI_ACTION_USE_SKILL",
|
|
||||||
L"AI_ACTION_DOCTOR",
|
|
||||||
L"AI_ACTION_DOCTOR_SELF",
|
|
||||||
L"AI_ACTION_SELFDETONATE",
|
|
||||||
L"AI_ACTION_STOP_MEDIC"
|
|
||||||
};
|
|
||||||
|
|
||||||
// sevenfm
|
// sevenfm
|
||||||
UINT32 guiAIStartCounter = 0, guiAILastCounter = 0;
|
UINT32 guiAIStartCounter = 0, guiAILastCounter = 0;
|
||||||
//UINT8 gubAISelectedSoldier = NOBODY;
|
//UINT8 gubAISelectedSoldier = NOBODY;
|
||||||
BOOLEAN gfLogsEnabled = TRUE;
|
BOOLEAN gfLogsEnabled = TRUE;
|
||||||
bool gLogDecideActionRed = true;
|
|
||||||
bool gLogDecideActionBlack = true;
|
|
||||||
|
|
||||||
void DebugAI( INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, bool doLog, INT8 bAction)
|
void DebugAI( INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, INT8 bAction )
|
||||||
{
|
{
|
||||||
FILE* DebugFile;
|
FILE* DebugFile;
|
||||||
CHAR8 msg[1024];
|
CHAR8 msg[1024];
|
||||||
CHAR8 buf[1024];
|
CHAR8 buf[1024];
|
||||||
|
|
||||||
if (!gfTurnBasedAI || !gfLogsEnabled || !doLog || pSoldier == nullptr)
|
if (!gfLogsEnabled || pSoldier == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(buf, 0, 1024 * sizeof(char));
|
memset(buf, 0, 1024 * sizeof(char));
|
||||||
@@ -337,7 +258,7 @@ void DebugAI( INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, bool doLog, IN
|
|||||||
strcat(msg, buf);
|
strcat(msg, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bAction >= AI_ACTION_NONE && bAction < AI_ACTION_INVALID)
|
if (bAction >= AI_ACTION_NONE && bAction <= AI_ACTION_LAST)
|
||||||
{
|
{
|
||||||
strcat(msg, " ");
|
strcat(msg, " ");
|
||||||
strcat(msg, szAction[bAction]);
|
strcat(msg, szAction[bAction]);
|
||||||
@@ -380,19 +301,16 @@ void DebugAI( INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, bool doLog, IN
|
|||||||
}
|
}
|
||||||
|
|
||||||
// also log to individual file for selected soldier
|
// also log to individual file for selected soldier
|
||||||
if (pSoldier)
|
sprintf(buf, "Logs\\AI_Decisions [%d].txt", pSoldier->ubID.i);
|
||||||
|
if ((DebugFile = fopen(buf, "a+t")) != NULL)
|
||||||
{
|
{
|
||||||
sprintf(buf, "Logs\\AI_Decisions [%d].txt", pSoldier->ubID.i);
|
if (bMsgType == AI_MSG_START)
|
||||||
if ((DebugFile = fopen(buf, "a+t")) != NULL)
|
|
||||||
{
|
{
|
||||||
if (bMsgType == AI_MSG_START)
|
|
||||||
{
|
|
||||||
fputs("\n", DebugFile);
|
|
||||||
}
|
|
||||||
fputs(msg, DebugFile);
|
|
||||||
fputs("\n", DebugFile);
|
fputs("\n", DebugFile);
|
||||||
fclose(DebugFile);
|
|
||||||
}
|
}
|
||||||
|
fputs(msg, DebugFile);
|
||||||
|
fputs("\n", DebugFile);
|
||||||
|
fclose(DebugFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,27 +354,6 @@ void DebugQuestInfo(STR szOutput)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static INT16 ShouldActionStayInProgress(SOLDIERTYPE* pSoldier)
|
|
||||||
{
|
|
||||||
// this here should never happen, but it seems to (turns sometimes hang!)
|
|
||||||
if ((pSoldier->aiData.bAction == AI_ACTION_CHANGE_FACING) && (pSoldier->pathing.bDesiredDirection != pSoldier->aiData.usActionData))
|
|
||||||
{
|
|
||||||
// don't try to pay any more APs for this, it was paid for once already!
|
|
||||||
pSoldier->pathing.bDesiredDirection = (INT8)pSoldier->aiData.usActionData; // turn to face direction in actionData
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
else if ((pSoldier->aiData.bAction == AI_ACTION_CHANGE_FACING) && (pSoldier->pathing.bDesiredDirection == pSoldier->aiData.usActionData))
|
|
||||||
{
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
else if (pSoldier->aiData.bAction == AI_ACTION_END_TURN || pSoldier->aiData.bAction == AI_ACTION_NONE)
|
|
||||||
{
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
// needs more time to complete action
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN InitAI( void )
|
BOOLEAN InitAI( void )
|
||||||
{
|
{
|
||||||
@@ -464,6 +361,13 @@ BOOLEAN InitAI( void )
|
|||||||
FILE * DebugFile;
|
FILE * DebugFile;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (gfDisplayCoverValues)
|
||||||
|
{
|
||||||
|
//memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//If we are not loading a saved game ( if we are, this has already been called )
|
//If we are not loading a saved game ( if we are, this has already been called )
|
||||||
if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
||||||
{
|
{
|
||||||
@@ -495,6 +399,10 @@ BOOLEAN InitAI( void )
|
|||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN AimingGun(SOLDIERTYPE *pSoldier)
|
||||||
|
{
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named inappropriately
|
void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named inappropriately
|
||||||
{
|
{
|
||||||
@@ -737,9 +645,6 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
{
|
{
|
||||||
// traversing offmap, ignore new situations
|
// traversing offmap, ignore new situations
|
||||||
}
|
}
|
||||||
// FIXME: Disabled temporarily to prevent AI actions constantly being cancelled during normal turn based combat.
|
|
||||||
// Need to find out when this conditional is actually needed.
|
|
||||||
#if 0
|
|
||||||
else if ( pSoldier->ubQuoteRecord == 0 && !gTacticalStatus.fAutoBandageMode )
|
else if ( pSoldier->ubQuoteRecord == 0 && !gTacticalStatus.fAutoBandageMode )
|
||||||
{
|
{
|
||||||
// don't force, don't want escorted mercs reacting to new opponents, etc.
|
// don't force, don't want escorted mercs reacting to new opponents, etc.
|
||||||
@@ -753,7 +658,6 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
}
|
}
|
||||||
DecideAlertStatus( pSoldier );
|
DecideAlertStatus( pSoldier );
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( pSoldier->ubQuoteRecord )
|
if ( pSoldier->ubQuoteRecord )
|
||||||
@@ -761,15 +665,6 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
// make sure we're not using combat AI
|
// make sure we're not using combat AI
|
||||||
pSoldier->aiData.bAlertStatus = STATUS_GREEN;
|
pSoldier->aiData.bAlertStatus = STATUS_GREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent AI deadlocking in case enemy is performing an action and player gets an interrupt.
|
|
||||||
// Without this, if player doesn't move any mercs, the AI soldier will wait until the deadlock is broken.
|
|
||||||
// By canceling the AI action, the AI can then reconsider actions.
|
|
||||||
//if (pSoldier->aiData.bAction == AI_ACTION_FIRE_GUN || pSoldier->aiData.bAction == AI_ACTION_KNIFE_MOVE || pSoldier->aiData.bAction == AI_ACTION_STEAL_MOVE || pSoldier->aiData.bAction == AI_ACTION_KNIFE_STAB)
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("New Situation"));
|
|
||||||
CancelAIAction(pSoldier, FALSE);
|
|
||||||
}
|
|
||||||
pSoldier->aiData.bNewSituation = WAS_NEW_SITUATION;
|
pSoldier->aiData.bNewSituation = WAS_NEW_SITUATION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,6 +674,7 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
// might have been in 'was' state; no longer so...
|
// might have been in 'was' state; no longer so...
|
||||||
pSoldier->aiData.bNewSituation = NOT_NEW_SITUATION;
|
pSoldier->aiData.bNewSituation = NOT_NEW_SITUATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TESTAI
|
#ifdef TESTAI
|
||||||
DebugMsg( TOPIC_JA2AI, DBG_LEVEL_3,String( ".... HANDLING AI FOR %d",pSoldier->ubID));
|
DebugMsg( TOPIC_JA2AI, DBG_LEVEL_3,String( ".... HANDLING AI FOR %d",pSoldier->ubID));
|
||||||
#endif
|
#endif
|
||||||
@@ -786,79 +682,42 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
/*********
|
/*********
|
||||||
Start of new overall AI system
|
Start of new overall AI system
|
||||||
********/
|
********/
|
||||||
|
|
||||||
if (gfTurnBasedAI)
|
if (gfTurnBasedAI)
|
||||||
{
|
{
|
||||||
#if 0
|
time_t tCurrentTime = time(0);
|
||||||
|
UINT32 uiShortDelay = 10;
|
||||||
|
UINT32 uiDelay = (UINT32)gGameExternalOptions.gubDeadLockDelay;
|
||||||
|
UINT32 uiTime = (UINT32)(tCurrentTime - gtTimeSinceMercAIStart);
|
||||||
|
BOOLEAN fKeyPressed = _KeyDown(ESC);
|
||||||
|
|
||||||
|
if ((uiTime > uiDelay || uiTime > uiShortDelay && fKeyPressed) && !gfUIInDeadlock)
|
||||||
|
//if ( ( GetJA2Clock() - gTacticalStatus.uiTimeSinceMercAIStart ) > ( (UINT32)gGameExternalOptions.gubDeadLockDelay * 1000 ) && !gfUIInDeadlock )
|
||||||
{
|
{
|
||||||
// added by Flugente: static pointers, used to break out of an endless circles
|
// ATE: Display message that deadlock occured...
|
||||||
static SOLDIERTYPE* pLastDecisionSoldier = NULL;
|
LiveMessage( "Breaking Deadlock" );
|
||||||
static INT16 lastdecisioncount = 0;
|
|
||||||
|
|
||||||
// simple solution to prevent an endless clock: remember the last soldier that decided an action. If its the same one, increase the counter.
|
|
||||||
// if counter is high enough, end this guy's turn
|
|
||||||
if (pSoldier == pLastDecisionSoldier)
|
|
||||||
{
|
|
||||||
// we will only end our turn this way if this function was called over 100 times with same soldier without ending a turn.
|
|
||||||
// so many actions in a single turn smell of an endless clock.
|
|
||||||
// If we end a turn normally, the counter will be set back to 0, so this wont be a problem if you have a single soldier left for multiple turns
|
|
||||||
if (lastdecisioncount >= 600)
|
|
||||||
{
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, wszAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData);
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, szAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData));
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Last action was %s ", szAction[pSoldier->aiData.bLastAction]));
|
|
||||||
|
|
||||||
EndAIDeadlock();
|
|
||||||
//EndAIGuysTurn(pSoldier);
|
|
||||||
lastdecisioncount = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++lastdecisioncount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pLastDecisionSoldier = pSoldier;
|
|
||||||
lastdecisioncount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
time_t tCurrentTime = time(0);
|
|
||||||
UINT32 uiShortDelay = 10;
|
|
||||||
UINT32 uiDelay = (UINT32)gGameExternalOptions.gubDeadLockDelay;
|
|
||||||
UINT32 uiTime = (UINT32)(tCurrentTime - gtTimeSinceMercAIStart);
|
|
||||||
BOOLEAN fKeyPressed = _KeyDown(ESC);
|
|
||||||
|
|
||||||
if ((uiTime > uiDelay || uiTime > uiShortDelay && fKeyPressed) && !gfUIInDeadlock)
|
|
||||||
//if ( ( GetJA2Clock() - gTacticalStatus.uiTimeSinceMercAIStart ) > ( (UINT32)gGameExternalOptions.gubDeadLockDelay * 1000 ) && !gfUIInDeadlock )
|
|
||||||
{
|
|
||||||
// ATE: Display message that deadlock occured...
|
|
||||||
LiveMessage( "Breaking Deadlock" );
|
|
||||||
|
|
||||||
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, wszAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData);
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, szAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData));
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Last action was %s ", szAction[pSoldier->aiData.bLastAction]));
|
|
||||||
|
|
||||||
|
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Aborting AI deadlock for [%d] %s %s data %d", pSoldier->ubID.i, pSoldier->GetName(), utf8_to_wstring(std::string(szAction[pSoldier->aiData.bAction])), pSoldier->aiData.usActionData);
|
||||||
|
DebugAI(String("Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, szAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData));
|
||||||
|
|
||||||
#ifdef JA2TESTVERSION
|
#ifdef JA2TESTVERSION
|
||||||
// display deadlock message
|
// display deadlock message
|
||||||
gfUIInDeadlock = TRUE;
|
gfUIInDeadlock = TRUE;
|
||||||
DebugAI( String("DEADLOCK soldier %d action %s ABC %d", pSoldier->ubID.i, gzActionStr[pSoldier->aiData.bAction], gTacticalStatus.ubAttackBusyCount ) );
|
DebugAI( String("DEADLOCK soldier %d action %s ABC %d", pSoldier->ubID.i, gzActionStr[pSoldier->aiData.bAction], gTacticalStatus.ubAttackBusyCount ) );
|
||||||
#else
|
#else
|
||||||
// If we are in beta version, also report message!
|
|
||||||
|
// If we are in beta version, also report message!
|
||||||
#ifdef JA2BETAVERSION
|
#ifdef JA2BETAVERSION
|
||||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_ERROR, L"Aborting AI deadlock for %d. Please sent DEBUG.TXT file and SAVE.", pSoldier->ubID.i );
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_ERROR, L"Aborting AI deadlock for %d. Please sent DEBUG.TXT file and SAVE.", pSoldier->ubID.i );
|
||||||
#endif
|
|
||||||
// just abort
|
|
||||||
EndAIDeadlock();
|
|
||||||
if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_UNDERAICONTROL) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
// just abort
|
||||||
|
EndAIDeadlock();
|
||||||
|
if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_UNDERAICONTROL) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We STILL do not want to issue new orders while an attack busy situation is going on. This can happen, for example,
|
// We STILL do not want to issue new orders while an attack busy situation is going on. This can happen, for example,
|
||||||
@@ -868,7 +727,7 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pSoldier->aiData.bActionInProgress)
|
if (pSoldier->aiData.bAction == AI_ACTION_NONE)
|
||||||
{
|
{
|
||||||
// being handled so turn off muzzle flash
|
// being handled so turn off muzzle flash
|
||||||
if ( pSoldier->flags.fMuzzleFlash )
|
if ( pSoldier->flags.fMuzzleFlash )
|
||||||
@@ -1004,12 +863,6 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
|||||||
{
|
{
|
||||||
ActionDone(pSoldier);
|
ActionDone(pSoldier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ShouldActionStayInProgress(pSoldier))
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Action %s was stuck as being in progress. Canceling action", szAction[pSoldier->aiData.bAction]));
|
|
||||||
ActionDone(pSoldier);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*********
|
/*********
|
||||||
End of new overall AI system
|
End of new overall AI system
|
||||||
@@ -1474,7 +1327,7 @@ void FreeUpNPCFromRoofClimb(SOLDIERTYPE *pSoldier )
|
|||||||
void ActionDone(SOLDIERTYPE *pSoldier)
|
void ActionDone(SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
// if an action is currently selected
|
// if an action is currently selected
|
||||||
//if (pSoldier->aiData.bAction != AI_ACTION_NONE)
|
if (pSoldier->aiData.bAction != AI_ACTION_NONE)
|
||||||
{
|
{
|
||||||
if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
|
||||||
{
|
{
|
||||||
@@ -1694,6 +1547,33 @@ INT16 ActionInProgress(SOLDIERTYPE *pSoldier)
|
|||||||
|
|
||||||
void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
|
void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
|
// added by Flugente: static pointers, used to break out of an endless circles (currently only used for zombie AI)
|
||||||
|
static SOLDIERTYPE* pLastDecisionSoldier = NULL;
|
||||||
|
static INT16 lastdecisioncount = 0;
|
||||||
|
|
||||||
|
// simple solution to prevent an endless clock: remember the last soldier that decided an action. If its the same one, increase the counter.
|
||||||
|
// if counter is high enough, end this guy's turn
|
||||||
|
if ( pSoldier == pLastDecisionSoldier )
|
||||||
|
{
|
||||||
|
// we will only end our turn this way if this function was called over 100 times with same soldier without ending a turn.
|
||||||
|
// so many actions in a single turn smell of an endless clock.
|
||||||
|
// If we end a turn normally, the counter will be set back to 0, so this wont be a problem if you have a single soldier left for multiple turns
|
||||||
|
if ( lastdecisioncount >= 100 )
|
||||||
|
{
|
||||||
|
// zombie is done doing harm...
|
||||||
|
EndAIGuysTurn( pSoldier);
|
||||||
|
lastdecisioncount = 0;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++lastdecisioncount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pLastDecisionSoldier = pSoldier;
|
||||||
|
lastdecisioncount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// yikes, this shouldn't occur! we should be trying to finish our move!
|
// yikes, this shouldn't occur! we should be trying to finish our move!
|
||||||
// pSoldier->flags.fNoAPToFinishMove = FALSE;
|
// pSoldier->flags.fNoAPToFinishMove = FALSE;
|
||||||
|
|
||||||
@@ -1726,8 +1606,6 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
|
|||||||
#ifdef DEBUGBUSY
|
#ifdef DEBUGBUSY
|
||||||
AINumMessage("Busy with action, skipping guy#",pSoldier->ubID);
|
AINumMessage("Busy with action, skipping guy#",pSoldier->ubID);
|
||||||
#endif
|
#endif
|
||||||
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Busy with action %s, skipping guy [%d]", wszAction[pSoldier->aiData.bAction], pSoldier->ubID);
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("Busy with action %s, skipping guy [%d]", wszAction[pSoldier->aiData.bAction], pSoldier->ubID));
|
|
||||||
|
|
||||||
// let it continue
|
// let it continue
|
||||||
return;
|
return;
|
||||||
@@ -1853,41 +1731,42 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
|
|||||||
{
|
{
|
||||||
pSoldier->aiData.bAction = AI_ACTION_NONE;
|
pSoldier->aiData.bAction = AI_ACTION_NONE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if he chose to continue doing nothing
|
// if he chose to continue doing nothing
|
||||||
if (pSoldier->aiData.bAction == AI_ACTION_NONE)
|
if (pSoldier->aiData.bAction == AI_ACTION_NONE)
|
||||||
{
|
|
||||||
#ifdef RECORDNET
|
|
||||||
fprintf(NetDebugFile,"\tMOVED BECOMING TRUE: Chose to do nothing, guynum %d\n",pSoldier->ubID);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DebugMsg (TOPIC_JA2AI,DBG_LEVEL_3,"NPC has no action assigned");
|
|
||||||
NPCDoesNothing(pSoldier); // sets pSoldier->moved to TRUE
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// to get here, we MUST have an action selected, but not in progress...
|
|
||||||
// see if we can afford to do this action
|
|
||||||
if (IsActionAffordable(pSoldier))
|
|
||||||
{
|
|
||||||
NPCDoesAct(pSoldier);
|
|
||||||
|
|
||||||
// perform the chosen action
|
|
||||||
pSoldier->aiData.bActionInProgress = ExecuteAction(pSoldier); // if started, mark us as busy
|
|
||||||
|
|
||||||
if ( !pSoldier->aiData.bActionInProgress && !TileIsOutOfBounds(pSoldier->sAbsoluteFinalDestination))
|
|
||||||
{
|
{
|
||||||
// turn based... abort this guy's turn
|
#ifdef RECORDNET
|
||||||
EndAIGuysTurn( pSoldier );
|
fprintf(NetDebugFile,"\tMOVED BECOMING TRUE: Chose to do nothing, guynum %d\n",pSoldier->ubID);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DEBUGDECISIONS
|
|
||||||
AINumMessage("HandleManAI - Not enough APs, skipping guy#",pSoldier->ubID);
|
|
||||||
#endif
|
#endif
|
||||||
HaltMoveForSoldierOutOfPoints( pSoldier);
|
|
||||||
return;
|
DebugMsg (TOPIC_JA2AI,DBG_LEVEL_3,"NPC has no action assigned");
|
||||||
|
NPCDoesNothing(pSoldier); // sets pSoldier->moved to TRUE
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// to get here, we MUST have an action selected, but not in progress...
|
||||||
|
// see if we can afford to do this action
|
||||||
|
if (IsActionAffordable(pSoldier))
|
||||||
|
{
|
||||||
|
NPCDoesAct(pSoldier);
|
||||||
|
|
||||||
|
// perform the chosen action
|
||||||
|
pSoldier->aiData.bActionInProgress = ExecuteAction(pSoldier); // if started, mark us as busy
|
||||||
|
|
||||||
|
if ( !pSoldier->aiData.bActionInProgress && !TileIsOutOfBounds(pSoldier->sAbsoluteFinalDestination))
|
||||||
|
{
|
||||||
|
// turn based... abort this guy's turn
|
||||||
|
EndAIGuysTurn( pSoldier );
|
||||||
|
lastdecisioncount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef DEBUGDECISIONS
|
||||||
|
AINumMessage("HandleManAI - Not enough APs, skipping guy#",pSoldier->ubID);
|
||||||
|
#endif
|
||||||
|
HaltMoveForSoldierOutOfPoints( pSoldier);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1920,7 +1799,6 @@ void RefreshAI(SOLDIERTYPE *pSoldier)
|
|||||||
if ((pSoldier->aiData.bAlertStatus == STATUS_BLACK) || (pSoldier->aiData.bAlertStatus == STATUS_RED))
|
if ((pSoldier->aiData.bAlertStatus == STATUS_BLACK) || (pSoldier->aiData.bAlertStatus == STATUS_RED))
|
||||||
{
|
{
|
||||||
// always freshly rethink things at start of his turn
|
// always freshly rethink things at start of his turn
|
||||||
//CancelAIAction(pSoldier, FALSE);
|
|
||||||
pSoldier->aiData.bNewSituation = IS_NEW_SITUATION;
|
pSoldier->aiData.bNewSituation = IS_NEW_SITUATION;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2403,24 +2281,14 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
|
|||||||
usHandItem = GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS]);
|
usHandItem = GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS]);
|
||||||
|
|
||||||
iRetCode = HandleItem( pSoldier, pSoldier->aiData.usActionData, pSoldier->bTargetLevel, usHandItem, FALSE );
|
iRetCode = HandleItem( pSoldier, pSoldier->aiData.usActionData, pSoldier->bTargetLevel, usHandItem, FALSE );
|
||||||
// If AI cannot shoot because of lack of APs, attempt to try again with lower aim.
|
|
||||||
// Usually happens when they have to turn before shooting. Without this, the game would cancel soldier's whole turn
|
|
||||||
if (iRetCode == ITEM_HANDLE_NOAPS && pSoldier->aiData.bAimTime > 0)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
pSoldier->aiData.bAimTime -= 1;
|
|
||||||
iRetCode = HandleItem(pSoldier, pSoldier->aiData.usActionData, pSoldier->bTargetLevel, usHandItem, FALSE);
|
|
||||||
} while (iRetCode == ITEM_HANDLE_NOAPS && pSoldier->aiData.bAimTime > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( iRetCode != ITEM_HANDLE_OK)
|
if ( iRetCode != ITEM_HANDLE_OK)
|
||||||
{
|
{
|
||||||
if ( iRetCode != ITEM_HANDLE_BROKEN ) // if the item broke, this is 'legal' and doesn't need reporting
|
if ( iRetCode != ITEM_HANDLE_BROKEN ) // if the item broke, this is 'legal' and doesn't need reporting
|
||||||
{
|
{
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String( "AI %d got error code %ld from HandleItem, doing action %d, has %d APs... aborting deadlock!", pSoldier->ubID, iRetCode, pSoldier->aiData.bAction, pSoldier->bActionPoints ) );
|
DebugAI( String( "AI %d got error code %ld from HandleItem, doing action %d, has %d APs... aborting deadlock!", pSoldier->ubID, iRetCode, pSoldier->aiData.bAction, pSoldier->bActionPoints ) );
|
||||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"AI %d got error code %ld from HandleItem, doing action %d... aborting deadlock!", pSoldier->ubID, iRetCode, pSoldier->aiData.bAction );
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"AI %d got error code %ld from HandleItem, doing action %d... aborting deadlock!", pSoldier->ubID, iRetCode, pSoldier->aiData.bAction );
|
||||||
}
|
}
|
||||||
|
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: !ITEM_HANDLE_OK"));
|
||||||
CancelAIAction( pSoldier, FORCE);
|
CancelAIAction( pSoldier, FORCE);
|
||||||
#ifdef TESTAICONTROL
|
#ifdef TESTAICONTROL
|
||||||
if (gfTurnBasedAI)
|
if (gfTurnBasedAI)
|
||||||
@@ -2744,30 +2612,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
|
|||||||
|
|
||||||
case AI_ACTION_JUMP_WINDOW:
|
case AI_ACTION_JUMP_WINDOW:
|
||||||
{
|
{
|
||||||
pSoldier->BeginSoldierJumpWindowAI();
|
pSoldier->BeginSoldierClimbWindow();
|
||||||
if ( gfTurnBasedAI )
|
|
||||||
{
|
|
||||||
//if (pSoldier->bActionPoints >= GetAPsToJumpThroughWindows(pSoldier, FALSE) + GetAPsToLook(pSoldier))
|
|
||||||
if ( pSoldier->bActionPoints >= GetAPsToLook(pSoldier) )
|
|
||||||
{
|
|
||||||
pSoldier->aiData.bNextAction = AI_ACTION_CHANGE_FACING;
|
|
||||||
INT32 sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
|
||||||
if ( !TileIsOutOfBounds(sClosestOpponent) )
|
|
||||||
pSoldier->aiData.usNextActionData = AIDirection(pSoldier->sGridNo, sClosestOpponent);
|
|
||||||
else
|
|
||||||
pSoldier->aiData.usNextActionData = PreRandom(8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pSoldier->aiData.bNextAction = AI_ACTION_END_TURN;
|
|
||||||
pSoldier->aiData.usNextActionData = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pSoldier->aiData.bNextAction = AI_ACTION_WAIT;
|
|
||||||
pSoldier->aiData.usNextActionData = REALTIME_AI_DELAY / 10;
|
|
||||||
}
|
|
||||||
ActionDone( pSoldier );
|
ActionDone( pSoldier );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2830,73 +2675,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_ACTION_DRINK_CANTEEN:
|
default:
|
||||||
DrinkFromInventory(pSoldier);
|
|
||||||
ActionDone(pSoldier);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AI_ACTION_HANDLE_ITEM:
|
|
||||||
iRetCode = HandleItem(pSoldier, pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, pSoldier->inv[HANDPOS].usItem, FALSE);
|
|
||||||
if ( iRetCode != ITEM_HANDLE_OK )
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction (AI_ACTION_HANDLE_ITEM): HandleItem error code %d", iRetCode));
|
|
||||||
CancelAIAction(pSoldier, FORCE);
|
|
||||||
EndAIGuysTurn(pSoldier);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AI_ACTION_PLANT_BOMB:
|
|
||||||
if ( pSoldier->inv[HANDPOS].exists() &&
|
|
||||||
(Item[pSoldier->inv[HANDPOS].usItem].usItemClass & IC_BOMB) )
|
|
||||||
{
|
|
||||||
OBJECTTYPE bombobj;
|
|
||||||
INT32 sSpot = pSoldier->sGridNo;
|
|
||||||
|
|
||||||
if ( !TileIsOutOfBounds(sSpot) &&
|
|
||||||
pSoldier->inv[HANDPOS].MoveThisObjectTo(bombobj, 1) == 0 )
|
|
||||||
{
|
|
||||||
bombobj.fFlags |= OBJECT_ARMED_BOMB;
|
|
||||||
bombobj[0]->data.misc.bDetonatorType = BOMB_TIMED;
|
|
||||||
bombobj[0]->data.misc.usBombItem = bombobj.usItem;
|
|
||||||
//bombobj[0]->data.misc.ubBombOwner = pSoldier->ubID + 2;
|
|
||||||
bombobj[0]->data.misc.ubBombOwner = 1;
|
|
||||||
bombobj[0]->data.misc.bDelay = 1 + Random(2);
|
|
||||||
//pSoldier->inv[HANDPOS][0]->data.bTrap = EffectiveExplosive(pSoldier) / 20 + EffectiveExpLevel(pSoldier, TRUE) / 2;
|
|
||||||
pSoldier->inv[HANDPOS][0]->data.bTrap = 6 + SoldierDifficultyLevel(pSoldier);
|
|
||||||
AddItemToPool(sSpot, &bombobj, INVISIBLE, pSoldier->pathing.bLevel, WORLD_ITEM_ARMED_BOMB, 0);
|
|
||||||
NotifySoldiersToLookforItems();
|
|
||||||
DeductPoints(pSoldier, APBPConstants[AP_INVENTORY_ARM] + APBPConstants[AP_DROP_BOMB], APBPConstants[BP_INVENTORY_ARM] + APBPConstants[BP_DROP_BOMB]);
|
|
||||||
if ( gAnimControl[pSoldier->usAnimState].ubHeight == ANIM_STAND )
|
|
||||||
{
|
|
||||||
pSoldier->EVENT_InitNewSoldierAnim(DROP_ITEM, 0, FALSE);
|
|
||||||
}
|
|
||||||
else if ( gAnimControl[pSoldier->usAnimState].ubHeight == ANIM_CROUCH )
|
|
||||||
{
|
|
||||||
pSoldier->EVENT_InitNewSoldierAnim(CUTTING_FENCE, 0, FALSE);
|
|
||||||
}
|
|
||||||
if ( pSoldier->bVisible != -1 )
|
|
||||||
{
|
|
||||||
PlayJA2Sample(THROW_IMPACT_2, RATE_11025, SoundVolume(MIDVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
|
|
||||||
}
|
|
||||||
ActionDone(pSoldier);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction (AI_ACTION_PLANT_BOMB): failed to move object"));
|
|
||||||
CancelAIAction(pSoldier, FORCE);
|
|
||||||
EndAIGuysTurn(pSoldier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction (AI_ACTION_PLANT_BOMB): failed to find bomb in hand"));
|
|
||||||
CancelAIAction(pSoldier, FORCE);
|
|
||||||
EndAIGuysTurn(pSoldier);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
#ifdef BETAVERSION
|
#ifdef BETAVERSION
|
||||||
NumMessage("ExecuteAction - Illegal action type = ",pSoldier->aiData.bAction);
|
NumMessage("ExecuteAction - Illegal action type = ",pSoldier->aiData.bAction);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+24
-353
@@ -27,7 +27,6 @@
|
|||||||
#include "SmokeEffects.h" // sevenfm
|
#include "SmokeEffects.h" // sevenfm
|
||||||
|
|
||||||
#include "GameInitOptionsScreen.h"
|
#include "GameInitOptionsScreen.h"
|
||||||
#include "Structure Wrap.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne()
|
// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne()
|
||||||
@@ -135,17 +134,18 @@ INT8 OKToAttack(SOLDIERTYPE * pSoldier, int target)
|
|||||||
|
|
||||||
BOOLEAN ConsiderProne( SOLDIERTYPE * pSoldier )
|
BOOLEAN ConsiderProne( SOLDIERTYPE * pSoldier )
|
||||||
{
|
{
|
||||||
INT32 sOpponentGridNo;
|
INT32 sOpponentGridNo;
|
||||||
INT8 bOpponentLevel;
|
INT8 bOpponentLevel;
|
||||||
INT32 iRangeInCellCoords;
|
INT32 iRange;
|
||||||
|
|
||||||
if (pSoldier->aiData.bAIMorale >= MORALE_NORMAL)
|
if (pSoldier->aiData.bAIMorale >= MORALE_NORMAL)
|
||||||
{
|
{
|
||||||
return( FALSE );
|
return( FALSE );
|
||||||
}
|
}
|
||||||
// We don't want to go prone if there is a nearby enemy
|
// We don't want to go prone if there is a nearby enemy
|
||||||
ClosestKnownOpponent( pSoldier, &sOpponentGridNo, &bOpponentLevel, nullptr, &iRangeInCellCoords);
|
ClosestKnownOpponent( pSoldier, &sOpponentGridNo, &bOpponentLevel );
|
||||||
if ( iRangeInCellCoords > 10*CELL_X_SIZE)
|
iRange = PythSpacesAway( pSoldier->sGridNo, sOpponentGridNo );
|
||||||
|
if (iRange > 10)
|
||||||
{
|
{
|
||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
@@ -397,11 +397,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
// sevenfm: movement mode tweaks
|
// sevenfm: movement mode tweaks
|
||||||
if (gGameExternalOptions.fAIMovementMode)
|
if (gGameExternalOptions.fAIMovementMode)
|
||||||
{
|
{
|
||||||
INT32 distanceToThreat;
|
INT32 sClosestThreat = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||||
const INT32 sClosestThreat = ClosestKnownOpponent(pSoldier, NULL, NULL, NULL, &distanceToThreat);
|
|
||||||
const auto mediumRange = TACTICAL_RANGE_CELL_COORDS / 2;
|
|
||||||
const auto close = TACTICAL_RANGE_CELL_COORDS / 4;
|
|
||||||
const auto reallyClose = TACTICAL_RANGE_CELL_COORDS / 8;
|
|
||||||
|
|
||||||
// use walking mode if no enemy known
|
// use walking mode if no enemy known
|
||||||
if (pSoldier->aiData.bAlertStatus < STATUS_RED &&
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED &&
|
||||||
@@ -422,12 +418,11 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
if (IS_MERC_BODY_TYPE(pSoldier) &&
|
if (IS_MERC_BODY_TYPE(pSoldier) &&
|
||||||
pSoldier->aiData.bAlertStatus >= STATUS_YELLOW &&
|
pSoldier->aiData.bAlertStatus >= STATUS_YELLOW &&
|
||||||
!InWaterGasOrSmoke(pSoldier, pSoldier->sGridNo) &&
|
!InWaterGasOrSmoke(pSoldier, pSoldier->sGridNo) &&
|
||||||
!BOXER(pSoldier) &&
|
!(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) &&
|
||||||
!TileIsOutOfBounds(sClosestThreat) &&
|
!TileIsOutOfBounds(sClosestThreat) &&
|
||||||
(pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM))
|
(pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM))
|
||||||
{
|
{
|
||||||
INT16 sDistanceVisible = VISION_RANGE;
|
INT16 sDistanceVisible = VISION_RANGE;
|
||||||
const auto beyondVisionRange = (CELL_X_SIZE * 3 * sDistanceVisible) / 2;
|
|
||||||
INT32 iRCD = RangeChangeDesire(pSoldier);
|
INT32 iRCD = RangeChangeDesire(pSoldier);
|
||||||
|
|
||||||
// use running when in light at night
|
// use running when in light at night
|
||||||
@@ -450,7 +445,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
!GuySawEnemy(pSoldier) &&
|
!GuySawEnemy(pSoldier) &&
|
||||||
(NightTime() || gAnimControl[pSoldier->usAnimState].ubEndHeight <= ANIM_CROUCH) &&
|
(NightTime() || gAnimControl[pSoldier->usAnimState].ubEndHeight <= ANIM_CROUCH) &&
|
||||||
CountNearbyFriends(pSoldier, pSoldier->sGridNo, TACTICAL_RANGE / 4) < 3 &&
|
CountNearbyFriends(pSoldier, pSoldier->sGridNo, TACTICAL_RANGE / 4) < 3 &&
|
||||||
distanceToThreat < beyondVisionRange &&
|
PythSpacesAway(pSoldier->sGridNo, sClosestThreat) < 3 * sDistanceVisible / 2 &&
|
||||||
CountFriendsBlack(pSoldier) == 0 &&
|
CountFriendsBlack(pSoldier) == 0 &&
|
||||||
bAction == AI_ACTION_SEEK_OPPONENT)
|
bAction == AI_ACTION_SEEK_OPPONENT)
|
||||||
{
|
{
|
||||||
@@ -459,7 +454,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
|
|
||||||
// use swatting for taking cover
|
// use swatting for taking cover
|
||||||
if (pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
if (pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
||||||
distanceToThreat > reallyClose &&
|
PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 8 &&
|
||||||
(pSoldier->aiData.bUnderFire && iRCD < 4 ||
|
(pSoldier->aiData.bUnderFire && iRCD < 4 ||
|
||||||
pSoldier->aiData.bShock > 2 * iRCD ||
|
pSoldier->aiData.bShock > 2 * iRCD ||
|
||||||
pSoldier->aiData.bShock > 0 && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE) &&
|
pSoldier->aiData.bShock > 0 && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE) &&
|
||||||
@@ -471,9 +466,9 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
|
|
||||||
// use SWATTING when under fire
|
// use SWATTING when under fire
|
||||||
if (pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
if (pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
||||||
(pSoldier->aiData.bShock > iRCD && distanceToThreat > mediumRange ||
|
(pSoldier->aiData.bShock > iRCD && PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 2 ||
|
||||||
pSoldier->aiData.bShock > 0 && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE && distanceToThreat > close) &&
|
pSoldier->aiData.bShock > 0 && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE && PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 4) &&
|
||||||
distanceToThreat < beyondVisionRange &&
|
PythSpacesAway(pSoldier->sGridNo, sClosestThreat) < 3 * sDistanceVisible / 2 &&
|
||||||
gAnimControl[pSoldier->usAnimState].ubEndHeight <= ANIM_CROUCH &&
|
gAnimControl[pSoldier->usAnimState].ubEndHeight <= ANIM_CROUCH &&
|
||||||
!pSoldier->aiData.bLastAttackHit &&
|
!pSoldier->aiData.bLastAttackHit &&
|
||||||
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
||||||
@@ -490,7 +485,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
(pSoldier->aiData.bOrders == SNIPER ||
|
(pSoldier->aiData.bOrders == SNIPER ||
|
||||||
pSoldier->aiData.bOrders == STATIONARY ||
|
pSoldier->aiData.bOrders == STATIONARY ||
|
||||||
(GuySawEnemy(pSoldier) || pSoldier->aiData.bShock > 0) && iRCD < 4) &&
|
(GuySawEnemy(pSoldier) || pSoldier->aiData.bShock > 0) && iRCD < 4) &&
|
||||||
distanceToThreat > close &&
|
PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 4 &&
|
||||||
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
||||||
bAction == AI_ACTION_GET_CLOSER ||
|
bAction == AI_ACTION_GET_CLOSER ||
|
||||||
bAction == AI_ACTION_SEEK_FRIEND ||
|
bAction == AI_ACTION_SEEK_FRIEND ||
|
||||||
@@ -506,7 +501,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
(pSoldier->aiData.bOrders == SNIPER ||
|
(pSoldier->aiData.bOrders == SNIPER ||
|
||||||
pSoldier->aiData.bOrders == STATIONARY ||
|
pSoldier->aiData.bOrders == STATIONARY ||
|
||||||
pSoldier->aiData.bShock > 0 && iRCD < 4) &&
|
pSoldier->aiData.bShock > 0 && iRCD < 4) &&
|
||||||
distanceToThreat > close &&
|
PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 4 &&
|
||||||
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
(bAction == AI_ACTION_SEEK_OPPONENT ||
|
||||||
bAction == AI_ACTION_GET_CLOSER ||
|
bAction == AI_ACTION_GET_CLOSER ||
|
||||||
bAction == AI_ACTION_SEEK_FRIEND ||
|
bAction == AI_ACTION_SEEK_FRIEND ||
|
||||||
@@ -520,7 +515,7 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
if (!pSoldier->aiData.bUnderFire &&
|
if (!pSoldier->aiData.bUnderFire &&
|
||||||
bAction == AI_ACTION_TAKE_COVER &&
|
bAction == AI_ACTION_TAKE_COVER &&
|
||||||
pSoldier->bInitialActionPoints > APBPConstants[AP_MINIMUM] &&
|
pSoldier->bInitialActionPoints > APBPConstants[AP_MINIMUM] &&
|
||||||
(!InARoom(pSoldier->sGridNo, NULL) || distanceToThreat > sDistanceVisible * 20) &&
|
(!InARoom(pSoldier->sGridNo, NULL) || PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > sDistanceVisible * 2) &&
|
||||||
pSoldier->aiData.bAIMorale >= MORALE_NORMAL &&
|
pSoldier->aiData.bAIMorale >= MORALE_NORMAL &&
|
||||||
pSoldier->bBreath > 25 &&
|
pSoldier->bBreath > 25 &&
|
||||||
pSoldier->pathing.bLevel == 0 &&
|
pSoldier->pathing.bLevel == 0 &&
|
||||||
@@ -544,14 +539,14 @@ UINT16 DetermineMovementMode( SOLDIERTYPE * pSoldier, INT8 bAction )
|
|||||||
else if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH)
|
else if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH)
|
||||||
{
|
{
|
||||||
if (WeaponReady(pSoldier) && !pSoldier->aiData.bUnderFire && pSoldier->aiData.bAlertStatus == STATUS_BLACK ||
|
if (WeaponReady(pSoldier) && !pSoldier->aiData.bUnderFire && pSoldier->aiData.bAlertStatus == STATUS_BLACK ||
|
||||||
pSoldier->aiData.bUnderFire && distanceToThreat > reallyClose )
|
pSoldier->aiData.bUnderFire && PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 8)
|
||||||
return SWATTING;
|
return SWATTING;
|
||||||
else
|
else
|
||||||
return RUNNING;
|
return RUNNING;
|
||||||
}
|
}
|
||||||
else if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE)
|
else if (gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_PRONE)
|
||||||
{
|
{
|
||||||
if (pSoldier->aiData.bUnderFire && !pSoldier->aiData.bLastAttackHit && distanceToThreat > reallyClose )
|
if (pSoldier->aiData.bUnderFire && !pSoldier->aiData.bLastAttackHit && PythSpacesAway(pSoldier->sGridNo, sClosestThreat) > (INT16)TACTICAL_RANGE / 8)
|
||||||
return SWATTING;
|
return SWATTING;
|
||||||
else
|
else
|
||||||
return RUNNING;
|
return RUNNING;
|
||||||
@@ -813,18 +808,6 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier, INT8 bAction)
|
|||||||
bMinPointsNeeded = 20; // TODO
|
bMinPointsNeeded = 20; // TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AI_ACTION_DRINK_CANTEEN:
|
|
||||||
bMinPointsNeeded = APBPConstants[AP_DRINK];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AI_ACTION_HANDLE_ITEM:
|
|
||||||
bMinPointsNeeded = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AI_ACTION_PLANT_BOMB:
|
|
||||||
bMinPointsNeeded = APBPConstants[AP_INVENTORY_ARM] + APBPConstants[AP_DROP_BOMB];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef BETAVERSION
|
#ifdef BETAVERSION
|
||||||
//NumMessage("AffordableAction - Illegal action type = ",pSoldier->aiData.bAction);
|
//NumMessage("AffordableAction - Illegal action type = ",pSoldier->aiData.bAction);
|
||||||
@@ -1396,7 +1379,7 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, BOOLEAN * pfChangeLevel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, SoldierID * pubOpponentID, INT32 * distanceInCellCoords)
|
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, SoldierID * pubOpponentID)
|
||||||
{
|
{
|
||||||
INT32 *psLastLoc,sGridNo, sClosestOpponent = NOWHERE;
|
INT32 *psLastLoc,sGridNo, sClosestOpponent = NOWHERE;
|
||||||
UINT32 uiLoop;
|
UINT32 uiLoop;
|
||||||
@@ -1492,7 +1475,7 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
|
|
||||||
if (sClosestOpponent == NOWHERE ||
|
if (sClosestOpponent == NOWHERE ||
|
||||||
iRange < iClosestRange ||
|
iRange < iClosestRange ||
|
||||||
pClosestOpponent && !pClosestOpponent->IsZombie() && !BOXER(pSoldier) && pClosestOpponent->stats.bLife < OKLIFE && pOpponent->stats.bLife >= OKLIFE)
|
pClosestOpponent && !pClosestOpponent->IsZombie() && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) && pClosestOpponent->stats.bLife < OKLIFE && pOpponent->stats.bLife >= OKLIFE)
|
||||||
{
|
{
|
||||||
iClosestRange = iRange;
|
iClosestRange = iRange;
|
||||||
sClosestOpponent = sGridNo;
|
sClosestOpponent = sGridNo;
|
||||||
@@ -1520,10 +1503,6 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
{
|
{
|
||||||
*pubOpponentID = pClosestOpponent->ubID;
|
*pubOpponentID = pClosestOpponent->ubID;
|
||||||
}
|
}
|
||||||
if ( distanceInCellCoords )
|
|
||||||
{
|
|
||||||
*distanceInCellCoords = iClosestRange;
|
|
||||||
}
|
|
||||||
return( sClosestOpponent );
|
return( sClosestOpponent );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2253,31 +2232,6 @@ INT16 DistanceToClosestFriend( SOLDIERTYPE * pSoldier )
|
|||||||
return( sMinDist );
|
return( sMinDist );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN InSmoke(SOLDIERTYPE* pSoldier, INT32 sGridNo)
|
|
||||||
{
|
|
||||||
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE) )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN InTearGas(SOLDIERTYPE* pSoldier, INT32 sGridNo)
|
|
||||||
{
|
|
||||||
if ( (gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_TEARGAS))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN InMustardGas(SOLDIERTYPE* pSoldier, INT32 sGridNo)
|
|
||||||
{
|
|
||||||
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_BURNABLEGAS | MAPELEMENT_EXT_CREATUREGAS | MAPELEMENT_EXT_MUSTARDGAS) )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||||
{
|
{
|
||||||
if (WaterTooDeepForAttacks( sGridNo, pSoldier->pathing.bLevel ))
|
if (WaterTooDeepForAttacks( sGridNo, pSoldier->pathing.bLevel ))
|
||||||
@@ -2296,12 +2250,6 @@ BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
|||||||
|
|
||||||
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||||
{
|
{
|
||||||
// Armed vehicles and robots do not care about gas or smoke
|
|
||||||
if (ARMED_VEHICLE(pSoldier) || ENEMYROBOT(pSoldier))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// smoke
|
// smoke
|
||||||
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) )
|
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_SIGNAL_SMOKE | MAPELEMENT_EXT_DEBRIS_SMOKE | MAPELEMENT_EXT_FIRERETARDANT_SMOKE ) )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -2349,12 +2297,6 @@ BOOLEAN InGas(SOLDIERTYPE *pSoldier, INT32 sGridNo)
|
|||||||
if (TileIsOutOfBounds(sGridNo))
|
if (TileIsOutOfBounds(sGridNo))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// Armed vehicles and robots do not care about gas or smoke
|
|
||||||
if (ARMED_VEHICLE(pSoldier) || ENEMYROBOT(pSoldier))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (InGasSpot(pSoldier, sGridNo, pSoldier->pathing.bLevel))
|
if (InGasSpot(pSoldier, sGridNo, pSoldier->pathing.bLevel))
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -2713,7 +2655,7 @@ INT32 CalcManThreatValue( SOLDIERTYPE *pEnemy, INT32 sMyGrid, UINT8 ubReduceForC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// in boxing mode, let only a boxer be considered a threat.
|
// in boxing mode, let only a boxer be considered a threat.
|
||||||
if ( (gTacticalStatus.bBoxingState == BOXING) && !BOXER(pEnemy) )
|
if ( (gTacticalStatus.bBoxingState == BOXING) && !(pEnemy->flags.uiStatusFlags & SOLDIER_BOXER) )
|
||||||
{
|
{
|
||||||
iThreatValue = -999;
|
iThreatValue = -999;
|
||||||
return( iThreatValue );
|
return( iThreatValue );
|
||||||
@@ -3954,6 +3896,8 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier)
|
|||||||
bMoraleCategory ++;
|
bMoraleCategory ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INT32 sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||||
|
|
||||||
// if last attack of this soldier hit enemy - increase morale
|
// if last attack of this soldier hit enemy - increase morale
|
||||||
if( pSoldier->aiData.bLastAttackHit )
|
if( pSoldier->aiData.bLastAttackHit )
|
||||||
{
|
{
|
||||||
@@ -4632,61 +4576,6 @@ UINT8 RedSmokeDanger(INT32 sGridNo, INT8 bLevel)
|
|||||||
return ubDangerPercent;
|
return ubDangerPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN FindClosestVisibleSmoke(SOLDIERTYPE* pSoldier, INT32& sSpot, INT8& bLevel, BOOLEAN fOnlyGas)
|
|
||||||
{
|
|
||||||
CHECKF(pSoldier);
|
|
||||||
|
|
||||||
INT32 sDist;
|
|
||||||
INT32 sClosestDist = INT32_MAX;
|
|
||||||
INT32 sCheckSpot;
|
|
||||||
INT8 bCheckLevel;
|
|
||||||
|
|
||||||
sSpot = NOWHERE;
|
|
||||||
bLevel = 0;
|
|
||||||
|
|
||||||
//loop through all smoke effects and find closest visible
|
|
||||||
for ( UINT32 uiCnt = 0; uiCnt < guiNumSmokeEffects; uiCnt++ )
|
|
||||||
{
|
|
||||||
if ( gSmokeEffectData[uiCnt].fAllocated &&
|
|
||||||
!TileIsOutOfBounds(gSmokeEffectData[uiCnt].sGridNo) )
|
|
||||||
{
|
|
||||||
// ignore smoke if not dangerous
|
|
||||||
if ( fOnlyGas &&
|
|
||||||
gSmokeEffectData[uiCnt].bType != TEARGAS_SMOKE_EFFECT &&
|
|
||||||
gSmokeEffectData[uiCnt].bType != MUSTARDGAS_SMOKE_EFFECT &&
|
|
||||||
gSmokeEffectData[uiCnt].bType != CREATURE_SMOKE_EFFECT )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sCheckSpot = gSmokeEffectData[uiCnt].sGridNo;
|
|
||||||
|
|
||||||
if ( gSmokeEffectData[uiCnt].bFlags & SMOKE_EFFECT_ON_ROOF )
|
|
||||||
bCheckLevel = 1;
|
|
||||||
else
|
|
||||||
bCheckLevel = 0;
|
|
||||||
|
|
||||||
sDist = PythSpacesAway(sCheckSpot, pSoldier->sGridNo);
|
|
||||||
|
|
||||||
if ( sDist < DAY_VISION_RANGE &&
|
|
||||||
SoldierToVirtualSoldierLineOfSightTest(pSoldier, sCheckSpot, bCheckLevel, ANIM_PRONE, 0, CALC_FROM_ALL_DIRS) &&
|
|
||||||
(sSpot == NOWHERE || sDist < sClosestDist) )
|
|
||||||
{
|
|
||||||
sClosestDist = sDist;
|
|
||||||
sSpot = sCheckSpot;
|
|
||||||
bLevel = bCheckLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !TileIsOutOfBounds(sSpot) )
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if artillery strike was ordered by any team
|
// check if artillery strike was ordered by any team
|
||||||
BOOLEAN CheckArtilleryStrike(void)
|
BOOLEAN CheckArtilleryStrike(void)
|
||||||
{
|
{
|
||||||
@@ -4895,7 +4784,7 @@ BOOLEAN ValidOpponent(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pOpponent)
|
|||||||
pSoldier->bSide == pOpponent->bSide ||
|
pSoldier->bSide == pOpponent->bSide ||
|
||||||
pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpponent->ubProfile != SLAY ||
|
pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpponent->ubProfile != SLAY ||
|
||||||
(pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle(pOpponent->bVehicleID) == 0) ||
|
(pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle(pOpponent->bVehicleID) == 0) ||
|
||||||
gTacticalStatus.bBoxingState == BOXING && BOXER(pSoldier) && !BOXER(pOpponent) ||
|
gTacticalStatus.bBoxingState == BOXING && (pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) && !(pOpponent->flags.uiStatusFlags & SOLDIER_BOXER) ||
|
||||||
pOpponent->ubBodyType == CROW)
|
pOpponent->ubBodyType == CROW)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -5004,7 +4893,7 @@ BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier)
|
|||||||
if (!IS_MERC_BODY_TYPE(pSoldier) ||
|
if (!IS_MERC_BODY_TYPE(pSoldier) ||
|
||||||
pSoldier->aiData.bNeutral ||
|
pSoldier->aiData.bNeutral ||
|
||||||
fCivilian ||
|
fCivilian ||
|
||||||
BOXER(pSoldier) ||
|
pSoldier->flags.uiStatusFlags & SOLDIER_BOXER ||
|
||||||
ARMED_VEHICLE(pSoldier) ||
|
ARMED_VEHICLE(pSoldier) ||
|
||||||
pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ||
|
pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ||
|
||||||
AM_A_ROBOT(pSoldier) ||
|
AM_A_ROBOT(pSoldier) ||
|
||||||
@@ -6340,221 +6229,3 @@ BOOLEAN CheckSuppressionDirection(SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, IN
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 CountKnownEnemies(SOLDIERTYPE* pSoldier, INT32 sSpot, INT16 sDistance, INT8 bLevel)
|
|
||||||
{
|
|
||||||
CHECKF(pSoldier);
|
|
||||||
|
|
||||||
SOLDIERTYPE* pOpponent;
|
|
||||||
INT32 sThreatLoc;
|
|
||||||
INT8 bThreatLevel;
|
|
||||||
UINT8 ubNum = 0;
|
|
||||||
|
|
||||||
// loop through all the enemies
|
|
||||||
for ( UINT32 uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop )
|
|
||||||
{
|
|
||||||
pOpponent = MercSlots[uiLoop];
|
|
||||||
|
|
||||||
// if this merc is inactive, at base, on assignment, dead, unconscious
|
|
||||||
if ( !pOpponent || pOpponent->stats.bLife < OKLIFE )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !ValidOpponent(pSoldier, pOpponent) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check knowledge
|
|
||||||
if ( Knowledge(pSoldier, pOpponent->ubID) == NOT_HEARD_OR_SEEN )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sThreatLoc = KnownLocation(pSoldier, pOpponent->ubID);
|
|
||||||
bThreatLevel = KnownLevel(pSoldier, pOpponent->ubID);
|
|
||||||
|
|
||||||
if ( TileIsOutOfBounds(sThreatLoc) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( PythSpacesAway(sSpot, sThreatLoc) > sDistance )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( bLevel >= 0 && bThreatLevel != bLevel )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ubNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 CountKnownEnemiesInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoom)
|
|
||||||
{
|
|
||||||
CHECKF(pSoldier);
|
|
||||||
|
|
||||||
UINT8 ubNum = 0;
|
|
||||||
for ( UINT32 uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop )
|
|
||||||
{
|
|
||||||
SOLDIERTYPE* pOpponent = MercSlots[uiLoop];
|
|
||||||
|
|
||||||
// if this merc is inactive, at base, on assignment, dead, unconscious
|
|
||||||
if ( !pOpponent || pOpponent->stats.bLife < OKLIFE )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !ValidOpponent(pSoldier, pOpponent) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check public knowledge
|
|
||||||
if ( Knowledge(pSoldier, pOpponent->ubID) == NOT_HEARD_OR_SEEN )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 sThreatLoc = KnownLocation(pSoldier, pOpponent->ubID);
|
|
||||||
|
|
||||||
if ( TileIsOutOfBounds(sThreatLoc) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check room
|
|
||||||
UINT16 usRoomNo;
|
|
||||||
if ( !InARoom(sThreatLoc, &usRoomNo) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( usRoomNo != usRoom )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ubNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 CountFriendsInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoom)
|
|
||||||
{
|
|
||||||
CHECKF(pSoldier);
|
|
||||||
|
|
||||||
SOLDIERTYPE* pFriend;
|
|
||||||
UINT8 ubFriendCount = 0;
|
|
||||||
UINT16 usRoomNo;
|
|
||||||
|
|
||||||
// Run through each friendly.
|
|
||||||
for ( SoldierID iCounter = gTacticalStatus.Team[pSoldier->bTeam].bFirstID; iCounter <= gTacticalStatus.Team[pSoldier->bTeam].bLastID; ++iCounter )
|
|
||||||
{
|
|
||||||
pFriend = iCounter;
|
|
||||||
|
|
||||||
if ( pFriend &&
|
|
||||||
pFriend != pSoldier &&
|
|
||||||
pFriend->bActive &&
|
|
||||||
pFriend->stats.bLife >= OKLIFE &&
|
|
||||||
InARoom(pFriend->sGridNo, &usRoomNo) &&
|
|
||||||
usRoomNo == usRoom )
|
|
||||||
{
|
|
||||||
ubFriendCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ubFriendCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 CountCorpsesInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoomNo, INT8 bLevel)
|
|
||||||
{
|
|
||||||
CHECKF(pSoldier);
|
|
||||||
|
|
||||||
ROTTING_CORPSE* pCorpse;
|
|
||||||
INT32 iCount = 0;
|
|
||||||
|
|
||||||
for ( INT32 cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
|
||||||
{
|
|
||||||
pCorpse = &(gRottingCorpse[cnt]);
|
|
||||||
|
|
||||||
if ( pCorpse &&
|
|
||||||
pCorpse->fActivated &&
|
|
||||||
pCorpse->def.ubType < ROTTING_STAGE2 &&
|
|
||||||
pCorpse->def.ubBodyType <= REGFEMALE &&
|
|
||||||
pCorpse->def.ubAIWarningValue > 0 &&
|
|
||||||
pCorpse->def.bLevel == bLevel &&
|
|
||||||
!TileIsOutOfBounds(pCorpse->def.sGridNo) &&
|
|
||||||
RoomNo(pCorpse->def.sGridNo) == usRoomNo &&
|
|
||||||
(pSoldier->bTeam == ENEMY_TEAM && CorpseEnemyTeam(pCorpse) || pSoldier->bTeam == MILITIA_TEAM && CorpseMilitiaTeam(pCorpse) || pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral) )
|
|
||||||
{
|
|
||||||
iCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return iCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN FindFenceAroundSpot(INT32 sSpot)
|
|
||||||
{
|
|
||||||
if ( TileIsOutOfBounds(sSpot) )
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 sTempSpot;
|
|
||||||
|
|
||||||
// check adjacent locations
|
|
||||||
for ( UINT8 ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++ )
|
|
||||||
{
|
|
||||||
sTempSpot = NewGridNo(sSpot, DirectionInc(ubDirection));
|
|
||||||
|
|
||||||
if ( sTempSpot != sSpot && IsCuttableWireFenceAtGridNo(sTempSpot) )
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN SameRoom(INT32 sSpot1, INT32 sSpot2)
|
|
||||||
{
|
|
||||||
if ( RoomNo(sSpot1) == RoomNo(sSpot2) && sSpot1 != NO_ROOM )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT16 RoomNo(INT32 sSpot)
|
|
||||||
{
|
|
||||||
if ( TileIsOutOfBounds(sSpot) )
|
|
||||||
return NO_ROOM;
|
|
||||||
|
|
||||||
return gusWorldRoomInfo[sSpot];
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN CheckWindow(INT32 sSpot, UINT8 ubDirection, BOOLEAN fAllowClosed)
|
|
||||||
{
|
|
||||||
CHECKF(!TileIsOutOfBounds(sSpot));
|
|
||||||
|
|
||||||
// find window spot
|
|
||||||
INT32 sWindowSpot = sSpot;
|
|
||||||
if ( ubDirection == NORTH || ubDirection == WEST )
|
|
||||||
sWindowSpot = NewGridNo(sSpot, (UINT16)DirectionInc(ubDirection));
|
|
||||||
|
|
||||||
//if (IsJumpableWindowPresentAtGridNo(sWindowSpot, ubDirection, gGameExternalOptions.fCanJumpThroughClosedWindows))
|
|
||||||
if ( IsJumpableWindowPresentAtGridNo(sWindowSpot, ubDirection, fAllowClosed) )
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-685
@@ -2207,7 +2207,7 @@ INT32 EstimateShotDamage(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT16 ub
|
|||||||
|
|
||||||
// check for ceramic plates; these do affect monster spit
|
// check for ceramic plates; these do affect monster spit
|
||||||
for (attachmentList::iterator iter = pOpponent->inv[VESTPOS][0]->attachments.begin(); iter != pOpponent->inv[VESTPOS][0]->attachments.end(); ++iter) {
|
for (attachmentList::iterator iter = pOpponent->inv[VESTPOS][0]->attachments.begin(); iter != pOpponent->inv[VESTPOS][0]->attachments.end(); ++iter) {
|
||||||
if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists() )
|
if ( iter->exists() && Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 )
|
||||||
{
|
{
|
||||||
iTorsoProt += (INT32) Armour[Item[iter->usItem].ubClassIndex].ubProtection *
|
iTorsoProt += (INT32) Armour[Item[iter->usItem].ubClassIndex].ubProtection *
|
||||||
(INT32) (*iter)[0]->data.objectStatus / 100;
|
(INT32) (*iter)[0]->data.objectStatus / 100;
|
||||||
@@ -4234,687 +4234,3 @@ void CheckTossGrenadeAt(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow, INT32 sTa
|
|||||||
|
|
||||||
pSoldier->bWeaponMode = WM_NORMAL;
|
pSoldier->bWeaponMode = WM_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void CalculatePossibleShots(SOLDIERTYPE* pSoldier, INT8 gun, std::vector<ATTACKTYPE> &possibleShots)
|
|
||||||
{
|
|
||||||
UINT32 uiLoop;
|
|
||||||
INT32 iAttackValue, iThreatValue, iHitRate, iBestHitRate, iPercentBetter, iEstDamage, iTrueLastTarget;
|
|
||||||
UINT16 usTrueState, usTurningCost, usRaiseGunCost;
|
|
||||||
INT16 sMinAPcost;
|
|
||||||
INT16 sRawAPCost;
|
|
||||||
INT16 sAimAPCost;
|
|
||||||
INT16 sBestAPcost;
|
|
||||||
INT16 sChanceToHit;
|
|
||||||
INT16 sAimTime;
|
|
||||||
INT16 sBestAimTime;
|
|
||||||
INT16 sMaxPossibleAimTime;
|
|
||||||
UINT8 ubChanceToGetThrough;
|
|
||||||
UINT8 ubBestChanceToGetThrough;
|
|
||||||
UINT8 ubFriendlyFireChance;
|
|
||||||
UINT8 ubBestFriendlyFireChance;
|
|
||||||
INT16 sBestChanceToHit;
|
|
||||||
INT16 sStanceAPcost;
|
|
||||||
BOOLEAN fAddingTurningCost, fAddingRaiseGunCost;
|
|
||||||
UINT8 ubStance, ubBestStance, ubChanceToReallyHit;
|
|
||||||
INT8 bScopeMode;
|
|
||||||
SOLDIERTYPE* pOpponent;
|
|
||||||
|
|
||||||
// sevenfm:
|
|
||||||
BOOLEAN fSuppression = FALSE;
|
|
||||||
BOOLEAN fReturnFire = FALSE;
|
|
||||||
INT32 sTarget = NOWHERE;
|
|
||||||
INT8 bLevel;
|
|
||||||
|
|
||||||
INT8 bKnowledge;
|
|
||||||
INT8 bPersonalKnowledge;
|
|
||||||
INT8 bPublicKnowledge;
|
|
||||||
|
|
||||||
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "CalcBestShot");
|
|
||||||
|
|
||||||
|
|
||||||
sBestChanceToHit = sBestAimTime = sChanceToHit = ubBestChanceToGetThrough = ubBestFriendlyFireChance = ubChanceToReallyHit = 0;
|
|
||||||
|
|
||||||
// sevenfm: set attacking hand and target
|
|
||||||
pSoldier->ubAttackingHand = HANDPOS;
|
|
||||||
pSoldier->ubTargetID = NOBODY;
|
|
||||||
|
|
||||||
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
|
|
||||||
pSoldier->bWeaponMode = WM_NORMAL;
|
|
||||||
|
|
||||||
std::map<INT8, OBJECTTYPE*> ObjList;
|
|
||||||
GetScopeLists(pSoldier, &pSoldier->inv[HANDPOS], ObjList);
|
|
||||||
pSoldier->bScopeMode = USE_BEST_SCOPE;
|
|
||||||
pSoldier->bDoBurst = 0;
|
|
||||||
pSoldier->bDoAutofire = 0;
|
|
||||||
|
|
||||||
// determine which attack against which target has the greatest attack value
|
|
||||||
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
||||||
{
|
|
||||||
ATTACKTYPE pBestShot;
|
|
||||||
pBestShot.ubPossible = FALSE;
|
|
||||||
pBestShot.ubChanceToReallyHit = 0;
|
|
||||||
pBestShot.iAttackValue = 0;
|
|
||||||
pBestShot.ubOpponent = NOBODY;
|
|
||||||
pBestShot.ubFriendlyFireChance = 0;
|
|
||||||
pBestShot.bWeaponIn = gun;
|
|
||||||
|
|
||||||
pOpponent = MercSlots[uiLoop];
|
|
||||||
fSuppression = FALSE;
|
|
||||||
fReturnFire = FALSE;
|
|
||||||
|
|
||||||
// if this merc is inactive, at base, on assignment, or dead
|
|
||||||
if (!pOpponent || !pOpponent->stats.bLife)
|
|
||||||
continue; // next merc
|
|
||||||
|
|
||||||
if (!ValidOpponent(pSoldier, pOpponent))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine return fire
|
|
||||||
if (pSoldier->aiData.bUnderFire &&
|
|
||||||
!pSoldier->bBlindedCounter &&
|
|
||||||
pSoldier->ubPreviousAttackerID == pOpponent->ubID)
|
|
||||||
{
|
|
||||||
fReturnFire = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bKnowledge = Knowledge(pSoldier, pOpponent->ubID);
|
|
||||||
bPersonalKnowledge = PersonalKnowledge(pSoldier, pOpponent->ubID);
|
|
||||||
bPublicKnowledge = PublicKnowledge(pSoldier->bTeam, pOpponent->ubID);
|
|
||||||
|
|
||||||
// check knowledge
|
|
||||||
if (bKnowledge != SEEN_CURRENTLY &&
|
|
||||||
bKnowledge != SEEN_THIS_TURN &&
|
|
||||||
bKnowledge != SEEN_LAST_TURN &&
|
|
||||||
bKnowledge != HEARD_THIS_TURN &&
|
|
||||||
bKnowledge != HEARD_LAST_TURN &&
|
|
||||||
!((bKnowledge == SEEN_2_TURNS_AGO || bKnowledge == SEEN_3_TURNS_AGO || bKnowledge == HEARD_2_TURNS_AGO) && Weapon[pSoldier->usAttackingWeapon].ubWeaponType == GUN_LMG))
|
|
||||||
{
|
|
||||||
continue; // next opponent
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: blind soldier can only attack seen/heard personally
|
|
||||||
if (pSoldier->bBlindedCounter > 0 &&
|
|
||||||
bPersonalKnowledge != SEEN_THIS_TURN &&
|
|
||||||
bPersonalKnowledge != HEARD_THIS_TURN)
|
|
||||||
{
|
|
||||||
continue; // next opponent
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: determine if we shoot on unseen target for suppression
|
|
||||||
if (bPersonalKnowledge != SEEN_CURRENTLY &&
|
|
||||||
bPublicKnowledge != SEEN_CURRENTLY &&
|
|
||||||
//!SoldierToSoldierLineOfSightTest(pSoldier, pOpponent, TRUE, CALC_FROM_ALL_DIRS))
|
|
||||||
!LOS_Raised(pSoldier, pOpponent, CALC_FROM_ALL_DIRS))
|
|
||||||
{
|
|
||||||
fSuppression = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: shooting at unseen opponents is optional
|
|
||||||
if (fSuppression && !gGameExternalOptions.fAIShootUnseen)
|
|
||||||
{
|
|
||||||
continue; // next opponent
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine enemy location
|
|
||||||
if (fSuppression)
|
|
||||||
{
|
|
||||||
// personal/public knowledge
|
|
||||||
sTarget = KnownLocation(pSoldier, pOpponent->ubID);
|
|
||||||
bLevel = KnownLevel(pSoldier, pOpponent->ubID);
|
|
||||||
// try to randomize location
|
|
||||||
sTarget = RandomizeLocation(sTarget, bLevel, 1, pSoldier);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we know exact enemy location
|
|
||||||
sTarget = pOpponent->sGridNo;
|
|
||||||
bLevel = pOpponent->pathing.bLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// safety check
|
|
||||||
if (TileIsOutOfBounds(sTarget))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip if we can see location and location is empty
|
|
||||||
if (SoldierToVirtualSoldierLineOfSightTest(pSoldier, sTarget, bLevel, ANIM_PRONE, TRUE, CALC_FROM_ALL_DIRS) &&
|
|
||||||
WhoIsThere2(sTarget, bLevel) == NOBODY)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no fire on unseen opponents with throwing knives
|
|
||||||
if ((Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE) &&
|
|
||||||
bPersonalKnowledge != SEEN_CURRENTLY &&
|
|
||||||
//!SoldierToSoldierLineOfSightTest(pSoldier, pOpponent, TRUE, CALC_FROM_ALL_DIRS))
|
|
||||||
!LOS_Raised(pSoldier, pOpponent, CALC_FROM_ALL_DIRS))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: only enemy team can use blind suppression fire
|
|
||||||
if (fSuppression &&
|
|
||||||
pSoldier->bTeam != ENEMY_TEAM)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: only try to suppress alive and conscious human targets
|
|
||||||
if (fSuppression &&
|
|
||||||
(pOpponent->stats.bLife < OKLIFE ||
|
|
||||||
pOpponent->bCollapsed && pOpponent->bBreath == 0 ||
|
|
||||||
pOpponent->IsCowering() ||
|
|
||||||
pOpponent->IsZombie() ||
|
|
||||||
!IS_MERC_BODY_TYPE(pOpponent)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// shoot through wall check
|
|
||||||
if (bPersonalKnowledge != SEEN_CURRENTLY &&
|
|
||||||
//!SoldierToSoldierLineOfSightTest(pSoldier, pOpponent, TRUE, CALC_FROM_ALL_DIRS) &&
|
|
||||||
!LOS_Raised(pSoldier, pOpponent, CALC_FROM_ALL_DIRS) &&
|
|
||||||
!SoldierToVirtualSoldierLineOfSightTest(pSoldier, sTarget, bLevel, ANIM_STAND, TRUE, NO_DISTANCE_LIMIT) &&
|
|
||||||
!LocationToLocationLineOfSightTest(pSoldier->sGridNo, pSoldier->pathing.bLevel, sTarget, bLevel, TRUE, NO_DISTANCE_LIMIT) &&
|
|
||||||
!fReturnFire &&
|
|
||||||
!(InARoom(sTarget, NULL) && bLevel == 0 && Weapon[pSoldier->usAttackingWeapon].ubWeaponType == GUN_LMG) && // bPublicKnowledge == SEEN_CURRENTLY &&
|
|
||||||
!(InARoom(sTarget, NULL) && bLevel == 0 && TeamPercentKilled(pSoldier->bTeam) > (100 - 20 * SoldierDifficultyLevel(pSoldier))))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUGATTACKS
|
|
||||||
DebugAI(String("%s sees %s at gridno %d\n", pSoldier->GetName(), ExtMen[pOpponent->ubID].GetName(), pOpponent->sGridNo));
|
|
||||||
#endif
|
|
||||||
sMinAPcost = MinAPsToAttack(pSoldier, sTarget, DONTADDTURNCOST, 0);
|
|
||||||
// later will be decide if shoot is possible this here is just best guess so ignore turnover
|
|
||||||
|
|
||||||
// if we don't have enough APs left to shoot even a snap-shot at this guy
|
|
||||||
if (sMinAPcost > pSoldier->bActionPoints)
|
|
||||||
continue; // next opponent
|
|
||||||
|
|
||||||
// sevenfm: check CTGT and friendly fire for each stance instead since they can be different
|
|
||||||
// calculate chance to get through the opponent's cover (if any)
|
|
||||||
//dnl ch61 180813
|
|
||||||
/*gUnderFire.Clear();
|
|
||||||
gUnderFire.Enable();
|
|
||||||
ubChanceToGetThrough = AISoldierToSoldierChanceToGetThrough( pSoldier, pOpponent );
|
|
||||||
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
|
||||||
gUnderFire.Disable();
|
|
||||||
|
|
||||||
// if we can't possibly get through all the cover
|
|
||||||
if (ubChanceToGetThrough == 0)
|
|
||||||
continue; // next opponent
|
|
||||||
|
|
||||||
// sevenfm: ignore opponent if we can hit friend
|
|
||||||
if (ubFriendlyFireChance > MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
|
||||||
continue;*/
|
|
||||||
|
|
||||||
if ((pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER) && (pSoldier->ubBodyType != QUEENMONSTER))
|
|
||||||
{
|
|
||||||
STRUCTURE_FILE_REF* pStructureFileRef;
|
|
||||||
UINT16 usAnimSurface;
|
|
||||||
|
|
||||||
usAnimSurface = DetermineSoldierAnimationSurface(pSoldier, pSoldier->usUIMovementMode);
|
|
||||||
pStructureFileRef = GetAnimationStructureRef(pSoldier->ubID, usAnimSurface, pSoldier->usUIMovementMode);
|
|
||||||
|
|
||||||
if (pStructureFileRef)
|
|
||||||
{
|
|
||||||
UINT16 usStructureID;
|
|
||||||
INT8 bDir;
|
|
||||||
|
|
||||||
// must make sure that structure data can be added in the direction of the target
|
|
||||||
bDir = (INT8)GetDirectionToGridNoFromGridNo(pSoldier->sGridNo, sTarget);
|
|
||||||
|
|
||||||
// ATE: Only if we have a levelnode...
|
|
||||||
if (pSoldier->pLevelNode != NULL && pSoldier->pLevelNode->pStructureData != NULL)
|
|
||||||
{
|
|
||||||
usStructureID = pSoldier->pLevelNode->pStructureData->usStructureID;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
usStructureID = INVALID_STRUCTURE_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!OkayToAddStructureToWorld(pSoldier->sGridNo, pSoldier->pathing.bLevel, &(pStructureFileRef->pDBStructureRef[gOneCDirection[bDir]]), usStructureID))
|
|
||||||
{
|
|
||||||
// can't turn in that dir.... next opponent
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iBestHitRate = 0; // reset best hit rate to minimum
|
|
||||||
|
|
||||||
//dnl ch69 130913 Hoping to optimize
|
|
||||||
// consider alternate holding mode and different scopes
|
|
||||||
// sevenfm: alt weapon holding scope mode is used only when ubAllowAlternativeWeaponHolding == 3
|
|
||||||
for (pSoldier->bScopeMode = (gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ? USE_ALT_WEAPON_HOLD : USE_BEST_SCOPE);
|
|
||||||
pSoldier->bScopeMode <= (gGameExternalOptions.fScopeModes ? NUM_SCOPE_MODES - 1 : USE_BEST_SCOPE);
|
|
||||||
pSoldier->bScopeMode++)
|
|
||||||
{
|
|
||||||
if (pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD)
|
|
||||||
{
|
|
||||||
//dnl ch71 180913 throwing knives cannot be used in fire from hip
|
|
||||||
if (Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// sevenfm: hip firing allowed only for human bodytypes
|
|
||||||
if (!IS_MERC_BODY_TYPE(pSoldier))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD || (pSoldier->bScopeMode >= USE_BEST_SCOPE && ObjList[pSoldier->bScopeMode] != NULL))
|
|
||||||
{
|
|
||||||
usTrueState = pSoldier->usAnimState; // because is used in CalculateRaiseGunCost, CalcAimingLevelsAvailableWithAP, CalculateTurningCost
|
|
||||||
iTrueLastTarget = pSoldier->sLastTarget; // because is used in MinAPsToShootOrStab
|
|
||||||
|
|
||||||
// --------- Standing ---------
|
|
||||||
ubStance = ANIM_STAND;
|
|
||||||
// sevenfm: take into account direction when checking stance
|
|
||||||
// sevenfm: shoot heavy guns in standing stance only when using hip fire
|
|
||||||
if (pSoldier->InternalIsValidStance(AIDirection(pSoldier->sGridNo, sTarget), ubStance) &&
|
|
||||||
(pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD || !Weapon[pSoldier->usAttackingWeapon].HeavyGun || !ItemIsTwoHanded(pSoldier->usAttackingWeapon) || !gGameExternalOptions.ubAllowAlternativeWeaponHolding))
|
|
||||||
{
|
|
||||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
|
||||||
if (sStanceAPcost)
|
|
||||||
{
|
|
||||||
// Going up so first is stance change then turnover, do animation change before APs calculation
|
|
||||||
pSoldier->usAnimState = STANDING;
|
|
||||||
pSoldier->sLastTarget = NOWHERE;
|
|
||||||
}
|
|
||||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, sTarget, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
|
||||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
|
||||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sTarget, 0);
|
|
||||||
if (fAddingTurningCost && fAddingRaiseGunCost)//dnl ch71 180913
|
|
||||||
{
|
|
||||||
if (usRaiseGunCost > usTurningCost)
|
|
||||||
usTurningCost = 0;
|
|
||||||
else
|
|
||||||
usRaiseGunCost = 0;
|
|
||||||
}
|
|
||||||
sRawAPCost = MinAPsToShootOrStab(pSoldier, sTarget, 0, FALSE, 2);
|
|
||||||
sMinAPcost = sRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
|
||||||
|
|
||||||
if (pSoldier->bActionPoints - sMinAPcost >= 0)
|
|
||||||
{
|
|
||||||
// calc next attack's minimum shooting cost (excludes readying & turning & raise gun)
|
|
||||||
sMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, sTarget, pSoldier->bActionPoints - sMinAPcost);
|
|
||||||
|
|
||||||
// sevenfm: check CTGT and friendly fire chance for every stance
|
|
||||||
gUnderFire.Clear();
|
|
||||||
gUnderFire.Enable();
|
|
||||||
if (fSuppression)
|
|
||||||
ubChanceToGetThrough = SoldierToLocationChanceToGetThrough(pSoldier, sTarget, bLevel, 3, NOBODY);
|
|
||||||
else
|
|
||||||
ubChanceToGetThrough = SoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
|
||||||
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
|
||||||
gUnderFire.Disable();
|
|
||||||
|
|
||||||
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
|
||||||
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
|
||||||
{
|
|
||||||
for (sAimTime = 0; sAimTime <= sMaxPossibleAimTime; sAimTime++)
|
|
||||||
{
|
|
||||||
sChanceToHit = AICalcChanceToHitGun(pSoldier, sTarget, sAimTime, AIM_SHOT_TORSO, bLevel, STANDING);
|
|
||||||
sAimAPCost = CalcAPCostForAiming(pSoldier, sTarget, (INT8)sAimTime);
|
|
||||||
iHitRate = sChanceToHit * (pSoldier->bActionPoints - (sMinAPcost - sRawAPCost)) / (sRawAPCost + sAimAPCost);
|
|
||||||
// sevenfm: take into account CTGT for every stance
|
|
||||||
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough ||
|
|
||||||
(Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE) && sChanceToHit > sBestChanceToHit)// rather take best chance for throwing knives
|
|
||||||
{
|
|
||||||
iBestHitRate = iHitRate;
|
|
||||||
sBestAimTime = sAimTime;
|
|
||||||
sBestChanceToHit = sChanceToHit;
|
|
||||||
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
|
||||||
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
|
||||||
sBestAPcost = sMinAPcost;
|
|
||||||
ubBestStance = ubStance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pSoldier->usAnimState = usTrueState;
|
|
||||||
pSoldier->sLastTarget = iTrueLastTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no crouched/prone if we are tank/using throwing knife/hip firing
|
|
||||||
if (pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD || ARMED_VEHICLE(pSoldier) || ENEMYROBOT(pSoldier) || (Item[pSoldier->usAttackingWeapon].usItemClass & IC_THROWING_KNIFE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// --------- Crouched ---------
|
|
||||||
ubStance = ANIM_CROUCH;
|
|
||||||
// sevenfm: take into account direction
|
|
||||||
if (pSoldier->InternalIsValidStance(AIDirection(pSoldier->sGridNo, sTarget), ubStance))
|
|
||||||
{
|
|
||||||
// change stance then turn
|
|
||||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
|
||||||
if (sStanceAPcost)
|
|
||||||
{
|
|
||||||
pSoldier->usAnimState = CROUCHING;
|
|
||||||
pSoldier->sLastTarget = NOWHERE;
|
|
||||||
}
|
|
||||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, sTarget, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
|
||||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
|
||||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sTarget, 0);
|
|
||||||
if (fAddingTurningCost && fAddingRaiseGunCost)//dnl ch71 180913
|
|
||||||
{
|
|
||||||
if (usRaiseGunCost > usTurningCost)
|
|
||||||
usTurningCost = 0;
|
|
||||||
else
|
|
||||||
usRaiseGunCost = 0;
|
|
||||||
}
|
|
||||||
sRawAPCost = MinAPsToShootOrStab(pSoldier, sTarget, 0, FALSE, 2);
|
|
||||||
sMinAPcost = sRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
|
||||||
|
|
||||||
if (pSoldier->bActionPoints - sMinAPcost >= 0)
|
|
||||||
{
|
|
||||||
sMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, sTarget, pSoldier->bActionPoints - sMinAPcost);
|
|
||||||
|
|
||||||
// sevenfm: check CTGT and friendly fire chance for every stance
|
|
||||||
gUnderFire.Clear();
|
|
||||||
gUnderFire.Enable();
|
|
||||||
if (fSuppression)
|
|
||||||
ubChanceToGetThrough = SoldierToLocationChanceToGetThrough(pSoldier, sTarget, bLevel, 3, NOBODY);
|
|
||||||
else
|
|
||||||
ubChanceToGetThrough = SoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
|
||||||
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
|
||||||
gUnderFire.Disable();
|
|
||||||
|
|
||||||
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
|
||||||
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
|
||||||
{
|
|
||||||
for (sAimTime = 0; sAimTime <= sMaxPossibleAimTime; sAimTime++)
|
|
||||||
{
|
|
||||||
sChanceToHit = AICalcChanceToHitGun(pSoldier, sTarget, sAimTime, AIM_SHOT_TORSO, bLevel, CROUCHING);
|
|
||||||
sAimAPCost = CalcAPCostForAiming(pSoldier, sTarget, (INT8)sAimTime);
|
|
||||||
iHitRate = sChanceToHit * (pSoldier->bActionPoints - (sMinAPcost - sRawAPCost)) / (sRawAPCost + sAimAPCost);
|
|
||||||
// sevenfm: take into account CTGT for every stance
|
|
||||||
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough)
|
|
||||||
{
|
|
||||||
iBestHitRate = iHitRate;
|
|
||||||
sBestAimTime = sAimTime;
|
|
||||||
sBestChanceToHit = sChanceToHit;
|
|
||||||
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
|
||||||
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
|
||||||
sBestAPcost = sMinAPcost;
|
|
||||||
ubBestStance = ubStance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pSoldier->usAnimState = usTrueState;
|
|
||||||
pSoldier->sLastTarget = iTrueLastTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no prone stance if we have to change direction and stance at the same time
|
|
||||||
if (pSoldier->ubDirection != AIDirection(pSoldier->sGridNo, sTarget) &&
|
|
||||||
gAnimControl[pSoldier->usAnimState].ubEndHeight > ANIM_PRONE)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------- Prone ---------
|
|
||||||
ubStance = ANIM_PRONE;
|
|
||||||
if (pSoldier->InternalIsValidStance(AIDirection(pSoldier->sGridNo, sTarget), ubStance))
|
|
||||||
{
|
|
||||||
sStanceAPcost = GetAPsToChangeStance(pSoldier, ubStance);
|
|
||||||
if (sStanceAPcost)
|
|
||||||
{
|
|
||||||
pSoldier->usAnimState = PRONE;
|
|
||||||
pSoldier->sLastTarget = NOWHERE;
|
|
||||||
}
|
|
||||||
GetAPChargeForShootOrStabWRTGunRaises(pSoldier, sTarget, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, 0);
|
|
||||||
usTurningCost = CalculateTurningCost(pSoldier, pSoldier->usAttackingWeapon, fAddingTurningCost);
|
|
||||||
usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sTarget, 0);
|
|
||||||
sRawAPCost = MinAPsToShootOrStab(pSoldier, sTarget, 0, FALSE, 2);
|
|
||||||
sMinAPcost = sRawAPCost + usTurningCost + sStanceAPcost + usRaiseGunCost;
|
|
||||||
|
|
||||||
if (pSoldier->bActionPoints - sMinAPcost >= 0)
|
|
||||||
{
|
|
||||||
sMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP(pSoldier, sTarget, pSoldier->bActionPoints - sMinAPcost);
|
|
||||||
|
|
||||||
// sevenfm: check CTGT and friendly fire chance for every stance
|
|
||||||
gUnderFire.Clear();
|
|
||||||
gUnderFire.Enable();
|
|
||||||
if (fSuppression)
|
|
||||||
ubChanceToGetThrough = SoldierToLocationChanceToGetThrough(pSoldier, sTarget, bLevel, 3, NOBODY);
|
|
||||||
else
|
|
||||||
ubChanceToGetThrough = SoldierToSoldierChanceToGetThrough(pSoldier, pOpponent);
|
|
||||||
ubFriendlyFireChance = gUnderFire.Chance(pSoldier->bTeam, pSoldier->bSide, TRUE);
|
|
||||||
gUnderFire.Disable();
|
|
||||||
|
|
||||||
// sevenfm: only use this stance if we can hit target and cannot hit friends
|
|
||||||
if (ubChanceToGetThrough > 0 && ubFriendlyFireChance <= MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE)
|
|
||||||
{
|
|
||||||
for (sAimTime = 0; sAimTime <= sMaxPossibleAimTime; sAimTime++)
|
|
||||||
{
|
|
||||||
sChanceToHit = AICalcChanceToHitGun(pSoldier, sTarget, sAimTime, AIM_SHOT_TORSO, bLevel, PRONE);
|
|
||||||
sAimAPCost = CalcAPCostForAiming(pSoldier, sTarget, (INT8)sAimTime);
|
|
||||||
iHitRate = sChanceToHit * (pSoldier->bActionPoints - (sMinAPcost - sRawAPCost)) / (sRawAPCost + sAimAPCost);
|
|
||||||
// sevenfm: take into account CTGT for every stance
|
|
||||||
if (iHitRate * ubChanceToGetThrough > iBestHitRate * ubBestChanceToGetThrough)
|
|
||||||
{
|
|
||||||
iBestHitRate = iHitRate;
|
|
||||||
sBestAimTime = sAimTime;
|
|
||||||
sBestChanceToHit = sChanceToHit;
|
|
||||||
ubBestChanceToGetThrough = ubChanceToGetThrough;
|
|
||||||
ubBestFriendlyFireChance = ubFriendlyFireChance;
|
|
||||||
bScopeMode = pSoldier->bScopeMode;
|
|
||||||
sBestAPcost = sMinAPcost;
|
|
||||||
ubBestStance = ubStance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pSoldier->usAnimState = usTrueState;
|
|
||||||
pSoldier->sLastTarget = iTrueLastTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we can't get any kind of hit rate at all
|
|
||||||
if (iBestHitRate == 0)
|
|
||||||
continue; // next opponent
|
|
||||||
|
|
||||||
// calculate chance to REALLY hit: shoot accurately AND get past cover
|
|
||||||
ubChanceToReallyHit = (UINT8)ceil((sBestChanceToHit * ubBestChanceToGetThrough) / 100.0f);
|
|
||||||
|
|
||||||
// if we can't REALLY hit at all
|
|
||||||
if (ubChanceToReallyHit == 0)
|
|
||||||
continue; // next opponent
|
|
||||||
|
|
||||||
// really limit knife throwing so it doesn't look wrong
|
|
||||||
if (Item[pSoldier->usAttackingWeapon].usItemClass == IC_THROWING_KNIFE &&
|
|
||||||
(ubChanceToReallyHit < 25 || (PythSpacesAway(pSoldier->sGridNo, sTarget) > CalcMaxTossRange(pSoldier, pSoldier->usAttackingWeapon, FALSE))))// Madd / 2 ) ) ) //dnl ch69 160913 was ubChanceToReallyHit < 30
|
|
||||||
continue; // don't bother... next opponent
|
|
||||||
|
|
||||||
// calculate this opponent's threat value (factor in my cover from him)
|
|
||||||
iThreatValue = CalcManThreatValue(pOpponent, pSoldier->sGridNo, TRUE, pSoldier);
|
|
||||||
|
|
||||||
// estimate the damage this shot would do to this opponent
|
|
||||||
iEstDamage = EstimateShotDamage(pSoldier, pOpponent, sBestChanceToHit);
|
|
||||||
//NumMessage("SHOT EstDamage = ",iEstDamage);
|
|
||||||
|
|
||||||
// calculate the combined "attack value" for this opponent
|
|
||||||
// highest possible value before division should be about 1.8 billion...
|
|
||||||
// normal value before division should be about 5 million...
|
|
||||||
iAttackValue = (iEstDamage * iBestHitRate * ubChanceToReallyHit * iThreatValue) / 1000;
|
|
||||||
//NumMessage("SHOT AttackValue = ",iAttackValue / 1000);
|
|
||||||
|
|
||||||
// sevenfm: penalize suppression fire
|
|
||||||
if (fSuppression)
|
|
||||||
{
|
|
||||||
// 25% penalty for shooting at invisible target
|
|
||||||
iAttackValue = iAttackValue / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// special stuff for assassins to ignore militia more
|
|
||||||
if (pSoldier->IsAssassin() && pOpponent->bTeam == MILITIA_TEAM)
|
|
||||||
{
|
|
||||||
iAttackValue /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: empty vehicles have very low priority
|
|
||||||
if (pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle(pOpponent->bVehicleID) == 0)
|
|
||||||
{
|
|
||||||
iAttackValue /= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: dying, cowering or unconscious soldiers have very low priority
|
|
||||||
if (pOpponent->stats.bLife < OKLIFE || pOpponent->bCollapsed || pOpponent->bBreathCollapsed)
|
|
||||||
{
|
|
||||||
iAttackValue /= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUGATTACKS
|
|
||||||
DebugAI(String("CalcBestShot: best AttackValue vs %d = %d\n", uiLoop, iAttackValue));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// if we can hurt the guy, OR probably not, but at least it's our best
|
|
||||||
// chance to actually hit him and maybe scare him, knock him down, etc.
|
|
||||||
if ((iAttackValue > 0) || (ubChanceToReallyHit > pBestShot.ubChanceToReallyHit))
|
|
||||||
{
|
|
||||||
#if 0 // if there already was another viable target
|
|
||||||
if (pBestShot.ubChanceToReallyHit > 0)
|
|
||||||
{
|
|
||||||
// OK, how does our chance to hit him compare to the previous best one?
|
|
||||||
iPercentBetter = ((ubChanceToReallyHit * 100) / pBestShot.ubChanceToReallyHit) - 100;
|
|
||||||
|
|
||||||
//dnl ch62 180813 ignore firing into breathless targets if there are targets in better condition
|
|
||||||
// sevenfm: check that best opponent exists
|
|
||||||
if (pBestShot.ubOpponent != NOBODY &&
|
|
||||||
(Menptr[pBestShot.ubOpponent].bCollapsed || Menptr[pBestShot.ubOpponent].bBreathCollapsed) &&
|
|
||||||
Menptr[pBestShot.ubOpponent].bBreath < OKBREATH
|
|
||||||
&& Menptr[pBestShot.ubOpponent].bBreath < pOpponent->bBreath)
|
|
||||||
{
|
|
||||||
iPercentBetter = PERCENT_TO_IGNORE_THREAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: if best opponent is dying and new opponent is ok, use new opponent
|
|
||||||
if (pBestShot.ubOpponent != NOBODY &&
|
|
||||||
Menptr[pBestShot.ubOpponent].stats.bLife < OKLIFE &&
|
|
||||||
pOpponent->stats.bLife >= OKLIFE)
|
|
||||||
{
|
|
||||||
iPercentBetter = PERCENT_TO_IGNORE_THREAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this chance to really hit is more than 50% worse, and the other
|
|
||||||
// guy is conscious at all
|
|
||||||
if (iPercentBetter < -PERCENT_TO_IGNORE_THREAT &&
|
|
||||||
pBestShot.ubOpponent != NOBODY &&
|
|
||||||
Menptr[pBestShot.ubOpponent].stats.bLife >= OKLIFE)
|
|
||||||
{
|
|
||||||
// then stick with the older guy as the better target
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this chance to really hit between 50% worse to 50% better
|
|
||||||
if (iPercentBetter < PERCENT_TO_IGNORE_THREAT)
|
|
||||||
{
|
|
||||||
// then the one with the higher ATTACK VALUE is the better target
|
|
||||||
if (iAttackValue < pBestShot.iAttackValue)
|
|
||||||
// the previous guy is more important since he's more dangerous
|
|
||||||
continue; // next opponent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: if new opponent is dying and best opponent is ok, ignore new opponent
|
|
||||||
if (pBestShot.ubOpponent != NOBODY &&
|
|
||||||
Menptr[pBestShot.ubOpponent].stats.bLife >= OKLIFE &&
|
|
||||||
pOpponent->stats.bLife < OKLIFE)
|
|
||||||
{
|
|
||||||
//DebugShot(pSoldier, String("new opponent is dying, best opponent is ok - skip"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// OOOF! That was a lot of work! But we've got a new viable target!
|
|
||||||
pBestShot.ubPossible = TRUE;
|
|
||||||
pBestShot.ubOpponent = pOpponent->ubID;
|
|
||||||
pBestShot.ubAimTime = sBestAimTime;
|
|
||||||
pBestShot.ubChanceToReallyHit = ubChanceToReallyHit;
|
|
||||||
pBestShot.sTarget = sTarget;
|
|
||||||
pBestShot.bTargetLevel = bLevel;
|
|
||||||
pBestShot.iAttackValue = iAttackValue;
|
|
||||||
pBestShot.ubAPCost = sBestAPcost;
|
|
||||||
pBestShot.ubStance = ubBestStance;
|
|
||||||
pBestShot.bScopeMode = bScopeMode;
|
|
||||||
pBestShot.ubFriendlyFireChance = ubBestFriendlyFireChance;
|
|
||||||
|
|
||||||
possibleShots.push_back(pBestShot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pSoldier->bScopeMode = USE_BEST_SCOPE; // better reset this back
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CompareAttacks(const ATTACKTYPE& a, const ATTACKTYPE& b)
|
|
||||||
{
|
|
||||||
if (a.iAttackValue > b.iAttackValue)
|
|
||||||
return true;
|
|
||||||
else if (a.iAttackValue < b.iAttackValue)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (a.ubChanceToReallyHit > b.ubChanceToReallyHit)
|
|
||||||
return true;
|
|
||||||
else if (a.ubChanceToReallyHit < b.ubChanceToReallyHit)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (a.ubFriendlyFireChance < b.ubFriendlyFireChance)
|
|
||||||
return true;
|
|
||||||
else if (a.ubFriendlyFireChance > b.ubFriendlyFireChance)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (a.ubAPCost < b.ubAPCost)
|
|
||||||
return true;
|
|
||||||
else if (a.ubAPCost > b.ubAPCost)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckIfShotsPossible(SOLDIERTYPE* pSoldier, std::vector<ATTACKTYPE>& possibleShots)
|
|
||||||
{
|
|
||||||
INT8 guns[] = { FindAIUsableObjClass(pSoldier, IC_GUN), FindAIUsableObjClass(pSoldier, IC_GUN, TRUE) };
|
|
||||||
// Only merc bodytypes can use a sidearm, also don't bother to check for targets if found sidearm is the same as main gun
|
|
||||||
if (!IS_MERC_BODY_TYPE(pSoldier) || guns[0] == guns[1])
|
|
||||||
{
|
|
||||||
guns[1] = NO_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
const auto gun = guns[i];
|
|
||||||
// if the soldier does have a gun
|
|
||||||
if (gun != NO_SLOT)
|
|
||||||
{
|
|
||||||
// if it's in his holster, swap it into his hand temporarily
|
|
||||||
if (gun != HANDPOS)
|
|
||||||
{
|
|
||||||
RearrangePocket(pSoldier, HANDPOS, gun, TEMPORARILY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the minimum cost to attack with this item
|
|
||||||
INT16 ubMinAPcost = MinAPsToAttack(pSoldier, pSoldier->sLastTarget, ADDTURNCOST, 0);
|
|
||||||
|
|
||||||
// if we can afford the minimum AP cost
|
|
||||||
if (pSoldier->bActionPoints >= ubMinAPcost)
|
|
||||||
{
|
|
||||||
// then look around for worthy targets
|
|
||||||
CalculatePossibleShots(pSoldier, gun, possibleShots);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it was in his holster, swap it back into his holster for now
|
|
||||||
if (gun != HANDPOS)
|
|
||||||
{
|
|
||||||
RearrangePocket(pSoldier, HANDPOS, gun, TEMPORARILY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,6 +14,4 @@ set(TacticalAISrc
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/QuestDebug.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/QuestDebug.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Realtime.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Realtime.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/ZombieDecideAction.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/ZombieDecideAction.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/UtilityAI.cpp"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/UtilityAI_ResponseCurve.cpp"
|
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
|||||||
@@ -844,8 +844,7 @@ INT8 CreatureDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
{
|
{
|
||||||
// determine the location of the known closest opponent
|
// determine the location of the known closest opponent
|
||||||
// (don't care if he's conscious, don't care if he's reachable at all)
|
// (don't care if he's conscious, don't care if he's reachable at all)
|
||||||
INT32 distanceToThreat;
|
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||||
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL, NULL, &distanceToThreat);
|
|
||||||
|
|
||||||
if (!TileIsOutOfBounds(sClosestOpponent))
|
if (!TileIsOutOfBounds(sClosestOpponent))
|
||||||
{
|
{
|
||||||
@@ -855,9 +854,9 @@ INT8 CreatureDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
// if soldier is not already facing in that direction,
|
// if soldier is not already facing in that direction,
|
||||||
// and the opponent is close enough that he could possibly be seen
|
// and the opponent is close enough that he could possibly be seen
|
||||||
// note, have to change this to use the level returned from ClosestKnownOpponent
|
// note, have to change this to use the level returned from ClosestKnownOpponent
|
||||||
sDistVisible = pSoldier->GetMaxDistanceVisible(sClosestOpponent, 0 ) * CELL_X_SIZE;
|
sDistVisible = pSoldier->GetMaxDistanceVisible(sClosestOpponent, 0 );
|
||||||
|
|
||||||
if ((pSoldier->ubDirection != ubOpponentDir) && (distanceToThreat <= sDistVisible))
|
if ((pSoldier->ubDirection != ubOpponentDir) && (PythSpacesAway(pSoldier->sGridNo,sClosestOpponent) <= sDistVisible))
|
||||||
{
|
{
|
||||||
// set base chance according to orders
|
// set base chance according to orders
|
||||||
if ((pSoldier->aiData.bOrders == STATIONARY) || (pSoldier->aiData.bOrders == ONGUARD))
|
if ((pSoldier->aiData.bOrders == STATIONARY) || (pSoldier->aiData.bOrders == ONGUARD))
|
||||||
@@ -1381,12 +1380,11 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier )
|
|||||||
{
|
{
|
||||||
// determine the location of the known closest opponent
|
// determine the location of the known closest opponent
|
||||||
// (don't care if he's conscious, don't care if he's reachable at all)
|
// (don't care if he's conscious, don't care if he's reachable at all)
|
||||||
INT32 distanceToThreat;
|
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||||
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL, NULL, &distanceToThreat);
|
|
||||||
// if we have a closest reachable opponent
|
// if we have a closest reachable opponent
|
||||||
if (!TileIsOutOfBounds(sClosestOpponent))
|
if (!TileIsOutOfBounds(sClosestOpponent))
|
||||||
{
|
{
|
||||||
if ( ubCanMove && distanceToThreat > 20 ) // 2 tiles -> 20 in fractional Cell Coordinates
|
if ( ubCanMove && PythSpacesAway( pSoldier->sGridNo, sClosestOpponent ) > 2 )
|
||||||
{
|
{
|
||||||
if ( bSpitIn != NO_SLOT )
|
if ( bSpitIn != NO_SLOT )
|
||||||
{
|
{
|
||||||
|
|||||||
+288
-12611
File diff suppressed because it is too large
Load Diff
+287
-138
@@ -15,6 +15,10 @@
|
|||||||
#include "Render Fun.h"
|
#include "Render Fun.h"
|
||||||
#include "Boxing.h"
|
#include "Boxing.h"
|
||||||
#include "Text.h"
|
#include "Text.h"
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include "renderworld.h"
|
||||||
|
#include "video.h"
|
||||||
|
#endif
|
||||||
#include "worldman.h"
|
#include "worldman.h"
|
||||||
#include "strategicmap.h"
|
#include "strategicmap.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
@@ -22,8 +26,7 @@
|
|||||||
#include "Buildings.h"
|
#include "Buildings.h"
|
||||||
#include "GameSettings.h"
|
#include "GameSettings.h"
|
||||||
#include "Soldier Profile.h"
|
#include "Soldier Profile.h"
|
||||||
#include "rotting corpses.h" // sevenfm
|
#include "Rotting Corpses.h" // sevenfm
|
||||||
#include <Cheats.h>
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -31,7 +34,17 @@
|
|||||||
// were changed to GetAPsCrouch() and GetAPsProne()
|
// were changed to GetAPsCrouch() and GetAPsProne()
|
||||||
// - also all "APBPConstants[AP_PICKUP_ITEM]" were replaced by GetBasicAPsToPickupItem()
|
// - also all "APBPConstants[AP_PICKUP_ITEM]" were replaced by GetBasicAPsToPickupItem()
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
INT16 gsBestCover;
|
|
||||||
|
INT16 * gsCoverValue = NULL;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
|
||||||
|
INT16 gsBestCover;
|
||||||
|
#ifndef PATHAI_VISIBLE_DEBUG
|
||||||
|
// NB Change this to true to get visible cover debug -- CJC
|
||||||
|
BOOLEAN gfDisplayCoverValues = FALSE;
|
||||||
|
#endif
|
||||||
|
extern void RenderCoverDebug( void );
|
||||||
|
#endif
|
||||||
|
|
||||||
INT16 gubAIPathCosts[19][19];
|
INT16 gubAIPathCosts[19][19];
|
||||||
|
|
||||||
@@ -600,115 +613,42 @@ UINT8 NumberOfTeamMatesAdjacent( SOLDIERTYPE * pSoldier, INT32 sGridNo )
|
|||||||
return( ubCount );
|
return( ubCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CalculateCoverValue(SOLDIERTYPE* pSoldier, const INT32 sGridNo, const INT32 iPathCost, const INT32 iMyThreatValue, const UINT32 uiThreatCnt, const UINT8 ubDiff, const BOOLEAN fNight, const UINT8 ubBackgroundLightPercent, const INT32 morale, INT32 &iCoverValue, INT32& iCoverScale)
|
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentBetter)
|
||||||
{
|
{
|
||||||
iCoverValue = 0;
|
|
||||||
iCoverScale = 0;
|
|
||||||
|
|
||||||
// sevenfm: check sight cover
|
|
||||||
BOOLEAN fProneCover = TRUE;
|
|
||||||
|
|
||||||
// for every opponent that threatens, consider this spot's cover vs. him
|
|
||||||
for (UINT32 uiLoop = 0; uiLoop < uiThreatCnt; uiLoop++)
|
|
||||||
{
|
|
||||||
// calculate the range we would be at from this opponent
|
|
||||||
INT32 iThreatRange = Threat[uiLoop].iOrigRange;
|
|
||||||
if (sGridNo != pSoldier->sGridNo)
|
|
||||||
{
|
|
||||||
iThreatRange = GetRangeInCellCoordsFromGridNoDiff(sGridNo, Threat[uiLoop].sGridNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this threat would be within 20 tiles, count it
|
|
||||||
if (iThreatRange <= MAX_THREAT_RANGE)
|
|
||||||
{
|
|
||||||
iCoverValue += CalcCoverValue(
|
|
||||||
pSoldier, sGridNo, iMyThreatValue,
|
|
||||||
(pSoldier->bActionPoints - iPathCost),
|
|
||||||
uiLoop, iThreatRange, morale, &iCoverScale
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: sight test
|
|
||||||
if (gGameExternalOptions.fAIBetterCover)
|
|
||||||
{
|
|
||||||
if (LocationToLocationLineOfSightTest(Threat[uiLoop].sGridNo, Threat[uiLoop].pOpponent->pathing.bLevel, sGridNo, pSoldier->pathing.bLevel, TRUE, MAX_VISION_RANGE, STANDING_LOS_POS, PRONE_LOS_POS))
|
|
||||||
//if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, -1 ) != 0 )
|
|
||||||
{
|
|
||||||
fProneCover = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//sprintf(tempstr,"iCoverValue after opponent %d is now %d",iLoop,iCoverValue);
|
|
||||||
//PopMessage(tempstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reduce cover for each person adjacent to this gridno who is on our team,
|
|
||||||
// by 10% (so locations next to several people will be very much frowned upon
|
|
||||||
iCoverValue -= (abs(iCoverValue) / 5) * NumberOfTeamMatesAdjacent(pSoldier, sGridNo);
|
|
||||||
|
|
||||||
if (gGameExternalOptions.fAIBetterCover)
|
|
||||||
{
|
|
||||||
// sevenfm: when defending (range change <= 3), prefer locations with sight cover
|
|
||||||
if (RangeChangeDesire(pSoldier) < 4)
|
|
||||||
{
|
|
||||||
if (fProneCover) { iCoverValue += abs(iCoverValue) / __max(2, 2 * RangeChangeDesire(pSoldier)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: check for nearby friends, add bonus/penalty 10%
|
|
||||||
UINT8 ubNearbyFriends = __max(0, CountNearbyFriends(pSoldier, sGridNo, TACTICAL_RANGE_CLOSE));
|
|
||||||
iCoverValue -= ubNearbyFriends * abs(iCoverValue) / (6 - ubDiff);
|
|
||||||
|
|
||||||
// sevenfm: penalize locations with fresh corpses
|
|
||||||
if (GetNearestRottingCorpseAIWarning(sGridNo) > 0)
|
|
||||||
{
|
|
||||||
iCoverValue -= abs(iCoverValue) / (6 - ubDiff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sevenfm: penalize locations near red smoke
|
|
||||||
iCoverValue -= abs(iCoverValue) * RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fNight && !(InARoom(sGridNo, NULL))) // ignore in buildings in case placed there
|
|
||||||
{
|
|
||||||
// reduce cover at nighttime based on how bright the light is at that location
|
|
||||||
// using the difference in sighting distance between the background and the
|
|
||||||
// light for this tile
|
|
||||||
//ubLightPercentDifference = (gbLightSighting[ 0 ][ LightTrueLevel( sGridNo, pSoldier->pathing.bLevel ) ] - ubBackgroundLightPercent );
|
|
||||||
UINT8 ubLightPercentDifference = (gGameExternalOptions.ubBrightnessVisionMod[LightTrueLevel(sGridNo, pSoldier->pathing.bLevel)] - ubBackgroundLightPercent);
|
|
||||||
iCoverValue -= (abs(iCoverValue) / 100) * ubLightPercentDifference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentBetter, INT32 targetGridNo, bool ignoreSearchRange)
|
|
||||||
{
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_COVERVALUE && DEBUG_CHEAT_LEVEL())
|
|
||||||
{
|
|
||||||
ResetDebugInfoValues();
|
|
||||||
}
|
|
||||||
DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("FindBestNearbyCover"));
|
DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("FindBestNearbyCover"));
|
||||||
|
|
||||||
// all 32-bit integers for max. speed
|
// all 32-bit integers for max. speed
|
||||||
|
UINT32 uiLoop;
|
||||||
INT32 iCurrentCoverValue, iCoverValue, iBestCoverValue;
|
INT32 iCurrentCoverValue, iCoverValue, iBestCoverValue;
|
||||||
INT32 iCurrentScale = -1, iCoverScale = -1, iBestCoverScale = -1;
|
INT32 iCurrentScale = -1, iCoverScale = -1, iBestCoverScale = -1;
|
||||||
INT32 iDistFromOrigin, iDistCoverFromOrigin;
|
INT32 iDistFromOrigin, iDistCoverFromOrigin;
|
||||||
|
//INT32 iThreatCertainty;
|
||||||
INT32 sGridNo, sBestCover = NOWHERE;
|
INT32 sGridNo, sBestCover = NOWHERE;
|
||||||
INT32 iPathCost;
|
INT32 iPathCost;
|
||||||
|
INT32 iThreatRange, iClosestThreatRange = 1500;
|
||||||
|
// INT16 sClosestThreatGridno = NOWHERE;
|
||||||
INT32 iMyThreatValue;
|
INT32 iMyThreatValue;
|
||||||
|
//INT32 sThreatLoc;
|
||||||
|
//INT32 iMaxThreatRange;
|
||||||
UINT32 uiThreatCnt = 0;
|
UINT32 uiThreatCnt = 0;
|
||||||
INT32 iMaxMoveTilesLeft, iSearchRange, iRoamRange;
|
INT32 iMaxMoveTilesLeft, iSearchRange, iRoamRange;
|
||||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||||
INT32 sOrigin; // has to be a short, need a pointer
|
INT32 sOrigin; // has to be a short, need a pointer
|
||||||
|
INT32 * pusLastLoc;
|
||||||
|
INT8 * pbPersOL;
|
||||||
|
INT8 * pbPublOL;
|
||||||
|
//SOLDIERTYPE *pOpponent;
|
||||||
UINT16 usMovementMode;
|
UINT16 usMovementMode;
|
||||||
|
|
||||||
UINT8 ubBackgroundLightLevel;
|
UINT8 ubBackgroundLightLevel;
|
||||||
UINT8 ubBackgroundLightPercent = 0;
|
UINT8 ubBackgroundLightPercent = 0;
|
||||||
|
UINT8 ubLightPercentDifference;
|
||||||
BOOLEAN fNight;
|
BOOLEAN fNight;
|
||||||
|
|
||||||
const UINT8 ubDiff = SoldierDifficultyLevel( pSoldier );
|
// sevenfm
|
||||||
|
UINT8 ubNearbyFriends;
|
||||||
if (targetGridNo == NOWHERE)
|
BOOLEAN fProneCover;
|
||||||
{
|
UINT8 ubDiff = SoldierDifficultyLevel( pSoldier );
|
||||||
targetGridNo = pSoldier->sGridNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no cover when boxing!
|
// There's no cover when boxing!
|
||||||
if (gTacticalStatus.bBoxingState == BOXING)
|
if (gTacticalStatus.bBoxingState == BOXING)
|
||||||
@@ -736,6 +676,25 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iBestCoverValue = -1;
|
||||||
|
|
||||||
|
#if defined( _DEBUG ) && defined( COVER_DEBUG )
|
||||||
|
if (gfDisplayCoverValues)
|
||||||
|
{
|
||||||
|
memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//NameMessage(pSoldier,"looking for some cover...");
|
||||||
|
|
||||||
|
// BUILD A LIST OF THREATENING GRID #s FROM PERSONAL & PUBLIC opplists
|
||||||
|
|
||||||
|
pusLastLoc = &(gsLastKnownOppLoc[pSoldier->ubID][0]);
|
||||||
|
|
||||||
|
// hang a pointer into personal opplist
|
||||||
|
pbPersOL = &(pSoldier->aiData.bOppList[0]);
|
||||||
|
// hang a pointer into public opplist
|
||||||
|
pbPublOL = &(gbPublicOpplist[pSoldier->bTeam][0]);
|
||||||
|
|
||||||
// decide how far we're gonna be looking
|
// decide how far we're gonna be looking
|
||||||
iSearchRange = gbDiff[DIFF_MAX_COVER_RANGE][ SoldierDifficultyLevel( pSoldier ) ];
|
iSearchRange = gbDiff[DIFF_MAX_COVER_RANGE][ SoldierDifficultyLevel( pSoldier ) ];
|
||||||
@@ -752,9 +711,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// maximum search range is 1 tile / 8 pts of wisdom
|
// maximum search range is 1 tile / 8 pts of wisdom
|
||||||
if (iSearchRange > (pSoldier->stats.bWisdom / 4))
|
if (iSearchRange > (pSoldier->stats.bWisdom / 8))
|
||||||
{
|
{
|
||||||
iSearchRange = (pSoldier->stats.bWisdom / 4);
|
iSearchRange = (pSoldier->stats.bWisdom / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gfTurnBasedAI)
|
if (!gfTurnBasedAI)
|
||||||
@@ -765,7 +724,6 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
|
|
||||||
usMovementMode = DetermineMovementMode( pSoldier, AI_ACTION_TAKE_COVER );
|
usMovementMode = DetermineMovementMode( pSoldier, AI_ACTION_TAKE_COVER );
|
||||||
|
|
||||||
#if 1
|
|
||||||
if (pSoldier->aiData.bAlertStatus >= STATUS_RED) // if already in battle
|
if (pSoldier->aiData.bAlertStatus >= STATUS_RED) // if already in battle
|
||||||
{
|
{
|
||||||
// must be able to reach the cover, so it can't possibly be more than
|
// must be able to reach the cover, so it can't possibly be more than
|
||||||
@@ -786,12 +744,6 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
iSearchRange = iMaxMoveTilesLeft;
|
iSearchRange = iMaxMoveTilesLeft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (ignoreSearchRange)
|
|
||||||
{
|
|
||||||
// For debugging
|
|
||||||
iSearchRange = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iSearchRange <= 0)
|
if (iSearchRange <= 0)
|
||||||
{
|
{
|
||||||
@@ -813,30 +765,95 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
|
|
||||||
// calculate our current cover value in the place we are now, since the
|
// calculate our current cover value in the place we are now, since the
|
||||||
// cover we are searching for must be better than what we have now!
|
// cover we are searching for must be better than what we have now!
|
||||||
CalculateCoverValue(pSoldier, targetGridNo, 0, iMyThreatValue, uiThreatCnt, ubDiff, fNight, ubBackgroundLightPercent, morale, iCurrentCoverValue, iCurrentScale);
|
iCurrentCoverValue = 0;
|
||||||
// the initial cover value to beat is our current cover value
|
iCurrentScale = 0;
|
||||||
iBestCoverValue = iCurrentCoverValue;
|
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_COVERVALUE && DEBUG_CHEAT_LEVEL())
|
// sevenfm: sight cover
|
||||||
|
fProneCover = TRUE;
|
||||||
|
|
||||||
|
// for every opponent that threatens, consider this spot's cover vs. him
|
||||||
|
for (uiLoop = 0; uiLoop < uiThreatCnt; uiLoop++)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[targetGridNo] = (INT32)(iCurrentCoverValue / 100);
|
// if this threat is CURRENTLY within 20 tiles
|
||||||
|
if (Threat[uiLoop].iOrigRange <= MAX_THREAT_RANGE)
|
||||||
|
{
|
||||||
|
// add this opponent's cover value to our current total cover value
|
||||||
|
iCurrentCoverValue += CalcCoverValue(pSoldier,pSoldier->sGridNo,iMyThreatValue,pSoldier->bActionPoints,uiLoop,Threat[uiLoop].iOrigRange,morale,&iCurrentScale);
|
||||||
|
}
|
||||||
|
// sevenfm: sight test
|
||||||
|
if( gGameExternalOptions.fAIBetterCover )
|
||||||
|
{
|
||||||
|
if ( LocationToLocationLineOfSightTest( Threat[uiLoop].sGridNo, Threat[uiLoop].pOpponent->pathing.bLevel, pSoldier->sGridNo, pSoldier->pathing.bLevel, TRUE, MAX_VISION_RANGE, STANDING_LOS_POS, PRONE_LOS_POS ) )
|
||||||
|
//if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, pSoldier->sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, NO_DISTANCE_LIMIT ) )
|
||||||
|
{
|
||||||
|
fProneCover = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//sprintf(tempstr,"iCurrentCoverValue after opponent %d is now %d",iLoop,iCurrentCoverValue);
|
||||||
|
//PopMessage(tempstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reduce cover for each person adjacent to this gridno who is on our team,
|
||||||
|
// by 10% (so locations next to several people will be very much frowned upon
|
||||||
|
if ( iCurrentCoverValue >= 0 )
|
||||||
|
{
|
||||||
|
iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// when negative, must add a negative to decrease the total
|
||||||
|
iCurrentCoverValue += (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( gGameExternalOptions.fAIBetterCover )
|
||||||
|
{
|
||||||
|
// sevenfm: when defending (range change <= 3), prefer locations with sight cover
|
||||||
|
if( RangeChangeDesire(pSoldier) < 4 )
|
||||||
|
{
|
||||||
|
if( fProneCover )
|
||||||
|
{
|
||||||
|
iCurrentCoverValue += abs(iCurrentCoverValue) / __max(2, 2*RangeChangeDesire(pSoldier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: check for nearby friends, add bonus/penalty
|
||||||
|
ubNearbyFriends = __min(5, CountNearbyFriends( pSoldier, pSoldier->sGridNo, 5 ));
|
||||||
|
iCurrentCoverValue -= ubNearbyFriends * abs(iCurrentCoverValue) / (10-ubDiff);
|
||||||
|
|
||||||
|
// sevenfm: penalize locations with fresh corpses
|
||||||
|
if(GetNearestRottingCorpseAIWarning( pSoldier->sGridNo ) > 0)
|
||||||
|
{
|
||||||
|
iCurrentCoverValue -= abs(iCurrentCoverValue) / (8-ubDiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: penalize locations near red smoke
|
||||||
|
iCurrentCoverValue -= abs(iCurrentCoverValue) * RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUGCOVER
|
||||||
|
// AINumMessage("Search Range = ",iSearchRange);
|
||||||
|
#endif
|
||||||
|
|
||||||
// determine maximum horizontal limits
|
// determine maximum horizontal limits
|
||||||
sMaxLeft = min(iSearchRange,(targetGridNo % MAXCOL));
|
sMaxLeft = min(iSearchRange,(pSoldier->sGridNo % MAXCOL));
|
||||||
sMaxRight = min(iSearchRange,MAXCOL - ((targetGridNo % MAXCOL) + 1));
|
//NumMessage("sMaxLeft = ",sMaxLeft);
|
||||||
|
sMaxRight = min(iSearchRange,MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||||
|
//NumMessage("sMaxRight = ",sMaxRight);
|
||||||
|
|
||||||
// determine maximum vertical limits
|
// determine maximum vertical limits
|
||||||
sMaxUp = min(iSearchRange,(targetGridNo / MAXROW));
|
sMaxUp = min(iSearchRange,(pSoldier->sGridNo / MAXROW));
|
||||||
sMaxDown = min(iSearchRange,MAXROW - ((targetGridNo / MAXROW) + 1));
|
//NumMessage("sMaxUp = ",sMaxUp);
|
||||||
|
sMaxDown = min(iSearchRange,MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
|
||||||
|
//NumMessage("sMaxDown = ",sMaxDown);
|
||||||
|
|
||||||
iRoamRange = RoamingRange(pSoldier,&sOrigin);
|
iRoamRange = RoamingRange(pSoldier,&sOrigin);
|
||||||
|
|
||||||
// if status isn't black (life & death combat), and roaming range is limited
|
// if status isn't black (life & death combat), and roaming range is limited
|
||||||
//if ((pSoldier->aiData.bAlertStatus != STATUS_BLACK) && (iRoamRange < MAX_ROAMING_RANGE) &&
|
if ((pSoldier->aiData.bAlertStatus != STATUS_BLACK) && (iRoamRange < MAX_ROAMING_RANGE) &&
|
||||||
if ((pSoldier->aiData.bAlertStatus < STATUS_RED) && (iRoamRange < MAX_ROAMING_RANGE) &&
|
|
||||||
(!TileIsOutOfBounds(sOrigin)))
|
(!TileIsOutOfBounds(sOrigin)))
|
||||||
{
|
{
|
||||||
// must try to stay within or return to the point of origin
|
// must try to stay within or return to the point of origin
|
||||||
iDistFromOrigin = SpacesAway(sOrigin,targetGridNo);
|
iDistFromOrigin = SpacesAway(sOrigin,pSoldier->sGridNo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -845,6 +862,19 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUGCOVER
|
||||||
|
DebugAI( String( "FBNC: iRoamRange %d, sMaxLeft %d, sMaxRight %d, sMaxUp %d, sMaxDown %d\n",iRoamRange,sMaxLeft,sMaxRight,sMaxUp,sMaxDown) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the initial cover value to beat is our current cover value
|
||||||
|
iBestCoverValue = iCurrentCoverValue;
|
||||||
|
|
||||||
|
#ifdef DEBUGDECISIONS
|
||||||
|
STR tempstr="";
|
||||||
|
sprintf( tempstr, "FBNC: CURRENT iCoverValue = %d\n",iCurrentCoverValue );
|
||||||
|
DebugAI( tempstr );
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pSoldier->aiData.bAlertStatus >= STATUS_RED) // if already in battle
|
if (pSoldier->aiData.bAlertStatus >= STATUS_RED) // if already in battle
|
||||||
{
|
{
|
||||||
// to speed this up, tell PathAI to cancel any paths beyond our AP reach!
|
// to speed this up, tell PathAI to cancel any paths beyond our AP reach!
|
||||||
@@ -870,7 +900,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
{
|
{
|
||||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||||
{
|
{
|
||||||
sGridNo = targetGridNo + sXOffset + (MAXCOL * sYOffset);
|
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -878,20 +908,22 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
gpWorldLevelData[sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
gpWorldLevelData[sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FindBestPath( pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, DetermineMovementMode( pSoldier, AI_ACTION_TAKE_COVER ), COPYREACHABLE_AND_APS, 0 );//dnl ch50 071009
|
FindBestPath( pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, DetermineMovementMode( pSoldier, AI_ACTION_TAKE_COVER ), COPYREACHABLE_AND_APS, 0 );//dnl ch50 071009
|
||||||
|
|
||||||
// Turn off the "reachable" flag for his current location
|
// Turn off the "reachable" flag for his current location
|
||||||
// so we don't consider it
|
// so we don't consider it
|
||||||
gpWorldLevelData[targetGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||||
|
|
||||||
// SET UP DOUBLE-LOOP TO STEP THROUGH POTENTIAL GRID #s
|
// SET UP DOUBLE-LOOP TO STEP THROUGH POTENTIAL GRID #s
|
||||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||||
{
|
{
|
||||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||||
{
|
{
|
||||||
|
//HandleMyMouseCursor(KEYBOARDALSO);
|
||||||
|
|
||||||
// calculate the next potential gridno
|
// calculate the next potential gridno
|
||||||
sGridNo = targetGridNo + sXOffset + (MAXCOL * sYOffset);
|
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -948,7 +980,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
|
|
||||||
// sevenfm: avoid moving into light
|
// sevenfm: avoid moving into light
|
||||||
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) &&
|
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) &&
|
||||||
!InLightAtNight(targetGridNo, pSoldier->pathing.bLevel) &&
|
!InLightAtNight(pSoldier->sGridNo, pSoldier->pathing.bLevel) &&
|
||||||
!pSoldier->aiData.bUnderFire)
|
!pSoldier->aiData.bUnderFire)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -957,19 +989,12 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
// avoid moving into red smoke
|
// avoid moving into red smoke
|
||||||
if (gGameExternalOptions.fAIBetterCover &&
|
if (gGameExternalOptions.fAIBetterCover &&
|
||||||
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) &&
|
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) &&
|
||||||
!RedSmokeDanger(targetGridNo, pSoldier->pathing.bLevel))
|
!RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||||
{
|
{
|
||||||
//DebugCover(pSoldier, String("moving into red smoke, skip"));
|
//DebugCover(pSoldier, String("moving into red smoke, skip"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid overcrowding
|
|
||||||
const auto nearbyFriends = CountNearbyFriends(pSoldier, sGridNo, TACTICAL_RANGE_VERYCLOSE);
|
|
||||||
if ( nearbyFriends > 1 && !pSoldier->IsZombie() )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// zombies only want to hide
|
// zombies only want to hide
|
||||||
if (pSoldier->IsZombie() && !SightCoverAtSpot(pSoldier, sGridNo, TRUE))
|
if (pSoldier->IsZombie() && !SightCoverAtSpot(pSoldier, sGridNo, TRUE))
|
||||||
{
|
{
|
||||||
@@ -1002,15 +1027,110 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
|
|
||||||
// OK, this place shows potential. How useful is it as cover?
|
// OK, this place shows potential. How useful is it as cover?
|
||||||
// EVALUATE EACH GRID #, remembering the BEST PROTECTED ONE
|
// EVALUATE EACH GRID #, remembering the BEST PROTECTED ONE
|
||||||
CalculateCoverValue(pSoldier, sGridNo, iPathCost, iMyThreatValue, uiThreatCnt, ubDiff, fNight, ubBackgroundLightPercent, morale, iCoverValue, iCoverScale);
|
iCoverValue = 0;
|
||||||
|
iCoverScale = 0;
|
||||||
|
|
||||||
|
// sevenfm: check sight cover
|
||||||
|
fProneCover = TRUE;
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_COVERVALUE && DEBUG_CHEAT_LEVEL())
|
// for every opponent that threatens, consider this spot's cover vs. him
|
||||||
|
for (uiLoop = 0; uiLoop < uiThreatCnt; uiLoop++)
|
||||||
{
|
{
|
||||||
gRenderDebugInfoValues[sGridNo] = (INT32) (iCoverValue / 100);
|
// calculate the range we would be at from this opponent
|
||||||
|
iThreatRange = GetRangeInCellCoordsFromGridNoDiff( sGridNo, Threat[uiLoop].sGridNo );
|
||||||
|
// if this threat would be within 20 tiles, count it
|
||||||
|
if (iThreatRange <= MAX_THREAT_RANGE)
|
||||||
|
{
|
||||||
|
iCoverValue += CalcCoverValue(pSoldier,sGridNo,iMyThreatValue,
|
||||||
|
(pSoldier->bActionPoints - iPathCost),
|
||||||
|
uiLoop,iThreatRange,morale,&iCoverScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: sight test
|
||||||
|
if( gGameExternalOptions.fAIBetterCover )
|
||||||
|
{
|
||||||
|
if ( LocationToLocationLineOfSightTest( Threat[uiLoop].sGridNo, Threat[uiLoop].pOpponent->pathing.bLevel, sGridNo, pSoldier->pathing.bLevel, TRUE, MAX_VISION_RANGE, STANDING_LOS_POS, PRONE_LOS_POS ) )
|
||||||
|
//if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, -1 ) != 0 )
|
||||||
|
{
|
||||||
|
fProneCover = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//sprintf(tempstr,"iCoverValue after opponent %d is now %d",iLoop,iCoverValue);
|
||||||
|
//PopMessage(tempstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reduce cover for each person adjacent to this gridno who is on our team,
|
||||||
|
// by 10% (so locations next to several people will be very much frowned upon
|
||||||
|
if ( iCoverValue >= 0 )
|
||||||
|
{
|
||||||
|
iCoverValue -= (iCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, sGridNo );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// when negative, must add a negative to decrease the total
|
||||||
|
iCoverValue += (iCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, sGridNo );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( gGameExternalOptions.fAIBetterCover )
|
||||||
|
{
|
||||||
|
// sevenfm: when defending (range change <= 3), prefer locations with sight cover
|
||||||
|
if( RangeChangeDesire(pSoldier) < 4 )
|
||||||
|
{
|
||||||
|
if( fProneCover )
|
||||||
|
iCoverValue += abs(iCoverValue) / __max(2, 2*RangeChangeDesire(pSoldier));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: check for nearby friends in 10 radius, add bonus/penalty 10%
|
||||||
|
ubNearbyFriends = __min(5, CountNearbyFriends( pSoldier, sGridNo, 5 ));
|
||||||
|
iCoverValue -= ubNearbyFriends * abs(iCoverValue) / (10-ubDiff);
|
||||||
|
|
||||||
|
// sevenfm: penalize locations with fresh corpses
|
||||||
|
if(GetNearestRottingCorpseAIWarning( sGridNo ) > 0)
|
||||||
|
{
|
||||||
|
iCoverValue -= abs(iCoverValue) / (8-ubDiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: penalize locations near red smoke
|
||||||
|
iCoverValue -= abs(iCoverValue) * RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fNight && !( InARoom( sGridNo, NULL ) ) ) // ignore in buildings in case placed there
|
||||||
|
{
|
||||||
|
// reduce cover at nighttime based on how bright the light is at that location
|
||||||
|
// using the difference in sighting distance between the background and the
|
||||||
|
// light for this tile
|
||||||
|
//ubLightPercentDifference = (gbLightSighting[ 0 ][ LightTrueLevel( sGridNo, pSoldier->pathing.bLevel ) ] - ubBackgroundLightPercent );
|
||||||
|
ubLightPercentDifference = (gGameExternalOptions.ubBrightnessVisionMod[ LightTrueLevel( sGridNo, pSoldier->pathing.bLevel ) ] - ubBackgroundLightPercent );
|
||||||
|
|
||||||
|
if ( iCoverValue >= 0 )
|
||||||
|
{
|
||||||
|
iCoverValue -= (iCoverValue / 100) * ubLightPercentDifference;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iCoverValue += (iCoverValue / 100) * ubLightPercentDifference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUGCOVER
|
||||||
|
// if there ARE multiple opponents
|
||||||
|
if (uiThreatCnt > 1)
|
||||||
|
{
|
||||||
|
DebugAI( String( "FBNC: Total iCoverValue at gridno %d is %d\n\n",sGridNo,iCoverValue ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( _DEBUG ) && defined( COVER_DEBUG )
|
||||||
|
if (gfDisplayCoverValues)
|
||||||
|
{
|
||||||
|
gsCoverValue[sGridNo] = (INT16) (iCoverValue / 100);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// if this is better than the best place found so far
|
// if this is better than the best place found so far
|
||||||
|
|
||||||
if (iCoverValue > iBestCoverValue)
|
if (iCoverValue > iBestCoverValue)
|
||||||
{
|
{
|
||||||
// ONLY DO THIS CHECK HERE IF WE'RE WAITING FOR OPPCHANCETODECIDE,
|
// ONLY DO THIS CHECK HERE IF WE'RE WAITING FOR OPPCHANCETODECIDE,
|
||||||
@@ -1028,6 +1148,11 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef DEBUGDECISIONS
|
||||||
|
STR tempstr;
|
||||||
|
sprintf( tempstr,"FBNC: NEW BEST iCoverValue at gridno %d is %d\n",sGridNo,iCoverValue );
|
||||||
|
DebugAI( tempstr );
|
||||||
|
#endif
|
||||||
// remember it instead
|
// remember it instead
|
||||||
sBestCover = sGridNo;
|
sBestCover = sGridNo;
|
||||||
iBestCoverValue = iCoverValue;
|
iBestCoverValue = iCoverValue;
|
||||||
@@ -1039,15 +1164,34 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
gubNPCAPBudget = 0;
|
gubNPCAPBudget = 0;
|
||||||
gubNPCDistLimit = 0;
|
gubNPCDistLimit = 0;
|
||||||
|
|
||||||
if (gRenderDebugInfoMode == DEBUG_COVERVALUE && DEBUG_CHEAT_LEVEL())
|
#if defined( _DEBUG ) && !defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
if (gfDisplayCoverValues)
|
||||||
{
|
{
|
||||||
|
// do a locate?
|
||||||
|
LocateSoldier( pSoldier->ubID, SETLOCATORFAST );
|
||||||
gsBestCover = sBestCover;
|
gsBestCover = sBestCover;
|
||||||
InvalidateRegion(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_WINDOW_END_Y);
|
SetRenderFlags( RENDER_FLAG_FULL );
|
||||||
|
RenderWorld();
|
||||||
|
RenderCoverDebug( );
|
||||||
|
InvalidateScreen( );
|
||||||
|
EndFrameBufferRender();
|
||||||
|
RefreshScreen( NULL );
|
||||||
|
/*
|
||||||
|
iLoop = GetJA2Clock();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
|
||||||
|
} while( ( GetJA2Clock( ) - iLoop ) < 2000 );
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// if a better cover location was found
|
// if a better cover location was found
|
||||||
if (!TileIsOutOfBounds(sBestCover))
|
if (!TileIsOutOfBounds(sBestCover))
|
||||||
{
|
{
|
||||||
|
#if defined( _DEBUG ) && !defined( PATHAI_VISIBLE_DEBUG )
|
||||||
|
gsBestCover = sBestCover;
|
||||||
|
#endif
|
||||||
// cover values already take the AP cost of getting there into account in
|
// cover values already take the AP cost of getting there into account in
|
||||||
// a BIG way, so no need to worry about that here, even small improvements
|
// a BIG way, so no need to worry about that here, even small improvements
|
||||||
// are actually very significant once we get our APs back (if we live!)
|
// are actually very significant once we get our APs back (if we live!)
|
||||||
@@ -1056,6 +1200,16 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
|||||||
// if best cover value found was at least 5% better than our current cover
|
// if best cover value found was at least 5% better than our current cover
|
||||||
if (*piPercentBetter >= MIN_PERCENT_BETTER)
|
if (*piPercentBetter >= MIN_PERCENT_BETTER)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUGDECISIONS
|
||||||
|
STR tempstr;
|
||||||
|
sprintf( tempstr,"Found Cover: current %ld, best %ld, %%%%Better %ld\n", iCurrentCoverValue,iBestCoverValue,*piPercentBetter );
|
||||||
|
DebugAI( tempstr );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BETAVERSION
|
||||||
|
SnuggleDebug(pSoldier,"Found Cover");
|
||||||
|
#endif
|
||||||
|
|
||||||
return(sBestCover); // return the gridno of that cover
|
return(sBestCover); // return the gridno of that cover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2974,11 +3128,7 @@ INT32 FindAdvanceSpot(SOLDIERTYPE *pSoldier, INT32 sTargetSpot, INT8 bAction, UI
|
|||||||
{
|
{
|
||||||
if (usMovementMode == RUNNING || usMovementMode == WALKING)
|
if (usMovementMode == RUNNING || usMovementMode == WALKING)
|
||||||
{
|
{
|
||||||
ubReserveAP = APBPConstants[AP_CHANGE_FACING] + GetAPsCrouch(pSoldier, TRUE) +GetAPsProne(pSoldier, TRUE);
|
ubReserveAP = APBPConstants[AP_CHANGE_FACING] + GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE);
|
||||||
if (pSoldier->bActionPoints <= ubReserveAP)
|
|
||||||
{
|
|
||||||
ubReserveAP = APBPConstants[AP_CHANGE_FACING] + GetAPsCrouch(pSoldier, TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3129,8 +3279,7 @@ INT32 FindAdvanceSpot(SOLDIERTYPE *pSoldier, INT32 sTargetSpot, INT8 bAction, UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// avoid overcrowding
|
// avoid overcrowding
|
||||||
const auto nearbyFriends = CountNearbyFriends(pSoldier, sGridNo, TACTICAL_RANGE_VERYCLOSE);
|
if (!pSoldier->IsZombie() && NumberOfTeamMatesAdjacent(pSoldier, sGridNo) > 1)
|
||||||
if ( nearbyFriends > 1 && !pSoldier->IsZombie() )
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
+106
-102
@@ -432,7 +432,7 @@ INT8 RandomPointPatrolAI(SOLDIERTYPE *pSoldier)
|
|||||||
INT32 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT16 bReserveAPs, INT8 bAction, INT8 fFlags )
|
INT32 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT16 bReserveAPs, INT8 bAction, INT8 fFlags )
|
||||||
{
|
{
|
||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
STR16 tempstr;
|
STR16 tempstr;
|
||||||
#endif
|
#endif
|
||||||
INT32 sLoop,sAPCost;
|
INT32 sLoop,sAPCost;
|
||||||
INT32 sTempDest,sGoToGrid;
|
INT32 sTempDest,sGoToGrid;
|
||||||
@@ -588,152 +588,156 @@ INT32 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, IN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HAVE FOUND AN OK destination AND PLOTTED A VALID BEST PATH TO IT
|
// HAVE FOUND AN OK destination AND PLOTTED A VALID BEST PATH TO IT
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
AINumMessage("Chosen legal destination is gridno ",sDesGrid);
|
AINumMessage("Chosen legal destination is gridno ",sDesGrid);
|
||||||
AINumMessage("Tracing along path, pathRouteToGo = ",pSoldier->pathing.usPathIndex);
|
AINumMessage("Tracing along path, pathRouteToGo = ",pSoldier->pathing.usPathIndex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sGoToGrid = pSoldier->sGridNo; // start back where soldier is standing now
|
sGoToGrid = pSoldier->sGridNo; // start back where soldier is standing now
|
||||||
sAPCost = 0; // initialize path cost counter
|
sAPCost = 0; // initialize path cost counter
|
||||||
|
|
||||||
// 0verhaul: If the destination is within the patrol route, allow it. This is necessary to allow an errant soldier
|
// 0verhaul: If the destination is within the patrol route, allow it. This is necessary to allow an errant soldier
|
||||||
// to return to his patrol route if flanking or other actions have pulled him beyond his allowed range from origin.
|
// to return to his patrol route if flanking or other actions have pulled him beyond his allowed range from origin.
|
||||||
if (SpacesAway(sOrigin,sDesGrid) <= usMaxDist)
|
if (SpacesAway(sOrigin,sDesGrid) <= usMaxDist)
|
||||||
{
|
{
|
||||||
fAllowDest = TRUE;
|
fAllowDest = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we'll only go as far along the plotted route as is within our
|
// we'll only go as far along the plotted route as is within our
|
||||||
// permitted roaming range, and we'll stop as soon as we're down to <= 5 APs
|
// permitted roaming range, and we'll stop as soon as we're down to <= 5 APs
|
||||||
|
|
||||||
sTempDest = pSoldier->sGridNo;
|
sTempDest = pSoldier->sGridNo;
|
||||||
|
|
||||||
for (sLoop = 0; sLoop < (pSoldier->pathing.usPathDataSize - pSoldier->pathing.usPathIndex); sLoop++)
|
for (sLoop = 0; sLoop < (pSoldier->pathing.usPathDataSize - pSoldier->pathing.usPathIndex); sLoop++)
|
||||||
{
|
{
|
||||||
// what is the next gridno in the path?
|
// what is the next gridno in the path?
|
||||||
|
|
||||||
//sTempDest = NewGridNo( sGoToGrid,DirectionInc( (INT16) (pSoldier->pathing.usPathingData[sLoop] + 1) ) );
|
//sTempDest = NewGridNo( sGoToGrid,DirectionInc( (INT16) (pSoldier->pathing.usPathingData[sLoop] + 1) ) );
|
||||||
//sTempDest = NewGridNo( sGoToGrid,DirectionInc( (UINT8) (pSoldier->pathing.usPathingData[sLoop]) ) );
|
//sTempDest = NewGridNo( sGoToGrid,DirectionInc( (UINT8) (pSoldier->pathing.usPathingData[sLoop]) ) );
|
||||||
sTempDest = NewGridNo( sTempDest,DirectionInc( (UINT8) (pSoldier->pathing.usPathingData[sLoop]) ) );
|
sTempDest = NewGridNo( sTempDest,DirectionInc( (UINT8) (pSoldier->pathing.usPathingData[sLoop]) ) );
|
||||||
|
|
||||||
// this should NEVER be out of bounds
|
// this should NEVER be out of bounds
|
||||||
if (sTempDest == sGoToGrid)
|
if (sTempDest == sGoToGrid)
|
||||||
{
|
{
|
||||||
#ifdef BETAVERSION
|
#ifdef BETAVERSION
|
||||||
sprintf(tempstr,"GoAsFarAsPossibleTowards: ERROR - gridno along valid route is invalid! guynum %d, sTempDest = %d",pSoldier->ubID,sTempDest);
|
sprintf(tempstr,"GoAsFarAsPossibleTowards: ERROR - gridno along valid route is invalid! guynum %d, sTempDest = %d",pSoldier->ubID,sTempDest);
|
||||||
|
|
||||||
#ifdef RECORDNET
|
#ifdef RECORDNET
|
||||||
fprintf(NetDebugFile,"\n\t%s\n",tempstr);
|
fprintf(NetDebugFile,"\n\t%s\n",tempstr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PopMessage(tempstr);
|
PopMessage(tempstr);
|
||||||
SaveGame(ERROR_SAVE);
|
SaveGame(ERROR_SAVE);
|
||||||
#endif
|
#endif
|
||||||
break; // quit here, sGoToGrid is where we are going
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this takes us beyond our permitted "roaming range"
|
break; // quit here, sGoToGrid is where we are going
|
||||||
// but if it brings us closer, then allow it!
|
}
|
||||||
if (SpacesAway(sOrigin,sTempDest) > usMaxDist && !fAllowDest)
|
|
||||||
break; // quit here, sGoToGrid is where we are going
|
// if this takes us beyond our permitted "roaming range"
|
||||||
|
// but if it brings us closer, then allow it!
|
||||||
|
if (SpacesAway(sOrigin,sTempDest) > usMaxDist && !fAllowDest)
|
||||||
|
break; // quit here, sGoToGrid is where we are going
|
||||||
|
|
||||||
|
|
||||||
if ( usRoomRequired )
|
if ( usRoomRequired )
|
||||||
|
{
|
||||||
|
if ( !( InARoom( sTempDest, &usTempRoom ) && usTempRoom == usRoomRequired ) )
|
||||||
{
|
{
|
||||||
if ( !( InARoom( sTempDest, &usTempRoom ) && usTempRoom == usRoomRequired ) )
|
// quit here, limited by room!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (fFlags & FLAG_STOPSHORT) && SpacesAway( sDesGrid, sTempDest ) <= STOPSHORTDIST )
|
||||||
|
{
|
||||||
|
break; // quit here, sGoToGrid is where we are going
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAN'T CALL PathCost() HERE! IT CALLS findBestPath() and overwrites
|
||||||
|
// pathRouteToGo !!! Gotta calculate the cost ourselves - Ian
|
||||||
|
//
|
||||||
|
//ubAPsLeft = pSoldier->bActionPoints - PathCost(pSoldier,sTempDest,FALSE,FALSE,FALSE,FALSE,FALSE);
|
||||||
|
|
||||||
|
if (gfTurnBasedAI)
|
||||||
|
{
|
||||||
|
// if we're just starting the "costing" process (first gridno)
|
||||||
|
if (sLoop == 0)
|
||||||
{
|
{
|
||||||
// quit here, limited by room!
|
if (pSoldier->usUIMovementMode == RUNNING)
|
||||||
break;
|
{
|
||||||
|
sAPCost += GetAPsStartRun( pSoldier ); // changed by SANDRO
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( (fFlags & FLAG_STOPSHORT) && SpacesAway( sDesGrid, sTempDest ) <= STOPSHORTDIST )
|
|
||||||
{
|
|
||||||
break; // quit here, sGoToGrid is where we are going
|
|
||||||
}
|
|
||||||
|
|
||||||
// CAN'T CALL PathCost() HERE! IT CALLS findBestPath() and overwrites
|
|
||||||
// pathRouteToGo !!! Gotta calculate the cost ourselves - Ian
|
|
||||||
//
|
|
||||||
//ubAPsLeft = pSoldier->bActionPoints - PathCost(pSoldier,sTempDest,FALSE,FALSE,FALSE,FALSE,FALSE);
|
|
||||||
|
|
||||||
if (gfTurnBasedAI)
|
|
||||||
{
|
|
||||||
// if we're just starting the "costing" process (first gridno)
|
|
||||||
if (sLoop == 0)
|
|
||||||
{
|
|
||||||
if (pSoldier->usUIMovementMode == RUNNING)
|
|
||||||
{
|
|
||||||
sAPCost += GetAPsStartRun( pSoldier ); // changed by SANDRO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ATE: Direction here?
|
// ATE: Direction here?
|
||||||
sAPCost += EstimateActionPointCost( pSoldier, sTempDest, (INT8) pSoldier->pathing.usPathingData[sLoop], pSoldier->usUIMovementMode, (INT8) sLoop, (INT8) pSoldier->pathing.usPathDataSize );
|
sAPCost += EstimateActionPointCost( pSoldier, sTempDest, (INT8) pSoldier->pathing.usPathingData[sLoop], pSoldier->usUIMovementMode, (INT8) sLoop, (INT8) pSoldier->pathing.usPathDataSize );
|
||||||
bAPsLeft = pSoldier->bActionPoints - sAPCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this gridno is NOT a legal NPC destination
|
bAPsLeft = pSoldier->bActionPoints - sAPCost;
|
||||||
// DONT'T test path again - that would replace the traced path! - Ian
|
}
|
||||||
// NOTE: It's OK to go *THROUGH* water to try and get to the destination!
|
|
||||||
// sevenfm: jump over fence code - if current gridno is not legal destination, check next gridno
|
// if this gridno is NOT a legal NPC destination
|
||||||
if (!LegalNPCDestination(pSoldier,sTempDest,IGNORE_PATH,WATEROK,0))
|
// DONT'T test path again - that would replace the traced path! - Ian
|
||||||
|
// NOTE: It's OK to go *THROUGH* water to try and get to the destination!
|
||||||
|
// sevenfm: jump over fence code - if current gridno is not legal destination, check next gridno
|
||||||
|
if (!LegalNPCDestination(pSoldier,sTempDest,IGNORE_PATH,WATEROK,0))
|
||||||
|
{
|
||||||
|
// break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if after this, we have <= 5 APs remaining, that's far enough, break out
|
||||||
|
// (the idea is to preserve APs so we can crouch or react if
|
||||||
|
// necessary, and benefit from the carry-over next turn if not needed)
|
||||||
|
// This routine is NOT used by any GREEN AI, so such caution is warranted!
|
||||||
|
|
||||||
|
if ( gfTurnBasedAI && (bAPsLeft < bReserveAPs) )
|
||||||
|
break;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// break;
|
sGoToGrid = sTempDest; // we're OK up to here
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if after this, we have <= 5 APs remaining, that's far enough, break out
|
// if exactly 5 APs left, don't bother checking any further
|
||||||
// (the idea is to preserve APs so we can crouch or react if
|
if ( gfTurnBasedAI && (bAPsLeft == bReserveAPs) )
|
||||||
// necessary, and benefit from the carry-over next turn if not needed)
|
|
||||||
// This routine is NOT used by any GREEN AI, so such caution is warranted!
|
|
||||||
|
|
||||||
if ( gfTurnBasedAI && (bAPsLeft < bReserveAPs) )
|
|
||||||
break;
|
break;
|
||||||
else
|
|
||||||
{
|
|
||||||
sGoToGrid = sTempDest; // we're OK up to here
|
|
||||||
|
|
||||||
// if exactly 5 APs left, don't bother checking any further
|
|
||||||
if ( gfTurnBasedAI && (bAPsLeft == bReserveAPs) )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if it turned out we couldn't go even 1 tile towards the desired gridno
|
// if it turned out we couldn't go even 1 tile towards the desired gridno
|
||||||
if (sGoToGrid == pSoldier->sGridNo)
|
if (sGoToGrid == pSoldier->sGridNo)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
sprintf(tempstr,"%s will go NOWHERE, path doesn't meet criteria",pSoldier->name);
|
sprintf(tempstr,"%s will go NOWHERE, path doesn't meet criteria",pSoldier->name);
|
||||||
AIPopMessage(tempstr);
|
AIPopMessage(tempstr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pSoldier->pathing.usPathIndex = pSoldier->pathing.usPathDataSize = 0;
|
pSoldier->pathing.usPathIndex = pSoldier->pathing.usPathDataSize = 0;
|
||||||
return(NOWHERE); // then go nowhere
|
return(NOWHERE); // then go nowhere
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// possible optimization - stored path IS good if we're going all the way
|
||||||
|
if (sGoToGrid == sDesGrid)
|
||||||
{
|
{
|
||||||
// possible optimization - stored path IS good if we're going all the way
|
pSoldier->pathing.bPathStored = TRUE;
|
||||||
if (sGoToGrid == sDesGrid)
|
pSoldier->pathing.sFinalDestination = sGoToGrid;
|
||||||
{
|
}
|
||||||
pSoldier->pathing.bPathStored = TRUE;
|
else if ( pSoldier->pathing.usPathIndex == 0 )
|
||||||
pSoldier->pathing.sFinalDestination = sGoToGrid;
|
{
|
||||||
}
|
// we can hack this surely! -- CJC
|
||||||
else if ( pSoldier->pathing.usPathIndex == 0 )
|
pSoldier->pathing.bPathStored = TRUE;
|
||||||
{
|
pSoldier->pathing.sFinalDestination = sGoToGrid;
|
||||||
// we can hack this surely! -- CJC
|
pSoldier->pathing.usPathDataSize = sLoop + 1;
|
||||||
pSoldier->pathing.bPathStored = TRUE;
|
}
|
||||||
pSoldier->pathing.sFinalDestination = sGoToGrid;
|
|
||||||
pSoldier->pathing.usPathDataSize = sLoop + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"%d to %d with %d APs left", pSoldier->ubID, sGoToGrid, pSoldier->bActionPoints );
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"%d to %d with %d APs left", pSoldier->ubID, sGoToGrid, pSoldier->bActionPoints );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
return( sGoToGrid );
|
return( sGoToGrid );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,6 @@
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
//SB: unify structure for all versions
|
//SB: unify structure for all versions
|
||||||
// #if defined( CRIPPLED_VERSION ) || defined( RUSSIAN )
|
|
||||||
// UINT8 ubIdentifier[4];
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
UINT16 fFlags;
|
UINT16 fFlags;
|
||||||
|
|
||||||
@@ -74,9 +71,7 @@ typedef struct
|
|||||||
INT16 sActionData; // special action value
|
INT16 sActionData; // special action value
|
||||||
|
|
||||||
//SB: unify structure for all versions
|
//SB: unify structure for all versions
|
||||||
//#if !defined( CRIPPLED_VERSION ) && !defined( RUSSIAN )
|
|
||||||
UINT8 ubUnused[4];
|
UINT8 ubUnused[4];
|
||||||
//#endif
|
|
||||||
|
|
||||||
} _old_NPCQuoteInfo; // 32 bytes
|
} _old_NPCQuoteInfo; // 32 bytes
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ void PossiblyMakeThisEnemyChosenOne( SOLDIERTYPE * pSoldier )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ActionType PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove)
|
INT8 PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove)
|
||||||
{
|
{
|
||||||
BOOLEAN fFoundRoute = FALSE;
|
BOOLEAN fFoundRoute = FALSE;
|
||||||
INT8 bSlot;
|
INT8 bSlot;
|
||||||
@@ -307,7 +307,7 @@ ActionType PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove)
|
|||||||
if (bPanicTrigger == -1)
|
if (bPanicTrigger == -1)
|
||||||
{
|
{
|
||||||
// augh!
|
// augh!
|
||||||
return( AI_ACTION_INVALID );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
sPanicTriggerGridNo = gTacticalStatus.sPanicTriggerGridNo[ bPanicTrigger ];
|
sPanicTriggerGridNo = gTacticalStatus.sPanicTriggerGridNo[ bPanicTrigger ];
|
||||||
@@ -430,7 +430,7 @@ ActionType PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no action decided
|
// no action decided
|
||||||
return(AI_ACTION_INVALID);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitPanicSystem( void )
|
void InitPanicSystem( void )
|
||||||
@@ -534,7 +534,7 @@ BOOLEAN NeedToRadioAboutPanicTrigger( void )
|
|||||||
#define STAIRCASE_GRIDNO 12067
|
#define STAIRCASE_GRIDNO 12067
|
||||||
#define STAIRCASE_DIRECTION 0
|
#define STAIRCASE_DIRECTION 0
|
||||||
|
|
||||||
ActionType HeadForTheStairCase( SOLDIERTYPE * pSoldier )
|
INT8 HeadForTheStairCase( SOLDIERTYPE * pSoldier )
|
||||||
{
|
{
|
||||||
UNDERGROUND_SECTORINFO * pBasementInfo;
|
UNDERGROUND_SECTORINFO * pBasementInfo;
|
||||||
|
|
||||||
|
|||||||
@@ -1,372 +0,0 @@
|
|||||||
#include "UtilityAI.h"
|
|
||||||
#include "UtilityAI_ResponseCurve.h"
|
|
||||||
#include "Overhead Types.h"
|
|
||||||
#include "Soldier Control.h"
|
|
||||||
#include "Isometric Utils.h"
|
|
||||||
#include "soldier profile type.h"
|
|
||||||
#include "AIInternals.h"
|
|
||||||
#include "Render Fun.h"
|
|
||||||
|
|
||||||
namespace UtilityAI
|
|
||||||
{
|
|
||||||
|
|
||||||
typedef enum DecisionInput
|
|
||||||
{
|
|
||||||
MyHealth,
|
|
||||||
MyStamina,
|
|
||||||
MyStance,
|
|
||||||
MyMorale,
|
|
||||||
MyCurrentWeaponRange,
|
|
||||||
DistanceFromMe,
|
|
||||||
HealthOfTarget,
|
|
||||||
AllyCount,
|
|
||||||
EnemyCount,
|
|
||||||
AllyEnemyRatio,
|
|
||||||
EnemiesNearTarget,
|
|
||||||
AlliesNearTarget,
|
|
||||||
HaveGasmaskInInventory,
|
|
||||||
HaveNVGInInventory,
|
|
||||||
HasKnife,
|
|
||||||
HasThrowingKnife,
|
|
||||||
HasSmokeGrenade,
|
|
||||||
IamInSmoke,
|
|
||||||
IamInTearGas,
|
|
||||||
IamInMustardGas, // Also fire & creature gas
|
|
||||||
NearSmoke,
|
|
||||||
NearTearGas,
|
|
||||||
NearMustardGas,
|
|
||||||
InShock,
|
|
||||||
InsideRoom,
|
|
||||||
NightTime,
|
|
||||||
InLightAtNight,
|
|
||||||
TakenLargeHit,
|
|
||||||
HasTrait_AutoWeapons,
|
|
||||||
HasTrait_HeavyWeapons,
|
|
||||||
HasTrait_Sniper,
|
|
||||||
HasTrait_Ranger,
|
|
||||||
HasTrait_Gunslinger,
|
|
||||||
HasTrait_MartialArts,
|
|
||||||
HasTrait_SquadLeader,
|
|
||||||
HasTrait_Technician,
|
|
||||||
HasTrait_Doctor,
|
|
||||||
HasTrait_Ambidextrous,
|
|
||||||
HasTrait_Melee,
|
|
||||||
HasTrait_Throwing,
|
|
||||||
HasTrait_NightOps,
|
|
||||||
HasTrait_Stealthy,
|
|
||||||
HasTrait_Athletics,
|
|
||||||
HasTrait_Bodybuilding,
|
|
||||||
HasTrait_Demolitions,
|
|
||||||
HasTrait_Teaching,
|
|
||||||
HasTrait_Scouting,
|
|
||||||
HasTrait_Covert,
|
|
||||||
HasTrait_RadioOperator,
|
|
||||||
HasTrait_Snitch,
|
|
||||||
HasTrait_Survival,
|
|
||||||
HasTraitOld_Lockpicking,
|
|
||||||
HasTraitOld_HandToHand,
|
|
||||||
HasTraitOld_Electronics,
|
|
||||||
HasTraitOld_NightOps,
|
|
||||||
HasTraitOld_Throwing,
|
|
||||||
HasTraitOld_Teaching,
|
|
||||||
HasTraitOld_HeavyWeapons,
|
|
||||||
HasTraitOld_AutoWeapons,
|
|
||||||
HasTraitOld_Stealthy,
|
|
||||||
HasTraitOld_Ambidextrous,
|
|
||||||
HasTraitOld_Thief,
|
|
||||||
HasTraitOld_MartialArts,
|
|
||||||
HasTraitOld_Knifing,
|
|
||||||
HasTraitOld_Sniper,
|
|
||||||
HasTraitOld_Camouflaged,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Consideration
|
|
||||||
{
|
|
||||||
DecisionInput input;
|
|
||||||
ResponseCurve curve;
|
|
||||||
SoldierID target;
|
|
||||||
INT32 targetLocation;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DecisionScoreEvaluator
|
|
||||||
{
|
|
||||||
ActionType Action;
|
|
||||||
float priorityWeight;
|
|
||||||
std::string description;
|
|
||||||
std::vector<Consideration> considerations;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DecisionScore
|
|
||||||
{
|
|
||||||
float score;
|
|
||||||
size_t idx; // Index into DM::decisions
|
|
||||||
|
|
||||||
bool operator<(const DecisionScore& a) const
|
|
||||||
{
|
|
||||||
return score < a.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const DecisionScore& a) const
|
|
||||||
{
|
|
||||||
return score > a.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const DecisionScore& a) const
|
|
||||||
{
|
|
||||||
return score == a.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DecisionMaker
|
|
||||||
{
|
|
||||||
std::vector<DecisionScoreEvaluator> decisions;
|
|
||||||
std::vector<DecisionScore> scores;
|
|
||||||
};
|
|
||||||
|
|
||||||
static float GetTrait(DecisionInput input, SOLDIERTYPE* soldier)
|
|
||||||
{
|
|
||||||
switch ( input )
|
|
||||||
{
|
|
||||||
case HasTrait_AutoWeapons:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, AUTO_WEAPONS_NT));
|
|
||||||
case HasTrait_HeavyWeapons:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, HEAVY_WEAPONS_NT));
|
|
||||||
case HasTrait_Sniper:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, SNIPER_NT));
|
|
||||||
case HasTrait_Ranger:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, RANGER_NT));
|
|
||||||
case HasTrait_Gunslinger:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, GUNSLINGER_NT));
|
|
||||||
case HasTrait_MartialArts:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, MARTIAL_ARTS_NT));
|
|
||||||
case HasTrait_SquadLeader:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, SQUADLEADER_NT));
|
|
||||||
case HasTrait_Technician:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, TECHNICIAN_NT));
|
|
||||||
case HasTrait_Doctor:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, DOCTOR_NT));
|
|
||||||
case HasTrait_Ambidextrous:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, AMBIDEXTROUS_NT));
|
|
||||||
case HasTrait_Melee:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, MELEE_NT));
|
|
||||||
case HasTrait_Throwing:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, THROWING_NT));
|
|
||||||
case HasTrait_NightOps:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, NIGHT_OPS_NT));
|
|
||||||
case HasTrait_Stealthy:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, STEALTHY_NT));
|
|
||||||
case HasTrait_Athletics:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, ATHLETICS_NT));
|
|
||||||
case HasTrait_Bodybuilding:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, BODYBUILDING_NT));
|
|
||||||
case HasTrait_Demolitions:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, DEMOLITIONS_NT));
|
|
||||||
case HasTrait_Teaching:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, TEACHING_NT));
|
|
||||||
case HasTrait_Scouting:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, SCOUTING_NT));
|
|
||||||
case HasTrait_Covert:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, COVERT_NT));
|
|
||||||
case HasTrait_RadioOperator:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, RADIO_OPERATOR_NT));
|
|
||||||
case HasTrait_Snitch:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, SNITCH_NT));
|
|
||||||
case HasTrait_Survival:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, SURVIVAL_NT));
|
|
||||||
case HasTraitOld_Lockpicking:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, LOCKPICKING_OT));
|
|
||||||
case HasTraitOld_HandToHand:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, HANDTOHAND_OT));
|
|
||||||
case HasTraitOld_Electronics:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, ELECTRONICS_OT));
|
|
||||||
case HasTraitOld_NightOps:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, NIGHTOPS_OT));
|
|
||||||
case HasTraitOld_Throwing:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, THROWING_OT));
|
|
||||||
case HasTraitOld_Teaching:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, TEACHING_OT));
|
|
||||||
case HasTraitOld_HeavyWeapons:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, HEAVY_WEAPS_OT));
|
|
||||||
case HasTraitOld_AutoWeapons:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, AUTO_WEAPS_OT));
|
|
||||||
case HasTraitOld_Stealthy:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, STEALTHY_OT));
|
|
||||||
case HasTraitOld_Ambidextrous:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, AMBIDEXT_OT));
|
|
||||||
case HasTraitOld_Thief:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, THIEF_OT));
|
|
||||||
case HasTraitOld_MartialArts:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, MARTIALARTS_OT));
|
|
||||||
case HasTraitOld_Knifing:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, KNIFING_OT));
|
|
||||||
case HasTraitOld_Sniper:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, PROF_SNIPER_OT));
|
|
||||||
case HasTraitOld_Camouflaged:
|
|
||||||
return static_cast<float>(HAS_SKILL_TRAIT(soldier, CAMOUFLAGED_OT));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetInputValue(DecisionInput input, SOLDIERTYPE* me, SoldierID target, INT32 targetLocation)
|
|
||||||
{
|
|
||||||
switch ( input )
|
|
||||||
{
|
|
||||||
case MyHealth:
|
|
||||||
{
|
|
||||||
const auto health = static_cast<float>(me->stats.bLife);
|
|
||||||
const auto min = 0.0f;
|
|
||||||
const auto max = static_cast<float>(me->stats.bLifeMax);
|
|
||||||
return NormalizeInput(health, min, max);
|
|
||||||
}
|
|
||||||
case MyMorale:
|
|
||||||
{
|
|
||||||
const auto morale = static_cast<float>(me->aiData.bAIMorale);
|
|
||||||
const auto min = 0.0f;
|
|
||||||
const auto max = static_cast<float>(MORALE_FEARLESS);
|
|
||||||
return NormalizeInput(morale, min, max);
|
|
||||||
}
|
|
||||||
case HaveGasmaskInInventory:
|
|
||||||
{
|
|
||||||
const auto gasmaskInvSlot = FindGasMask(me);
|
|
||||||
if ( gasmaskInvSlot != NO_SLOT ) { return 1.0f; }
|
|
||||||
else { return 0.0f; }
|
|
||||||
}
|
|
||||||
case HasKnife:
|
|
||||||
{
|
|
||||||
const auto bWeaponIn = FindAIUsableObjClass(me, (IC_BLADE));
|
|
||||||
if ( bWeaponIn != NO_SLOT ) { return 1.0f; }
|
|
||||||
else { return 0.0f; }
|
|
||||||
}
|
|
||||||
case HasThrowingKnife:
|
|
||||||
{
|
|
||||||
const auto bWeaponIn = FindAIUsableObjClass(me, (IC_THROWING_KNIFE));
|
|
||||||
if ( bWeaponIn != NO_SLOT ) { return 1.0f; }
|
|
||||||
else { return 0.0f; }
|
|
||||||
}
|
|
||||||
case HasSmokeGrenade:
|
|
||||||
{
|
|
||||||
const auto bGrenadeIn = FindThrowableGrenade(me, EXPLOSV_SMOKE);
|
|
||||||
if ( bGrenadeIn != NO_SLOT ) { return 1.0f; }
|
|
||||||
else { return 0.0f; }
|
|
||||||
}
|
|
||||||
case DistanceFromMe:
|
|
||||||
{
|
|
||||||
const auto distance = PythSpacesAway(me->sGridNo, targetLocation);
|
|
||||||
}
|
|
||||||
case IamInSmoke:
|
|
||||||
return static_cast<float>(InSmoke(me, me->sGridNo));
|
|
||||||
case IamInTearGas:
|
|
||||||
return static_cast<float>(InTearGas(me, me->sGridNo));
|
|
||||||
case IamInMustardGas:
|
|
||||||
return static_cast<float>(InMustardGas(me, me->sGridNo));
|
|
||||||
case NearSmoke:
|
|
||||||
|
|
||||||
case NearTearGas:
|
|
||||||
|
|
||||||
case NearMustardGas:
|
|
||||||
|
|
||||||
case InShock:
|
|
||||||
|
|
||||||
case InsideRoom:
|
|
||||||
return static_cast<float>(InARoom(me->sGridNo, NULL));
|
|
||||||
case NightTime:
|
|
||||||
|
|
||||||
case InLightAtNight:
|
|
||||||
|
|
||||||
case TakenLargeHit:
|
|
||||||
return static_cast<float>(me->TakenLargeHit());
|
|
||||||
|
|
||||||
case HasTrait_AutoWeapons:
|
|
||||||
case HasTrait_HeavyWeapons:
|
|
||||||
case HasTrait_Sniper:
|
|
||||||
case HasTrait_Ranger:
|
|
||||||
case HasTrait_Gunslinger:
|
|
||||||
case HasTrait_MartialArts:
|
|
||||||
case HasTrait_SquadLeader:
|
|
||||||
case HasTrait_Technician:
|
|
||||||
case HasTrait_Doctor:
|
|
||||||
case HasTrait_Ambidextrous:
|
|
||||||
case HasTrait_Melee:
|
|
||||||
case HasTrait_Throwing:
|
|
||||||
case HasTrait_NightOps:
|
|
||||||
case HasTrait_Stealthy:
|
|
||||||
case HasTrait_Athletics:
|
|
||||||
case HasTrait_Bodybuilding:
|
|
||||||
case HasTrait_Demolitions:
|
|
||||||
case HasTrait_Teaching:
|
|
||||||
case HasTrait_Scouting:
|
|
||||||
case HasTrait_Covert:
|
|
||||||
case HasTrait_RadioOperator:
|
|
||||||
case HasTrait_Snitch:
|
|
||||||
case HasTrait_Survival:
|
|
||||||
case HasTraitOld_Lockpicking:
|
|
||||||
case HasTraitOld_HandToHand:
|
|
||||||
case HasTraitOld_Electronics:
|
|
||||||
case HasTraitOld_NightOps:
|
|
||||||
case HasTraitOld_Throwing:
|
|
||||||
case HasTraitOld_Teaching:
|
|
||||||
case HasTraitOld_HeavyWeapons:
|
|
||||||
case HasTraitOld_AutoWeapons:
|
|
||||||
case HasTraitOld_Stealthy:
|
|
||||||
case HasTraitOld_Ambidextrous:
|
|
||||||
case HasTraitOld_Thief:
|
|
||||||
case HasTraitOld_MartialArts:
|
|
||||||
case HasTraitOld_Knifing:
|
|
||||||
case HasTraitOld_Sniper:
|
|
||||||
case HasTraitOld_Camouflaged:
|
|
||||||
return GetTrait(input, me);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float ScoreDSE(DecisionScoreEvaluator DSE, SOLDIERTYPE* me)
|
|
||||||
{
|
|
||||||
float finalScore = 1.0f;
|
|
||||||
|
|
||||||
for ( const auto& consideration : DSE.considerations )
|
|
||||||
{
|
|
||||||
if ( finalScore <= 0.0f ) { break; }
|
|
||||||
|
|
||||||
float curveInput = GetInputValue(consideration.input, me, consideration.target, consideration.targetLocation);
|
|
||||||
float considerationScore = CalculateResponse(curveInput, consideration.curve);
|
|
||||||
|
|
||||||
finalScore *= considerationScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add consideration compensation
|
|
||||||
const auto modificationFactor = 1 - 1 / (DSE.considerations.size());
|
|
||||||
const auto makeUpValue = (1 - finalScore) * modificationFactor;
|
|
||||||
finalScore += finalScore * makeUpValue;
|
|
||||||
|
|
||||||
// Add DSE priority weight
|
|
||||||
finalScore *= DSE.priorityWeight;
|
|
||||||
|
|
||||||
return finalScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScoreAllDecisions(DecisionMaker DM, SOLDIERTYPE* me)
|
|
||||||
{
|
|
||||||
size_t idx = 0;
|
|
||||||
for ( const auto& decision : DM.decisions )
|
|
||||||
{
|
|
||||||
DM.scores[idx].score = ScoreDSE(decision, me);
|
|
||||||
DM.scores[idx].idx = idx;
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort all scores from best to last
|
|
||||||
std::sort(DM.scores.begin(), DM.scores.end(), std::greater<DecisionScore>());
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionType SelectScoredAction(DecisionMaker DM)
|
|
||||||
{
|
|
||||||
// Select highest for now. TODO weighted random choice
|
|
||||||
const auto idx = DM.scores[0].idx;
|
|
||||||
const auto action = DM.decisions[idx].Action;
|
|
||||||
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
//void ScoreAllDecisions(DecisionMaker DM, SOLDIERTYPE* me);
|
|
||||||
//ActionType SelectScoredAction(DecisionMaker DM);
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#include "UtilityAI_ResponseCurve.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace UtilityAI
|
|
||||||
{
|
|
||||||
|
|
||||||
float NormalizeInput(float value, float min, float max)
|
|
||||||
{
|
|
||||||
const float normalizedValue = (value - min) / (max - min);
|
|
||||||
return normalizedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CalculateResponse(float x, ResponseCurve curve)
|
|
||||||
{
|
|
||||||
const auto min = curve.min;
|
|
||||||
const auto max = curve.max;
|
|
||||||
const auto type = curve.type;
|
|
||||||
const auto m = curve.m;
|
|
||||||
const auto k = curve.k;
|
|
||||||
const auto b = curve.b;
|
|
||||||
const auto c = curve.c;
|
|
||||||
|
|
||||||
float input = std::clamp(x, min, max);
|
|
||||||
input = NormalizeInput(input, min, max);
|
|
||||||
|
|
||||||
float y = 0.0f;
|
|
||||||
// Polynomial
|
|
||||||
float n;
|
|
||||||
// Logistic
|
|
||||||
const float e = 2.71828f; // Euler's number. I think? Lecture slides did not explain if this is what it's supposed to be.
|
|
||||||
const float exponent = -input + c;
|
|
||||||
const float denominator = 1.0f + 1000.0f * e * pow(m, exponent);
|
|
||||||
|
|
||||||
switch ( type )
|
|
||||||
{
|
|
||||||
case Step:
|
|
||||||
if ( input != 0.0f ) { return 1.0f; }
|
|
||||||
else { return 0.0f; }
|
|
||||||
case Linear:
|
|
||||||
case Polynomial:
|
|
||||||
n = input - c;
|
|
||||||
y = m * pow(n, k) + b;
|
|
||||||
break;
|
|
||||||
case Logistic:
|
|
||||||
y = (k / denominator) + b;
|
|
||||||
break;
|
|
||||||
//case Logit: // Not implemented yet
|
|
||||||
//break;
|
|
||||||
}
|
|
||||||
|
|
||||||
y = std::clamp(y, 0.0f, 1.0f);
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
Step,
|
|
||||||
Linear,
|
|
||||||
Polynomial,
|
|
||||||
Logistic,
|
|
||||||
Logit
|
|
||||||
} ResponseCurveType;
|
|
||||||
|
|
||||||
struct ResponseCurve
|
|
||||||
{
|
|
||||||
ResponseCurveType type;
|
|
||||||
float m;
|
|
||||||
float k;
|
|
||||||
float b;
|
|
||||||
float c;
|
|
||||||
float min;
|
|
||||||
float max;
|
|
||||||
};
|
|
||||||
|
|
||||||
float NormalizeInput(float value, float min, float max);
|
|
||||||
float CalculateResponse(float x, ResponseCurve curve);
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "Text.h"
|
#include "Text.h"
|
||||||
|
|
||||||
extern BOOLEAN gfHiddenInterrupt;
|
extern BOOLEAN gfHiddenInterrupt;
|
||||||
extern void LogDecideInfo(SOLDIERTYPE *pSoldier, bool doLog = true);
|
extern void LogDecideInfo(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
extern STR8 gStr8AlertStatus[];
|
extern STR8 gStr8AlertStatus[];
|
||||||
extern STR8 gStr8Attitude[];
|
extern STR8 gStr8Attitude[];
|
||||||
|
|||||||
+13
-40
@@ -12,6 +12,10 @@
|
|||||||
extern INT16 gubAIPathCosts[19][19];
|
extern INT16 gubAIPathCosts[19][19];
|
||||||
#define AI_PATHCOST_RADIUS 9
|
#define AI_PATHCOST_RADIUS 9
|
||||||
|
|
||||||
|
extern BOOLEAN gfDisplayCoverValues;
|
||||||
|
//extern INT16 gsCoverValue[WORLD_MAX];
|
||||||
|
extern INT16 * gsCoverValue;
|
||||||
|
|
||||||
// AI actions
|
// AI actions
|
||||||
|
|
||||||
enum CreatureCalls
|
enum CreatureCalls
|
||||||
@@ -106,10 +110,7 @@ typedef enum
|
|||||||
AI_ACTION_DOCTOR_SELF, // added by Flugente: AI-ONLY! bandage/surgery on self. DO NOT USE THIS FOR MERCS!!!
|
AI_ACTION_DOCTOR_SELF, // added by Flugente: AI-ONLY! bandage/surgery on self. DO NOT USE THIS FOR MERCS!!!
|
||||||
AI_ACTION_SELFDETONATE, // added by Flugente: blow up an explosive in own inventory
|
AI_ACTION_SELFDETONATE, // added by Flugente: blow up an explosive in own inventory
|
||||||
AI_ACTION_STOP_MEDIC, // sevenfm: stop giving aid animation
|
AI_ACTION_STOP_MEDIC, // sevenfm: stop giving aid animation
|
||||||
AI_ACTION_DRINK_CANTEEN, // sevenfm: drink from canteen in inventory
|
AI_ACTION_LAST = AI_ACTION_STOP_MEDIC
|
||||||
AI_ACTION_HANDLE_ITEM, // sevenfm: use item in hand
|
|
||||||
AI_ACTION_PLANT_BOMB, // sevenfm: plant bomb using item in hand
|
|
||||||
AI_ACTION_INVALID
|
|
||||||
} ActionType;
|
} ActionType;
|
||||||
|
|
||||||
|
|
||||||
@@ -174,36 +175,21 @@ void CheckForChangingOrders(SOLDIERTYPE *pSoldier );
|
|||||||
|
|
||||||
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
||||||
|
|
||||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, SoldierID *pubOpponentID = NULL, INT32 * distanceInCellCoords = NULL);
|
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel, SoldierID *pubOpponentID = NULL);
|
||||||
INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance );
|
INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance );
|
||||||
INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance ); // Flugente: like ClosestPC(...), but does not account for covert or not visible mercs
|
INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance ); // Flugente: like ClosestPC(...), but does not account for covert or not visible mercs
|
||||||
BOOLEAN CanAutoBandage( BOOLEAN fDoFullCheck );
|
BOOLEAN CanAutoBandage( BOOLEAN fDoFullCheck );
|
||||||
|
|
||||||
void DebugAI( STR szOutput );
|
void DebugAI( STR szOutput );
|
||||||
enum { AI_MSG_START, AI_MSG_DECIDE, AI_MSG_INFO, AI_MSG_TOPIC };
|
enum { AI_MSG_START, AI_MSG_DECIDE, AI_MSG_INFO, AI_MSG_TOPIC };
|
||||||
void DebugAI(INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, bool doLog = true, INT8 bAction = -1);
|
void DebugAI(INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, INT8 bAction = -1);
|
||||||
void DebugQuestInfo(STR szOutput);
|
void DebugQuestInfo(STR szOutput);
|
||||||
INT8 DecideAction(SOLDIERTYPE *pSoldier);
|
INT8 DecideAction(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier);
|
|
||||||
INT8 DecideActionYellow(SOLDIERTYPE *pSoldier);
|
|
||||||
INT8 DecideActionRed(SOLDIERTYPE *pSoldier);
|
|
||||||
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier);
|
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionGreenBoxer(SOLDIERTYPE* pSoldier);
|
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionBlackBoxer(SOLDIERTYPE* pSoldier);
|
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionGreenCivilian(SOLDIERTYPE* pSoldier);
|
INT8 DecideActionRed(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionYellowCivilian(SOLDIERTYPE* pSoldier);
|
INT8 DecideActionYellow(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionRedCivilian(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionBlackCivilian(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionGreenSoldier(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionYellowSoldier(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionRedSoldier(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionBlackSoldier(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionGreenRobot(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionYellowRobot(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionRedRobot(SOLDIERTYPE* pSoldier);
|
|
||||||
INT8 DecideActionBlackRobot(SOLDIERTYPE* pSoldier);
|
|
||||||
|
|
||||||
INT8 DecideActionBlackSoldierUtilityAI(SOLDIERTYPE* pSoldier);
|
|
||||||
|
|
||||||
INT16 DistanceToClosestFriend( SOLDIERTYPE * pSoldier );
|
INT16 DistanceToClosestFriend( SOLDIERTYPE * pSoldier );
|
||||||
|
|
||||||
@@ -213,12 +199,11 @@ void EndAIGuysTurn( SOLDIERTYPE *pSoldier );
|
|||||||
INT8 ExecuteAction(SOLDIERTYPE *pSoldier);
|
INT8 ExecuteAction(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
INT32 FindAdjacentSpotBeside(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
INT32 FindAdjacentSpotBeside(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||||
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *pPercentBetter, INT32 targetGridNo = NOWHERE, bool ignoreSearchRange = false);
|
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *pPercentBetter);
|
||||||
INT32 FindClosestDoor( SOLDIERTYPE * pSoldier );
|
INT32 FindClosestDoor( SOLDIERTYPE * pSoldier );
|
||||||
INT32 FindNearbyPointOnEdgeOfMap( SOLDIERTYPE * pSoldier, INT8 * pbDirection );
|
INT32 FindNearbyPointOnEdgeOfMap( SOLDIERTYPE * pSoldier, INT8 * pbDirection );
|
||||||
INT32 FindNearestEdgePoint( INT32 sGridNo );
|
INT32 FindNearestEdgePoint( INT32 sGridNo );
|
||||||
INT32 FindNearestPassableSpot( INT32 sGridNo, UINT8 usSearchRadius = 5 );
|
INT32 FindNearestPassableSpot( INT32 sGridNo, UINT8 usSearchRadius = 5 );
|
||||||
BOOLEAN FindFenceAroundSpot(INT32 sSpot);
|
|
||||||
|
|
||||||
//Kris: Added these as I need specific searches on certain sides.
|
//Kris: Added these as I need specific searches on certain sides.
|
||||||
enum
|
enum
|
||||||
@@ -259,7 +244,7 @@ void ManChecksOnFriends(SOLDIERTYPE *pSoldier);
|
|||||||
void NewDest(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
void NewDest(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||||
INT32 NextPatrolPoint(SOLDIERTYPE *pSoldier);
|
INT32 NextPatrolPoint(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
ActionType PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove);
|
INT8 PanicAI(SOLDIERTYPE *pSoldier, UINT8 ubCanMove);
|
||||||
void HaltMoveForSoldierOutOfPoints(SOLDIERTYPE *pSoldier);
|
void HaltMoveForSoldierOutOfPoints(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
INT32 RandDestWithinRange(SOLDIERTYPE *pSoldier);
|
INT32 RandDestWithinRange(SOLDIERTYPE *pSoldier);
|
||||||
@@ -303,7 +288,6 @@ SoldierID GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8
|
|||||||
// sevenfm:
|
// sevenfm:
|
||||||
BOOLEAN NightLight(void);
|
BOOLEAN NightLight(void);
|
||||||
BOOLEAN DuskLight(void);
|
BOOLEAN DuskLight(void);
|
||||||
BOOLEAN FindClosestVisibleSmoke(SOLDIERTYPE* pSoldier, INT32& sSpot, INT8& bLevel, BOOLEAN fOnlyGas);
|
|
||||||
BOOLEAN InSmokeNearby(INT32 sGridNo, INT8 bLevel);
|
BOOLEAN InSmokeNearby(INT32 sGridNo, INT8 bLevel);
|
||||||
INT16 MaxNormalVisionDistance( void );
|
INT16 MaxNormalVisionDistance( void );
|
||||||
UINT8 MinFlankDirections( SOLDIERTYPE *pSoldier );
|
UINT8 MinFlankDirections( SOLDIERTYPE *pSoldier );
|
||||||
@@ -316,13 +300,6 @@ UINT8 CountFriendsBlack( SOLDIERTYPE *pSoldier, INT32 sClosestOpponent = NOWHERE
|
|||||||
UINT16 CountTeamUnderAttack(INT8 bTeam, INT32 sGridNo, INT16 sDistance);
|
UINT16 CountTeamUnderAttack(INT8 bTeam, INT32 sGridNo, INT16 sDistance);
|
||||||
UINT16 CountPublicKnownEnemies(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 sDistance);
|
UINT16 CountPublicKnownEnemies(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 sDistance);
|
||||||
UINT16 CountPublicKnownEnemies(SOLDIERTYPE *pSoldier);
|
UINT16 CountPublicKnownEnemies(SOLDIERTYPE *pSoldier);
|
||||||
UINT8 CountKnownEnemies(SOLDIERTYPE* pSoldier, INT32 sSpot, INT16 sDistance, INT8 bLevel = HEARD_THIS_TURN);
|
|
||||||
UINT8 CountKnownEnemiesInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoom);
|
|
||||||
UINT8 CountFriendsInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoom);
|
|
||||||
INT32 CountCorpsesInRoom(SOLDIERTYPE* pSoldier, UINT16 usRoomNo, INT8 bLevel);
|
|
||||||
UINT16 RoomNo(INT32 sSpot);
|
|
||||||
BOOLEAN SameRoom(INT32 sSpot1, INT32 sSpot2);
|
|
||||||
BOOLEAN CheckWindow(INT32 sSpot, UINT8 ubDirection, BOOLEAN fAllowClosed);
|
|
||||||
|
|
||||||
UINT8 SectorCurfew(BOOLEAN fNight);
|
UINT8 SectorCurfew(BOOLEAN fNight);
|
||||||
UINT8 TeamPercentKilled(INT8 bTeam);
|
UINT8 TeamPercentKilled(INT8 bTeam);
|
||||||
@@ -443,10 +420,6 @@ INT8 KnownPublicLevel(UINT8 bTeam, SoldierID ubOpponentID);
|
|||||||
|
|
||||||
// sevenfm: distance for tactical AI checks, roughly equal to normal day vision range
|
// sevenfm: distance for tactical AI checks, roughly equal to normal day vision range
|
||||||
#define TACTICAL_RANGE (gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO * 2)
|
#define TACTICAL_RANGE (gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO * 2)
|
||||||
#define TACTICAL_RANGE_CELL_COORDS TACTICAL_RANGE*CELL_X_SIZE
|
|
||||||
#define BOMB_DETECTION_RANGE (TACTICAL_RANGE / 4)
|
#define BOMB_DETECTION_RANGE (TACTICAL_RANGE / 4)
|
||||||
#define TACTICAL_RANGE_HALF (TACTICAL_RANGE / 2)
|
|
||||||
#define TACTICAL_RANGE_CLOSE (TACTICAL_RANGE / 4)
|
|
||||||
#define TACTICAL_RANGE_VERYCLOSE (TACTICAL_RANGE / 6)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ UINT32 guiFireAmbientLastUpdate = 0;
|
|||||||
|
|
||||||
extern STR8 pVertStrings[];
|
extern STR8 pVertStrings[];
|
||||||
extern STR8 pHortStrings[];
|
extern STR8 pHortStrings[];
|
||||||
extern CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT];
|
extern CHAR16 (*pTownNames)[MAX_TOWN_NAME_LENGHT];
|
||||||
|
|
||||||
UINT8 gubCurrentSteadyStateAmbience = SSA_NONE;
|
UINT8 gubCurrentSteadyStateAmbience = SSA_NONE;
|
||||||
UINT8 gubCurrentSteadyStateSound = 0;
|
UINT8 gubCurrentSteadyStateSound = 0;
|
||||||
|
|||||||
@@ -1319,7 +1319,7 @@ BOOLEAN FindFenceJumpDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStar
|
|||||||
return( FALSE );
|
return( FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
//Simply chooses a random gridno within valid boundaries (for dropping things in unloaded sectors)
|
//Simply chooses a random gridno within valid boundaries (for dropping things in loaded sectors)
|
||||||
INT32 RandomGridNo()
|
INT32 RandomGridNo()
|
||||||
{
|
{
|
||||||
INT32 iMapXPos, iMapYPos, iMapIndex;
|
INT32 iMapXPos, iMapYPos, iMapIndex;
|
||||||
@@ -1332,6 +1332,69 @@ INT32 RandomGridNo()
|
|||||||
return iMapIndex;
|
return iMapIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool pointLeftOfEdge(INT32 xp, INT32 yp, INT32 x1, INT32 y1, INT32 x2, INT32 y2)
|
||||||
|
{
|
||||||
|
//Test whether the point(xp, yp) lies on the left-hand side of the edge(x1, y1) - (x2, y2)
|
||||||
|
const auto D = (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1);
|
||||||
|
return (D > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 RandomGridNoUnloadedSector(INT32 worldRows, INT32 worldCols)
|
||||||
|
{
|
||||||
|
INT32 iMapIndex;
|
||||||
|
const auto centerHeight = gpWorldLevelDataAutoResolve[gMapInformationAutoResolve.sCenterGridNo].sHeight;
|
||||||
|
|
||||||
|
const auto CenterWorldX = (WORLD_ROWS) / 2 * CELL_X_SIZE;
|
||||||
|
const auto CenterWorldY = (WORLD_COLS) / 2 * CELL_Y_SIZE;
|
||||||
|
|
||||||
|
// Sector corners are shifted inwards a bit to limit the area to be slightly smaller than actual sector.
|
||||||
|
// It fixed a few annyoing edge cases where a tile would evaluate to being inside the map, but it was juuust out of reach in actual gameplay
|
||||||
|
const auto TLX = 2*CELL_X_SIZE; // Shift X-coordinate by one tile inwards from actual edge.
|
||||||
|
const auto TLY = (WORLD_ROWS / 2) * CELL_X_SIZE;
|
||||||
|
|
||||||
|
const auto TRX = (WORLD_COLS / 2) * CELL_Y_SIZE;
|
||||||
|
const auto TRY = 2*CELL_X_SIZE; // Shift Y-coordinate by one tile inwards from actual edge
|
||||||
|
|
||||||
|
const auto BLX = ((WORLD_COLS / 2) * CELL_Y_SIZE);
|
||||||
|
const auto BLY = ((WORLD_ROWS-1) * CELL_Y_SIZE); // Shift Y-coordinate by one row inwards from actual edge
|
||||||
|
|
||||||
|
const auto BRX = ((WORLD_COLS-1) * CELL_Y_SIZE); // Shift X-coordinate by one row inwards from actual edge
|
||||||
|
const auto BRY = ((WORLD_ROWS / 2) * CELL_X_SIZE);
|
||||||
|
|
||||||
|
UINT8 randomGridHeight = 255;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
randomGridHeight = 255; // Reset height to be tested
|
||||||
|
INT32 iMapXPos = Random(worldCols);
|
||||||
|
INT32 iMapYPos = Random(worldRows);
|
||||||
|
iMapIndex = iMapYPos * worldCols + iMapXPos;
|
||||||
|
|
||||||
|
// Discard gridno that is not within map bounds.
|
||||||
|
// Check point against world area's edges. If any edge test fails, it means point is not inside.
|
||||||
|
// Edge traverals goes counterclockwise, Top Right -> Top Left -> Bottom Left -> Bottom Right -> Top Right
|
||||||
|
const auto pX = iMapXPos * CELL_X_SIZE;
|
||||||
|
const auto pY = iMapYPos * CELL_Y_SIZE;
|
||||||
|
|
||||||
|
//TR->TL
|
||||||
|
if ( !pointLeftOfEdge(pX, pY, TLX, TLY, TRX, TRY) )
|
||||||
|
continue;
|
||||||
|
//TL->BL
|
||||||
|
if ( !pointLeftOfEdge(pX, pY, BLX, BLY, TLX, TLY) )
|
||||||
|
continue;
|
||||||
|
//BL->BR
|
||||||
|
if ( !pointLeftOfEdge(pX, pY, BRX, BRY, BLX, BLY) )
|
||||||
|
continue;
|
||||||
|
//BR->TR
|
||||||
|
if ( !pointLeftOfEdge(pX, pY, TRX, TRY, BRX, BRY) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Compare randomGridHeight with height of the center grid of the map, as long as the center of the map is on walkable height it will work properly
|
||||||
|
randomGridHeight = gpWorldLevelDataAutoResolve[iMapIndex].sHeight;
|
||||||
|
} while ( !(randomGridHeight == centerHeight) );
|
||||||
|
return iMapIndex;
|
||||||
|
}
|
||||||
|
|
||||||
// Flugente: is this gridno near a player merc?
|
// Flugente: is this gridno near a player merc?
|
||||||
BOOLEAN GridNoNearPlayerMercs( INT32 sGridNo, INT16 sRadius )
|
BOOLEAN GridNoNearPlayerMercs( INT32 sGridNo, INT16 sRadius )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ BOOLEAN FindFenceJumpDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStar
|
|||||||
|
|
||||||
//Simply chooses a random gridno within valid boundaries (for dropping things in unloaded sectors)
|
//Simply chooses a random gridno within valid boundaries (for dropping things in unloaded sectors)
|
||||||
INT32 RandomGridNo();
|
INT32 RandomGridNo();
|
||||||
|
INT32 RandomGridNoUnloadedSector(INT32 worldRows, INT32 worldCols);
|
||||||
|
|
||||||
extern UINT32 guiForceRefreshMousePositionCalculation;
|
extern UINT32 guiForceRefreshMousePositionCalculation;
|
||||||
|
|
||||||
|
|||||||
+179
-175
@@ -23,7 +23,6 @@
|
|||||||
#include "LogicalBodyTypes/BodyTypeDB.h"
|
#include "LogicalBodyTypes/BodyTypeDB.h"
|
||||||
|
|
||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
#include <Cheats.h>
|
|
||||||
|
|
||||||
UINT32 guiShieldGraphic = 0;
|
UINT32 guiShieldGraphic = 0;
|
||||||
BOOLEAN fShieldGraphicInit = FALSE;
|
BOOLEAN fShieldGraphicInit = FALSE;
|
||||||
@@ -553,25 +552,22 @@ void ResetRenderParameters( );
|
|||||||
|
|
||||||
void RenderRoomInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
void RenderRoomInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
||||||
|
|
||||||
//extern UINT8 * gubFOVDebugInfoInfo;
|
|
||||||
//extern UINT8 * gubGridNoMarkers;
|
#ifdef _DEBUG
|
||||||
//extern UINT8 gubGridNoValue;
|
//extern UINT8 gubFOVDebugInfoInfo[ WORLD_MAX ];
|
||||||
//extern BOOLEAN gfDisplayGridNoVisibleValues = 0;
|
//extern UINT8 gubGridNoMarkers[ WORLD_MAX ];
|
||||||
//void RenderFOVDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
extern UINT8 * gubFOVDebugInfoInfo;
|
||||||
//void RenderGridNoVisibleDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
extern UINT8 * gubGridNoMarkers;
|
||||||
extern INT16 gsBestCover;
|
extern UINT8 gubGridNoValue;
|
||||||
INT32* gRenderDebugInfoValues = nullptr;
|
extern BOOLEAN gfDisplayCoverValues;
|
||||||
void RenderDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS);
|
extern BOOLEAN gfDisplayGridNoVisibleValues = 0;
|
||||||
void ResetDebugInfoValues()
|
//extern INT16 gsCoverValue[ WORLD_MAX ];
|
||||||
{
|
extern INT16 * gsCoverValue;
|
||||||
if (gRenderDebugInfoValues)
|
extern INT16 gsBestCover;
|
||||||
{
|
void RenderFOVDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
||||||
for (size_t i = 0; i < WORLD_MAX; i++)
|
void RenderCoverDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
||||||
{
|
void RenderGridNoVisibleDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS );
|
||||||
gRenderDebugInfoValues[i] = 0x7FFFFFFF;
|
#endif
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteFromWorld( UINT16 usTileIndex, UINT32 uiRenderTiles, UINT16 usIndex );
|
void DeleteFromWorld( UINT16 usTileIndex, UINT32 uiRenderTiles, UINT16 usIndex );
|
||||||
|
|
||||||
@@ -3276,10 +3272,23 @@ UINT32 cnt = 0;
|
|||||||
RenderRoomInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
RenderRoomInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_CHEAT_LEVEL() && gTacticalStatus.Team[OUR_TEAM].bTeamActive)
|
#ifdef _DEBUG
|
||||||
|
if( gRenderFlags&RENDER_FLAG_FOVDEBUG )
|
||||||
{
|
{
|
||||||
RenderDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
|
RenderFOVDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
}
|
}
|
||||||
|
else if (gfDisplayCoverValues)
|
||||||
|
{
|
||||||
|
RenderCoverDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
|
}
|
||||||
|
else if (gfDisplayGridNoVisibleValues)
|
||||||
|
{
|
||||||
|
RenderGridNoVisibleDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#endif
|
||||||
|
|
||||||
//RenderStaticWorldRect( gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y );
|
//RenderStaticWorldRect( gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y );
|
||||||
//AddBaseDirtyRect(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y );
|
//AddBaseDirtyRect(gsVIEWPORT_START_X, gsVIEWPORT_START_Y, gsVIEWPORT_END_X, gsVIEWPORT_END_Y );
|
||||||
@@ -8005,10 +8014,6 @@ void RenderRoomInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPoi
|
|||||||
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// From fov.cpp
|
|
||||||
extern UINT8* gubGridNoMarkers;
|
|
||||||
extern UINT8 gubGridNoValue;
|
|
||||||
extern UINT8* gubFOVDebugInfoInfo;
|
|
||||||
|
|
||||||
void RenderFOVDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS )
|
void RenderFOVDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS )
|
||||||
{
|
{
|
||||||
@@ -8119,7 +8124,114 @@ void RenderFOVDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStar
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This one just renders tile gridnos. Not much use nowadays
|
void RenderCoverDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS )
|
||||||
|
{
|
||||||
|
INT8 bXOddFlag = 0;
|
||||||
|
INT16 sAnchorPosX_M, sAnchorPosY_M;
|
||||||
|
INT16 sAnchorPosX_S, sAnchorPosY_S;
|
||||||
|
INT16 sTempPosX_M, sTempPosY_M;
|
||||||
|
INT16 sTempPosX_S, sTempPosY_S;
|
||||||
|
BOOLEAN fEndRenderRow = FALSE, fEndRenderCol = FALSE;
|
||||||
|
UINT16 usTileIndex;
|
||||||
|
INT16 sX, sY;
|
||||||
|
UINT32 uiDestPitchBYTES;
|
||||||
|
UINT8 *pDestBuf;
|
||||||
|
|
||||||
|
|
||||||
|
// Begin Render Loop
|
||||||
|
sAnchorPosX_M = sStartPointX_M;
|
||||||
|
sAnchorPosY_M = sStartPointY_M;
|
||||||
|
sAnchorPosX_S = sStartPointX_S;
|
||||||
|
sAnchorPosY_S = sStartPointY_S;
|
||||||
|
|
||||||
|
pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
|
||||||
|
fEndRenderRow = FALSE;
|
||||||
|
sTempPosX_M = sAnchorPosX_M;
|
||||||
|
sTempPosY_M = sAnchorPosY_M;
|
||||||
|
sTempPosX_S = sAnchorPosX_S;
|
||||||
|
sTempPosY_S = sAnchorPosY_S;
|
||||||
|
|
||||||
|
if(bXOddFlag > 0)
|
||||||
|
sTempPosX_S += 20;
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
|
||||||
|
usTileIndex=FASTMAPROWCOLTOPOS( sTempPosY_M, sTempPosX_M );
|
||||||
|
|
||||||
|
if ( usTileIndex < GRIDSIZE )
|
||||||
|
{
|
||||||
|
sX = sTempPosX_S + ( WORLD_TILE_X / 2 ) - 5;
|
||||||
|
sY = sTempPosY_S + ( WORLD_TILE_Y / 2 ) - 5;
|
||||||
|
|
||||||
|
// Adjust for interface level
|
||||||
|
sY -= gpWorldLevelData[ usTileIndex ].sHeight;
|
||||||
|
sY += gsRenderHeight;
|
||||||
|
|
||||||
|
if (gsCoverValue[ usTileIndex] != 0x7F7F)
|
||||||
|
{
|
||||||
|
SetFont( SMALLCOMPFONT );
|
||||||
|
SetFontDestBuffer( FRAME_BUFFER , 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y, FALSE );
|
||||||
|
if (usTileIndex == gsBestCover)
|
||||||
|
{
|
||||||
|
SetFontForeground( FONT_MCOLOR_RED );
|
||||||
|
}
|
||||||
|
else if (gsCoverValue[ usTileIndex ] < 0)
|
||||||
|
{
|
||||||
|
SetFontForeground( FONT_MCOLOR_WHITE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetFontForeground( FONT_GRAY3 );
|
||||||
|
}
|
||||||
|
mprintf_buffer( pDestBuf, uiDestPitchBYTES, TINYFONT1, sX, sY , L"%d", gsCoverValue[ usTileIndex ] );
|
||||||
|
SetFontDestBuffer( FRAME_BUFFER , 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sTempPosX_S += 40;
|
||||||
|
sTempPosX_M ++;
|
||||||
|
sTempPosY_M --;
|
||||||
|
|
||||||
|
if ( sTempPosX_S >= sEndXS )
|
||||||
|
{
|
||||||
|
fEndRenderRow = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while( !fEndRenderRow );
|
||||||
|
|
||||||
|
if ( bXOddFlag > 0 )
|
||||||
|
{
|
||||||
|
sAnchorPosY_M ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sAnchorPosX_M ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bXOddFlag = !bXOddFlag;
|
||||||
|
sAnchorPosY_S += 10;
|
||||||
|
|
||||||
|
if ( sAnchorPosY_S >= sEndYS )
|
||||||
|
{
|
||||||
|
fEndRenderCol = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while( !fEndRenderCol );
|
||||||
|
|
||||||
|
UnLockVideoSurface( FRAME_BUFFER );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderGridNoVisibleDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS )
|
void RenderGridNoVisibleDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS )
|
||||||
{
|
{
|
||||||
INT8 bXOddFlag = 0;
|
INT8 bXOddFlag = 0;
|
||||||
@@ -8222,148 +8334,9 @@ void RenderGridNoVisibleDebugInfo( INT16 sStartPointX_M, INT16 sStartPointY_M, I
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderFOVDebug()
|
|
||||||
{
|
|
||||||
RenderFOVDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderGridNoVisibleDebug()
|
|
||||||
{
|
|
||||||
RenderGridNoVisibleDebugInfo(gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void RenderDebugInfo(INT16 sStartPointX_M, INT16 sStartPointY_M, INT16 sStartPointX_S, INT16 sStartPointY_S, INT16 sEndXS, INT16 sEndYS)
|
|
||||||
{
|
|
||||||
INT8 bXOddFlag = 0;
|
|
||||||
INT16 sTempPosX_M, sTempPosY_M;
|
|
||||||
INT16 sTempPosX_S, sTempPosY_S;
|
|
||||||
BOOLEAN fEndRenderRow = FALSE, fEndRenderCol = FALSE;
|
|
||||||
|
|
||||||
// Begin Render Loop
|
|
||||||
INT16 sAnchorPosX_M = sStartPointX_M;
|
|
||||||
INT16 sAnchorPosY_M = sStartPointY_M;
|
|
||||||
INT16 sAnchorPosX_S = sStartPointX_S;
|
|
||||||
INT16 sAnchorPosY_S = sStartPointY_S;
|
|
||||||
|
|
||||||
UINT32 uiDestPitchBYTES;
|
|
||||||
UINT8* pDestBuf = LockVideoSurface(FRAME_BUFFER, &uiDestPitchBYTES);
|
|
||||||
|
|
||||||
const auto mode = gRenderDebugInfoMode;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
fEndRenderRow = FALSE;
|
|
||||||
sTempPosX_M = sAnchorPosX_M;
|
|
||||||
sTempPosY_M = sAnchorPosY_M;
|
|
||||||
sTempPosX_S = sAnchorPosX_S;
|
|
||||||
sTempPosY_S = sAnchorPosY_S;
|
|
||||||
|
|
||||||
if (bXOddFlag > 0)
|
|
||||||
sTempPosX_S += 20;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
UINT16 usTileIndex = FASTMAPROWCOLTOPOS(sTempPosY_M, sTempPosX_M);
|
|
||||||
if (usTileIndex < GRIDSIZE)
|
|
||||||
{
|
|
||||||
INT16 sX = sTempPosX_S + (WORLD_TILE_X / 2) - 5;
|
|
||||||
INT16 sY = sTempPosY_S + (WORLD_TILE_Y / 2) - 5;
|
|
||||||
|
|
||||||
// Adjust for interface level
|
|
||||||
sY -= gpWorldLevelData[usTileIndex].sHeight;
|
|
||||||
sY += gsRenderHeight;
|
|
||||||
|
|
||||||
|
|
||||||
if (gRenderDebugInfoValues[usTileIndex] != 0x7FFFFFFF)
|
|
||||||
{
|
|
||||||
SetFont(SMALLCOMPFONT);
|
|
||||||
SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, gsVIEWPORT_END_Y, FALSE);
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
// Debug mode specific setup
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case DEBUG_PATHFINDING:
|
|
||||||
if (gRenderDebugInfoValues[usTileIndex] < 0)
|
|
||||||
{
|
|
||||||
SetFontForeground(FONT_LTRED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetFontForeground(FONT_LTGREEN);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DEBUG_THREATVALUE:
|
|
||||||
//TODO implement
|
|
||||||
goto exit_loop;
|
|
||||||
break;
|
|
||||||
case DEBUG_COVERVALUE:
|
|
||||||
if (usTileIndex == gsBestCover)
|
|
||||||
{
|
|
||||||
SetFontForeground(FONT_YELLOW);
|
|
||||||
}
|
|
||||||
else if (gRenderDebugInfoValues[usTileIndex] < 0)
|
|
||||||
{
|
|
||||||
SetFontForeground(FONT_LTRED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetFontForeground(FONT_LTGREEN);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
goto exit_loop;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
mprintf_buffer(pDestBuf, uiDestPitchBYTES, TINYFONT1, sX, sY, L"%d", gRenderDebugInfoValues[usTileIndex]);
|
|
||||||
SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sTempPosX_S += 40;
|
|
||||||
sTempPosX_M++;
|
|
||||||
sTempPosY_M--;
|
|
||||||
|
|
||||||
if (sTempPosX_S >= sEndXS)
|
|
||||||
{
|
|
||||||
fEndRenderRow = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (!fEndRenderRow);
|
|
||||||
|
|
||||||
if (bXOddFlag > 0)
|
|
||||||
{
|
|
||||||
sAnchorPosY_M++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sAnchorPosX_M++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bXOddFlag = !bXOddFlag;
|
|
||||||
sAnchorPosY_S += 10;
|
|
||||||
|
|
||||||
if (sAnchorPosY_S >= sEndYS)
|
|
||||||
{
|
|
||||||
fEndRenderCol = TRUE;
|
|
||||||
}
|
|
||||||
} while (!fEndRenderCol);
|
|
||||||
|
|
||||||
exit_loop:
|
|
||||||
UnLockVideoSurface(FRAME_BUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ExamineZBufferRect( INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom)
|
void ExamineZBufferRect( INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom)
|
||||||
{
|
{
|
||||||
CalcRenderParameters( sLeft, sTop, sRight, sBottom );
|
CalcRenderParameters( sLeft, sTop, sRight, sBottom );
|
||||||
@@ -8545,8 +8518,7 @@ void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
|
|||||||
gsStartPointY_W = sRenderCenterY_W - sTempPosY_W;
|
gsStartPointY_W = sRenderCenterY_W - sTempPosY_W;
|
||||||
|
|
||||||
// NOTE: Increase X map value by 1 tile to offset where on screen we are...
|
// NOTE: Increase X map value by 1 tile to offset where on screen we are...
|
||||||
if ( gsStartPointX_W > 0 )
|
gsStartPointX_W += CELL_X_SIZE;
|
||||||
gsStartPointX_W += CELL_X_SIZE;
|
|
||||||
|
|
||||||
// d) screen start point is screen distances minus screen center
|
// d) screen start point is screen distances minus screen center
|
||||||
gsStartPointX_S = sLeft - VIEWPORT_XOFFSET_S;
|
gsStartPointX_S = sLeft - VIEWPORT_XOFFSET_S;
|
||||||
@@ -8554,8 +8526,8 @@ void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
|
|||||||
|
|
||||||
// STEP FOUR - Determine Start block
|
// STEP FOUR - Determine Start block
|
||||||
// a) Find start block
|
// a) Find start block
|
||||||
gsStartPointX_M = ( gsStartPointX_W ) / CELL_X_SIZE;
|
gsStartPointX_M = floor( DOUBLE(gsStartPointX_W) / DOUBLE(CELL_X_SIZE) );
|
||||||
gsStartPointY_M = ( gsStartPointY_W ) / CELL_Y_SIZE;
|
gsStartPointY_M = floor( DOUBLE(gsStartPointY_W) / DOUBLE(CELL_Y_SIZE) );
|
||||||
|
|
||||||
// STEP 5 - Determine Deltas for center and find screen values
|
// STEP 5 - Determine Deltas for center and find screen values
|
||||||
//Make sure these coordinates are multiples of scroll steps
|
//Make sure these coordinates are multiples of scroll steps
|
||||||
@@ -8591,7 +8563,7 @@ void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
|
|||||||
gsLEndXS = sRight + LARGER_VIEWPORT_XOFFSET_S;
|
gsLEndXS = sRight + LARGER_VIEWPORT_XOFFSET_S;
|
||||||
gsLEndYS = sBottom + LARGER_VIEWPORT_YOFFSET_S;
|
gsLEndYS = sBottom + LARGER_VIEWPORT_YOFFSET_S;
|
||||||
|
|
||||||
// STEP THREE - determine starting point in world coords
|
// STEP THREE - determine starting point in world coords
|
||||||
// a) Determine where in screen coords to start rendering
|
// a) Determine where in screen coords to start rendering
|
||||||
gsLStartPointX_S = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) - (sLeft - LARGER_VIEWPORT_XOFFSET_S);
|
gsLStartPointX_S = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) - (sLeft - LARGER_VIEWPORT_XOFFSET_S);
|
||||||
gsLStartPointY_S = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) - (sTop - LARGER_VIEWPORT_YOFFSET_S);
|
gsLStartPointY_S = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) - (sTop - LARGER_VIEWPORT_YOFFSET_S);
|
||||||
@@ -8605,8 +8577,7 @@ void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
|
|||||||
gsLStartPointY_W = sRenderCenterY_W - sTempPosY_W;
|
gsLStartPointY_W = sRenderCenterY_W - sTempPosY_W;
|
||||||
|
|
||||||
// NOTE: Increase X map value by 1 tile to offset where on screen we are...
|
// NOTE: Increase X map value by 1 tile to offset where on screen we are...
|
||||||
if ( gsLStartPointX_W > 0 )
|
gsLStartPointX_W += CELL_X_SIZE;
|
||||||
gsLStartPointX_W += CELL_X_SIZE;
|
|
||||||
|
|
||||||
// d) screen start point is screen distances minus screen center
|
// d) screen start point is screen distances minus screen center
|
||||||
gsLStartPointX_S = sLeft - LARGER_VIEWPORT_XOFFSET_S;
|
gsLStartPointX_S = sLeft - LARGER_VIEWPORT_XOFFSET_S;
|
||||||
@@ -8614,8 +8585,23 @@ void CalcRenderParameters(INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
|
|||||||
|
|
||||||
// STEP FOUR - Determine Start block
|
// STEP FOUR - Determine Start block
|
||||||
// a) Find start block
|
// a) Find start block
|
||||||
gsLStartPointX_M = ( gsLStartPointX_W ) / CELL_X_SIZE;
|
gsLStartPointX_M = floor( DOUBLE(gsLStartPointX_W) / DOUBLE(CELL_X_SIZE) );
|
||||||
gsLStartPointY_M = ( gsLStartPointY_W ) / CELL_Y_SIZE;
|
gsLStartPointY_M = floor( DOUBLE(gsLStartPointY_W) / DOUBLE(CELL_Y_SIZE) );
|
||||||
|
|
||||||
|
// Check and correct the difference between smaller and larger start blocks in tile coordinates.
|
||||||
|
// Regardless of resolution, the difference between the start blocks are constant 10 tiles in X- and 6 tiles in Y-direction.
|
||||||
|
// If the difference doesn't match, static world is rendered in the wrong place relative to dynamic world.
|
||||||
|
// Mainly evident in 960x540 resolution.
|
||||||
|
const auto ratioX_M = gsStartPointX_M - gsLStartPointX_M;
|
||||||
|
if ( ratioX_M != 10)
|
||||||
|
{
|
||||||
|
gsLStartPointX_M -= 10 - ratioX_M;
|
||||||
|
}
|
||||||
|
const auto ratioY_M = gsStartPointY_M - gsLStartPointY_M;
|
||||||
|
if ( ratioY_M != 6 )
|
||||||
|
{
|
||||||
|
gsLStartPointY_M -= 6 - ratioY_M;
|
||||||
|
}
|
||||||
|
|
||||||
// Adjust starting screen coordinates
|
// Adjust starting screen coordinates
|
||||||
gsLStartPointX_S -= sOffsetX_S;
|
gsLStartPointX_S -= sOffsetX_S;
|
||||||
@@ -9024,3 +9010,21 @@ void SetRenderCenter( INT16 sNewX, INT16 sNewY )
|
|||||||
gfScrollInertia = FALSE;
|
gfScrollInertia = FALSE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void RenderFOVDebug( )
|
||||||
|
{
|
||||||
|
RenderFOVDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderCoverDebug( )
|
||||||
|
{
|
||||||
|
RenderCoverDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RenderGridNoVisibleDebug( )
|
||||||
|
{
|
||||||
|
RenderGridNoVisibleDebugInfo( gsStartPointX_M, gsStartPointY_M, gsStartPointX_S, gsStartPointY_S, gsEndXS, gsEndYS );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user