mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5a90c955 | ||
|
|
95f26ef625 | ||
|
|
bc7654392a | ||
|
|
760b035a3a | ||
|
|
ce2fd88c24 | ||
|
|
3d6c02ffe2 | ||
|
|
2aae150981 |
No files matched your search
+1
-14
@@ -4,28 +4,20 @@ modernize-*,\
|
||||
-modernize-avoid-c-arrays,\
|
||||
-modernize-make-unique,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-default-member-init,\
|
||||
-modernize-use-nodiscard,\
|
||||
-modernize-use-trailing-return-type,\
|
||||
-modernize-use-using,\
|
||||
performance-*,\
|
||||
-performance-no-int-to-ptr,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
-misc-include-cleaner,\
|
||||
-misc-macro-parentheses,\
|
||||
-misc-misplaced-widening-cast,\
|
||||
-misc-no-recursion,\
|
||||
-misc-non-private-member-variables-in-classes,\
|
||||
-misc-static-assert,\
|
||||
-misc-unused-parameters,\
|
||||
-misc-use-anonymous-namespace,\
|
||||
readability-*,\
|
||||
-readability-avoid-const-params-in-decls,\
|
||||
-readability-else-after-return,\
|
||||
-readability-function-cognitive-complexity,\
|
||||
-readability-function-size,\
|
||||
-readability-identifier-length,\
|
||||
-readability-identifier-naming,\
|
||||
-readability-implicit-bool-conversion,\
|
||||
-readability-inconsistent-declaration-parameter-name,\
|
||||
@@ -37,18 +29,13 @@ readability-*,\
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: 'misc-assert-side-effect.AssertMacros'
|
||||
value: 'assert,Assert,Assertion'
|
||||
- key: 'misc-const-correctness.AnalyzeValues'
|
||||
value: 'false'
|
||||
- key: 'misc-const-correctness.TransformValues'
|
||||
value: 'false'
|
||||
- key: 'modernize-use-emplace.ContainersWithPushBack'
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
- key: 'readability-braces-around-statements.ShortStatementLines'
|
||||
value: '4' # Avoid flagging simple if (...) return false; statements
|
||||
- key: 'performance-move-const-arg.CheckTriviallyCopyableMove' # This isn't actually performance relevant, but using move on trivially copyable types can well indicate that the variable should not be used anymore, such as when passing a builder type to the finialization function
|
||||
value: 'false'
|
||||
...
|
||||
|
||||
@@ -13,23 +13,14 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
name: Linux
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -54,45 +45,33 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
linux_zip:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release-${{ matrix.arch }}
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug-${{ matrix.arch }}
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
- name: Fix permissions
|
||||
working-directory: ./builds
|
||||
shell: bash
|
||||
run: chmod 755 *.AppImage
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
working-directory: ./builds
|
||||
@@ -110,15 +89,12 @@ jobs:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
@@ -144,9 +120,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -161,16 +137,16 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -188,7 +164,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -196,27 +172,24 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -261,18 +234,15 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
@@ -317,7 +287,7 @@ jobs:
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -325,27 +295,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
|
||||
@@ -41,26 +41,17 @@ jobs:
|
||||
# Run this job for each configuration
|
||||
# The current config running is accesible with `matrix.configuration`
|
||||
configuration: [FastDebug, Release]
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
name: Linux
|
||||
needs: create_release # Don't run this job until create_release is done and successful
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -85,7 +76,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
# Upload the url file for use with other runners
|
||||
# upload-artifact.inputs:
|
||||
# if-no-files-found=warn What to do if path fails to find any files.
|
||||
@@ -96,52 +87,40 @@ jobs:
|
||||
# 0 Use default retention policy of the repo
|
||||
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
linux_zip:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release-${{ matrix.arch }}
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
# Grab the debug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug-${{ matrix.arch }}
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
- name: Fix permissions
|
||||
working-directory: ./builds
|
||||
shell: bash
|
||||
run: chmod 755 *.AppImage
|
||||
- name: Create Distribution package
|
||||
# Zip both builds together
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
# Stash the result to artifact filespace
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
@@ -161,17 +140,14 @@ jobs:
|
||||
simd: [SSE2, AVX]
|
||||
needs: create_release
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
# Checkout repo
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -200,9 +176,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -217,16 +193,16 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -244,7 +220,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -253,7 +229,7 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
fail-fast: false # Run the other jobs in the matrix instead of failing them
|
||||
matrix:
|
||||
@@ -261,23 +237,20 @@ jobs:
|
||||
simd: [SSE2, AVX]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -292,13 +265,13 @@ jobs:
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
|
||||
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
- name: Upload debug package
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.debug_name }}
|
||||
path: ${{ steps.generate_package.outputs.debug_path }}
|
||||
@@ -336,19 +309,16 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -387,7 +357,7 @@ jobs:
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -395,27 +365,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
@@ -431,7 +398,7 @@ jobs:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
@@ -15,15 +15,12 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Set up test version
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -54,7 +51,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -62,24 +59,21 @@ jobs:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -102,15 +96,12 @@ jobs:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Set up test version
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -142,9 +133,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -159,16 +150,16 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 17 2022" -T "v143" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -186,7 +177,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -194,28 +185,25 @@ jobs:
|
||||
name: Build Windows distribution zip
|
||||
needs: build_windows
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -260,18 +248,15 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
@@ -315,7 +300,7 @@ jobs:
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -323,27 +308,24 @@ jobs:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-844131c
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
|
||||
@@ -25,17 +25,12 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- name: Install Qt dependencies
|
||||
run: apt-get -yq update && apt-get -yq install libfontconfig1
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
|
||||
@@ -45,13 +45,11 @@ jobs:
|
||||
run: echo "github.event_name= ${{ github.event_name }}"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
ref: ${{ env.RELEASE_TAG }}
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install -r ci/post/requirements.txt
|
||||
|
||||
|
||||
@@ -20,26 +20,15 @@ jobs:
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Debug
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- name: Install Qt dependencies
|
||||
run: apt-get -yq update && apt-get -yq install libfontconfig1
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
@@ -81,21 +70,18 @@ jobs:
|
||||
build_windows:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, FastDebug, Release]
|
||||
configuration: [Debug, Release]
|
||||
compiler: [MSVC]
|
||||
arch: [Win32, x64]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Prepare Environment
|
||||
run: choco install ninja
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
@@ -121,9 +107,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -147,12 +133,12 @@ jobs:
|
||||
else
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 17 2022" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v143" -A "$ARCHITECTURE" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 17 2022" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v143" -A "$ARCHITECTURE" -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
fi
|
||||
- name: Compile
|
||||
@@ -205,23 +191,20 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
|
||||
@@ -2,14 +2,17 @@ name: Weekly Coverity Scan for Freespace Open
|
||||
# adapted from code by "albert-github" on the doxygen repository
|
||||
# many thanks for figuring this out first so it could be less painful for us!
|
||||
|
||||
# keep this from running on everyone's fork
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
|
||||
#This mode is for testing
|
||||
#on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
on:
|
||||
schedule:
|
||||
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
- cron: "57 18 * * *" # Run once per a week on Friday morning (4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
coverity_email: [email protected]
|
||||
@@ -18,23 +21,17 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
if: github.repository == 'scp-fs2open/fs2open.github.com'
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
- name: Set workspace as safe
|
||||
# This appears to be broken in current actions, so do it manually
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
@@ -50,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Configure CMake for FSO
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
CONFIGURATION: FastDebug
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
@@ -69,8 +66,4 @@ jobs:
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl -X POST -d token=${{ env.coverity_token }} -d email=${{ env.coverity_email }} -d file_name="'cov-scan.tgz'" -d version=${{ github.ref }} -d description="Automatic GHA scan" 'https://scan.coverity.com/projects/870/builds/init' | tee response
|
||||
upload_url=$(jq -r '.url' response)
|
||||
build_id=$(jq -r '.build_id' response)
|
||||
curl -X PUT --header 'Content-Type: application/json' --upload-file cov-scan.tgz $upload_url
|
||||
curl -X PUT -d token=${{ env.coverity_token }} https://scan.coverity.com/projects/870/builds/$build_id/enqueue
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form file=@cov-scan.tgz --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
@@ -42,7 +42,6 @@ _ReSharper*/
|
||||
|
||||
#Project files
|
||||
[Bb]uild/
|
||||
[Oo]ut/
|
||||
|
||||
#Subversion files
|
||||
.svn
|
||||
@@ -260,5 +259,3 @@ CMakePresets.json
|
||||
!/code/scripting/lua/LuaConvert.h
|
||||
!/code/debugconsole/
|
||||
!/docker/build
|
||||
CMakeFiles/cmake.check_cache
|
||||
CMakeCache.txt
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
[submodule "cmake/external/rpavlik-cmake-modules"]
|
||||
path = cmake/external/rpavlik-cmake-modules
|
||||
url = https://github.com/rpavlik/cmake-modules.git
|
||||
url = https://github.com/asarium/cmake-modules.git
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/scp-fs2open/libRocket.git
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
|
||||
+20
-59
@@ -1,5 +1,5 @@
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.21)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.4)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Make sure the source and binary directory are not the sample
|
||||
@@ -8,12 +8,12 @@ if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
include(cmake/util.cmake)
|
||||
include(cmake/embed_file.cmake)
|
||||
|
||||
# Set a few policies
|
||||
set_policy(CMP0051 NEW)
|
||||
set_policy(CMP0053 NEW)
|
||||
set_policy(CMP0054 NEW)
|
||||
set_policy(CMP0091 NEW) # Enable use of CMAKE_MSVC_RUNTIME_LIBRARY
|
||||
|
||||
SET(FSO_PROJECT_DESCRIPTION "Open source project based on the original FreeSpace 2 source code.")
|
||||
|
||||
@@ -47,6 +47,11 @@ endif()
|
||||
|
||||
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
# Check if the external modules exists
|
||||
IF(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules/launcher-templates")
|
||||
message(FATAL_ERROR "External submodules could not be found. Please make sure you have updated your submodules.")
|
||||
@@ -57,16 +62,12 @@ LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
|
||||
|
||||
INCLUDE(globals)
|
||||
INCLUDE(toolchain)
|
||||
include(embed_file)
|
||||
|
||||
IF(RESET_INSTALL_PREFIX)
|
||||
IF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
IF(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
MESSAGE(WARNING "The path '$ENV{FS2PATH}' of the environment variable FS2PATH does not point to a directory! Install prefix wasn't set.")
|
||||
ELSE(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
SET(CMAKE_INSTALL_PREFIX "$ENV{FS2PATH}" CACHE PATH "Install path" FORCE)
|
||||
SET(CMAKE_INSTALL_PREFIX "$ENV{FS2PATH}" CACHE FILEPATH "Install path" FORCE)
|
||||
FILE(TO_CMAKE_PATH ${CMAKE_INSTALL_PREFIX} CMAKE_INSTALL_PREFIX)
|
||||
ENDIF(NOT IS_DIRECTORY $ENV{FS2PATH})
|
||||
ELSE(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
@@ -74,11 +75,9 @@ IF(RESET_INSTALL_PREFIX)
|
||||
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
ENDIF(RESET_INSTALL_PREFIX)
|
||||
|
||||
IF(WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
IF(WIN32 OR APPLE)
|
||||
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" ON)
|
||||
ELSE()
|
||||
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" OFF)
|
||||
ENDIF()
|
||||
ENDIF(WIN32 OR APPLE)
|
||||
|
||||
IF (WIN32)
|
||||
OPTION(FSO_USE_VOICEREC "Enable voice recognition support" ON)
|
||||
@@ -111,7 +110,7 @@ OPTION(FSO_USE_OPENALSOFT "Download and build OpenAL Soft instead of using the s
|
||||
|
||||
OPTION(FSO_FATAL_WARNINGS "Determines if warnings in the build are considered fatal errors, primarily used for CI" OFF)
|
||||
|
||||
SET(FSO_FREESPACE_PATH "${CMAKE_INSTALL_PREFIX}" CACHE PATH "The path of the FreeSpace directory you want to use. Please note that you will have to change CMAKE_INSTALL_PREFIX if you change this at some point.")
|
||||
SET(FSO_FREESPACE_PATH "${CMAKE_INSTALL_PREFIX}" CACHE FILEPATH "The path of the FreeSpace directory you want to use. Please note that you will have to change CMAKE_INSTALL_PREFIX if you change this at some point.")
|
||||
|
||||
SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generated executable when run with the generated build files.")
|
||||
|
||||
@@ -123,43 +122,13 @@ option(FSO_RELEASE_LOGGING "Enable logging output for release builds" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_FFMPEG "Enable the usage of FFmpeg for sound and custscenes" ON)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_DISCORD "Build with Discord support" ON)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_ES "When building OpenGL, use OpenGL ES compatibility layer (External shaders only!)" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
|
||||
if(NOT FSO_BUILD_WITH_OPENGL AND FSO_BUILD_WITH_OPENGL_ES)
|
||||
# Disable GLES if not building with OpenGL
|
||||
set(FSO_BUILD_WITH_OPENGL_ES OFF FORCE)
|
||||
endif()
|
||||
|
||||
|
||||
if(FSO_BUILD_WITH_OPENGL_ES)
|
||||
add_definitions(-DUSE_OPENGL_ES)
|
||||
IF(FSO_BUILD_WITH_OPENXR)
|
||||
MESSAGE(WARNING "FSO_BUILD_WITH_OPENXR is ON. But not supported on OpenGL ES for now - setting to OFF.")
|
||||
SET(FSO_BUILD_WITH_OPENXR OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
IF(NOT APPLE AND NOT FSO_BUILD_WITH_OPENGL_ES)
|
||||
SET(OPENXR_BUILD_DEFAULT ON)
|
||||
ELSE()
|
||||
SET(OPENXR_BUILD_DEFAULT OFF)
|
||||
ENDIF()
|
||||
OPTION(FSO_BUILD_WITH_OPENXR "Build with OpenXR support" ${OPENXR_BUILD_DEFAULT})
|
||||
IF(FSO_BUILD_WITH_OPENXR AND APPLE)
|
||||
MESSAGE(WARNING "FSO_BUILD_WITH_OPENXR is ON. Not supported on macOS - setting to OFF.")
|
||||
SET(FSO_BUILD_WITH_OPENXR OFF CACHE BOOL "" FORCE)
|
||||
ENDIF()
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENXR_DEBUG "Enables debug option for OpenXR" OFF)
|
||||
|
||||
OPTION(FSO_USE_LTO "Build using LTO (only for release builds)" ON)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
@@ -170,14 +139,16 @@ mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
|
||||
mark_as_advanced(FORCE ENABLE_COTIRE)
|
||||
mark_as_advanced(FORCE FSO_RELEASE_LOGGING)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_FFMPEG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_DISCORD)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_DEBUG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_ES)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_VULKAN)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
|
||||
INCLUDE(globals)
|
||||
INCLUDE(toolchain)
|
||||
INCLUDE(platforms)
|
||||
include(version)
|
||||
|
||||
@@ -188,20 +159,11 @@ SET(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated_source)
|
||||
include(generateHeaders)
|
||||
|
||||
if(FSO_BUILD_APPIMAGE)
|
||||
SET(BINARY_DESTINATION "bin")
|
||||
SET(LIBRAY_DESTINATION "lib")
|
||||
include(appimage)
|
||||
endif()
|
||||
|
||||
include(clang-tidy)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT LTO_AVAILABLE)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
message("Enabled LTO")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
|
||||
|
||||
# This includes source code for some tools, either used in the build or also for something else
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
@@ -245,7 +207,9 @@ include(package)
|
||||
include(doxygen)
|
||||
|
||||
# Print used options to log
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
IF(WIN32 OR APPLE)
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
ENDIF()
|
||||
IF (WIN32)
|
||||
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
@@ -257,8 +221,5 @@ message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
message(STATUS "Release logging: ${FSO_RELEASE_LOGGING}")
|
||||
message(STATUS "With FFmpeg: ${FSO_BUILD_WITH_FFMPEG}")
|
||||
message(STATUS "With Discord: ${FSO_BUILD_WITH_DISCORD}")
|
||||
message(STATUS "With OpenGL: ${FSO_BUILD_WITH_OPENGL}")
|
||||
message(STATUS "With OpenGL ES: ${FSO_BUILD_WITH_OPENGL_ES}")
|
||||
message(STATUS "With Vulkan: ${FSO_BUILD_WITH_VULKAN}")
|
||||
message(STATUS "With OpenXR: ${FSO_BUILD_WITH_OPENXR}")
|
||||
@@ -5,8 +5,6 @@ set -e
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
HERE=$(dirname "$SCRIPT")
|
||||
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
COMMIT_RANGE=$1..$2
|
||||
|
||||
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
|
||||
@@ -18,13 +16,8 @@ fi
|
||||
# branch
|
||||
BASE_COMMIT=$(git merge-base $1 $2)
|
||||
|
||||
# Note: Manually passing in the Vulkan flags that are normally provided by cmake (but are not so, here), to ensure
|
||||
# that the source files are checked with the actual configuration used.
|
||||
echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
|
||||
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
|
||||
-extra-arg="-DWITH_VULKAN" \
|
||||
-extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \
|
||||
-extra-arg="-DVK_NO_PROTOTYPES" \
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)|(\/def_files\/data)))|freespace2|qtfred|test\/src|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
@@ -21,13 +21,16 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
else
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2 -DUSE_STATIC_LIBCXX=ON"
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
|
||||
fi
|
||||
|
||||
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
|
||||
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
|
||||
# force clang to silently allow -static-libstdc++ flag
|
||||
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
|
||||
fi
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
@@ -42,7 +45,7 @@ export CXXFLAGS
|
||||
export CFLAGS
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
if [ "$RUNNER_OS" = "macOS" ] && [ ! -x "$(which ninja)" ]; then
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
brew install ninja
|
||||
fi
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ OS="$1"
|
||||
source $HERE/dist_functions.sh
|
||||
|
||||
if [ "$OS" = "Linux" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Linux-$ARCH.tar.gz" *
|
||||
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
|
||||
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Windows" ]; then
|
||||
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
|
||||
|
||||
|
||||
@@ -2,48 +2,13 @@
|
||||
|
||||
INSTALL_FOLDER=$1
|
||||
|
||||
# safety check
|
||||
if [ ! -d bin -o ! -f cmake_install.cmake ]; then
|
||||
echo "ERROR! This script must be run from within the build root!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$(which wget)" ]; then
|
||||
echo "ERROR! Required utility is not available: wget"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# install newest appimagetool if it's not already available
|
||||
if [ ! -x ./bin/appimagetool ]; then
|
||||
APPIMAGE_TOOL_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage"
|
||||
|
||||
wget -O ./bin/appimagetool "$APPIMAGE_TOOL_URL" || { echo "ERROR! Failed to get appimagetool!" && exit 1; }
|
||||
chmod +x ./bin/appimagetool
|
||||
fi
|
||||
|
||||
# This shouldn't be needed with newer runtimes, but they still generate an
|
||||
# error if fusermount is missing even though it works. So to skip error msg
|
||||
# and have max compatibility with runtimes and containers we'll use it.
|
||||
export APPIMAGE_EXTRACT_AND_RUN=1
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/Freespace2 -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/Freespace2 -DCOMPONENT=Freespace2 -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER -DCOMPONENT=Freespace2 -P cmake_install.cmake
|
||||
|
||||
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
|
||||
FILENAME="$(find $INSTALL_FOLDER/Freespace2/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
./bin/appimagetool -n "$INSTALL_FOLDER/Freespace2" "$INSTALL_FOLDER/$FILENAME"
|
||||
FILENAME="$(find $INSTALL_FOLDER/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
appimagetool -n $INSTALL_FOLDER "$INSTALL_FOLDER/$FILENAME"
|
||||
chmod +x "$INSTALL_FOLDER/$FILENAME"
|
||||
|
||||
# Maybe install qtFRED targets
|
||||
if [ -f qtfred/cmake_install.cmake ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/qtFRED -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_FOLDER/qtFRED -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
|
||||
FILENAME="$(find $INSTALL_FOLDER/qtFRED/bin -iname 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
./bin/appimagetool -n "$INSTALL_FOLDER/qtFRED" "$INSTALL_FOLDER/$FILENAME"
|
||||
chmod +x "$INSTALL_FOLDER/$FILENAME"
|
||||
fi
|
||||
|
||||
ls -al $INSTALL_FOLDER
|
||||
+5
-95
@@ -12,61 +12,6 @@ from subprocess import check_output
|
||||
MAX_PAGES = 100 # maximum number of PR pages to go through
|
||||
warnings = 0
|
||||
|
||||
label_scores = {
|
||||
"fred" : 6,
|
||||
"qtfred" : 6,
|
||||
"vr" : 6,
|
||||
"multi" : 6,
|
||||
"Lab" : 6,
|
||||
"pilot file" : 6,
|
||||
"scripting" : 6,
|
||||
"sexps" : 6,
|
||||
"ai" : 6,
|
||||
"controls" : 6,
|
||||
"HUD" : 6,
|
||||
"models" : 6,
|
||||
"sound" : 6,
|
||||
"graphics" : 6,
|
||||
"physics" : 6,
|
||||
"ui" : 6,
|
||||
"localization / translation" : 6,
|
||||
"optimization" : 6,
|
||||
"gameplay" : 5,
|
||||
"general modding" : 4,
|
||||
"fix" : 3,
|
||||
"enhancement" : 2,
|
||||
"backport" : 1,
|
||||
"cleanup" : 0
|
||||
}
|
||||
|
||||
label_to_category = {
|
||||
"fred" : "FRED",
|
||||
"qtfred" : "QtFRED",
|
||||
"vr" : "VR",
|
||||
"multi" : "Multiplayer",
|
||||
"Lab" : "Lab",
|
||||
"pilot file" : "Pilot File",
|
||||
"scripting" : "Scripting",
|
||||
"sexps" : "SEXPs",
|
||||
"ai" : "AI",
|
||||
"controls" : "Controls",
|
||||
"HUD" : "HUD",
|
||||
"models" : "Models",
|
||||
"sound" : "Sound",
|
||||
"graphics" : "Graphics",
|
||||
"physics" : "Physics",
|
||||
"ui" : "UI",
|
||||
"localization / translation" : "Localization",
|
||||
"optimization" : "Optimization",
|
||||
"gameplay" : "Gameplay",
|
||||
"general modding" : "General Modding",
|
||||
"fix" : "Fix",
|
||||
"enhancement" : "Enhancement",
|
||||
"backport" : "Backport",
|
||||
"cleanup" : "Cleanup",
|
||||
"misc" : "Misc."
|
||||
}
|
||||
|
||||
def get_last_page(response: requests.Response) -> int:
|
||||
"""
|
||||
@brief Extract the last page number from the response header
|
||||
@@ -95,33 +40,7 @@ def get_last_page(response: requests.Response) -> int:
|
||||
return MAX_PAGES
|
||||
else:
|
||||
return last_page
|
||||
|
||||
def label_score(label):
|
||||
try:
|
||||
return label_scores[label['name']]
|
||||
except KeyError:
|
||||
return -1
|
||||
|
||||
def get_label(labels) -> str:
|
||||
"""
|
||||
@brief Get the primary label from a list of labels
|
||||
|
||||
@param[in] labels The list of labels from a pull request
|
||||
|
||||
@returns The primary label to be used for sorting in the changelog
|
||||
"""
|
||||
if len(labels) < 1:
|
||||
return "misc"
|
||||
|
||||
# Sort the labels based on their score and grab the highest valued label
|
||||
name = sorted(labels, key=label_score, reverse=True)[0]['name']
|
||||
|
||||
# If a label couldn't be found, toss it into a miscellaneous bin
|
||||
if name not in label_scores:
|
||||
name = "misc"
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Retrieves a log of commit messages and attempts to pretty them into a human-readable format")
|
||||
@@ -219,16 +138,11 @@ def main():
|
||||
print("Found old pull #{} ({}), stopping loop...".format(pull['number'], pull['updated_at']))
|
||||
page = last_page + 1
|
||||
break
|
||||
|
||||
# If a label isn't in the changelog, create a bin for it
|
||||
label = get_label(pull['labels'])
|
||||
if label not in changelog:
|
||||
changelog[label] = {}
|
||||
|
||||
# Add the pull to the changelog, indexed by its pull.number
|
||||
if pull['number'] not in changelog[label]:
|
||||
if pull['number'] not in changelog:
|
||||
# only add if the key isn't there already
|
||||
changelog[label][pull['number']] = {
|
||||
changelog[pull['number']] = {
|
||||
"date": merge_date,
|
||||
"title": pull['title'],
|
||||
"labels": pull['labels'],
|
||||
@@ -244,13 +158,9 @@ def main():
|
||||
# 2021-09-28 | (#3661) Fix homing child weapons in niche circumstances
|
||||
print("Writing to change.log...")
|
||||
str = ''
|
||||
for label, pulls in dict(sorted(changelog.items())).items():
|
||||
str += "[size=18pt]{}[/size]\n".format(label_to_category[label])
|
||||
str += "[list]\n"
|
||||
for key, value in pulls.items():
|
||||
str += "[li](#{}) {} [/li]\n".format(key, value['title'])
|
||||
str += "[/list]\n\n"
|
||||
|
||||
for key, value in changelog.items():
|
||||
str += "{} | (#{}) {} \n".format(value['date'].strftime("%Y-%m-%d"), key, value['title'])
|
||||
|
||||
with open("change.log", "w") as file:
|
||||
file.write(str)
|
||||
|
||||
|
||||
+5
-9
@@ -7,8 +7,7 @@ import requests
|
||||
from file_list import ReleaseFile
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
LINUX_X64_KEY = "Linux-x86_64"
|
||||
LINUX_ARM64_KEY = "Linux-arm64"
|
||||
LINUX_KEY = "Linux"
|
||||
MACOSX_X64_KEY = "Mac-x86_64"
|
||||
MACOSX_ARM64_KEY = "Mac-arm64"
|
||||
WIN32_SSE2_KEY = "Win32-SSE2"
|
||||
@@ -35,8 +34,7 @@ metadata = {
|
||||
}
|
||||
|
||||
platforms = {
|
||||
LINUX_X64_KEY: 'linux',
|
||||
LINUX_ARM64_KEY: 'linux',
|
||||
LINUX_KEY: 'linux',
|
||||
MACOSX_X64_KEY: 'macosx',
|
||||
MACOSX_ARM64_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
@@ -46,8 +44,7 @@ platforms = {
|
||||
}
|
||||
|
||||
envs = {
|
||||
LINUX_X64_KEY: 'linux && x86_64',
|
||||
LINUX_ARM64_KEY: 'linux && arm64',
|
||||
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
|
||||
MACOSX_X64_KEY: 'macosx && x86_64',
|
||||
MACOSX_ARM64_KEY: 'macosx && arm64',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
@@ -116,7 +113,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
'filename': dest_fn
|
||||
})
|
||||
|
||||
if group.startswith('Linux') and fn.endswith('.AppImage'):
|
||||
if group == LINUX_KEY and fn.endswith('.AppImage'):
|
||||
if 'qtfred' in fn:
|
||||
if '-FASTDBG' in fn:
|
||||
label = 'QtFRED Debug'
|
||||
@@ -130,8 +127,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
label = None
|
||||
|
||||
props = {
|
||||
"arm64": "arm64" in fn,
|
||||
"x64": "x64" in fn,
|
||||
"x64": True, # All Linux builds are 64-bit
|
||||
"sse2": True, # Linux builds are forced to compile with SSE2 but not AVX
|
||||
"avx": False,
|
||||
"avx2": False,
|
||||
|
||||
@@ -44,10 +44,9 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
Don't want to deal with that? Use [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 20.04 LTS, GCC 9[/size]
|
||||
[b]x86_64:[/b] ${build(groups["Linux"].subFiles["x86_64"])}
|
||||
[b]arm64:[/b] ${build(groups["Linux"].subFiles["arm64"])}
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
|
||||
${build(groups["Linux"].mainFile)}
|
||||
|
||||
These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
|
||||
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Mako==1.3.12
|
||||
requests==2.33.0
|
||||
Mako==1.2.2
|
||||
requests==2.31.0
|
||||
semantic-version==2.8.5
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,21 @@
|
||||
|
||||
SET(BINARY_DESTINATION "bin")
|
||||
SET(LIBRAY_DESTINATION "lib")
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen" @ONLY)
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>"
|
||||
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen")
|
||||
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun"
|
||||
COMPONENT "Freespace2")
|
||||
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppImage.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen" @ONLY)
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop"
|
||||
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen")
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop"
|
||||
COMPONENT "Freespace2")
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION "."
|
||||
COMPONENT "Freespace2")
|
||||
+14
-36
@@ -2,72 +2,50 @@
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
// Windows
|
||||
#define cpuid __cpuidex
|
||||
#define xgetbv _xgetbv
|
||||
#define cpuid __cpuid
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// GCC Inline Assembly
|
||||
void cpuid(int CPUInfo[4], int InfoType, int SubType){
|
||||
void cpuid(int CPUInfo[4],int InfoType){
|
||||
__asm__ __volatile__ (
|
||||
"cpuid":
|
||||
"=a" (CPUInfo[0]),
|
||||
"=b" (CPUInfo[1]),
|
||||
"=c" (CPUInfo[2]),
|
||||
"=d" (CPUInfo[3]) :
|
||||
"a" (InfoType),
|
||||
"c" (SubType)
|
||||
"a" (InfoType)
|
||||
);
|
||||
}
|
||||
|
||||
uint64_t xgetbv(uint32_t xcr) {
|
||||
uint32_t lower, higher;
|
||||
__asm__ __volatile__ (
|
||||
"xgetbv":
|
||||
"=a"(lower),
|
||||
"=d"(higher) :
|
||||
"c"(xcr)
|
||||
);
|
||||
return (static_cast<uint64_t>(higher) << static_cast<uint64_t>(32)) | static_cast<uint64_t>(lower);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
bool SSE = false;
|
||||
bool SSE2 = false;
|
||||
bool OSXSAVE = false;
|
||||
bool AVX = false;
|
||||
bool AVX2 = false;
|
||||
int SSE = false;
|
||||
int SSE2 = false;
|
||||
int AVX = false;
|
||||
int AVX2 = false;
|
||||
|
||||
int info[4];
|
||||
cpuid(info, 0, 0);
|
||||
cpuid(info, 0);
|
||||
int nIds = info[0];
|
||||
|
||||
// Detect Instruction Set
|
||||
if (nIds >= 1){
|
||||
cpuid(info, 0x00000001, 0);
|
||||
SSE = (info[3] & ((int)1 << 25)) != 0;
|
||||
SSE2 = (info[3] & ((int)1 << 26)) != 0;
|
||||
OSXSAVE = (info[2] & ((int)1 << 27)) != 0;
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
cpuid(info,0x00000001);
|
||||
SSE = (info[3] & ((int)1 << 25)) != 0;
|
||||
SSE2 = (info[3] & ((int)1 << 26)) != 0;
|
||||
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
}
|
||||
if (nIds >= 7){
|
||||
cpuid(info,0x00000007, 0);
|
||||
cpuid(info,0x00000007);
|
||||
AVX2 = (info[1] & ((int)1 << 5)) != 0;
|
||||
}
|
||||
|
||||
// Detect OS Support
|
||||
if (!OSXSAVE || (xgetbv(0) & 0x6) == 0) {
|
||||
AVX = false;
|
||||
AVX2 = false;
|
||||
}
|
||||
|
||||
if (AVX2)
|
||||
std::cout << "AVX2";
|
||||
else if(AVX)
|
||||
|
||||
@@ -24,19 +24,3 @@ set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
if (FSO_BUILD_WITH_DISCORD)
|
||||
message(WARNING "Discord support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_BUILD_WITH_DISCORD:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_BUILD_FRED2)
|
||||
message(WARNING "FRED2 support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_BUILD_FRED2:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_USE_SPEECH)
|
||||
message(WARNING "Speech support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_USE_SPEECH:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_USE_VOICEREC)
|
||||
message(WARNING "Voice recognition support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_USE_VOICEREC:BOOL=OFF")
|
||||
endif()
|
||||
+1
-11
@@ -97,19 +97,9 @@ function(handle_embedded_files _target)
|
||||
set(INCLUDE_LIST "${INCLUDE_LIST}\n#include \"${HEADER_FILE}\"")
|
||||
set(ARRAY_ELEMENTS "${ARRAY_ELEMENTS}\n\t{ \"${_pathType}\", \"${FILE_NAME}\" , ${FIELD_NAME} , ${FIELD_NAME}_size },")
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(EMBEDFILE_PATH "EMBEDFILE-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to an embedfile of a cmake build for the host OS")
|
||||
IF(EMBEDFILE_PATH STREQUAL "EMBEDFILE-NOTFOUND")
|
||||
#This could, possibly, be configured to compile an embedfile using host compilation automatically, but that seems to be a challenge.
|
||||
message(FATAL_ERROR "A manual embedfile path must be configured for cross compilation. Set EMBEDFILE_PATH to the location of an embedfile executable, found in the build directories for the host OS.")
|
||||
ENDIF()
|
||||
ELSE(CMAKE_CROSSCOMPILING)
|
||||
SET(EMBEDFILE_PATH "embedfile")
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${ALL_OUTPUTS}
|
||||
COMMAND ${EMBEDFILE_PATH} "${_filePath}" "${_outputBasePath}" "${FIELD_NAME}"
|
||||
COMMAND embedfile "${_filePath}" "${_outputBasePath}" "${FIELD_NAME}"
|
||||
MAIN_DEPENDENCY "${_filePath}"
|
||||
COMMENT "Generating string file for ${_filePath}"
|
||||
)
|
||||
|
||||
Vendored
+4054
File diff suppressed because it is too large.
Load diff
@@ -11,8 +11,6 @@ if (WIN32)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
# it should just work
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# uses speech-dispatcher with dlopen
|
||||
else()
|
||||
message(SEND_ERROR "Text to Speech is not supported on this platform!")
|
||||
endif()
|
||||
|
||||
+4
-32
@@ -8,36 +8,8 @@ else()
|
||||
set(IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
set(IS_ARM64 FALSE)
|
||||
set(IS_ARMV7A FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^(armv7)")
|
||||
set(IS_ARMV7A TRUE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7)")
|
||||
set(IS_ARMV7A TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IS_RISCV FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(riscv64|RISCV64|riscv32|RISCV32)")
|
||||
set(IS_RISCV TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv64|RISCV64|riscv32|RISCV32)")
|
||||
set(IS_RISCV TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IS_X86 FALSE)
|
||||
if (NOT IS_ARM64 AND NOT IS_RISCV AND NOT IS_ARMV7A)
|
||||
set(IS_X86 TRUE)
|
||||
endif()
|
||||
set(IS_ARM64 FALSE)
|
||||
endif()
|
||||
@@ -11,8 +11,7 @@ endif()
|
||||
|
||||
target_link_libraries(platform INTERFACE ${COCOA_LIBRARY})
|
||||
|
||||
# To support C++17 we need to target at least 10.13. maybe 10.14 for some rare features
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
|
||||
|
||||
SET(CMAKE_SKIP_RPATH FALSE)
|
||||
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
#cmakedefine01 IS_ARM64
|
||||
#cmakedefine01 IS_RISCV
|
||||
|
||||
#cmakedefine01 SCP_HAVE_STRCASECMP
|
||||
#cmakedefine01 SCP_HAVE_STRNCASECMP
|
||||
|
||||
@@ -13,6 +13,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
+11
-40
@@ -10,41 +10,8 @@ option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
|
||||
option(CLANG_USE_LIBCXX "Use libc++" OFF)
|
||||
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-pipe")
|
||||
set(CXX_BASE_FLAGS "-pipe")
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(CLANG_EXTENSIONS "-march=native")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
|
||||
else ()
|
||||
message( FATAL_ERROR "Unknown instruction set encountered for clang. Update toolchain-clang.cmake!" )
|
||||
endif()
|
||||
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
||||
elseif(IS_ARM)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
|
||||
endif ()
|
||||
elseif(IS_RISCV)
|
||||
# Default C/CXX_BASE_FLAGS are fine for RISC-V
|
||||
endif()
|
||||
|
||||
if (USE_STATIC_LIBCXX)
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++ -Qunused-arguments")
|
||||
set(CLANG_USE_LIBCXX ON)
|
||||
endif()
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CXXFLAGS})
|
||||
@@ -68,6 +35,10 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "argument unused during compilation" when clang is used with ccache.
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Qunused-arguments")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
||||
# Force color diagnostics for Ninja generator
|
||||
@@ -116,17 +87,17 @@ endif()
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_DEBUG "-O0")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_DEBUG "-O0")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
|
||||
@@ -12,49 +12,8 @@ option(GCC_USE_GOLD "Use the gold linker instead of the standard linker" OFF)
|
||||
option(GCC_GENERATE_GDB_INDEX "Adds linker option to generate the gdb index for debug builds" OFF)
|
||||
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-pipe")
|
||||
set(CXX_BASE_FLAGS "-pipe")
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(GCC_EXTENSIONS "-march=native")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(GCC_EXTENSIONS "-march=x86-64")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
set(GCC_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
set(GCC_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
set(GCC_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
set(GCC_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
|
||||
else ()
|
||||
message( FATAL_ERROR "Unknown instruction set encountered for GCC. Update toolchain-gcc.cmake!" )
|
||||
endif()
|
||||
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} ${GCC_EXTENSIONS}")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${GCC_EXTENSIONS}")
|
||||
|
||||
if (IS_64BIT)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -m64")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -m64")
|
||||
endif()
|
||||
elseif(IS_ARM)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
|
||||
endif ()
|
||||
elseif(IS_RISCV)
|
||||
# You do not need to pass a -march, passing nothing will make gcc to choose itself.
|
||||
# If you want a specific set of instructions like vectors, set -march in CFLAGS and CXXFLAGS env variables
|
||||
# Example for vectors: -march=rv64gcv
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html
|
||||
# As such, default C/CXX_BASE_FLAGS are sufficient.
|
||||
endif()
|
||||
|
||||
if (USE_STATIC_LIBCXX)
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++")
|
||||
endif()
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CFLAGS})
|
||||
@@ -158,17 +117,17 @@ endif()
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_DEBUG "-O0")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_DEBUG "-O0")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
|
||||
+56
-33
@@ -46,13 +46,9 @@ target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "")
|
||||
|
||||
if(NOT IS_ARM64)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
|
||||
endif()
|
||||
|
||||
# Release
|
||||
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
@@ -71,50 +67,77 @@ if (MSVC_RELEASE_DEBUGGING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# This should be kept in sync with the corresponding IF() in fred2/CMakeLists.txt
|
||||
IF(MSVC_USE_RUNTIME_DLL OR FSO_BUILD_QTFRED)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>DLL")
|
||||
add_compile_definitions(_AFXDLL)
|
||||
ELSE()
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>")
|
||||
ENDIF()
|
||||
IF(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
|
||||
ELSE(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
|
||||
# Debug
|
||||
set(CMAKE_C_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL:NO /MAPINFO:EXPORTS /NODEFAULTLIB:libcmt.lib")
|
||||
|
||||
IF(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
|
||||
ELSE(MSVC_USE_RUNTIME_DLL)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
|
||||
INCLUDE(MSVCMultipleProcessCompile)
|
||||
|
||||
# Visual Studio supports compiling for multiple vector instruction sets
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
# MSVC has no direct -march=native equivalent, so just use the detected extensions.
|
||||
SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
|
||||
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
|
||||
|
||||
if(FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(MSVC_SIMD_INSTRUCTIONS "IA32")
|
||||
else()
|
||||
set(MSVC_SIMD_INSTRUCTIONS ${FSO_INSTRUCTION_SET})
|
||||
endif()
|
||||
SET(MSVC_SIMD_INSTRUCTIONS "${MSVC_DETECTED_SIMD_INSTRUCTIONS}" CACHE FILEPATH "The SIMD instructions which will be used, possible values are ${POSSIBLE_INSTUCTION_SETS}")
|
||||
MARK_AS_ADVANCED(FORCE MSVC_SIMD_INSTRUCTIONS)
|
||||
endif()
|
||||
set(FSO_INSTRUCTION_SET ${MSVC_SIMD_INSTRUCTIONS})
|
||||
|
||||
if (NOT (IS_64BIT AND (MSVC_SIMD_INSTRUCTIONS STREQUAL "IA32" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE2")))
|
||||
# 32-Bit and SSE(2) mustn't be set, as these are implied in x86_64 and thus MSVC does not support it for the /arch argument
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:${MSVC_SIMD_INSTRUCTIONS}" COMPILER_SUPPORTS_ARCH)
|
||||
LIST(FIND POSSIBLE_INSTUCTION_SETS "${MSVC_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
|
||||
ELSE()
|
||||
message( FATAL_ERROR "Your version of MSVC does not support the requested instruction set. Consider updating!" )
|
||||
ENDIF()
|
||||
endif()
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An invalid instruction set was specified, defaulting to no special compiler options.")
|
||||
else()
|
||||
IF (NOT SET_INDEX EQUAL 0)
|
||||
SET(FOUND)
|
||||
|
||||
FOREACH(list_index RANGE ${SET_INDEX} 1)
|
||||
list(GET POSSIBLE_INSTUCTION_SETS ${list_index} _simd_set)
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:${_simd_set}" COMPILER_SUPPORTS_ARCH_${_simd_set})
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH_${_simd_set})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${_simd_set}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${_simd_set}")
|
||||
|
||||
SET(FOUND TRUE)
|
||||
BREAK()
|
||||
ENDIF()
|
||||
ENDFOREACH(list_index)
|
||||
|
||||
IF(NOT FOUND)
|
||||
# Don't set anything, it will likely not work
|
||||
MESSAGE(STATUS "Your compiler does not support any optimization flags, defaulting to none")
|
||||
ENDIF(NOT FOUND)
|
||||
ELSE()
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:IA32" COMPILER_SUPPORTS_ARCH_IA32)
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH_IA32)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:IA32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:IA32")
|
||||
ENDIF(COMPILER_SUPPORTS_ARCH_IA32)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
|
||||
"$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>" _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
|
||||
@@ -5,55 +5,6 @@ add_library(compiler INTERFACE)
|
||||
|
||||
target_compile_definitions(compiler INTERFACE "$<$<CONFIG:Release>:NDEBUG>;$<$<CONFIG:Debug>:_DEBUG>;$<$<CONFIG:FastDebug>:_DEBUG>")
|
||||
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS ON CACHE BOOL "Override instruction set detection and compile with the maximum possible instructions for the current system.")
|
||||
IF(IS_X86)
|
||||
SET(POSSIBLE_INSTRUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
message("Cross-Compile cannot detect supported instruction sets. Defaulting to SSE2. Disabling host-optimization.")
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS OFF)
|
||||
set(DETECTED_SIMD_INSTRUCTIONS SSE2)
|
||||
else()
|
||||
detect_simd_instructions(DETECTED_SIMD_INSTRUCTIONS)
|
||||
endif()
|
||||
|
||||
set(FORCED_SIMD_INSTRUCTIONS "" CACHE STRING "Overrides any instruction set settings (including forced-native). Any of ${POSSIBLE_INSTRUCTION_SETS}.")
|
||||
if (NOT FORCED_SIMD_INSTRUCTIONS STREQUAL "")
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS OFF)
|
||||
LIST(FIND POSSIBLE_INSTRUCTION_SETS "${FORCED_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An invalid instruction set was specified, defaulting to no special compiler options.")
|
||||
set(FSO_INSTRUCTION_SET "")
|
||||
else ()
|
||||
LIST(FIND POSSIBLE_INSTRUCTION_SETS "${DETECTED_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An instruction set was specified which is unsupported on this platform. Compiled binary might not be executable.")
|
||||
endif()
|
||||
|
||||
set(FSO_INSTRUCTION_SET ${FORCED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
else()
|
||||
SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
MESSAGE(STATUS "Using instruction set level ${FSO_INSTRUCTION_SET}. Optimizations for host-system specifically: ${FORCED_NATIVE_SIMD_INSTRUCTIONS}.")
|
||||
|
||||
if (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
add_compile_definitions(FSO_SIMD_AVX)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
add_compile_definitions(FSO_SIMD_AVX)
|
||||
add_compile_definitions(FSO_SIMD_AVX2)
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
include(toolchain-gcc)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
+21
-11
@@ -158,17 +158,27 @@ function(set_precompiled_header _target _headerPath)
|
||||
target_compile_definitions(${_target} PRIVATE CMAKE_PCH)
|
||||
target_precompile_headers(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${_headerPath}>")
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
if (ENABLE_COTIRE)
|
||||
message("${_headerPath}")
|
||||
set_target_properties(${_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${_headerPath}")
|
||||
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
|
||||
cotire(${_target})
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(${_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${_headerPath}>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
+2
-8
@@ -6,7 +6,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 25)
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 24)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
@@ -35,13 +35,7 @@ ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
|
||||
ENDIF()
|
||||
|
||||
IF(IS_RISCV)
|
||||
IF(IS_64BIT)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv64")
|
||||
ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv32")
|
||||
ENDIF()
|
||||
ELSEIF(IS_ARM64)
|
||||
IF(IS_ARM64)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
|
||||
ELSEIF(IS_64BIT)
|
||||
# This is a 64-bit builds
|
||||
|
||||
+12
-13
@@ -6,7 +6,7 @@ INCLUDE(voice_rec.cmake)
|
||||
|
||||
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
|
||||
|
||||
target_compile_features(code PUBLIC cxx_std_17)
|
||||
target_compile_features(code PUBLIC cxx_std_11)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(code PUBLIC "PDB_DEBUGGING=1")
|
||||
@@ -25,11 +25,7 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR)
|
||||
add_definitions(-DFS_OPENXR)
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG AND FSO_BUILD_WITH_OPENXR)
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
add_definitions(-DFS_OPENXR_DEBUG)
|
||||
endif()
|
||||
|
||||
@@ -52,14 +48,11 @@ TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
target_link_libraries(code PUBLIC md5)
|
||||
|
||||
if (FSO_BUILD_WITH_DISCORD)
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
add_definitions(-DWITH_DISCORD)
|
||||
endif()
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
|
||||
target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
target_link_libraries(code PUBLIC pcpnatpmp)
|
||||
target_link_libraries(code PUBLIC pcp)
|
||||
|
||||
target_link_libraries(code PUBLIC parsers)
|
||||
|
||||
@@ -74,13 +67,19 @@ ENDIF(FSO_USE_SPEECH)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
|
||||
target_link_libraries(code PUBLIC variant)
|
||||
|
||||
target_link_libraries(code PUBLIC any)
|
||||
|
||||
target_link_libraries(code PUBLIC optional)
|
||||
|
||||
target_link_libraries(code PUBLIC anl)
|
||||
|
||||
target_link_libraries(code PUBLIC hidapi::hidapi)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
IF(FSO_BUILD_WITH_OPENXR)
|
||||
IF(NOT APPLE)
|
||||
target_link_libraries(code PUBLIC OpenXR::openxr_loader)
|
||||
target_include_directories(code PUBLIC OpenXR::Headers)
|
||||
ENDIF()
|
||||
@@ -140,4 +139,4 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[va
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
|
||||
|
||||
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
|
||||
suppress_file_warnings(scripting/lua/bitop/bit.c)
|
||||
suppress_file_warnings(scripting/lua/bitop/bit.c)
|
||||
@@ -30,7 +30,7 @@ class BuiltinActionDefinition : public ActionDefinition {
|
||||
// This should have been caught earlier
|
||||
Assertion(paramIter != parameterExpressions.cend(), "Could not find built-in parameter!");
|
||||
|
||||
return std::make_unique<TAction>(paramIter->second.template asTyped<ActionValueType>());
|
||||
return std::unique_ptr<Action>(new TAction(paramIter->second.template asTyped<ActionValueType>()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ expression::ProgramVariables getDefaultTableVariables()
|
||||
expression::ProgramVariables vars;
|
||||
|
||||
vars.setValue({"locals", "position"}, expression::Value(vmd_zero_vector));
|
||||
vars.setValue({"locals", "direction"}, expression::Value(vmd_z_vector));
|
||||
vars.setValue({"locals", "direction"}, expression::Value(vmd_zero_vector));
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType,
|
||||
|
||||
stuff_string(expressionText, F_NAME);
|
||||
|
||||
ExpressionParser parser(std::move(expressionText));
|
||||
ExpressionParser parser(expressionText);
|
||||
|
||||
auto expression = parser.parse(context);
|
||||
|
||||
@@ -45,7 +45,7 @@ ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType,
|
||||
}
|
||||
|
||||
// Everything is valid
|
||||
return ActionExpression(std::move(expression));
|
||||
return ActionExpression(expression);
|
||||
}
|
||||
|
||||
Value ActionExpression::execute(const ProgramVariables& variables) const
|
||||
|
||||
@@ -51,8 +51,8 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
operatorText = context->MINUS()->getText();
|
||||
}
|
||||
|
||||
const auto leftExpr = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0)));
|
||||
const auto rightExpr = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1)));
|
||||
const auto leftExpr = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
const auto rightExpr = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto operatorExpression = std::make_shared<nodes::FunctionCallExpression>(operatorTok,
|
||||
true,
|
||||
@@ -88,8 +88,8 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext* context) override
|
||||
{
|
||||
auto expression = std::make_shared<nodes::RandomRangeExpression>(context->RAND_L_PAREN()->getSymbol(),
|
||||
std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0))),
|
||||
std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1))));
|
||||
visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>(),
|
||||
visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>());
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext* context) override
|
||||
@@ -122,9 +122,9 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
}
|
||||
antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext* context) override
|
||||
{
|
||||
const auto xExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(0)));
|
||||
const auto yExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(1)));
|
||||
const auto zExpression = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(visit(context->expression(2)));
|
||||
auto xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto zExpression = visit(context->expression(2)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto expression = std::make_shared<nodes::VectorConstructorExpression>(context->L_PAREN()->getSymbol(),
|
||||
xExpression,
|
||||
@@ -157,7 +157,7 @@ std::shared_ptr<nodes::AbstractExpression> ExpressionParser::parse(const ParseCo
|
||||
if (errListener.diagnostics.empty()) {
|
||||
// Only do semantic checking if syntax is valid
|
||||
ExpressionBuilderVisitor builder;
|
||||
exprReturn = std::any_cast<std::shared_ptr<nodes::AbstractExpression>>(tree->accept(&builder));
|
||||
exprReturn = tree->accept(&builder).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
if (!exprReturn->validate(&parser, context)) {
|
||||
exprReturn = nullptr;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace expression {
|
||||
|
||||
ProgramVariablesDefinition& ProgramVariablesDefinition::addScope(const SCP_string& name)
|
||||
{
|
||||
auto scope = std::make_unique<ProgramVariablesDefinition>();
|
||||
auto scope = std::unique_ptr<ProgramVariablesDefinition>(new ProgramVariablesDefinition());
|
||||
|
||||
auto scopePtr = scope.get();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <variant>
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
@@ -85,10 +85,10 @@ class Value {
|
||||
|
||||
if (currentType == expectedType) {
|
||||
// No conversion necessary
|
||||
return std::get<T>(m_value);
|
||||
return mpark::get<T>(m_value);
|
||||
}
|
||||
|
||||
return std::visit(detail::implicit_conversion<T>{}, m_value);
|
||||
return mpark::visit(detail::implicit_conversion<T>{}, m_value);
|
||||
}
|
||||
|
||||
friend bool operator==(const Value& lhs, const Value& rhs);
|
||||
@@ -97,7 +97,7 @@ class Value {
|
||||
friend std::ostream& operator<<(std::ostream& os, const Value& value);
|
||||
|
||||
private:
|
||||
std::variant<std::monostate, int, float, vec3d, SCP_string> m_value;
|
||||
mpark::variant<mpark::monostate, int, float, vec3d, SCP_string> m_value;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
|
||||
@@ -26,8 +26,10 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
// The calling code should ensure that this never happens
|
||||
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
|
||||
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
const auto destinationSubObject = m_subObjectExpression.execute(locals.variables);
|
||||
@@ -55,7 +57,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
|
||||
// We need to do a linear search for the right subobject
|
||||
for (int i = 0; i < pm->n_models; ++i) {
|
||||
const auto& submodel = pm->submodel[i];
|
||||
const auto submodel = pm->submodel[i];
|
||||
|
||||
if (subsystem_stricmp(destinationSubObject.c_str(), submodel.name) == 0) {
|
||||
// Found something!
|
||||
@@ -70,7 +72,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
|
||||
std::unique_ptr<Action> MoveToSubmodel::clone() const
|
||||
{
|
||||
return std::make_unique<MoveToSubmodel>(*this);
|
||||
return std::unique_ptr<Action>(new MoveToSubmodel(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "math/vecmat.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "particle/hosts/EffectHostObject.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
#include <utility>
|
||||
@@ -39,8 +37,10 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
@@ -58,18 +58,18 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
|
||||
matrix orientation;
|
||||
vm_vector_2_matrix_norm(&orientation, &direction); // direction is normalized in SetDirectionAction::execute
|
||||
|
||||
source->setHost(std::make_unique<EffectHostObject>(locals.host.objp(), local_pos, orientation, true));
|
||||
source->finishCreation();
|
||||
source.moveToObject(locals.host.objp, &local_pos);
|
||||
source.setOrientationFromNormalizedVec(&direction, true);
|
||||
|
||||
source.finish();
|
||||
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> ParticleEffectAction::clone() const
|
||||
{
|
||||
return std::make_unique<ParticleEffectAction>(*this);
|
||||
return std::unique_ptr<Action>(new ParticleEffectAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
@@ -26,8 +26,10 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
@@ -45,8 +47,8 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
vec3d global_pos;
|
||||
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp()->orient);
|
||||
global_pos += locals.host.objp()->pos;
|
||||
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
|
||||
global_pos += locals.host.objp->pos;
|
||||
|
||||
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
|
||||
|
||||
@@ -57,7 +59,7 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
}
|
||||
std::unique_ptr<Action> PlaySoundAction::clone() const
|
||||
{
|
||||
return std::make_unique<PlaySoundAction>(*this);
|
||||
return std::unique_ptr<Action>(new PlaySoundAction(*this));
|
||||
}
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -32,7 +32,7 @@ ActionResult SetDirectionAction::execute(ProgramLocals& locals) const
|
||||
|
||||
std::unique_ptr<Action> SetDirectionAction::clone() const
|
||||
{
|
||||
return std::make_unique<SetDirectionAction>(*this);
|
||||
return std::unique_ptr<Action>(new SetDirectionAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
|
||||
@@ -27,7 +27,7 @@ ActionResult SetPositionAction::execute(ProgramLocals& locals) const
|
||||
|
||||
std::unique_ptr<Action> SetPositionAction::clone() const
|
||||
{
|
||||
return std::make_unique<SetPositionAction>(*this);
|
||||
return std::unique_ptr<Action>(new SetPositionAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
|
||||
@@ -41,7 +41,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
}
|
||||
std::unique_ptr<Action> WaitAction::clone() const
|
||||
{
|
||||
return std::make_unique<WaitAction>(*this);
|
||||
return std::unique_ptr<Action>(new WaitAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
|
||||
+14
-17
@@ -36,13 +36,12 @@ typedef struct ai_flag_name {
|
||||
|
||||
typedef struct ai_flag_description {
|
||||
AI::AI_Flags flag;
|
||||
const char *flag_desc;
|
||||
SCP_string flag_desc;
|
||||
} ai_flag_description;
|
||||
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
extern ai_flag_description Ai_flag_descriptions[];
|
||||
extern const int Num_ai_flag_names;
|
||||
extern const size_t Num_ai_flag_descriptions;
|
||||
|
||||
// dock_orient_and_approach() modes.
|
||||
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
|
||||
@@ -97,7 +96,6 @@ extern const size_t Num_ai_flag_descriptions;
|
||||
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
#define AI_ACTIVE_GOAL_NONE -1
|
||||
#define AI_ACTIVE_GOAL_DYNAMIC 999
|
||||
|
||||
typedef struct ai_class {
|
||||
@@ -278,8 +276,8 @@ typedef struct ai_info {
|
||||
int ai_class; // Class. Might be override of default.
|
||||
|
||||
// Probably become obsolete, to be replaced by path_start, path_cur, etc.
|
||||
int wp_list_index; // index of waypoint list being followed
|
||||
int wp_index; // index of waypoint in list
|
||||
waypoint_list *wp_list; // waypoint list being followed
|
||||
int wp_index; // waypoint index in list
|
||||
int wp_flags; // waypoint flags, see WPF_xxxx
|
||||
int waypoint_speed_cap; // -1 no cap, otherwise cap - changed to int by Goober5000
|
||||
|
||||
@@ -319,7 +317,7 @@ typedef struct ai_info {
|
||||
//Unlike the predicted position stuff, also takes into account velocity
|
||||
//Only used against small ships
|
||||
fix next_aim_pos_time;
|
||||
vec3d last_aim_enemy_pos; // Normally this is the position of the enemy a turret is targeting but in the F3 Lab, this is used to pass raw target coordinates to the turret firing methods.
|
||||
vec3d last_aim_enemy_pos;
|
||||
vec3d last_aim_enemy_vel;
|
||||
|
||||
ai_goal goals[MAX_AI_GOALS];
|
||||
@@ -331,7 +329,7 @@ typedef struct ai_info {
|
||||
float time_enemy_near; // SUSHI: amount of time enemy continuously "near" the player
|
||||
fix last_attack_time; // Missiontime of last time this ship attacked its enemy.
|
||||
fix last_hit_time; // Missiontime of last time this ship was hit by anyone.
|
||||
int danger_shield_quadrant; // Shield section AI will prefer to prioritize for recharging, it if possible.
|
||||
int last_hit_quadrant; // Shield section of last hit.
|
||||
fix last_hit_target_time; // Missiontime of last time this ship successfully hit target.
|
||||
int hitter_objnum; // Object index of ship that hit this ship last time.
|
||||
int hitter_signature; // Signature of hitter. Prevents stupidity if hitter gets killed.
|
||||
@@ -486,7 +484,7 @@ typedef struct {
|
||||
#define SUBSYS_PATH_DIST 500.0f
|
||||
|
||||
// Friendly damage defines
|
||||
#define MAX_BURST_DAMAGE 20.0f // max damage that can be done in BURST_DURATION
|
||||
#define MAX_BURST_DAMAGE 20 // max damage that can be done in BURST_DURATION
|
||||
#define BURST_DURATION 500 // decay time over which Player->damage_this_burst falls from MAX_BURST_DAMAGE to 0
|
||||
|
||||
extern int Mission_all_attack; // !0 means all teams attack all teams.
|
||||
@@ -528,15 +526,15 @@ const char *ai_get_goal_target_name(const char *name, int *index);
|
||||
void ai_clear_goal_target_names();
|
||||
|
||||
extern void init_ai_system(void);
|
||||
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1, int class_type = -1);
|
||||
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1);
|
||||
extern void ai_evade_object(object *evader, object *evaded);
|
||||
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
|
||||
extern void ai_ignore_wing(object *ignorer, int wingnum);
|
||||
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, int wl_index, int wp_flags, int start_index, bool force = false);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, const vec3d *hit_normal);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
|
||||
extern void ai_turn_towards_vector(const vec3d *dest, object *objp, const vec3d *slide_vec, const vec3d *rel_pos, float bank_override, int flags, const vec3d *rvec = nullptr, const vec3d* turnrate_mod = nullptr);
|
||||
@@ -560,7 +558,7 @@ extern void ai_set_guard_wing(object *objp, int wingnum);
|
||||
extern void ai_warp_out(object *objp, vec3d *vp);
|
||||
extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info* aip, int objnum);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
@@ -597,14 +595,13 @@ extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
|
||||
|
||||
extern int is_instructor(object *objp);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1, int class_type = -1);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
|
||||
|
||||
float ai_get_weapon_speed(const ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
|
||||
// function to change rearm status for ai ships (called from sexpression code)
|
||||
extern void ai_set_good_rearm_time( int team, int time );
|
||||
extern void ai_set_bad_rearm_time(int team, int time);
|
||||
extern void ai_set_rearm_status( int team, int new_status );
|
||||
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, const char *shipname );
|
||||
|
||||
extern void ai_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
|
||||
@@ -618,7 +615,7 @@ extern float dock_orient_and_approach(object *docker_objp, int docker_index, obj
|
||||
void ai_set_mode_warp_out(object *objp, ai_info *aip);
|
||||
|
||||
// prototyped by Goober5000
|
||||
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index, int class_type = -1);
|
||||
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index);
|
||||
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
@@ -637,6 +634,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
|
||||
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
|
||||
|
||||
|
||||
bool test_line_of_sight(const vec3d* from, const vec3d* to, SCP_unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
|
||||
#endif
|
||||
+4
-35
@@ -32,8 +32,6 @@ namespace AI {
|
||||
Unload_primaries, // Fire primaries as fast as possible!
|
||||
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
|
||||
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
|
||||
Waypoints_no_formation, // wont get into formation when running waypoints as part of a wing
|
||||
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -43,16 +41,13 @@ namespace AI {
|
||||
Dockee_index_valid, // when set, index field for dockee is valid
|
||||
Goal_on_hold, // when set, this goal cannot currently be satisfied, although it could be in the future
|
||||
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
|
||||
Goal_override, // paired with ai_goal_type::DYNAMIC to mean this goal overrides any other goal
|
||||
Want_override, // a goal should set this flag if Goal_override should be assigned when the goal is achievable
|
||||
Goal_override, // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
|
||||
Purge, // purge this goal next time we process
|
||||
Purge_when_new_goal_added, // this goal is perpetual until any other goal is added, at which time it sets its own Purge flag
|
||||
Goals_purged, // this goal has already caused other goals to get purged (because it is something like ai-disarm that renders other goals invalid)
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team, // this attack goal is allowed to target friendlies
|
||||
Afterburn_hard, // afterburn as hard as possible to the goal
|
||||
Waypoints_in_reverse, // decrement instead of increment
|
||||
Clear_all_goals_first, // this goal wipes all goals (including itself) before it runs (handled separately, and in a different place, from purging invalid goals)
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -104,10 +99,6 @@ namespace AI {
|
||||
Fix_heat_seeker_stealth_bug,
|
||||
Fix_linked_primary_bug,
|
||||
Fix_ramming_stationary_targets_bug,
|
||||
Fix_avoid_shockwave_bugs, // a) waiting until a homing weapon actually homes before evading;
|
||||
// b) picking the correct expected impact position for capships;
|
||||
// c) not clearing shockwave_object for ships;
|
||||
// d) checking the explosion damage of the correct ship
|
||||
Force_beam_turret_fov,
|
||||
Free_afterburner_use,
|
||||
Glide_decay_requires_thrust,
|
||||
@@ -132,7 +123,6 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turret_tagged_only_targeting,
|
||||
Ships_intercept_mines, // all AI-controlled ships autonomously engage hostile mines within mine_targetable_range of themselves
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
@@ -145,12 +135,10 @@ namespace AI {
|
||||
All_nonshielded_ships_can_manage_ets,
|
||||
Fightercraft_nonshielded_ships_can_manage_ets,
|
||||
Ships_playing_dead_dont_manage_ets,
|
||||
Better_combat_collision_avoidance,
|
||||
Better_combat_collision_avoid_includes_target,
|
||||
Better_guard_collision_avoidance,
|
||||
Better_collision_avoidance,
|
||||
Require_exact_los,
|
||||
Improved_missile_avoidance,
|
||||
Unify_usage_countermeasure_firechance,
|
||||
Friendlies_use_countermeasure_firechance,
|
||||
Improved_subsystem_attack_pathing,
|
||||
Fixed_ship_weapon_collision,
|
||||
No_shield_damage_from_ship_collisions,
|
||||
@@ -172,25 +160,6 @@ namespace AI {
|
||||
Player_orders_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
Align_to_target_when_guarding_still,
|
||||
Debris_respects_big_damage,
|
||||
Dont_limit_change_in_speed_due_to_physics_whack,
|
||||
Guards_ignore_protected_attackers,
|
||||
Fix_standard_strafe,
|
||||
Standard_strafe_used_more,
|
||||
Unify_usage_ai_shield_manage_delay,
|
||||
Fix_AI_shield_management_bug,
|
||||
AI_balances_shields_when_attacked,
|
||||
Disable_ai_transferring_energy,
|
||||
Freespace_1_missile_behavior,
|
||||
ETS_uses_power_output,
|
||||
ETS_energy_same_regardless_of_system_presence,
|
||||
Dont_form_on_wing_at_mission_start,
|
||||
Do_not_clear_goals_when_running_form_on_wing,
|
||||
Do_not_clear_goals_when_running_stay_still,
|
||||
Do_not_set_override_when_assigning_form_on_wing,
|
||||
Purge_player_issued_form_on_wing_after_subsequent_order,
|
||||
Cancel_future_waves_of_any_wing_launched_from_an_exited_ship,
|
||||
Fix_ignore_if_dead_flag,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+8
-160
@@ -42,7 +42,6 @@ void set_flag(ai_profile_t *profile, const char *name, AI::Profile_Flags flag)
|
||||
const char *AI_path_types[] = {
|
||||
"normal",
|
||||
"alt1",
|
||||
"alt2",
|
||||
};
|
||||
|
||||
int Num_ai_path_types = sizeof(AI_path_types)/sizeof(char*);
|
||||
@@ -185,14 +184,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
if (optional_string("$Max Beam Friendly Fire Damage:"))
|
||||
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Max Weapon Friendly Fire Damage:")) {
|
||||
parse_float_list(profile->weapon_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Max Weapon Self Damage:")) {
|
||||
parse_float_list(profile->weapon_self_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Player Countermeasure Life Scale:"))
|
||||
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
@@ -378,7 +369,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
|
||||
if (optional_string("$Detail Distance Multiplier:"))
|
||||
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_VALUE + 1);
|
||||
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1);
|
||||
|
||||
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships);
|
||||
|
||||
@@ -478,25 +469,12 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$support don't add primaries:", AI::Profile_Flags::Support_dont_add_primaries);
|
||||
|
||||
if (optional_string("$max allies rearming threshold:"))
|
||||
stuff_int(&profile->max_allies_rearming_threshold);
|
||||
|
||||
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
|
||||
if (optional_string("$exact los minimum detection radius:")) {
|
||||
stuff_float(&profile->los_min_detection_radius);
|
||||
}
|
||||
|
||||
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$debris damage respects 'big damage' flag:", AI::Profile_Flags::Debris_respects_big_damage);
|
||||
|
||||
set_flag(profile, "$don't limit change in speed due to physics whack:", AI::Profile_Flags::Dont_limit_change_in_speed_due_to_physics_whack);
|
||||
|
||||
set_flag(profile, "$guards ignore protected attackers:", AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
|
||||
if (optional_string("$ai path mode:"))
|
||||
{
|
||||
stuff_string(buf, F_NAME, NAME_LENGTH);
|
||||
@@ -586,27 +564,11 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
|
||||
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_combat_collision_avoidance);
|
||||
|
||||
if (optional_string("+combat collision avoidance aggression for fightercraft:")) {
|
||||
stuff_float(&profile->better_collision_avoid_aggression_combat);
|
||||
}
|
||||
|
||||
set_flag(profile, "+combat collision avoidance for fightercraft includes target:", AI::Profile_Flags::Better_combat_collision_avoid_includes_target);
|
||||
|
||||
set_flag(profile, "$better guard collision avoidance for fightercraft:", AI::Profile_Flags::Better_guard_collision_avoidance);
|
||||
|
||||
if (optional_string("+guard collision avoidance aggression for fightercraft:")) {
|
||||
stuff_float(&profile->better_collision_avoid_aggression_guard);
|
||||
}
|
||||
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
|
||||
|
||||
set_flag(profile, "$improved missile avoidance for fightercraft:", AI::Profile_Flags::Improved_missile_avoidance);
|
||||
|
||||
if (optional_string_either("$friendly ships use AI profile countermeasure chance:", "$unify usage of AI profile countermeasure chance:", true) >= 0) {
|
||||
bool val;
|
||||
stuff_boolean(&val);
|
||||
profile->flags.set(AI::Profile_Flags::Unify_usage_countermeasure_firechance, val);
|
||||
}
|
||||
set_flag(profile, "$friendly ships use AI profile countermeasure chance:", AI::Profile_Flags::Friendlies_use_countermeasure_firechance);
|
||||
|
||||
set_flag(profile, "$improved subsystem attack pathing:", AI::Profile_Flags::Improved_subsystem_attack_pathing);
|
||||
|
||||
@@ -669,96 +631,13 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
|
||||
|
||||
if (optional_string("$rotation factor multiplier for player collisions:")) {
|
||||
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
|
||||
}
|
||||
|
||||
set_flag(profile, "$fix avoid-shockwave bugs:", AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
|
||||
set_flag(profile, "$fix standard strafe:", AI::Profile_Flags::Fix_standard_strafe);
|
||||
|
||||
set_flag(profile, "$standard strafe used more:", AI::Profile_Flags::Standard_strafe_used_more);
|
||||
|
||||
if (optional_string("$standard strafe triggers under this speed:")) {
|
||||
stuff_float(&profile->standard_strafe_when_below_speed);
|
||||
}
|
||||
|
||||
if (optional_string("$strafe distance from target bounding box:")) {
|
||||
stuff_float(&profile->strafe_retreat_box_dist);
|
||||
}
|
||||
|
||||
if (optional_string("$strafe stops after time unhit:")) {
|
||||
stuff_float(&profile->strafe_max_unhit_time);
|
||||
}
|
||||
|
||||
if (optional_string("$guard uses big-orbit for target radius above:")) {
|
||||
stuff_float(&profile->guard_big_orbit_above_target_radius);
|
||||
}
|
||||
|
||||
if (optional_string("$guard with big-orbit uses max speed percent:")) {
|
||||
float max_percent;
|
||||
stuff_float(&max_percent);
|
||||
if (max_percent > 0.0f && max_percent <= 1.0f) {
|
||||
profile->guard_big_orbit_max_speed_percent = max_percent;
|
||||
} else {
|
||||
mprintf(("Warning: \"$guard with big-orbit uses max speed percent:\" should be > 0 and <= 1 (read %f). Value will not be used.\n", max_percent));
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$attack-any idle circle distance:")) {
|
||||
stuff_float(&profile->attack_any_idle_circle_distance);
|
||||
}
|
||||
|
||||
set_flag(profile, "$unify usage of AI Shield Manage Delay:", AI::Profile_Flags::Unify_usage_ai_shield_manage_delay);
|
||||
|
||||
set_flag(profile, "$fix AI shield management bug:", AI::Profile_Flags::Fix_AI_shield_management_bug);
|
||||
|
||||
set_flag(profile, "$AI balances shields instead of directs when attacked:", AI::Profile_Flags::AI_balances_shields_when_attacked);
|
||||
|
||||
set_flag(profile, "$disable AI transferring energy:", AI::Profile_Flags::Disable_ai_transferring_energy);
|
||||
|
||||
set_flag(profile, "$enable freespace 1 style missile behavior:", AI::Profile_Flags::Freespace_1_missile_behavior);
|
||||
|
||||
set_flag(profile, "$ETS uses ship class power output:", AI::Profile_Flags::ETS_uses_power_output);
|
||||
|
||||
set_flag(profile, "$ETS energy same regardless of system presence:", AI::Profile_Flags::ETS_energy_same_regardless_of_system_presence);
|
||||
|
||||
set_flag(profile, "$don't issue form-on-wing goals at mission start:", AI::Profile_Flags::Dont_form_on_wing_at_mission_start);
|
||||
|
||||
if (optional_string("$default form-on-wing priority:")) {
|
||||
int priority;
|
||||
stuff_int(&priority);
|
||||
if (priority > 0) {
|
||||
profile->default_form_on_wing_priority = priority;
|
||||
} else {
|
||||
mprintf(("Warning: $default form-on-wing priority: should be > 0 (read %d). Value will not be used.\n", priority));
|
||||
}
|
||||
}
|
||||
|
||||
set_flag(profile, "$do not clear goals when running form-on-wing:", AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing);
|
||||
|
||||
set_flag(profile, "$do not clear goals when running stay-still:", AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still);
|
||||
|
||||
set_flag(profile, "$do not set override when assigning form-on-wing:", AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing);
|
||||
|
||||
set_flag(profile, "$purge player-issued form-on-wing after subsequent order:", AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order);
|
||||
|
||||
set_flag(profile, "$cancel future waves of any wing launched from an exited ship:", AI::Profile_Flags::Cancel_future_waves_of_any_wing_launched_from_an_exited_ship);
|
||||
|
||||
set_flag(profile, "$ships intercept mines:", AI::Profile_Flags::Ships_intercept_mines);
|
||||
|
||||
set_flag(profile, "$fix 'ignore if dead' flag:", AI::Profile_Flags::Fix_ignore_if_dead_flag);
|
||||
|
||||
|
||||
// end of options ----------------------------------------
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
char tmp[60];
|
||||
memset(tmp, 0, 60);
|
||||
strncpy(tmp, Mp, 59);
|
||||
mprintf(("WARNING: Unrecognized parameter in %s: %s\n", filename, tmp));
|
||||
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
|
||||
|
||||
Mp++;
|
||||
}
|
||||
@@ -817,7 +696,7 @@ void ai_profiles_init()
|
||||
Ai_profiles_initted = 1;
|
||||
}
|
||||
|
||||
int ai_profile_lookup(const char *name)
|
||||
int ai_profile_lookup(char *name)
|
||||
{
|
||||
for (int i = 0; i < Num_ai_profiles; i++)
|
||||
if (!stricmp(name, Ai_profiles[i].profile_name))
|
||||
@@ -832,7 +711,6 @@ void ai_profile_t::reset()
|
||||
|
||||
flags.reset();
|
||||
|
||||
los_min_detection_radius = 10.0f;
|
||||
ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
subsystem_path_radii = 0;
|
||||
bay_arrive_speed_mult = 1.0f;
|
||||
@@ -840,21 +718,6 @@ void ai_profile_t::reset()
|
||||
second_order_lead_predict_factor = 0;
|
||||
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
|
||||
turret_target_recheck_time = 2000.0f;
|
||||
rot_fac_multiplier_ply_collisions = 0.0f;
|
||||
max_allies_rearming_threshold = 2;
|
||||
|
||||
better_collision_avoid_aggression_combat = 3.5f;
|
||||
better_collision_avoid_aggression_guard = 3.5f;
|
||||
|
||||
standard_strafe_when_below_speed = 3.0f;
|
||||
strafe_retreat_box_dist = 300.0f;
|
||||
strafe_max_unhit_time = 20.0f;
|
||||
|
||||
guard_big_orbit_above_target_radius = 500.0f;
|
||||
guard_big_orbit_max_speed_percent = 1.0f;
|
||||
attack_any_idle_circle_distance = 100.0f;
|
||||
|
||||
default_form_on_wing_priority = 99; // as originally assigned in ai_add_goal_sub_sexp()
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
@@ -877,12 +740,10 @@ void ai_profile_t::reset()
|
||||
shield_energy_scale[i] = 0;
|
||||
afterburner_recharge_scale[i] = 0;
|
||||
player_damage_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
|
||||
subsys_damage_scale[i] = 0;
|
||||
beam_friendly_damage_cap[i] = -1.f;
|
||||
weapon_friendly_damage_cap[i] = -1.f;
|
||||
weapon_self_damage_cap[i] = -1.f;
|
||||
beam_friendly_damage_cap[i] = 0;
|
||||
turn_time_scale[i] = 0;
|
||||
glide_attack_percent[i] = 0;
|
||||
circle_strafe_percent[i] = 0;
|
||||
@@ -913,7 +774,7 @@ void ai_profile_t::reset()
|
||||
player_autoaim_fov[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= MAX_DETAIL_VALUE; ++i) {
|
||||
for (int i = 0; i <= MAX_DETAIL_LEVEL; ++i) {
|
||||
detail_distance_mult[i] = 0;
|
||||
}
|
||||
|
||||
@@ -962,17 +823,4 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
if (mod_supports_version(24, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Debris_respects_big_damage);
|
||||
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
|
||||
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
}
|
||||
if (mod_supports_version(25, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
flags.set(AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order);
|
||||
flags.set(AI::Profile_Flags::Cancel_future_waves_of_any_wing_launched_from_an_exited_ship);
|
||||
}
|
||||
if (mod_supports_version(26, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_ignore_if_dead_flag);
|
||||
}
|
||||
}
|
||||
+2
-37
@@ -17,7 +17,6 @@
|
||||
// AI Path types
|
||||
#define AI_PATH_MODE_NORMAL 0
|
||||
#define AI_PATH_MODE_ALT1 1
|
||||
#define AI_PATH_MODE_ALT2 2
|
||||
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
|
||||
@@ -58,8 +57,6 @@ public:
|
||||
|
||||
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
|
||||
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
|
||||
float weapon_friendly_damage_cap[NUM_SKILL_LEVELS];
|
||||
float weapon_self_damage_cap[NUM_SKILL_LEVELS];
|
||||
float turn_time_scale[NUM_SKILL_LEVELS]; // speed at which enemy ships turn
|
||||
float glide_attack_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "glide attack" move
|
||||
float circle_strafe_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "circle strafe" move
|
||||
@@ -100,13 +97,7 @@ public:
|
||||
// Player-specific autoaim FOV override
|
||||
float player_autoaim_fov[NUM_SKILL_LEVELS];
|
||||
|
||||
float detail_distance_mult[MAX_DETAIL_VALUE + 1]; //MAX_DETAIL_VALUE really needs to be 4
|
||||
|
||||
// max number of allies allowed to be rearming at the same time
|
||||
int max_allies_rearming_threshold;
|
||||
|
||||
// minimum radius for the line-of-sight (los) detection --wookieejedi
|
||||
float los_min_detection_radius;
|
||||
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
|
||||
|
||||
int ai_path_mode;
|
||||
|
||||
@@ -127,32 +118,6 @@ public:
|
||||
// how often turrets shoulds check for new targets, milliseconds
|
||||
float turret_target_recheck_time;
|
||||
|
||||
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
|
||||
float rot_fac_multiplier_ply_collisions;
|
||||
|
||||
// Collision avoidance options --developed by asteroth, exposed by wookieejedi
|
||||
// Velocity / turn rate gives us a vector which represents the minimum 'bug out' distance.
|
||||
// However this will be a significant underestimate, it doesn't take into account acceleration
|
||||
// with regards to its turn speed, nor already existing rotvel, nor the angular distance
|
||||
// to the particular avoidance vector it comes up with.
|
||||
// These would significantly complicate the calculation, so for now, it is all bundled into these magic numbers.
|
||||
float better_collision_avoid_aggression_combat;
|
||||
float better_collision_avoid_aggression_guard;
|
||||
|
||||
// AI strafing options --wookieejedi
|
||||
float standard_strafe_when_below_speed; // Speed at which standard strafing large ships is possibly triggered
|
||||
float strafe_retreat_box_dist; // Distance beyond the bounding box to retreat to strafing point
|
||||
float strafe_max_unhit_time; // Maximum amount of time to stay in strafe mode if not hit
|
||||
|
||||
// AI guard options --wookieejedi
|
||||
float guard_big_orbit_above_target_radius; // Radius of guardee that triggers ai_big_guard()
|
||||
float guard_big_orbit_max_speed_percent; // Max percent of forward speed that is used in ai_big_guard()
|
||||
|
||||
// AI attack any option --wookieejedi
|
||||
float attack_any_idle_circle_distance; // Radius that AI circles around a point while waiting for new enemies in attack-any mode
|
||||
|
||||
int default_form_on_wing_priority; // the priority used if not specified in the sexp
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
@@ -165,6 +130,6 @@ extern ai_profile_t Ai_profiles[MAX_AI_PROFILES];
|
||||
|
||||
void ai_profiles_init();
|
||||
|
||||
int ai_profile_lookup(const char *name);
|
||||
int ai_profile_lookup(char *name);
|
||||
|
||||
#endif
|
||||
+48
-72
@@ -39,9 +39,10 @@
|
||||
#define MIN_DOT_TO_ATTACK_MOVING_SUBSYS 0.97f
|
||||
|
||||
// AI BIG MAGIC NUMBERS
|
||||
// Select strafing options are now exposed to modders --wookieejedi
|
||||
#define STRAFE_RETREAT_COLLIDE_TIME 2.0 // when anticipated collision time is less than this, begin retreat
|
||||
#define STRAFE_RETREAT_COLLIDE_DIST 100 // when perpendicular distance to *surface* is less than this, begin retreat
|
||||
#define STRAFE_RETREAT_BOX_DIST 300 // distance beyond the bounding box to retreat
|
||||
#define STRAFE_MAX_UNHIT_TIME 20 // Maximum amount of time to stay in strafe mode if not hit
|
||||
|
||||
#define EVADE_BOX_BASE_DISTANCE 300 // standard distance to end evade submode
|
||||
#define EVADE_BOX_MIN_DISTANCE 200 // minimun distance to end evade submode, after long time
|
||||
@@ -62,12 +63,12 @@
|
||||
void ai_big_evade_ship();
|
||||
void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float dist_to_enemy, int modelnum);
|
||||
void ai_big_avoid_ship();
|
||||
bool ai_big_maybe_follow_subsys_path(bool do_dot_check=true);
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern void compute_desired_rvec(vec3d *rvec, const vec3d *goal_pos, const vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(const object *objp, const object *big_objp, const vec3d *collision_normal);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
|
||||
// Called by ai_big_pick_attack_point.
|
||||
@@ -146,10 +147,6 @@ done_1:
|
||||
|
||||
*attack_point = best_point;
|
||||
|
||||
//The following raycast tends to make up 10%(!) of total AI-frametime for basically no benefit, especially in the common case for turrets where the normal isn't even queried.
|
||||
if (surface_normal == nullptr && Disable_expensive_turret_target_check)
|
||||
return;
|
||||
|
||||
// Cast from attack_objp_pos to local_attack_pos and check for nearest collision.
|
||||
// If no collision, cast to (0,0,0) [center of big ship]** [best_point initialized to 000]
|
||||
|
||||
@@ -351,10 +348,10 @@ void ai_big_subsys_path_cleanup(ai_info *aip)
|
||||
}
|
||||
|
||||
// Maybe Pl_objp needs to follow a path to get in line-of-sight to a subsystem
|
||||
// input: do_dot_check => default value true, flag to indicate whether check should be done to ensure
|
||||
// input: do_dot_check => default value 0, flag to indicate whether check should be done to ensure
|
||||
// subsystem is within certain field of view. We don't want to check fov when
|
||||
// strafing, since ship is weaving to avoid turret fire
|
||||
bool ai_big_maybe_follow_subsys_path(bool do_dot_check)
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
{
|
||||
ai_info *aip;
|
||||
float dot = 1.0f, min_dot;
|
||||
@@ -722,21 +719,19 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since ship is moving slowly and attacking a large ship, scan if enemy fighters are near, if so
|
||||
// then enter strafe mode
|
||||
if ( ai_big_maybe_start_strafe(aip, sip) ) {
|
||||
aip->previous_mode = aip->mode;
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
ai_big_strafe_position();
|
||||
return;
|
||||
}
|
||||
|
||||
} // end if ( Pl_objp->phys_info.speed < 3.0f )
|
||||
|
||||
// if moving slowly and attacking a large ship,
|
||||
// check if need to enter standard strafe mode
|
||||
// including ai_profile flag and if enemy fighters are near
|
||||
if (Pl_objp->phys_info.speed < The_mission.ai_profile->standard_strafe_when_below_speed &&
|
||||
(The_mission.ai_profile->flags[AI::Profile_Flags::Standard_strafe_used_more] || ai_big_maybe_start_strafe(aip, sip))) {
|
||||
aip->previous_mode = aip->mode;
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
ai_big_strafe_position();
|
||||
return;
|
||||
}
|
||||
|
||||
//Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
|
||||
aip->previous_mode = aip->mode;
|
||||
@@ -868,7 +863,7 @@ void ai_big_chase_ct()
|
||||
extern bool ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
|
||||
extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst);
|
||||
extern bool ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern bool maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
|
||||
@@ -918,13 +913,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if ( !(En_objp->flags[Object::Object_Flags::Protected]) || ai_goal_is_disable_or_disarm(aip->goals[0].ai_mode) ) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if ( !(En_objp->flags[Object::Object_Flags::Protected]) || (ai_goal_is_disable_or_disarm(aip->goals[0].ai_mode) && swip->wi_flags[Weapon::Info_Flags::Puncture]) ) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
@@ -1420,7 +1415,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
|
||||
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
|
||||
// AIS_STRAFE_RETREAT
|
||||
static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
{
|
||||
ai_info *aip;
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
@@ -1428,54 +1423,37 @@ static bool ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
vec3d vec_to_target;
|
||||
vm_vec_sub(&vec_to_target, target_pos, &Pl_objp->pos);
|
||||
|
||||
float dist_to_target = vm_vec_mag(&vec_to_target);
|
||||
float dist_to_target, dist_normal_to_target, time_to_target;
|
||||
dist_to_target = vm_vec_mag_quick(&vec_to_target);
|
||||
if (vm_vec_mag_quick(&aip->big_attack_surface_normal) > 0.9) {
|
||||
dist_normal_to_target = -vm_vec_dot(&vec_to_target, &aip->big_attack_surface_normal);
|
||||
} else {
|
||||
dist_normal_to_target = 0.2f * vm_vec_mag_quick(&vec_to_target);
|
||||
}
|
||||
|
||||
dist_normal_to_target = MAX(0.2f*dist_to_target, dist_normal_to_target);
|
||||
time_to_target = dist_normal_to_target / Pl_objp->phys_info.speed;
|
||||
|
||||
// add distance penalty for going too fast
|
||||
float speed_to_dist_penalty = MAX(0.0f, (Pl_objp->phys_info.speed-50));
|
||||
|
||||
bool collide_time;
|
||||
bool collide_distance;
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_standard_strafe]) {
|
||||
// check if ship facing target, as likely will only collide if facing
|
||||
vec3d vec_to_tpos;
|
||||
vm_vec_normalized_dir(&vec_to_tpos, target_pos, &Pl_objp->pos);
|
||||
float dot = vm_vec_dot(&vec_to_tpos, &Pl_objp->orient.vec.fvec);
|
||||
if (dot <= 0.0f) {
|
||||
collide_time = false;
|
||||
collide_distance = false;
|
||||
} else {
|
||||
collide_time = (dist_to_target / Pl_objp->phys_info.speed) < STRAFE_RETREAT_COLLIDE_TIME;
|
||||
collide_distance = dist_to_target < (STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty);
|
||||
}
|
||||
} else {
|
||||
float dist_normal_to_target;
|
||||
if (vm_vec_mag(&aip->big_attack_surface_normal) > 0.9) {
|
||||
dist_normal_to_target =
|
||||
MAX(0.2f * dist_to_target, -vm_vec_dot(&vec_to_target, &aip->big_attack_surface_normal));
|
||||
} else {
|
||||
dist_normal_to_target = 0.2f * dist_to_target;
|
||||
}
|
||||
collide_time = (dist_normal_to_target / Pl_objp->phys_info.speed) < STRAFE_RETREAT_COLLIDE_TIME;
|
||||
collide_distance = dist_normal_to_target < (STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty);
|
||||
}
|
||||
|
||||
//if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f))
|
||||
|
||||
// Inside 2 sec retreat, setting goal point to box point + strafe_retreat_box_dist
|
||||
// Inside 2 sec retreat, setting goal point to box point + 300m
|
||||
// If collision, use std collision resolution.
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (collide_time) || (collide_distance)) ) {
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + strafe_retreat_box_dist
|
||||
// too close for comfort so fly to box point + 300
|
||||
aip->submode = AIS_STRAFE_RETREAT1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
int is_inside;
|
||||
vec3d goal_point;
|
||||
get_world_closest_box_point_with_delta(&goal_point, En_objp, &Pl_objp->pos, &is_inside, The_mission.ai_profile->strafe_retreat_box_dist);
|
||||
get_world_closest_box_point_with_delta(&goal_point, En_objp, &Pl_objp->pos, &is_inside, STRAFE_RETREAT_BOX_DIST);
|
||||
|
||||
// set goal point
|
||||
aip->goal_point = goal_point;
|
||||
@@ -1507,7 +1485,7 @@ void ai_big_strafe_attack()
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(false))
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
return;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
@@ -1590,7 +1568,8 @@ void ai_big_strafe_attack()
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
fix long_enough = fl2f(The_mission.ai_profile->strafe_max_unhit_time);
|
||||
fix long_enough;
|
||||
long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
|
||||
if ( (last_hit > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
|
||||
ai_big_switch_to_chase_mode(aip);
|
||||
}
|
||||
@@ -1627,7 +1606,7 @@ void ai_big_strafe_glide_attack()
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(false))
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
return;
|
||||
|
||||
//Gets a point on the target ship to attack, as well as distance and the angle between the nose of the attacker and that point.
|
||||
@@ -1637,11 +1616,11 @@ void ai_big_strafe_glide_attack()
|
||||
//If we haven't chosen the goal point yet, do so now
|
||||
if (aip->submode_parm1 == 0) {
|
||||
//Pick goal point. This should be a random point that passes through the circle whose normal is the vector between attacker and target
|
||||
vec3d targetToAttackerDir;
|
||||
vm_vec_normalized_dir(&targetToAttackerDir, &Pl_objp->pos, &target_objp->pos);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix_norm(&orient, &targetToAttackerDir, nullptr, nullptr);
|
||||
vec3d targetToAttacker;
|
||||
vec3d tangentPoint;
|
||||
vm_vec_sub(&targetToAttacker, &Pl_objp->pos, &target_objp->pos);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix(&orient, &targetToAttacker, NULL, NULL);
|
||||
vm_vec_random_in_circle(&tangentPoint, &target_objp->pos, &orient, target_objp->radius + GLIDE_STRAFE_DISTANCE, true);
|
||||
//Get tangent point in coords relative to ship, scale it up so the actual goal point is far away, then put back in world coords
|
||||
vm_vec_sub2(&tangentPoint, &Pl_objp->pos);
|
||||
@@ -1662,7 +1641,7 @@ void ai_big_strafe_glide_attack()
|
||||
//Keep going until we are too far away.
|
||||
//If we are still on approach but too far away, this will still trigger. This will allow us to reposition the target
|
||||
//point and allow for a "jinking" effect.
|
||||
if (target_ship_dist > (The_mission.ai_profile->strafe_retreat_box_dist + target_objp->radius) &&
|
||||
if (target_ship_dist > (STRAFE_RETREAT_BOX_DIST + target_objp->radius) &&
|
||||
Missiontime - aip->submode_start_time > i2f(GLIDE_STRAFE_MIN_TIME)) {
|
||||
//This checks whether we are moving toward the target or away from it. If moving towards, we reset the stage so that we
|
||||
//pick a new attack vector (jinking). If moving away, we're at the end of a run so do a full reset (possibly allowing a
|
||||
@@ -1712,7 +1691,7 @@ void ai_big_strafe_glide_attack()
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
// (same as ai_big_strafe_attack)
|
||||
fix long_enough = fl2f(The_mission.ai_profile->strafe_max_unhit_time);
|
||||
fix long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
|
||||
if ( (Missiontime - aip->last_hit_time > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
|
||||
ai_big_switch_to_chase_mode(aip);
|
||||
}
|
||||
@@ -1908,7 +1887,7 @@ void ai_big_strafe()
|
||||
{
|
||||
//Re-roll for random sidethrust every 2 seconds
|
||||
if (static_randf((Missiontime + static_rand(aip->shipnum)) >> 17) < aip->ai_random_sidethrust_percent) {
|
||||
do_random_sidethrust(aip, &Ship_info[Ships[aip->shipnum].ship_info_index]);
|
||||
do_random_sidethrust(aip, &Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1954,10 +1933,7 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
weapon_objp = &Objects[weapon_objnum];
|
||||
Assert(weapon_objp->type == OBJ_WEAPON);
|
||||
|
||||
if (weapon_objp->parent < 0) {
|
||||
return 0;
|
||||
}
|
||||
Assert(weapon_objp->parent < MAX_OBJECTS);
|
||||
Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
|
||||
parent_objp = &Objects[weapon_objp->parent];
|
||||
if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
|
||||
return 0;
|
||||
|
||||
+193
-595
File diff suppressed because it is too large.
Load diff
+208
-423
File diff suppressed because it is too large.
Load diff
+74
-85
@@ -24,88 +24,81 @@ struct ai_info;
|
||||
|
||||
// macros for goals which get set via sexpressions in the mission code
|
||||
|
||||
// types of ai goals -- these will help us to determine which goals should
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
enum class ai_goal_type
|
||||
{
|
||||
INVALID = 0,
|
||||
EVENT_SHIP, // from mission event direct to ship
|
||||
EVENT_WING, // from mission event direct to wing
|
||||
PLAYER_SHIP, // from player direct to ship
|
||||
PLAYER_WING, // from player direct to wing
|
||||
DYNAMIC // created on the fly
|
||||
};
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x enum, be sure to update the functions
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x define, be sure to update the functions
|
||||
// ai_update_goal_references() and query_referenced_in_ai_goals() or else risk breaking
|
||||
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
|
||||
// to worry about doing this. Also add it to list in Fred\Management.cpp, and let Hoffoss know!
|
||||
// WMC - Oh and add them to Ai_goal_names plz. TY! :)
|
||||
// Goober5000 - As well as Ai_goal_text and Ai_goal_list, if appropriate
|
||||
enum ai_goal_mode : uint8_t
|
||||
{
|
||||
AI_GOAL_NONE = 0,
|
||||
AI_GOAL_SCHROEDINGER, // used for FRED when multiple ships are selected with different orders
|
||||
#define AI_GOAL_CHASE (1<<1) // 0x00000002
|
||||
#define AI_GOAL_DOCK (1<<2) // 0x00000004 // used for undocking as well
|
||||
#define AI_GOAL_WAYPOINTS (1<<3) // 0x00000008
|
||||
#define AI_GOAL_WAYPOINTS_ONCE (1<<4) // 0x00000010
|
||||
#define AI_GOAL_WARP (1<<5) // 0x00000020
|
||||
#define AI_GOAL_DESTROY_SUBSYSTEM (1<<6) // 0x00000040
|
||||
#define AI_GOAL_FORM_ON_WING (1<<7) // 0x00000080
|
||||
#define AI_GOAL_UNDOCK (1<<8) // 0x00000100
|
||||
#define AI_GOAL_CHASE_WING (1<<9) // 0x00000200
|
||||
#define AI_GOAL_GUARD (1<<10) // 0x00000400
|
||||
#define AI_GOAL_DISABLE_SHIP (1<<11) // 0x00000800
|
||||
#define AI_GOAL_DISARM_SHIP (1<<12) // 0x00001000
|
||||
#define AI_GOAL_CHASE_ANY (1<<13) // 0x00002000
|
||||
#define AI_GOAL_IGNORE (1<<14) // 0x00004000
|
||||
#define AI_GOAL_GUARD_WING (1<<15) // 0x00008000
|
||||
#define AI_GOAL_EVADE_SHIP (1<<16) // 0x00010000
|
||||
|
||||
AI_GOAL_CHASE,
|
||||
AI_GOAL_DOCK, // used for undocking as well
|
||||
AI_GOAL_WAYPOINTS,
|
||||
AI_GOAL_WAYPOINTS_ONCE,
|
||||
AI_GOAL_WARP,
|
||||
AI_GOAL_DESTROY_SUBSYSTEM,
|
||||
AI_GOAL_FORM_ON_WING,
|
||||
AI_GOAL_UNDOCK,
|
||||
AI_GOAL_CHASE_WING,
|
||||
AI_GOAL_GUARD,
|
||||
AI_GOAL_DISABLE_SHIP,
|
||||
AI_GOAL_DISARM_SHIP,
|
||||
AI_GOAL_CHASE_ANY,
|
||||
AI_GOAL_IGNORE,
|
||||
AI_GOAL_GUARD_WING,
|
||||
AI_GOAL_EVADE_SHIP,
|
||||
// the next goals are for support ships only
|
||||
#define AI_GOAL_STAY_NEAR_SHIP (1<<17) // 0x00020000
|
||||
#define AI_GOAL_KEEP_SAFE_DISTANCE (1<<18) // 0x00040000
|
||||
#define AI_GOAL_REARM_REPAIR (1<<19) // 0x00080000
|
||||
|
||||
// the next goals are for support ships only
|
||||
AI_GOAL_STAY_NEAR_SHIP,
|
||||
AI_GOAL_KEEP_SAFE_DISTANCE,
|
||||
AI_GOAL_REARM_REPAIR,
|
||||
// resume regular goals
|
||||
#define AI_GOAL_STAY_STILL (1<<20) // 0x00100000
|
||||
#define AI_GOAL_PLAY_DEAD (1<<21) // 0x00200000
|
||||
|
||||
// resume regular goals
|
||||
AI_GOAL_STAY_STILL,
|
||||
AI_GOAL_PLAY_DEAD,
|
||||
// added by SCP
|
||||
#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
|
||||
// added by SCP
|
||||
AI_GOAL_CHASE_WEAPON,
|
||||
AI_GOAL_FLY_TO_SHIP,
|
||||
AI_GOAL_IGNORE_NEW,
|
||||
AI_GOAL_CHASE_SHIP_CLASS,
|
||||
AI_GOAL_CHASE_SHIP_TYPE,
|
||||
AI_GOAL_PLAY_DEAD_PERSISTENT, // Disables subsystem rotation/translation among other things but there is a carveout for that in the lab in ship_move_subsystems() and ai_process_subobjects()
|
||||
AI_GOAL_LUA,
|
||||
AI_GOAL_DISARM_SHIP_TACTICAL,
|
||||
AI_GOAL_DISABLE_SHIP_TACTICAL,
|
||||
// now the masks for ship types
|
||||
|
||||
AI_GOAL_NUM_VALUES
|
||||
};
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_FREIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CRUISER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FREIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CORVETTE ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_GAS_MINER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_AWACS ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CAPITAL ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER & ~(AI_GOAL_DOCK | AI_GOAL_UNDOCK) | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPERCAP ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CAPITAL | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT )
|
||||
#define AI_GOAL_ACCEPT_ESCAPEPOD ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT| AI_GOAL_STAY_NEAR_SHIP )
|
||||
*/
|
||||
|
||||
inline ai_goal_mode int_to_ai_goal_mode(int int_mode)
|
||||
{
|
||||
if (int_mode >= 0 && int_mode < AI_GOAL_NUM_VALUES)
|
||||
return static_cast<ai_goal_mode>(int_mode);
|
||||
|
||||
Warning(LOCATION, "ai_goal_mode %d out of range! Setting to AI_GOAL_NONE.", int_mode);
|
||||
return AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
inline bool ai_goal_is_disable_or_disarm(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_DISABLE_SHIP || ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL || ai_mode == AI_GOAL_DISARM_SHIP || ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
}
|
||||
inline bool ai_goal_is_specific_chase(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_CHASE || ai_mode == AI_GOAL_CHASE_WING || ai_mode == AI_GOAL_CHASE_SHIP_CLASS || ai_mode == AI_GOAL_CHASE_SHIP_TYPE;
|
||||
}
|
||||
#define MAX_AI_DOCK_NAMES 25
|
||||
|
||||
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
|
||||
|
||||
@@ -117,16 +110,16 @@ struct ai_lua_parameters {
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
ai_goal_mode ai_mode; // one of the AI_GOAL_* modes for this goal
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
ai_goal_type type; // one of the ai_goal_type (originally AIG_TYPE_*) values above
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
int wp_list_index; // waypoints that this ship might fly.
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
@@ -151,22 +144,18 @@ typedef struct ai_goal {
|
||||
|
||||
} ai_goal;
|
||||
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, ai_goal_mode ai_mode = AI_GOAL_NONE, int ai_submode = -1, ai_goal_type type = ai_goal_type::INVALID);
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, int ai_mode = AI_GOAL_NONE, int ai_submode = -1, int type = -1);
|
||||
|
||||
// Reset all path points. Used in the ship lab. Missions clean up path points with the garbage collector in garbage_collect_path_points()
|
||||
extern void reset_ai_path_points();
|
||||
|
||||
typedef flag_def_list_templated<ai_goal_mode> ai_goal_list;
|
||||
typedef flag_def_list ai_goal_list;
|
||||
|
||||
extern ai_goal_list Ai_goal_names[];
|
||||
extern int Num_ai_goals;
|
||||
|
||||
#define MAX_AI_DOCK_NAMES 25
|
||||
|
||||
extern int Num_ai_dock_names;
|
||||
extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
extern const char *Ai_goal_text(ai_goal_mode goal, int submode);
|
||||
extern const char *Ai_goal_text(int goal, int submode);
|
||||
|
||||
// every goal in a mission gets a unique signature
|
||||
extern int Ai_goal_signature;
|
||||
@@ -179,17 +168,17 @@ extern void ai_process_mission_orders( int objnum, ai_info *aip );
|
||||
extern int ai_goal_num(ai_goal *goals);
|
||||
|
||||
// adds goals to ships/wing through sexpressions
|
||||
extern void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data);
|
||||
extern void ai_add_ship_goal_sexp(int sexp, ai_goal_type type, ai_info *aip);
|
||||
extern void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp);
|
||||
extern void ai_add_goal_sub_sexp(int sexp, ai_goal_type type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, wing *wingp );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more );
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
|
||||
|
||||
// adds goals to ships/sings through player orders
|
||||
extern void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, ai_info* aip, int int_data = 0, float float_data = 0.0f, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, int wingnum, int int_data = 0, float float_data = 0.0f, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_ship_goal_player(int type, int mode, int submode, const char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(int type, int mode, int submode, const char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
|
||||
extern void ai_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
@@ -204,7 +193,7 @@ extern void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const
|
||||
extern bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name);
|
||||
extern char *ai_add_dock_name(const char *str);
|
||||
|
||||
extern int ai_query_goal_valid( int ship, ai_goal_mode ai_mode );
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
extern void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate = 1 );
|
||||
|
||||
|
||||
+166
-288
@@ -6,7 +6,6 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "freespace.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "iff_defs/iff_defs.h"
|
||||
@@ -26,7 +25,6 @@
|
||||
#include "weapon/muzzleflash.h"
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
#include "utils/modular_curves.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
@@ -135,7 +133,7 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
|
||||
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
break;
|
||||
case OBJ_ASTEROID:
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
|
||||
break;
|
||||
default:
|
||||
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
|
||||
@@ -479,12 +477,6 @@ int valid_turret_enemy(object *objp, object *turret_parent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mines are only targetable within their configured detection range
|
||||
if (wip->is_mine()) {
|
||||
if (vm_vec_dist(&objp->pos, &turret_parent->pos) > wip->mine_targetable_range)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1095,11 +1087,9 @@ int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d
|
||||
int target_objnum = aip->target_objnum;
|
||||
|
||||
if (Objects[target_objnum].signature == aip->target_signature) {
|
||||
ship* target_shipp = &Ships[Objects[target_objnum].instance];
|
||||
if (target_shipp && iff_matches_mask(target_shipp->team, enemy_team_mask)) {
|
||||
if (!(Objects[target_objnum].flags[Object::Object_Flags::Protected])) { // check this flag as well
|
||||
// nprintf(("AI", "Frame %i: Object %i resuming goal of object %i\n", AI_FrameCount, objnum,
|
||||
// target_objnum));
|
||||
if (iff_matches_mask(Ships[Objects[target_objnum].instance].team, enemy_team_mask)) {
|
||||
if ( !(Objects[target_objnum].flags[Object::Object_Flags::Protected]) ) { // check this flag as well
|
||||
// nprintf(("AI", "Frame %i: Object %i resuming goal of object %i\n", AI_FrameCount, objnum, target_objnum));
|
||||
return target_objnum;
|
||||
}
|
||||
}
|
||||
@@ -1225,7 +1215,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
|
||||
}
|
||||
|
||||
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
|
||||
// we might not need to calculate this
|
||||
if (!gvec)
|
||||
@@ -1233,7 +1222,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
|
||||
|
||||
if (use_angles) {
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
|
||||
vm_vec_normalize(gvec);
|
||||
} else {
|
||||
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
|
||||
vm_vec_normalized_dir(gvec, targetp, gpos);
|
||||
@@ -1342,17 +1330,16 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
|
||||
if (!in_lab && ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem* tp = ss->system_info;
|
||||
|
||||
// Get the normalized dir between the turret and the predicted enemy position.
|
||||
// If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
//Get the normalized dir between the turret and the predicted enemy position.
|
||||
//If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
|
||||
|
||||
bool in_fov;
|
||||
|
||||
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
|
||||
|
||||
if (in_fov) {
|
||||
@@ -1360,15 +1347,8 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
} else if (!in_lab && (ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
} else if (in_lab) {
|
||||
// in the lab, if predicted_enemy_pos is zero vec, then go to initial, else try to aim at the target
|
||||
if (predicted_enemy_pos != nullptr && *predicted_enemy_pos == vmd_zero_vector) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
} else {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
|
||||
@@ -1558,29 +1538,22 @@ bool turret_should_pick_new_target(ship_subsys *turret)
|
||||
/**
|
||||
* Set the next fire timestamp for a turret, based on weapon type and ai class
|
||||
*/
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip, const WeaponLaunchCurveData& launch_curve_data)
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
float wait = 1000.0f;
|
||||
// we have to add 1 to wip->burst_shots so that the multiplier behaves as expected, then remove 1 from burst_shots to match the zero-indexed burst_counter
|
||||
int base_burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points : wip->burst_shots + 1);
|
||||
float burst_shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_SHOTS_MULT, launch_curve_data);
|
||||
int burst_shots = MAX(fl2i(i2fl(base_burst_shots) * burst_shots_mult) - 1, 0);
|
||||
// should subtract 1 from firepoints to match behavior of wip->burst_shots
|
||||
int burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points - 1 : wip->burst_shots);
|
||||
|
||||
bool burst = burst_shots > turret->weapons.burst_counter[weapon_num];
|
||||
|
||||
if (burst) {
|
||||
if (burst_shots > turret->weapons.burst_counter[weapon_num]) {
|
||||
wait *= wip->burst_delay;
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_DELAY_MULT, launch_curve_data);
|
||||
turret->weapons.burst_counter[weapon_num]++;
|
||||
} else {
|
||||
// Random fire delay (DahBlount) used in ship_fire_primary(), added here by wookieejedi to correct oversight
|
||||
if (wip->max_delay != 0.0f && wip->min_delay != 0.0f) {
|
||||
wait *= frand_range(wip->min_delay, wip->max_delay);
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::FIRE_WAIT_MULT, launch_curve_data);
|
||||
} else {
|
||||
wait *= wip->fire_wait;
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::FIRE_WAIT_MULT, launch_curve_data);
|
||||
}
|
||||
if ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
turret->weapons.burst_counter[weapon_num] = Random::next(burst_shots);
|
||||
@@ -1626,7 +1599,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
} else {
|
||||
// flak guns need to fire more rapidly
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
|
||||
} else {
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile * 0.5f;
|
||||
@@ -1651,7 +1624,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
}
|
||||
} else {
|
||||
// give team friendly an advantage
|
||||
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly;
|
||||
} else {
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile;
|
||||
@@ -1669,7 +1642,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
wait *= frand_range(0.9f, 1.1f);
|
||||
}
|
||||
|
||||
if(turret->rof_scaler != 1.0f && !(burst && turret->system_info->flags[Model::Subsystem_Flags::Burst_ignores_RoF_Mult]))
|
||||
if(turret->rof_scaler != 1.0f)
|
||||
wait /= get_adjusted_turret_rof(turret);
|
||||
|
||||
(*fs_dest) = timestamp((int)wait);
|
||||
@@ -1706,15 +1679,7 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
|
||||
/**
|
||||
* Fire a weapon from a turret
|
||||
*/
|
||||
bool turret_fire_weapon(int weapon_num,
|
||||
ship_subsys *turret,
|
||||
int parent_objnum,
|
||||
const WeaponLaunchCurveData& launch_curve_data,
|
||||
const vec3d *orig_firing_pos,
|
||||
const vec3d *orig_firing_vec,
|
||||
const vec3d *predicted_pos = nullptr,
|
||||
float flak_range_override = 100.0f,
|
||||
bool play_sound = true)
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
{
|
||||
matrix firing_orient;
|
||||
int weapon_objnum;
|
||||
@@ -1729,12 +1694,6 @@ bool turret_fire_weapon(int weapon_num,
|
||||
if (!wip)
|
||||
return false;
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
|
||||
if (in_lab) {
|
||||
predicted_pos = nullptr;
|
||||
}
|
||||
|
||||
bool last_shot_in_salvo = true;
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
{
|
||||
@@ -1798,7 +1757,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
firing_vec = &firing_vec_buf;
|
||||
}
|
||||
|
||||
vm_vector_2_matrix_norm(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
|
||||
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
|
||||
int old_burst_seed = swp->burst_seed[weapon_num];
|
||||
@@ -1814,63 +1773,53 @@ bool turret_fire_weapon(int weapon_num,
|
||||
|
||||
// set next fire timestamp for the turret
|
||||
if (last_shot_in_salvo)
|
||||
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip, launch_curve_data);
|
||||
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
|
||||
|
||||
// if this weapon is a beam weapon, handle it specially
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
|
||||
// if this beam isn't free to fire
|
||||
if (!in_lab && !(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
return false;
|
||||
}
|
||||
beam_fire_info fire_info;
|
||||
|
||||
for (int i = 0; i < wip->shots; i++) {
|
||||
beam_fire_info fire_info;
|
||||
// stuff beam firing info
|
||||
memset(&fire_info, 0, sizeof(beam_fire_info));
|
||||
fire_info.accuracy = 1.0f;
|
||||
fire_info.beam_info_index = turret_weapon_class;
|
||||
fire_info.beam_info_override = nullptr;
|
||||
fire_info.shooter = &Objects[parent_objnum];
|
||||
fire_info.target = turret_enemy_objp;
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
|
||||
fire_info.target_subsys = turret->targeted_subsys;
|
||||
else
|
||||
fire_info.target_subsys = nullptr;
|
||||
fire_info.turret = turret;
|
||||
fire_info.burst_seed = old_burst_seed;
|
||||
fire_info.fire_method = BFM_TURRET_FIRED;
|
||||
fire_info.per_burst_rotation = swp->per_burst_rot;
|
||||
fire_info.burst_index = old_burst_counter;
|
||||
|
||||
// stuff beam firing info
|
||||
memset(&fire_info, 0, sizeof(beam_fire_info));
|
||||
fire_info.accuracy = 1.0f;
|
||||
fire_info.beam_info_index = turret_weapon_class;
|
||||
fire_info.beam_info_override = nullptr;
|
||||
fire_info.shooter = &Objects[parent_objnum];
|
||||
fire_info.target = turret_enemy_objp;
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
|
||||
fire_info.target_subsys = turret->targeted_subsys;
|
||||
else
|
||||
fire_info.target_subsys = nullptr;
|
||||
fire_info.turret = turret;
|
||||
fire_info.burst_seed = old_burst_seed;
|
||||
fire_info.fire_method = BFM_TURRET_FIRED;
|
||||
fire_info.per_burst_rotation = swp->per_burst_rot;
|
||||
fire_info.burst_index = (old_burst_counter * wip->shots) + i;
|
||||
// fire a beam weapon
|
||||
weapon_objnum = beam_fire(&fire_info);
|
||||
|
||||
// If we're in the lab then force fire
|
||||
if (in_lab) {
|
||||
fire_info.fire_method = BFM_TURRET_FORCE_FIRED;
|
||||
fire_info.bfi_flags |= BFIF_TARGETING_COORDS;
|
||||
fire_info.target_pos1 = turret->last_aim_enemy_pos;
|
||||
}
|
||||
if (weapon_objnum != -1) {
|
||||
objp = &Objects[weapon_objnum];
|
||||
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
// fire a beam weapon
|
||||
weapon_objnum = beam_fire(&fire_info);
|
||||
|
||||
if (weapon_objnum != -1) {
|
||||
objp = &Objects[weapon_objnum];
|
||||
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Beam", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Beam", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
|
||||
return true;
|
||||
}
|
||||
@@ -1880,7 +1829,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
swp->current_secondary_bank = 0;
|
||||
}
|
||||
int bank_to_fire = swp->current_secondary_bank;
|
||||
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
|
||||
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
|
||||
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
|
||||
swp->current_secondary_bank++;
|
||||
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
|
||||
@@ -1891,7 +1840,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos, in_lab);
|
||||
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos);
|
||||
|
||||
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
|
||||
return true;
|
||||
@@ -1899,10 +1848,8 @@ bool turret_fire_weapon(int weapon_num,
|
||||
}
|
||||
// now do anything else
|
||||
else {
|
||||
float shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::SHOTS_MULT, launch_curve_data);
|
||||
int shots = fl2i(i2fl(wip->shots) * shots_mult);
|
||||
for (int i = 0; i < shots; i++) {
|
||||
if (!in_lab && turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
|
||||
for (int i = 0; i < wip->shots; i++) {
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
|
||||
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
|
||||
if (wip->subtype == WP_LASER) {
|
||||
int points;
|
||||
@@ -1997,7 +1944,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
// so we need to get the position info separately for each shot
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
|
||||
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, 0.0f, turret, launch_curve_data);
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
|
||||
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
|
||||
|
||||
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
|
||||
@@ -2026,7 +1973,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
// if the gun is a flak gun
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
|
||||
if(predicted_pos != nullptr)
|
||||
if(predicted_pos != NULL)
|
||||
{
|
||||
// pick a firing range so that it detonates properly
|
||||
flak_pick_range(objp, firing_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
@@ -2041,17 +1988,8 @@ bool turret_fire_weapon(int weapon_num,
|
||||
}
|
||||
|
||||
// do mflash if the weapon has it
|
||||
if (wip->muzzle_effect.isValid()) {
|
||||
float radius_mult = 1.f;
|
||||
if (wip->render_type == WRT_LASER) {
|
||||
radius_mult = wip->weapon_curves.get_output(weapon_info::WeaponCurveOutputs::LASER_RADIUS_MULT, *wp, &wp->modular_curves_instance);
|
||||
}
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
|
||||
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos, false));
|
||||
particleSource->setTriggerRadius(objp->radius * radius_mult);
|
||||
particleSource->setTriggerVelocity(vm_vec_mag_quick(&objp->phys_info.vel));
|
||||
particleSource->finishCreation();
|
||||
if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
}
|
||||
|
||||
// in multiplayer (and the master), then send a turret fired packet.
|
||||
@@ -2061,9 +1999,9 @@ bool turret_fire_weapon(int weapon_num,
|
||||
subsys_index = ship_get_subsys_index(turret);
|
||||
Assert( subsys_index != -1 );
|
||||
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
|
||||
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
|
||||
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
|
||||
} else {
|
||||
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
|
||||
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2131,16 +2069,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix_norm(&firing_orient, &turret_fvec, nullptr, nullptr);
|
||||
|
||||
auto launch_curve_data = WeaponLaunchCurveData {
|
||||
tsi->turret->system_info->turret_num_firing_points,
|
||||
0.f,
|
||||
0.f,
|
||||
};
|
||||
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
|
||||
|
||||
// create weapon and homing info
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, 0.0f, tsi->turret, launch_curve_data);
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
|
||||
|
||||
// do other cool stuff if weapon is created.
|
||||
@@ -2166,12 +2098,8 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// muzzle flash?
|
||||
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
|
||||
particleSource->setHost(std::make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1, false));
|
||||
particleSource->setTriggerRadius(Objects[weapon_objnum].radius);
|
||||
particleSource->finishCreation();
|
||||
if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
|
||||
mflash_create(&turret_pos, &turret_fvec, &Objects[tsi->parent_objnum].phys_info, Weapon_info[tsi->weapon_class].muzzle_flash);
|
||||
}
|
||||
|
||||
// maybe sound
|
||||
@@ -2188,7 +2116,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
|
||||
subsys_index = ship_get_subsys_index(tsi->turret);
|
||||
Assert( subsys_index != -1 );
|
||||
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum, 0.f, 0.f);
|
||||
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2214,20 +2142,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
vec3d predicted_enemy_pos = vmd_zero_vector;
|
||||
object *objp;
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
|
||||
if (in_lab) {
|
||||
// Adjust behavior for Lab
|
||||
ss->turret_enemy_objnum = -1;
|
||||
lep = nullptr;
|
||||
}
|
||||
|
||||
// Reset the points to target value
|
||||
ss->points_to_target = -1.0f;
|
||||
ss->base_rotation_rate_pct = 0.0f;
|
||||
ss->gun_rotation_rate_pct = 0.0f;
|
||||
|
||||
if (!in_lab && !Ai_firing_enabled) {
|
||||
if (!Ai_firing_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2240,7 +2160,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
}
|
||||
|
||||
// Check turret free
|
||||
if (!in_lab && ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
|
||||
if (ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2305,13 +2225,8 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
|
||||
}
|
||||
|
||||
if (!in_lab) {
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
} else {
|
||||
// Lab hijacks this value to use as the target position
|
||||
predicted_enemy_pos = ss->last_aim_enemy_pos;
|
||||
}
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
|
||||
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
|
||||
bool use_angles = aifft_rotate_turret(objp, shipp, ss, &global_gun_pos, &global_gun_vec, &predicted_enemy_pos);
|
||||
@@ -2335,20 +2250,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range
|
||||
// WMC moved the range check to within the loop, but we can still calculate the enemy distance here
|
||||
float base_dist_to_enemy = 0.0f;
|
||||
float dist_to_enemy = 0.0f;
|
||||
if (lep) {
|
||||
base_dist_to_enemy = vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = base_dist_to_enemy;
|
||||
if (!The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius]) {
|
||||
dist_to_enemy -= lep->radius;
|
||||
}
|
||||
base_dist_to_enemy = MAX(0.0f, base_dist_to_enemy);
|
||||
dist_to_enemy = MAX(0.0f, dist_to_enemy);
|
||||
} else if (in_lab) {
|
||||
base_dist_to_enemy = 500.0f;
|
||||
dist_to_enemy = base_dist_to_enemy;
|
||||
vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos));
|
||||
else
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
|
||||
}
|
||||
|
||||
// count the number of enemies, in case we have a spawning weapon
|
||||
@@ -2360,19 +2267,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
float turret_barrel_length = -1.0f;
|
||||
|
||||
float target_radius = 0.f;
|
||||
|
||||
if (lep != nullptr) {
|
||||
target_radius = lep->radius;
|
||||
}
|
||||
|
||||
// grab the data for the launch curve inputs
|
||||
auto launch_curve_data = WeaponLaunchCurveData {
|
||||
ss->system_info->turret_num_firing_points,
|
||||
base_dist_to_enemy,
|
||||
target_radius,
|
||||
};
|
||||
|
||||
//WMC - go through all valid weapons. Fire spawns if there are any.
|
||||
int valid_weapons[MAX_SHIP_WEAPONS];
|
||||
int num_valid = 0;
|
||||
@@ -2401,10 +2295,10 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
// Turret spawn weapons are a special case. They fire if there are enough enemies in the
|
||||
// immediate area (not necessarily in the turret fov).
|
||||
// However, if this is a 'smart spawn', just use it like a normal weapon
|
||||
if (!in_lab && (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
{
|
||||
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
|
||||
turret_fire_weapon(i, ss, parent_objnum, launch_curve_data, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
turret_fire_weapon(i, ss, parent_objnum, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
} else {
|
||||
// Regardless of firing rate, don't check whether should fire for awhile.
|
||||
if (tp->flags[Model::Subsystem_Flags::Use_multiple_guns])
|
||||
@@ -2419,13 +2313,13 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
we_did_non_spawning_logic = true; // for the post-loop check
|
||||
|
||||
// If beam weapon, check beam free
|
||||
if (!in_lab && wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// the remaining checks in this loop all require a valid lep
|
||||
if (!in_lab && !lep)
|
||||
if (!lep)
|
||||
continue;
|
||||
|
||||
// Get weapon range
|
||||
@@ -2465,88 +2359,84 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
}
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range (or within min range)
|
||||
// In lab we ignore range issues
|
||||
if (!in_lab && (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range)) {
|
||||
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
|
||||
// it's possible another weapon is in range, but if not,
|
||||
// we will end up selecting a new target
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_lab) {
|
||||
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
|
||||
|
||||
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
|
||||
|
||||
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
|
||||
if ( lep->type != OBJ_SHIP ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar check for small weapons
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
|
||||
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
|
||||
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
|
||||
|
||||
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
|
||||
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
|
||||
if (lep->type == OBJ_SHIP) {
|
||||
// Check if we're targeting a protected ship
|
||||
if (lep->flags[Object::Object_Flags::Protected]) {
|
||||
// *none* of the weapons will work on this ship, so just quit the loop
|
||||
tentative_return = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we're targeting a beam protected ship with a beam weapon
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a flak protected ship with a flak weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a laser protected ship with a laser weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a missile protected ship with a missile weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if weapon or turret is set to tagged-only
|
||||
// must check here in case turret has multiple weapons and not all are tagged-only
|
||||
else if (tagged_only && !ship_is_tagged(lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
|
||||
if ( lep->type != OBJ_SHIP ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// check tagged-only for bombs only if the flag is set; see Mantis #3114
|
||||
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar check for small weapons
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
|
||||
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
|
||||
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
|
||||
|
||||
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
|
||||
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
|
||||
if (lep->type == OBJ_SHIP) {
|
||||
// Check if we're targeting a protected ship
|
||||
if (lep->flags[Object::Object_Flags::Protected]) {
|
||||
// *none* of the weapons will work on this ship, so just quit the loop
|
||||
tentative_return = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we're targeting a beam protected ship with a beam weapon
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a flak protected ship with a flak weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a laser protected ship with a laser weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a missile protected ship with a missile weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if weapon or turret is set to tagged-only
|
||||
// must check here in case turret has multiple weapons and not all are tagged-only
|
||||
else if (tagged_only && !ship_is_tagged(lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check tagged-only for bombs only if the flag is set; see Mantis #3114
|
||||
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2640,20 +2530,18 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
lep = &Objects[ss->turret_enemy_objnum];
|
||||
} else {
|
||||
if (!in_lab) {
|
||||
if (timestamp_until(ss->turret_next_fire_stamp) < 500) {
|
||||
ss->turret_next_fire_stamp = timestamp(500);
|
||||
}
|
||||
return;
|
||||
if (timestamp_until(ss->turret_next_fire_stamp) < 500) {
|
||||
ss->turret_next_fire_stamp = timestamp(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//This can't happen. See above code -- Except in the Lab as of 4/26/2025
|
||||
//This can't happen. See above code
|
||||
//if ( lep == nullptr ){
|
||||
// return;
|
||||
//}
|
||||
|
||||
//This can't happen. See above code -- Except in the Lab as of 4/26/2025
|
||||
//This can't happen. See above code
|
||||
//Assert(ss->turret_enemy_objnum != -1);
|
||||
|
||||
bool in_fov = turret_fov_test(ss, &global_gun_vec, &v2e);
|
||||
@@ -2661,7 +2549,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
|
||||
// its a ballistic trajectory with no valid path
|
||||
if (in_lab || (in_fov && num_valid && predicted_enemy_pos != vmd_zero_vector)) {
|
||||
if (in_fov && num_valid && predicted_enemy_pos != vmd_zero_vector) {
|
||||
|
||||
// Do salvo thing separately - to prevent messing up things
|
||||
int number_of_firings;
|
||||
@@ -2715,7 +2603,8 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// Fire in the direction the turret is facing, not right at the target regardless of turret dir.
|
||||
// [Yet this retail comment precedes the calculation of vector-to-enemy...]
|
||||
dist_to_enemy = vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = vm_vec_normalize(&v2e);
|
||||
float dot = vm_vec_dot(&v2e, &global_gun_vec);
|
||||
|
||||
// (flak jitter moved to after we obtain shoot_vector below)
|
||||
@@ -2837,27 +2726,16 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// (Despite the retail comment above, retail actually fired toward the enemy; v2e = vector-to-enemy)
|
||||
vec3d shoot_vector = v2e;
|
||||
if (in_lab || tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
if (tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
shoot_vector = global_gun_vec;
|
||||
|
||||
// In the lab the order of operations is a little fuzzy since we're faking targets so always fire along the turret's current vector no matter what if we're a multipart turret
|
||||
if (in_lab && (ss->system_info->turret_gun_sobj >= 0 && ss->system_info->subobj_num != ss->system_info->turret_gun_sobj)) {
|
||||
vec3d new_pos;
|
||||
vec3d new_vec;
|
||||
ship_get_global_turret_gun_info(objp, ss, &new_pos, false, &new_vec, true, nullptr);
|
||||
shoot_vector = new_vec;
|
||||
vm_vec_normalize(&shoot_vector);
|
||||
global_gun_pos = new_pos;
|
||||
predicted_enemy_pos = new_pos + new_vec * 500.0f;
|
||||
}
|
||||
|
||||
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
|
||||
// to make a cool visual effect and make them less lethal
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
flak_jitter_aim(&shoot_vector, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
|
||||
}
|
||||
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, launch_curve_data, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2870,7 +2748,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
// make sure salvo fire mode does not turn into autofire
|
||||
if ((tp->flags[Model::Subsystem_Flags::Turret_salvo]) && ((i + 1) == number_of_firings)) {
|
||||
ai_info *parent_aip = &Ai_info[shipp->ai_index];
|
||||
turret_set_next_fire_timestamp(valid_weapons[valid_index], wip, ss, parent_aip, launch_curve_data);
|
||||
turret_set_next_fire_timestamp(valid_weapons[valid_index], wip, ss, parent_aip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2893,16 +2771,16 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
{
|
||||
//something did fire, get the lowest valid timestamp
|
||||
// don't do this if we already set a turret timestamp previously in the function
|
||||
if (timestamp_since(ss->turret_next_fire_stamp) >= 0)
|
||||
if (timestamp_since(ss->turret_next_fire_stamp) > 0)
|
||||
{
|
||||
int minimum_stamp = -1;
|
||||
|
||||
for (int i = 0; i < MAX_SHIP_WEAPONS; ++i)
|
||||
{
|
||||
{
|
||||
int stamp = (i < MAX_SHIP_PRIMARY_BANKS) ? swp->next_primary_fire_stamp[i] : swp->next_secondary_fire_stamp[i - MAX_SHIP_PRIMARY_BANKS];
|
||||
|
||||
// valid timestamps start at 2; stamp must be in the future
|
||||
if (stamp < 2 || timestamp_since(stamp) >= 0)
|
||||
if (stamp < 2 || timestamp_since(stamp) > 0)
|
||||
continue;
|
||||
|
||||
// find minimum
|
||||
|
||||
+17
-6
@@ -667,10 +667,12 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
*
|
||||
* @param real_filename Filename of animation
|
||||
* @param cf_dir_type
|
||||
*
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
anim *ptr;
|
||||
CFILE *fp;
|
||||
@@ -695,7 +697,7 @@ anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
fp = cfopen(name, "rb", cf_dir_type);
|
||||
fp = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
|
||||
if ( !fp )
|
||||
return NULL;
|
||||
|
||||
@@ -741,9 +743,18 @@ anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
|
||||
ptr->cfile_ptr = NULL;
|
||||
|
||||
// NOTE: mapped files no longer supported!!
|
||||
ptr->flags |= ANF_STREAMED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", cf_dir_type);
|
||||
if ( file_mapped == PAGE_FROM_MEM) {
|
||||
// Try mapping the file to memory
|
||||
ptr->flags |= ANF_MEM_MAPPED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", CFILE_MEMORY_MAPPED, cf_dir_type);
|
||||
}
|
||||
|
||||
// couldn't memory-map file... must be in a packfile, so stream manually
|
||||
if ( file_mapped == PAGE_FROM_MEM && !ptr->cfile_ptr ) {
|
||||
ptr->flags &= ~ANF_MEM_MAPPED;
|
||||
ptr->flags |= ANF_STREAMED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
|
||||
}
|
||||
|
||||
ptr->cache = NULL;
|
||||
|
||||
|
||||
@@ -38,6 +38,12 @@ typedef struct {
|
||||
int ping_pong;
|
||||
} anim_play_struct;
|
||||
|
||||
enum
|
||||
{
|
||||
PAGE_FROM_DISK = 0,
|
||||
PAGE_FROM_MEM = 1
|
||||
};
|
||||
|
||||
extern int Anim_paused;
|
||||
|
||||
void anim_init();
|
||||
@@ -51,7 +57,7 @@ void anim_ignore_next_frametime();
|
||||
int anim_show_next_frame(anim_instance *instance, float frametime);
|
||||
void anim_release_all_instances(int screen_id = 0);
|
||||
void anim_release_render_instance(anim_instance* instance);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_DISK);
|
||||
int anim_free(anim *ptr);
|
||||
void anim_read_header(anim *ptr, CFILE *fp);
|
||||
void anim_reverse_direction(anim_instance *ai); // called automatically for ping-ponging, and can also be called externally
|
||||
|
||||
+10
-18
@@ -142,15 +142,11 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8:
|
||||
// 8-bit-per-pixel HUD gauge ANI aabitmaps use the palette index directly as an alpha value —
|
||||
// the actual RGB colors stored in the palette are completely ignored. The valid range is [0, 15]:
|
||||
// [0]: fully transparent (alpha 0)
|
||||
// [1-14]: black-to-white gradient (alpha = index * 18)
|
||||
// [15]: special HUD background (alpha 18, matching index 1, for a dark transparent tint)
|
||||
// [>15]: clamped to fully opaque (alpha 255)
|
||||
// Because only the index value matters, the palette in the source file must be ordered so that
|
||||
// index 0 is the transparent end and index 14 is the opaque end. A reversed palette causes the
|
||||
// gauge to render as a solid white square (see GitHub issue #4148).
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
|
||||
// palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
|
||||
// range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
|
||||
// area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
|
||||
// transparent background.
|
||||
if (pix > 15) {
|
||||
bit_8 = 255;
|
||||
}
|
||||
@@ -244,15 +240,11 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8 :
|
||||
// 8-bit-per-pixel HUD gauge ANI aabitmaps use the palette index directly as an alpha value —
|
||||
// the actual RGB colors stored in the palette are completely ignored. The valid range is [0, 15]:
|
||||
// [0]: fully transparent (alpha 0)
|
||||
// [1-14]: black-to-white gradient (alpha = index * 18)
|
||||
// [15]: special HUD background (alpha 18, matching index 1, for a dark transparent tint)
|
||||
// [>15]: clamped to fully opaque (alpha 255)
|
||||
// Because only the index value matters, the palette in the source file must be ordered so that
|
||||
// index 0 is the transparent end and index 14 is the opaque end. A reversed palette causes the
|
||||
// gauge to render as a solid white square (see GitHub issue #4148).
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use a palette index value in the range [0, 15]. These
|
||||
// palette indexes must be remapped to alpha values between [0, 255] which is what graphics code expects. Palette
|
||||
// range [0, 14] is a gradient from black to white, and palette index 15 is a special color which indicates the background
|
||||
// area of a HUD gauge. Retail code uses the final alpha value for index 1 for this special index to give gauges a dark
|
||||
// transparent background.
|
||||
if (pix > 15) {
|
||||
bit_8 = 255;
|
||||
}
|
||||
|
||||
+251
-446
File diff suppressed because it is too large.
Load diff
+24
-49
@@ -14,10 +14,7 @@
|
||||
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "object/object_flags.h"
|
||||
#include "io/timer.h"
|
||||
#include "particle/ParticleSource.h"
|
||||
#include "math/vecmat.h"
|
||||
|
||||
class object;
|
||||
class polymodel;
|
||||
@@ -27,14 +24,15 @@ class model_draw_list;
|
||||
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
|
||||
|
||||
#define NUM_ASTEROID_SIZES 3
|
||||
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
|
||||
|
||||
#define ASTEROID_TYPE_DEBRIS -1
|
||||
#define ASTEROID_TYPE_SMALL 0
|
||||
#define ASTEROID_TYPE_MEDIUM 1
|
||||
#define ASTEROID_TYPE_LARGE 2
|
||||
|
||||
// Only used for parsing & saving retail compatible mission files
|
||||
#define MAX_RETAIL_DEBRIS_TYPES 3
|
||||
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
|
||||
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
|
||||
|
||||
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
|
||||
#define MAX_ASTEROID_DETAIL_LEVELS 5
|
||||
@@ -56,19 +54,13 @@ typedef struct asteroid_split_info {
|
||||
int max; //maximum asteroids to spawn
|
||||
} asteroid_split_info;
|
||||
|
||||
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
|
||||
typedef struct asteroid_subtype_info {
|
||||
char pof_filename[MAX_FILENAME_LEN];
|
||||
int model_number;
|
||||
SCP_string type_name;
|
||||
} asteroid_subtype_info;
|
||||
|
||||
class asteroid_info
|
||||
{
|
||||
public:
|
||||
char name[NAME_LENGTH]; // name for the asteroid
|
||||
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
|
||||
int num_detail_levels; // number of detail levels for this asteroid
|
||||
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
|
||||
int num_detail_levels; // number of detail levels for this ship
|
||||
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
|
||||
float max_speed; // cap on speed for asteroid
|
||||
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
|
||||
@@ -80,25 +72,31 @@ public:
|
||||
float blast; // maximum blast impulse from area effect explosion
|
||||
float initial_asteroid_strength; // starting strength of asteroid
|
||||
SCP_vector< asteroid_split_info > split_info;
|
||||
polymodel *modelp[NUM_ASTEROID_POFS];
|
||||
int model_num[NUM_ASTEROID_POFS];
|
||||
SCP_vector<int> explosion_bitmap_anims;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
particle::ParticleEffectHandle end_particles;
|
||||
std::optional<float> breakup_delay;
|
||||
SCP_string display_name; // only used for hud targeting display and for debris
|
||||
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
|
||||
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
SCP_vector<asteroid_subtype_info> subtypes;
|
||||
|
||||
asteroid_info( )
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
|
||||
rotational_vel_multiplier(1), damage_type_idx(0),
|
||||
damage_type_idx_sav( -1 ), inner_rad( 0 ), outer_rad( 0 ),
|
||||
damage( 0 ), blast( 0 ), initial_asteroid_strength( 0 ),
|
||||
fireball_radius_multiplier( -1 ), end_particles( particle::ParticleEffectHandle::invalid() ), breakup_delay( std::nullopt ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
{
|
||||
name[ 0 ] = 0;
|
||||
display_name = "";
|
||||
memset( detail_distance, 0, sizeof( detail_distance ) );
|
||||
|
||||
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
|
||||
{
|
||||
modelp[i] = NULL;
|
||||
model_num[i] = -1;
|
||||
pof_files[i][0] = '\0';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,7 +105,6 @@ public:
|
||||
|
||||
typedef struct asteroid {
|
||||
int flags;
|
||||
flagset<Object::Raw_Pof_Flags> render_flags; // Render flags
|
||||
int objnum;
|
||||
int model_instance_num;
|
||||
int asteroid_type; // 0..MAX_DEBRIS_TYPES
|
||||
@@ -134,7 +131,7 @@ typedef enum {
|
||||
FT_PASSIVE
|
||||
} field_type_t;
|
||||
|
||||
struct asteroid_field {
|
||||
typedef struct asteroid_field {
|
||||
vec3d min_bound; // Minimum range of field.
|
||||
vec3d max_bound; // Maximum range of field.
|
||||
float bound_rad;
|
||||
@@ -146,29 +143,12 @@ struct asteroid_field {
|
||||
int num_initial_asteroids; // Number of asteroids at creation.
|
||||
field_type_t field_type; // active throws and wraps, passive does not
|
||||
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
|
||||
SCP_vector<int> field_debris_type; // one of the debris type defines above
|
||||
SCP_vector<SCP_string> field_asteroid_type; // one of the asteroid subtypes
|
||||
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
|
||||
int num_used_field_debris_types; // how many of the above are used
|
||||
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
|
||||
asteroid_field()
|
||||
{
|
||||
num_initial_asteroids = 0; // disable the field by default
|
||||
speed = 0.0f;
|
||||
vm_vec_make(&min_bound, -1000.0f, -1000.0f, -1000.0f);
|
||||
vm_vec_make(&max_bound, 1000.0f, 1000.0f, 1000.0f);
|
||||
vm_vec_make(&inner_min_bound, -500.0f, -500.0f, -500.0f);
|
||||
vm_vec_make(&inner_max_bound, 500.0f, 500.0f, 500.0f);
|
||||
has_inner_bound = false;
|
||||
field_type = FT_ACTIVE;
|
||||
debris_genre = DG_ASTEROID;
|
||||
enhanced_visibility_checks = false;
|
||||
bound_rad = 0.0f;
|
||||
vel = ZERO_VECTOR;
|
||||
// the vectors default-construct to empty
|
||||
}
|
||||
};
|
||||
} asteroid_field;
|
||||
|
||||
extern SCP_vector< asteroid_info > Asteroid_info;
|
||||
extern asteroid Asteroids[MAX_ASTEROIDS];
|
||||
@@ -185,8 +165,8 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = f
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_render(object* obj, model_draw_list* scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
@@ -200,11 +180,6 @@ void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes();
|
||||
int get_asteroid_subtype_index_by_name(const SCP_string& name, int asteroid_idx);
|
||||
|
||||
// extern for the lab
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype);
|
||||
|
||||
// need to extern for keycontrol debug commands
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <map>
|
||||
|
||||
// Extern functions/variables
|
||||
extern bool Player_use_ai;
|
||||
extern int Player_use_ai;
|
||||
extern int get_wing_index(object *objp, int wingnum);
|
||||
extern object * get_wing_leader(int wingnum);
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
@@ -66,7 +66,7 @@ int start_dist;
|
||||
void autopilot_ai_waypoint_goal_fixup(ai_goal* aigp)
|
||||
{
|
||||
// this function sets wp_index properly;
|
||||
aigp->wp_list_index = find_matching_waypoint_list_index(aigp->target_name);
|
||||
aigp->wp_list = find_matching_waypoint_list(aigp->target_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,15 +111,13 @@ const vec3d *NavPoint::GetPosition()
|
||||
{
|
||||
if (flags & NP_WAYPOINT)
|
||||
{
|
||||
auto wpt = find_waypoint_at_indexes(target_index, waypoint_num-1);
|
||||
Assert(wpt != nullptr);
|
||||
if (wpt == nullptr)
|
||||
return &vmd_zero_vector;
|
||||
waypoint *wpt = find_waypoint_at_index((waypoint_list*) target_obj, waypoint_num-1);
|
||||
Assert(wpt != NULL);
|
||||
return wpt->get_pos();
|
||||
}
|
||||
else
|
||||
{
|
||||
return &Objects[target_index].pos;
|
||||
return &Objects[((ship*) target_obj)->objnum].pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +239,7 @@ bool StartAutopilot()
|
||||
// is support ship trying to rearm-repair
|
||||
if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
|
||||
// no, so tell it to depart
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_WARP, -1, nullptr, support_ship_aip );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
|
||||
} else {
|
||||
// yes
|
||||
send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING);
|
||||
@@ -270,7 +268,7 @@ bool StartAutopilot()
|
||||
LockAPConv = _timestamp(); // lock convergence instantly
|
||||
else
|
||||
LockAPConv = _timestamp(3 * MILLISECONDS_PER_SECOND); // 3 seconds before we lock convergence
|
||||
Player_use_ai = true;
|
||||
Player_use_ai = 1;
|
||||
set_time_compression(1);
|
||||
lock_time_compression(true);
|
||||
|
||||
@@ -300,16 +298,15 @@ bool StartAutopilot()
|
||||
autopilot_wings.clear();
|
||||
|
||||
// vars for usage w/ cinematic
|
||||
vec3d pos, perp, tpos, rpos = Player_obj->pos, zero;
|
||||
vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero;
|
||||
memset(&zero, 0, sizeof(vec3d));
|
||||
|
||||
|
||||
// instantly turn player toward tpos
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
{
|
||||
vec3d norm1;
|
||||
vm_vec_normalized_dir(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix_norm(&Player_obj->orient, &norm1, nullptr, nullptr);
|
||||
vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_SHIPS; i++)
|
||||
@@ -396,12 +393,10 @@ bool StartAutopilot()
|
||||
radius = Objects[Ships[i].objnum].radius;
|
||||
}
|
||||
|
||||
// instantly turn the ship to match the direction player is looking
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
{
|
||||
vec3d norm1;
|
||||
vm_vec_normalized_dir(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix_norm(&Objects[Ships[i].objnum].orient, &norm1, nullptr, nullptr);
|
||||
{// instantly turn the ship to match the direction player is looking
|
||||
//vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
|
||||
}
|
||||
|
||||
// snap wings into formation
|
||||
@@ -467,12 +462,12 @@ bool StartAutopilot()
|
||||
{
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), &Ai_info[Ships[i].ai_index] );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
|
||||
//fixup has to wait until after wing goals
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, &Ai_info[Ships[i].ai_index] );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -488,15 +483,15 @@ bool StartAutopilot()
|
||||
{
|
||||
//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
|
||||
|
||||
//ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
|
||||
//ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) );
|
||||
|
||||
ai_clear_wing_goals( &Wings[i] );
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
|
||||
ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), i );
|
||||
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i );
|
||||
|
||||
// "fix up" the goal
|
||||
for (j = 0; j < MAX_AI_GOALS; j++)
|
||||
@@ -510,7 +505,7 @@ bool StartAutopilot()
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, i );
|
||||
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -858,7 +853,7 @@ void EndAutoPilot()
|
||||
|
||||
set_time_compression(1);
|
||||
lock_time_compression(false);
|
||||
Player_use_ai = false;
|
||||
Player_use_ai = 0;
|
||||
//Clear AI Goals
|
||||
|
||||
if (CinematicStarted) // clear cinematic if we need to
|
||||
@@ -879,12 +874,12 @@ void EndAutoPilot()
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
goal = AI_GOAL_WAYPOINTS_ONCE;
|
||||
goal_name = Waypoint_lists[Navs[CurrentNav].target_index].get_name();
|
||||
goal_name = ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
goal = AI_GOAL_FLY_TO_SHIP;
|
||||
goal_name = Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name;
|
||||
goal_name = ((ship*)Navs[CurrentNav].target_obj)->ship_name;
|
||||
}
|
||||
|
||||
// assign ship goals
|
||||
@@ -1099,9 +1094,9 @@ void NavSystem_Do()
|
||||
|
||||
for (i = 0; i < MAX_NAVPOINTS; i++)
|
||||
{
|
||||
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_index >= 0))
|
||||
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_obj != NULL))
|
||||
{
|
||||
if (Objects[Navs[i].target_index].flags[Object::Object_Flags::Should_be_dead])
|
||||
if (((ship*)Navs[i].target_obj)->objnum == -1)
|
||||
{
|
||||
if (CurrentNav == i)
|
||||
CurrentNav = -1;
|
||||
@@ -1113,7 +1108,7 @@ void NavSystem_Do()
|
||||
// check if we're reached a Node
|
||||
for (i = 0; i < MAX_NAVPOINTS; i++)
|
||||
{
|
||||
if (Navs[i].target_index >= 0)
|
||||
if (Navs[i].target_obj != NULL)
|
||||
{
|
||||
if (Navs[i].flags & NP_VALIDTYPE && DistanceTo(i) < 1000)
|
||||
Navs[i].flags |= NP_VISITED;
|
||||
@@ -1397,7 +1392,7 @@ bool AddNav_Ship(const char *Nav, const char *TargetName, int flags)
|
||||
{
|
||||
if (Ships[i].objnum != -1 && !stricmp(TargetName, Ships[i].ship_name))
|
||||
{
|
||||
tnav.target_index = Ships[i].objnum;
|
||||
tnav.target_obj = (void *)&Ships[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1438,7 +1433,7 @@ bool AddNav_Waypoint(const char *Nav, const char *WP_Path, int node, int flags)
|
||||
|
||||
Assert(!(tnav.flags & NP_SHIP));
|
||||
|
||||
tnav.target_index = find_matching_waypoint_list_index(WP_Path);
|
||||
tnav.target_obj = find_matching_waypoint_list(WP_Path);
|
||||
tnav.waypoint_num = node;
|
||||
|
||||
// copy it into it's location
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
|
||||
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };
|
||||
|
||||
int target_index = -1; //waypoint list index if NP_WAYPOINT, otherwise object index
|
||||
const void *target_obj = nullptr;
|
||||
int waypoint_num = -1; //only used when flags & NP_WAYPOINT
|
||||
|
||||
const vec3d *GetPosition();
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
visited_color[1] = 0xFF;
|
||||
visited_color[2] = 0x00;
|
||||
|
||||
target_index = -1;
|
||||
target_obj = nullptr;
|
||||
waypoint_num = -1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ struct bitmap_entry {
|
||||
// Stuff to keep track of usage
|
||||
ubyte preloaded; //!< If set, then this was loaded from the lst file
|
||||
int preload_count; //!< how many times this gets used in game, for unlocking
|
||||
uint used_flags; //!< What flags it was accessed thru
|
||||
ushort used_flags; //!< What flags it was accessed thru
|
||||
int load_count;
|
||||
|
||||
bitmap bm; //!< Bitmap info
|
||||
@@ -93,15 +93,14 @@ struct bitmap_slot {
|
||||
};
|
||||
|
||||
// image specific lock functions
|
||||
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert = true );
|
||||
void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags);
|
||||
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true );
|
||||
|
||||
const size_t BM_BLOCK_SIZE = 4096;
|
||||
|
||||
|
||||
+19
-124
@@ -32,7 +32,6 @@
|
||||
#include "tgautils/tgautils.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "ktxutils/ktxutils.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
@@ -60,8 +59,8 @@ size_t bm_texture_ram = 0;
|
||||
int Bm_paging = 0;
|
||||
|
||||
// Extension type lists
|
||||
const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX, BM_TYPE_KTX };
|
||||
const char* bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx", ".ktx" };
|
||||
const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX };
|
||||
const char *bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx" };
|
||||
const int BM_NUM_TYPES = sizeof(bm_type_list) / sizeof(bm_type_list[0]);
|
||||
|
||||
const BM_TYPE bm_ani_type_list[] = { BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG };
|
||||
@@ -206,7 +205,7 @@ void clear_bm_lookup_cache() {
|
||||
/**
|
||||
* Converts the bitmap referenced by bmp to the type specified by flags
|
||||
*/
|
||||
static void bm_convert_format(bitmap *bmp, uint flags);
|
||||
static void bm_convert_format(bitmap *bmp, ushort flags);
|
||||
|
||||
/**
|
||||
* Frees a bitmap's data if it can
|
||||
@@ -640,7 +639,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
return n;
|
||||
}
|
||||
|
||||
void bm_convert_format(bitmap *bmp, uint flags) {
|
||||
void bm_convert_format(bitmap *bmp, ushort flags) {
|
||||
int idx;
|
||||
|
||||
// no transparency for 24 bpp images
|
||||
@@ -902,7 +901,7 @@ void bm_get_frame_usage(int *ntotal, int *nnew) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int bm_get_info(int handle, int *w, int * h, uint* flags, int *nframes, int *fps) {
|
||||
int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *fps) {
|
||||
bitmap * bmp;
|
||||
|
||||
if (!bm_inited) return -1;
|
||||
@@ -1028,6 +1027,10 @@ int bm_is_compressed(int num) {
|
||||
auto entry = bm_get_entry(num);
|
||||
BM_TYPE type = BM_TYPE_NONE;
|
||||
|
||||
//duh
|
||||
if (!Use_compressed_textures)
|
||||
return 0;
|
||||
|
||||
type = entry->comp_type;
|
||||
|
||||
switch (type) {
|
||||
@@ -1056,24 +1059,6 @@ int bm_is_compressed(int num) {
|
||||
case BM_TYPE_CUBEMAP_DXT5:
|
||||
return DDS_CUBEMAP_DXT5;
|
||||
|
||||
case BM_TYPE_ETC2_RGB:
|
||||
return KTX_ETC2_RGB;
|
||||
|
||||
case BM_TYPE_ETC2_SRGB:
|
||||
return KTX_ETC2_SRGB;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA_EAC:
|
||||
return KTX_ETC2_RGBA_EAC;
|
||||
|
||||
case BM_TYPE_ETC2_SRGBA_EAC:
|
||||
return KTX_ETC2_SRGBA_EAC;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA1:
|
||||
return KTX_ETC2_RGB_A1;
|
||||
|
||||
case BM_TYPE_ETC2_SRGBA1:
|
||||
return KTX_ETC2_SRGB_A1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1167,16 +1152,6 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// its a KTX file
|
||||
else if (type == BM_TYPE_KTX) {
|
||||
int ktx_ct;
|
||||
int ktx_error = ktx1_read_header(filename, img_cfp, w, h, bpp, &ktx_ct, mm_lvl, size);
|
||||
if (ktx_error != KTX1_ERROR_NONE) {
|
||||
mprintf(("ktx: could not open '%s'\n", filename));
|
||||
return -1;
|
||||
}
|
||||
*c_type = (BM_TYPE)ktx_ct;
|
||||
}
|
||||
// if its a tga file
|
||||
else if (type == BM_TYPE_TGA) {
|
||||
int tga_error = targa_read_header(filename, img_cfp, w, h, bpp, NULL);
|
||||
@@ -1390,8 +1365,6 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
|
||||
c_type = BM_TYPE_JPG;
|
||||
} else if (!stricmp(NOX("pcx"), ext)) {
|
||||
c_type = BM_TYPE_PCX;
|
||||
} else if (!stricmp(NOX("ktx"), ext)) {
|
||||
c_type = BM_TYPE_KTX;
|
||||
} else {
|
||||
mprintf(("BMPMAN: Unknown file type in EFF parse!\n"));
|
||||
return false;
|
||||
@@ -1421,7 +1394,7 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
|
||||
/**
|
||||
* Lock an image files data into memory
|
||||
*/
|
||||
static int bm_load_image_data(int handle, int bpp, uint flags, bool nodebug)
|
||||
static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
|
||||
{
|
||||
BM_TYPE c_type = BM_TYPE_NONE;
|
||||
int true_bpp;
|
||||
@@ -1513,10 +1486,6 @@ static int bm_load_image_data(int handle, int bpp, uint flags, bool nodebug)
|
||||
bm_lock_user(handle, bs, bmp, true_bpp, flags, false);
|
||||
break;
|
||||
|
||||
case BM_TYPE_KTX:
|
||||
bm_lock_ktx1(handle, bs, bmp, true_bpp, flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
|
||||
return -1;
|
||||
@@ -1976,7 +1945,7 @@ int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitmap * bm_lock(int handle, int bpp, uint flags, bool nodebug) {
|
||||
bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
|
||||
bitmap *bmp;
|
||||
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
@@ -2073,7 +2042,7 @@ bitmap * bm_lock(int handle, int bpp, uint flags, bool nodebug) {
|
||||
return bmp;
|
||||
}
|
||||
|
||||
void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, uint flags) {
|
||||
void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, ushort flags) {
|
||||
anim *the_anim;
|
||||
anim_instance *the_anim_instance;
|
||||
bitmap *bm;
|
||||
@@ -2199,7 +2168,7 @@ void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, uint
|
||||
}
|
||||
|
||||
|
||||
void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) {
|
||||
void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) {
|
||||
auto be = &bs->entry;
|
||||
int first_frame = be->info.ani.first_frame;
|
||||
auto first_entry = bm_get_entry(first_frame);
|
||||
@@ -2249,7 +2218,7 @@ void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*
|
||||
}
|
||||
|
||||
|
||||
void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) {
|
||||
void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) {
|
||||
ubyte *data = NULL;
|
||||
int error;
|
||||
ubyte dds_bpp = 0;
|
||||
@@ -2313,7 +2282,7 @@ void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*f
|
||||
#endif
|
||||
}
|
||||
|
||||
void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) {
|
||||
void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) {
|
||||
ubyte *data = NULL;
|
||||
int d_size = 0;
|
||||
int jpg_error = JPEG_ERROR_INVALID;
|
||||
@@ -2360,7 +2329,7 @@ void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags
|
||||
#endif
|
||||
}
|
||||
|
||||
void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) {
|
||||
void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
|
||||
ubyte *data;
|
||||
int pcx_error;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
@@ -2405,7 +2374,7 @@ void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags)
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) {
|
||||
void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) {
|
||||
ubyte *data = NULL;
|
||||
//assume 32 bit - libpng should expand everything
|
||||
int d_size;
|
||||
@@ -2450,7 +2419,7 @@ void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*f
|
||||
#endif
|
||||
}
|
||||
|
||||
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) {
|
||||
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
|
||||
ubyte *data = NULL;
|
||||
int byte_size;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
@@ -2509,7 +2478,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags)
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert) {
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) {
|
||||
auto be = &bs->entry;
|
||||
|
||||
// Unload any existing data
|
||||
@@ -2802,21 +2771,6 @@ void bm_page_in_texture(int bitmapnum, int nframes) {
|
||||
frame_entry->used_flags = BMP_TEX_CUBEMAP;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGB:
|
||||
case BM_TYPE_ETC2_SRGB:
|
||||
frame_entry->used_flags = BMP_TEX_ETC2_RGB8;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA1:
|
||||
case BM_TYPE_ETC2_SRGBA1:
|
||||
frame_entry->used_flags = BMP_TEX_ETC2_RGBA1;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA_EAC:
|
||||
case BM_TYPE_ETC2_SRGBA_EAC:
|
||||
frame_entry->used_flags = BMP_TEX_ETC2_RGBA8;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@@ -2862,21 +2816,6 @@ void bm_page_in_xparent_texture(int bitmapnum, int nframes) {
|
||||
entry->used_flags = BMP_TEX_CUBEMAP;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGB:
|
||||
case BM_TYPE_ETC2_SRGB:
|
||||
entry->used_flags = BMP_TEX_ETC2_RGB8;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA1:
|
||||
case BM_TYPE_ETC2_SRGBA1:
|
||||
entry->used_flags = BMP_TEX_ETC2_RGBA1;
|
||||
continue;
|
||||
|
||||
case BM_TYPE_ETC2_RGBA_EAC:
|
||||
case BM_TYPE_ETC2_SRGBA_EAC:
|
||||
entry->used_flags = BMP_TEX_ETC2_RGBA8;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@@ -3497,47 +3436,3 @@ SDL_Surface* bm_to_sdl_surface(int handle) {
|
||||
return bitmapSurface;
|
||||
|
||||
}
|
||||
|
||||
// copied bm_lock_dds and adjusted for ktx. missing BIG_ENDIAN
|
||||
void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags)
|
||||
{
|
||||
(void)bpp;
|
||||
(void)flags;
|
||||
ubyte* data = nullptr;
|
||||
ubyte ktx_bpp = 0;
|
||||
int ktx_error = KTX1_ERROR_NONE;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
|
||||
auto be = &bs->entry;
|
||||
|
||||
bm_free_data(bs);
|
||||
|
||||
Assert(be->mem_taken > 0);
|
||||
Assert(&be->bm == bmp);
|
||||
|
||||
data = (ubyte*)bm_malloc(handle, be->mem_taken);
|
||||
if (!data)
|
||||
return;
|
||||
memset(data, 0, be->mem_taken);
|
||||
|
||||
// make sure we are using the correct filename in the case of an EFF.
|
||||
// this will populate filename[] whether it's EFF or not
|
||||
EFF_FILENAME_CHECK;
|
||||
|
||||
ktx_error = ktx1_read_bitmap(filename, data, &ktx_bpp);
|
||||
|
||||
if (ktx_error != KTX1_ERROR_NONE)
|
||||
{
|
||||
mprintf(("KTX: read_bitmap error=%d file='%s'\n", ktx_error, filename));
|
||||
bm_free_data(bs);
|
||||
return;
|
||||
}
|
||||
|
||||
bmp->bpp = ktx_bpp;
|
||||
bmp->data = (ptr_u)data;
|
||||
bmp->flags = 0;
|
||||
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
Assert(be->data_size > 0);
|
||||
#endif
|
||||
}
|
||||
+5
-20
@@ -34,7 +34,6 @@
|
||||
|
||||
// Flag positions for bitmap.flags
|
||||
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
|
||||
// Update: bitmap.flags type changed to 16-bit
|
||||
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
|
||||
#define BMP_TEX_XPARENT (1<<1) //!< transparent texture
|
||||
#define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures
|
||||
@@ -44,14 +43,9 @@
|
||||
#define BMP_TEX_BC7 (1<<6) //!< BC7 compressed 8r8g8b8a (32bit)
|
||||
#define BMP_TEX_CUBEMAP (1<<7) //!< a texture made for cubic environment map
|
||||
#define BMP_MASK_BITMAP (1<<8) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
|
||||
#define BMP_TEX_ETC2_RGB8 (1 << 9) //!< ETC2 RGB compressed (24bit, no alpha)
|
||||
#define BMP_TEX_ETC2_RGBA1 (1 << 10) //!< ETC2 RGBA1 compressed (24bit, 1 alpha)
|
||||
#define BMP_TEX_ETC2_RGBA8 (1 << 11) //!< ETC2 RGBA8 compressed (32bit, 8 alpha)
|
||||
|
||||
|
||||
// Combined flags
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB8 |\
|
||||
BMP_TEX_ETC2_RGBA1 | BMP_TEX_ETC2_RGBA8 ) //!< Compressed textures
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 ) //!< Compressed textures
|
||||
#define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures
|
||||
#define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture
|
||||
|
||||
@@ -87,15 +81,7 @@ enum BM_TYPE
|
||||
BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
|
||||
BM_TYPE_3D, //!< 3D in-memory
|
||||
|
||||
BM_TYPE_KTX, //!< generic identifier for KTX1
|
||||
BM_TYPE_ETC2_RGB, //!< 24 bit, no alpha
|
||||
BM_TYPE_ETC2_SRGB, //!< 24 bit, no alpha, signed
|
||||
BM_TYPE_ETC2_RGBA1, //!< 24 bit, 1 bit alpha
|
||||
BM_TYPE_ETC2_SRGBA1, //!< 24 bit, 1 bit alpha, signed
|
||||
BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit, 8 bit alpha
|
||||
BM_TYPE_ETC2_SRGBA_EAC //!< 32 bit, 8 bit alpha, signed
|
||||
BM_TYPE_3D //!< 3D in-memory
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,7 +96,7 @@ struct bitmap
|
||||
short rowsize; //!< What you need to add to go to next row
|
||||
int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
|
||||
int true_bpp; //!< The image's actual bitdepth
|
||||
uint flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
|
||||
ushort flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
|
||||
ptr_u data; //!< Pointer to data, or maybe offset into VRAM.
|
||||
ubyte *palette; /**< @brief Pointer to this bitmap's palette (if it has one).
|
||||
* @details If BMP_NO_PALETTE_MAP flag is cleared, this palette just points to the screen palette. (gr_palette)
|
||||
@@ -149,7 +135,6 @@ void bm_close();
|
||||
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
|
||||
#define BMP_FLAG_CUBEMAP (1<<2)
|
||||
#define BMP_FLAG_RENDER_TARGET_MIPMAP (1<<3)
|
||||
#define BMP_FLAG_RENDER_TARGET_DEPTH_ATTACHMENT (1<<4)
|
||||
|
||||
/**
|
||||
* @brief Allocates memory for the given handle.
|
||||
@@ -359,7 +344,7 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i
|
||||
* @returns A pointer to the bitmap that's valid until bm_unlock is called if successful, or
|
||||
* @returns NULL if unsuccessful
|
||||
*/
|
||||
bitmap* bm_lock(int handle, int bpp, uint flags, bool nodebug = false);
|
||||
bitmap* bm_lock(int handle, int bpp, ushort flags, bool nodebug = false);
|
||||
|
||||
/**
|
||||
* @brief Returns the image type of the given bitmap handle
|
||||
@@ -402,7 +387,7 @@ int bm_is_valid(int handle);
|
||||
* @returns The handle to the first frame on success, or
|
||||
* @returns -1 on failure
|
||||
*/
|
||||
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, uint* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
|
||||
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Gets 3D info on the bitmap indexed by handle.
|
||||
|
||||
+65
-61
@@ -48,14 +48,14 @@ struct apply_##name##_to_fov { \
|
||||
} \
|
||||
}; \
|
||||
fov_t operator op (const fov_t& zoom, const float& scale) { \
|
||||
return std::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
}
|
||||
APPLY_TO_FOV_T(*, mul)
|
||||
APPLY_TO_FOV_T(+, add)
|
||||
APPLY_TO_FOV_T(-, sub)
|
||||
|
||||
// Used to set the default value for in-game options
|
||||
static float fov_default = DEFAULT_FOV;
|
||||
static constexpr float fov_default = DEFAULT_FOV;
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
@@ -64,16 +64,6 @@ static SCP_string fov_display(float val)
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void parse_fov_func()
|
||||
{
|
||||
float value;
|
||||
stuff_float(&value);
|
||||
CLAMP(value, 0.436332f, 1.5708f);
|
||||
fov_default = value;
|
||||
}
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
std::pair<const char*, int>{"Field Of View", 1703},
|
||||
std::pair<const char*, int>{"The vertical field of view", 1704})
|
||||
@@ -84,15 +74,13 @@ auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_func([]() { return fov_default; })
|
||||
.default_val(fov_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.parser(parse_fov_func)
|
||||
.finish();
|
||||
|
||||
bool Use_cockpit_fov = false;
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVToggle",
|
||||
std::pair<const char*, int>{"Cockpit FOV Toggle", 1838},
|
||||
std::pair<const char*, int>{"Whether or not to use a different FOV for cockpit rendering from normal rendering", 1839})
|
||||
@@ -109,7 +97,6 @@ auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVT
|
||||
.importance(61)
|
||||
.finish();
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
|
||||
std::pair<const char*, int>{"Cockpit Field Of View", 1840},
|
||||
std::pair<const char*, int>{"The vertical field of view for cockpit rendering. Only works if cockpits are active and cockpit FOV toggle is turned on.", 1841})
|
||||
@@ -213,35 +200,25 @@ void camera::set_object_host(object *objp, int n_object_host_submodel)
|
||||
object_host_submodel = n_object_host_submodel;
|
||||
set_custom_position_function(NULL);
|
||||
set_custom_orientation_function(NULL);
|
||||
|
||||
if (n_object_host_submodel >= 0 && objp != nullptr && objp->type == OBJ_SHIP)
|
||||
if(n_object_host_submodel > 0)
|
||||
{
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while (ssp != END_OF_LIST(&Ships[objp->instance].subsys_list))
|
||||
if(objp != nullptr && objp->type == OBJ_SHIP)
|
||||
{
|
||||
if (ssp->system_info->subobj_num == n_object_host_submodel)
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
|
||||
{
|
||||
if (ssp->system_info->type == SUBSYSTEM_TURRET)
|
||||
if(ssp->system_info->subobj_num == n_object_host_submodel)
|
||||
{
|
||||
set_custom_position_function(get_turret_cam_pos);
|
||||
set_custom_orientation_function(get_turret_cam_orient);
|
||||
if(ssp->system_info->type == SUBSYSTEM_TURRET)
|
||||
{
|
||||
set_custom_position_function(get_turret_cam_pos);
|
||||
set_custom_orientation_function(get_turret_cam_orient);
|
||||
}
|
||||
}
|
||||
ssp = GET_NEXT( ssp );
|
||||
}
|
||||
ssp = GET_NEXT(ssp);
|
||||
}
|
||||
}
|
||||
else if (Use_model_eyepoint_for_set_camera_host && object_host.isValid())
|
||||
{
|
||||
const object* host = object_host.objp();
|
||||
|
||||
vec3d eye_pos;
|
||||
matrix eye_orient;
|
||||
|
||||
object_get_eye(&eye_pos, &eye_orient, host, false, true, true);
|
||||
|
||||
set_position(&eye_pos);
|
||||
set_rotation(&eye_orient);
|
||||
}
|
||||
}
|
||||
|
||||
void camera::set_object_target(object *objp, int n_object_target_submodel)
|
||||
@@ -360,7 +337,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
if (Use_host_orientation_for_set_camera_facing)
|
||||
{
|
||||
// point along the target vector, but using the host orient's roll
|
||||
vm_vector_2_matrix_norm(&temp_matrix, &targetvec, &orient->vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(&temp_matrix, &targetvec, &orient->vec.uvec, nullptr);
|
||||
|
||||
// if we have a host, we need the difference between the camera's current orient and the orient we want
|
||||
// if not, we will later set the absolute orientation, rather than the orientation relative to the host
|
||||
@@ -373,7 +350,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
else
|
||||
{
|
||||
// point directly along the target vector
|
||||
vm_vector_2_matrix_norm(&temp_matrix, &targetvec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&temp_matrix, &targetvec, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,7 +364,10 @@ void camera::do_frame(float /*in_frametime*/)
|
||||
|
||||
object *camera::get_object_host()
|
||||
{
|
||||
return object_host.objp_or_null();
|
||||
if(object_host.isValid())
|
||||
return object_host.objp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int camera::get_object_host_submodel()
|
||||
@@ -397,7 +377,10 @@ int camera::get_object_host_submodel()
|
||||
|
||||
object *camera::get_object_target()
|
||||
{
|
||||
return object_target.objp_or_null();
|
||||
if(object_target.isValid())
|
||||
return object_target.objp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int camera::get_object_target_submodel()
|
||||
@@ -441,14 +424,22 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
|
||||
if(object_host.isValid())
|
||||
{
|
||||
object *objp = object_host.objp();
|
||||
polymodel *pm = object_get_model(objp);
|
||||
polymodel_instance *pmi = object_get_model_instance(objp);
|
||||
object *objp = object_host.objp;
|
||||
int model_num = object_get_model(objp);
|
||||
polymodel *pm = nullptr;
|
||||
polymodel_instance *pmi = nullptr;
|
||||
|
||||
if(model_num >= 0)
|
||||
{
|
||||
pm = model_get(model_num);
|
||||
if (objp->type == OBJ_SHIP)
|
||||
pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
}
|
||||
|
||||
if(object_host_submodel < 0 || pm == NULL)
|
||||
{
|
||||
vm_vec_unrotate(&c_pos, &pt, &object_host.objp()->orient);
|
||||
vm_vec_add2(&c_pos, &object_host.objp()->pos);
|
||||
vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
|
||||
vm_vec_add2(&c_pos, &object_host.objp->pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,10 +488,19 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
{
|
||||
if(object_target.isValid())
|
||||
{
|
||||
object *target_objp = object_target.objp();
|
||||
polymodel *target_pm = object_get_model(target_objp);
|
||||
polymodel_instance *target_pmi = object_get_model_instance(target_objp);
|
||||
object *target_objp = object_target.objp;
|
||||
int model_num = object_get_model(target_objp);
|
||||
polymodel *target_pm = nullptr;
|
||||
polymodel_instance *target_pmi = nullptr;
|
||||
vec3d target_pos = vmd_zero_vector;
|
||||
|
||||
//See if we can get the model
|
||||
if(model_num >= 0)
|
||||
{
|
||||
target_pm = model_get(model_num);
|
||||
if (target_objp->type == OBJ_SHIP)
|
||||
target_pmi = model_get_instance(Ships[target_objp->instance].model_instance_num);
|
||||
}
|
||||
|
||||
//If we don't have a submodel or don't have the model use object pos
|
||||
//Otherwise, find the submodel pos as it is rotated
|
||||
@@ -518,14 +518,14 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
|
||||
vec3d targetvec;
|
||||
vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos);
|
||||
vm_vector_2_matrix_norm(&c_ori, &targetvec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if(object_host.isValid())
|
||||
{
|
||||
if(eyep)
|
||||
{
|
||||
vm_vector_2_matrix_norm(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp()->orient.vec.uvec) ? nullptr : &object_host.objp()->orient.vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if (use_host_orient)
|
||||
@@ -534,7 +534,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
}
|
||||
else
|
||||
{
|
||||
c_ori = object_host.objp()->orient;
|
||||
c_ori = object_host.objp->orient;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -581,7 +581,7 @@ warp_camera::warp_camera(object *objp)
|
||||
|
||||
vec3d object_pos = objp->pos;
|
||||
matrix tmp;
|
||||
object_get_eye(&object_pos, &tmp, objp);
|
||||
ship_get_eye(&object_pos, &tmp, objp);
|
||||
|
||||
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.rvec, 0.0f );
|
||||
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.uvec, 0.952f );
|
||||
@@ -735,7 +735,6 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
|
||||
text_buf = in_text;
|
||||
sexp_replace_variable_names_with_values(text_buf);
|
||||
sexp_container_replace_refs_with_values(text_buf);
|
||||
// (message_translate_tokens is called when the subtitle is queued, so does not need to be called here)
|
||||
in_text = text_buf.c_str();
|
||||
}
|
||||
|
||||
@@ -795,7 +794,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
|
||||
//Get text size
|
||||
for(int i = 0; i < num_text_lines; i++)
|
||||
{
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], 1.0f, static_cast<size_t>(text_line_lens[i]));
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], static_cast<size_t>(text_line_lens[i]));
|
||||
|
||||
if(w > tw)
|
||||
tw = w;
|
||||
@@ -1089,6 +1088,13 @@ int cam_get_next_sig()
|
||||
return next_sig++;
|
||||
}
|
||||
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
matrix ori;
|
||||
vm_vector_2_matrix_norm(&ori, n_norm);
|
||||
return cam_create(n_name, n_pos, &ori, n_object, n_object_host_submodel);
|
||||
}
|
||||
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
camera *cam = NULL;
|
||||
@@ -1232,7 +1238,7 @@ void subtitles_do_frame_post_shaded(float frametime)
|
||||
}
|
||||
}
|
||||
|
||||
static vec3d normal_cache;
|
||||
vec3d normal_cache;
|
||||
|
||||
void get_turret_cam_pos(camera *cam, vec3d *pos)
|
||||
{
|
||||
@@ -1260,7 +1266,7 @@ void get_turret_cam_orient(camera *cam, matrix *ori)
|
||||
object_h obj(cam->get_object_host());
|
||||
if(!obj.isValid())
|
||||
return;
|
||||
vm_vector_2_matrix_norm(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec) ? nullptr : &cam->get_object_host()->orient.vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec)?NULL:&cam->get_object_host()->orient.vec.uvec, NULL);
|
||||
}
|
||||
|
||||
eye* get_submodel_eye(polymodel *pm, int submodel_num)
|
||||
@@ -1297,10 +1303,8 @@ float cam_get_bbox_dist(const object* viewer_obj, float preferred_distance, cons
|
||||
if (preferred_distance > (viewer_obj->radius * EXTERN_CAM_BBOX_MULTIPLIER_PADDING + EXTERN_CAM_BBOX_CONSTANT_PADDING) * 1.5f)
|
||||
return preferred_distance;
|
||||
|
||||
polymodel* pm = object_get_model(viewer_obj);
|
||||
if (pm == nullptr)
|
||||
return preferred_distance;
|
||||
|
||||
int modelnum = object_get_model(viewer_obj);
|
||||
polymodel* pm = model_get(modelnum);
|
||||
vec3d adjusted_bbox;
|
||||
const vec3d* cam_vec = &cam_orient->vec.fvec;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <variant>
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
#define CAM_STATIONARY_FOV (1<<0)
|
||||
#define CAM_STATIONARY_ORI (1<<1)
|
||||
@@ -28,7 +28,7 @@ struct asymmetric_fov {
|
||||
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
|
||||
};
|
||||
using fov_t = std::variant<float, asymmetric_fov>;
|
||||
using fov_t = mpark::variant<float, asymmetric_fov>;
|
||||
fov_t operator* (const fov_t&, const float&);
|
||||
fov_t operator+ (const fov_t&, const float&);
|
||||
fov_t operator- (const fov_t&, const float&);
|
||||
@@ -179,6 +179,7 @@ void cam_init();
|
||||
void cam_close();
|
||||
void cam_do_frame(float frametime);
|
||||
camid cam_create(const char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
void cam_delete(camid cid);
|
||||
bool cam_set_camera(camid cid);
|
||||
void cam_reset_camera();
|
||||
|
||||
@@ -1,609 +0,0 @@
|
||||
#include "freespace.h"
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "camera/camera.h"
|
||||
#include "camera/photomode.h"
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
#include "debugconsole/console.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/font.h"
|
||||
#include "hud/hud.h"
|
||||
#include "io/keycontrol.h"
|
||||
#include "localization/localize.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "object/object.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "playerman/player.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "sound/audiostr.h"
|
||||
|
||||
bool Photo_mode_active = false;
|
||||
camid Photo_mode_id;
|
||||
fix Photo_mode_saved_time_compression = F1_0;
|
||||
bool Photo_mode_saved_lock_state = false;
|
||||
bool Photo_mode_screenshot_queued_this_frame = false;
|
||||
bool Photo_mode_allowed = true;
|
||||
bool Photo_mode_audio_paused = false;
|
||||
|
||||
const float Photo_mode_turn_rate = PI_2; // radians/sec
|
||||
constexpr float Photo_mode_move_speed = 90.0f;
|
||||
constexpr float Photo_mode_boost_multiplier = 6.0f;
|
||||
constexpr float Photo_mode_time_compression = 0.01f;
|
||||
|
||||
struct photo_mode_post_effect_state {
|
||||
SCP_string name;
|
||||
float intensity = 0.0f;
|
||||
vec3d rgb = vmd_zero_vector;
|
||||
int effect_idx = -1; // index into Post_processing_manager->getPostEffects()
|
||||
};
|
||||
|
||||
enum class photo_mode_param_type {
|
||||
INT_RANGE, // adjustable integer value with min/max
|
||||
BOOL_TOGGLE // on/off toggle
|
||||
};
|
||||
|
||||
enum class photo_mode_param_role {
|
||||
NONE,
|
||||
GRID_OVERLAY, // bool toggle that enables the rule of thirds grid
|
||||
POST_EFFECT // drives a post processing effect by name
|
||||
};
|
||||
|
||||
struct photo_mode_param {
|
||||
const char* label; // display name
|
||||
int xstr_id; // XSTR localization ID
|
||||
photo_mode_param_type type;
|
||||
photo_mode_param_role role;
|
||||
|
||||
// For POST_EFFECT role: post processing effect name, range, and values
|
||||
const char* effect_name; // post processing effect to control (nullptr if role != POST_EFFECT)
|
||||
int effect_idx; // index into Post_processing_manager->getPostEffects() (-1 if unresolved)
|
||||
int min_val;
|
||||
int max_val;
|
||||
int value;
|
||||
int saved_value;
|
||||
|
||||
// For BOOL_TOGGLE
|
||||
bool bool_value;
|
||||
};
|
||||
|
||||
// Parameter definitions
|
||||
SCP_vector<photo_mode_param> Photo_mode_params = {
|
||||
{"Grid", 1906, photo_mode_param_type::BOOL_TOGGLE, photo_mode_param_role::GRID_OVERLAY, nullptr, -1, 0, 0, 0, 0, false},
|
||||
{"Saturation", 1903, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "saturation", -1, 0, 200, 100, 100, false},
|
||||
{"Brightness", 1904, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "brightness", -1, 0, 200, 100, 100, false},
|
||||
{"Contrast", 1905, photo_mode_param_type::INT_RANGE, photo_mode_param_role::POST_EFFECT, "contrast", -1, 0, 200, 100, 100, false},
|
||||
};
|
||||
|
||||
SCP_vector<photo_mode_post_effect_state> Photo_mode_saved_post_effects;
|
||||
int Photo_mode_selected_parameter = 0;
|
||||
int Photo_mode_panel_width = 0;
|
||||
int Photo_mode_panel_padding_w = 0;
|
||||
|
||||
void photo_mode_capture_post_effect_state()
|
||||
{
|
||||
Photo_mode_saved_post_effects.clear();
|
||||
|
||||
if (graphics::Post_processing_manager == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
|
||||
Photo_mode_saved_post_effects.reserve(post_effects.size());
|
||||
|
||||
for (int i = 0; i < static_cast<int>(post_effects.size()); ++i) {
|
||||
const auto& effect = post_effects[i];
|
||||
photo_mode_post_effect_state state;
|
||||
state.name = effect.name;
|
||||
state.intensity = effect.intensity;
|
||||
state.rgb = effect.rgb;
|
||||
state.effect_idx = i;
|
||||
Photo_mode_saved_post_effects.push_back(state);
|
||||
}
|
||||
|
||||
// Resolve effect indices for each param.
|
||||
// Done once here rather than on every frame or every key press.
|
||||
for (auto& param : Photo_mode_params) {
|
||||
if (param.role != photo_mode_param_role::POST_EFFECT) {
|
||||
param.effect_idx = -1;
|
||||
continue;
|
||||
}
|
||||
param.effect_idx = -1;
|
||||
for (int j = 0; j < static_cast<int>(post_effects.size()); ++j) {
|
||||
if (!stricmp(post_effects[j].name.c_str(), param.effect_name)) {
|
||||
param.effect_idx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void photo_mode_apply_saved_post_effect_state(bool clear_saved_state)
|
||||
{
|
||||
if (graphics::Post_processing_manager == nullptr) {
|
||||
if (clear_saved_state) {
|
||||
Photo_mode_saved_post_effects.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
|
||||
for (const auto& saved_state : Photo_mode_saved_post_effects) {
|
||||
if (saved_state.effect_idx < 0 || saved_state.effect_idx >= static_cast<int>(post_effects.size())) {
|
||||
continue;
|
||||
}
|
||||
const auto& effect = post_effects[saved_state.effect_idx];
|
||||
const int value = static_cast<int>(std::lround((saved_state.intensity - effect.add) * effect.div));
|
||||
gr_post_process_set_effect(saved_state.name.c_str(), value, &saved_state.rgb);
|
||||
}
|
||||
|
||||
if (clear_saved_state) {
|
||||
Photo_mode_saved_post_effects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
int photo_mode_get_saved_post_effect_value(int effect_idx)
|
||||
{
|
||||
int value = 100;
|
||||
|
||||
if (effect_idx < 0 || graphics::Post_processing_manager == nullptr) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const auto& post_effects = graphics::Post_processing_manager->getPostEffects();
|
||||
if (effect_idx >= static_cast<int>(post_effects.size())) {
|
||||
return value;
|
||||
}
|
||||
|
||||
for (const auto& saved_state : Photo_mode_saved_post_effects) {
|
||||
if (saved_state.effect_idx != effect_idx) {
|
||||
continue;
|
||||
}
|
||||
const auto& effect = post_effects[effect_idx];
|
||||
value = static_cast<int>(std::lround((saved_state.intensity - effect.add) * effect.div));
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void photo_mode_sync_parameter_values_from_saved_state()
|
||||
{
|
||||
for (auto& param : Photo_mode_params) {
|
||||
if (param.role == photo_mode_param_role::POST_EFFECT) {
|
||||
param.saved_value = photo_mode_get_saved_post_effect_value(param.effect_idx);
|
||||
param.value = param.saved_value;
|
||||
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
|
||||
param.bool_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Photo_mode_selected_parameter = 0;
|
||||
}
|
||||
|
||||
void photo_mode_apply_parameter_values()
|
||||
{
|
||||
for (const auto& param : Photo_mode_params) {
|
||||
if (param.role == photo_mode_param_role::POST_EFFECT) {
|
||||
gr_post_process_set_effect(param.effect_name, param.value, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCP_string format_photo_mode_keybind(int action)
|
||||
{
|
||||
auto primary = Control_config[action].first.textify();
|
||||
auto secondary = Control_config[action].second.textify();
|
||||
|
||||
if (primary.empty() && secondary.empty()) {
|
||||
return XSTR("Unbound", 1907);
|
||||
}
|
||||
if (primary.empty()) {
|
||||
return secondary;
|
||||
}
|
||||
if (secondary.empty()) {
|
||||
return primary;
|
||||
}
|
||||
|
||||
return primary + " / " + secondary;
|
||||
}
|
||||
|
||||
void photo_mode_compute_hud_layout()
|
||||
{
|
||||
const auto old_font = font::get_current_fontnum();
|
||||
font::set_font(font::FONT1);
|
||||
|
||||
int max_text_width = 0;
|
||||
char buf[512];
|
||||
auto measure = [&](const char* text) {
|
||||
int w = 0;
|
||||
gr_get_string_size(&w, nullptr, text);
|
||||
if (w > max_text_width) max_text_width = w;
|
||||
};
|
||||
|
||||
// Find the longest string
|
||||
measure(XSTR("Photo Mode", 1892));
|
||||
measure(XSTR("Controls", 1893));
|
||||
measure(XSTR("Status", 1900));
|
||||
measure(XSTR("Effects", 1914));
|
||||
snprintf(buf, sizeof(buf), XSTR("Toggle: %s", 1894), format_photo_mode_keybind(TOGGLE_PHOTO_MODE).c_str());
|
||||
measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Previous Filter: %s", 1895), format_photo_mode_keybind(PHOTO_MODE_FILTER_PREV).c_str());
|
||||
measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Next Filter: %s", 1896), format_photo_mode_keybind(PHOTO_MODE_FILTER_NEXT).c_str());
|
||||
measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Reset Filters: %s", 1897), format_photo_mode_keybind(PHOTO_MODE_FILTER_RESET).c_str());
|
||||
measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Decrease Parameter: %s", 1898), format_photo_mode_keybind(PHOTO_MODE_PARAM_DECREASE).c_str());
|
||||
measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Increase Parameter: %s", 1899), format_photo_mode_keybind(PHOTO_MODE_PARAM_INCREASE).c_str());
|
||||
measure(buf);
|
||||
|
||||
// Use worst case placeholder values for the dynamic status strings so the
|
||||
// panel width stays stable as these change during a session.
|
||||
snprintf(buf, sizeof(buf), XSTR("Time Compression: %.2fx", 1901), 64.0f); measure(buf);
|
||||
snprintf(buf, sizeof(buf), XSTR("Cam Pos: X %.1f Y %.1f Z %.1f", 1902), -99999.9f, -99999.9f, -99999.9f); measure(buf);
|
||||
|
||||
for (const auto& param : Photo_mode_params) {
|
||||
if (param.type == photo_mode_param_type::INT_RANGE) {
|
||||
snprintf(buf, sizeof(buf), "%s: %d", XSTR(param.label, param.xstr_id), param.max_val);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%s: %s", XSTR(param.label, param.xstr_id), XSTR("Off", 1285));
|
||||
}
|
||||
measure(buf);
|
||||
}
|
||||
|
||||
font::set_font(old_font);
|
||||
|
||||
Photo_mode_panel_padding_w = max_text_width / 10;
|
||||
Photo_mode_panel_width = max_text_width + Photo_mode_panel_padding_w * 2;
|
||||
}
|
||||
|
||||
void photo_mode_set_active(bool active)
|
||||
{
|
||||
if (active == Photo_mode_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
if (!Photo_mode_allowed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Game_mode & GM_MULTIPLAYER) != 0 || Player_obj == nullptr || !(Game_mode & GM_IN_MISSION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time_compression_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Player_obj->type != OBJ_SHIP) {
|
||||
return;
|
||||
}
|
||||
|
||||
Photo_mode_saved_time_compression = Game_time_compression;
|
||||
Photo_mode_saved_lock_state = Time_compression_locked;
|
||||
|
||||
Photo_mode_id = cam_create("Photo Mode", &Eye_position, &Eye_matrix);
|
||||
if (!Photo_mode_id.isValid() || !cam_set_camera(Photo_mode_id)) {
|
||||
cam_delete(Photo_mode_id);
|
||||
Photo_mode_id = camid();
|
||||
return;
|
||||
}
|
||||
|
||||
set_time_compression(Photo_mode_time_compression, 0.0f);
|
||||
lock_time_compression(true);
|
||||
|
||||
photo_mode_capture_post_effect_state();
|
||||
photo_mode_sync_parameter_values_from_saved_state();
|
||||
photo_mode_apply_parameter_values();
|
||||
photo_mode_compute_hud_layout();
|
||||
|
||||
audiostream_pause_all();
|
||||
message_pause_all();
|
||||
Photo_mode_audio_paused = true;
|
||||
|
||||
Photo_mode_active = true;
|
||||
mprintf(("Photo Mode enabled.\n"));
|
||||
|
||||
if (scripting::hooks::OnPhotoModeStarted->isActive()) {
|
||||
scripting::hooks::OnPhotoModeStarted->run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cam_reset_camera();
|
||||
cam_delete(Photo_mode_id);
|
||||
Photo_mode_id = camid();
|
||||
|
||||
set_time_compression(f2fl(Photo_mode_saved_time_compression), 0.0f);
|
||||
lock_time_compression(Photo_mode_saved_lock_state);
|
||||
|
||||
if (Photo_mode_audio_paused) {
|
||||
audiostream_unpause_all();
|
||||
message_resume_all();
|
||||
Photo_mode_audio_paused = false;
|
||||
}
|
||||
|
||||
photo_mode_apply_saved_post_effect_state(true);
|
||||
for (auto& param : Photo_mode_params) {
|
||||
if (param.type == photo_mode_param_type::INT_RANGE) {
|
||||
param.value = 100;
|
||||
param.saved_value = 100;
|
||||
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
|
||||
param.bool_value = false;
|
||||
}
|
||||
}
|
||||
Photo_mode_selected_parameter = 0;
|
||||
|
||||
Photo_mode_active = false;
|
||||
mprintf(("Photo Mode disabled.\n"));
|
||||
|
||||
if (scripting::hooks::OnPhotoModeEnded->isActive()) {
|
||||
scripting::hooks::OnPhotoModeEnded->run();
|
||||
}
|
||||
}
|
||||
|
||||
void photo_mode_do_frame(float frame_time)
|
||||
{
|
||||
if (!Photo_mode_active || !Photo_mode_id.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Photo_mode_allowed) {
|
||||
photo_mode_set_active(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto photo_mode = Photo_mode_id.getCamera();
|
||||
if (photo_mode == nullptr) {
|
||||
photo_mode_set_active(false);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3d cam_pos = vmd_zero_vector;
|
||||
matrix cam_orient = vmd_identity_matrix;
|
||||
photo_mode->get_info(&cam_pos, &cam_orient);
|
||||
|
||||
angles delta_angles{};
|
||||
float pitch = check_control_timef(PITCH_FORWARD) - check_control_timef(PITCH_BACK);
|
||||
float heading = check_control_timef(YAW_RIGHT) - check_control_timef(YAW_LEFT);
|
||||
float bank = check_control_timef(BANK_LEFT) - check_control_timef(BANK_RIGHT);
|
||||
|
||||
int axis[Action::NUM_VALUES] = {0};
|
||||
control_get_axes_readings(axis, flRealframetime);
|
||||
pitch += -f2fl(axis[Action::PITCH]);
|
||||
heading += f2fl(axis[Action::HEADING]);
|
||||
bank -= f2fl(axis[Action::BANK]);
|
||||
|
||||
CLAMP(pitch, -1.0f, 1.0f);
|
||||
CLAMP(heading, -1.0f, 1.0f);
|
||||
CLAMP(bank, -1.0f, 1.0f);
|
||||
|
||||
delta_angles.p = pitch * Photo_mode_turn_rate * frame_time;
|
||||
delta_angles.h = heading * Photo_mode_turn_rate * frame_time;
|
||||
delta_angles.b = bank * Photo_mode_turn_rate * frame_time;
|
||||
|
||||
matrix delta_orient = vmd_identity_matrix;
|
||||
vm_angles_2_matrix(&delta_orient, &delta_angles);
|
||||
vm_matrix_x_matrix(&cam_orient, &cam_orient, &delta_orient);
|
||||
vm_fix_matrix(&cam_orient);
|
||||
|
||||
float speed = Photo_mode_move_speed;
|
||||
if (check_control(AFTERBURNER)) {
|
||||
speed *= Photo_mode_boost_multiplier;
|
||||
}
|
||||
|
||||
float forward = check_control_timef(FORWARD_THRUST) - check_control_timef(REVERSE_THRUST);
|
||||
float right = check_control_timef(RIGHT_SLIDE_THRUST) - check_control_timef(LEFT_SLIDE_THRUST);
|
||||
float up = check_control_timef(UP_SLIDE_THRUST) - check_control_timef(DOWN_SLIDE_THRUST);
|
||||
|
||||
CLAMP(forward, -1.0f, 1.0f);
|
||||
CLAMP(right, -1.0f, 1.0f);
|
||||
CLAMP(up, -1.0f, 1.0f);
|
||||
|
||||
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.fvec, forward * speed * frame_time);
|
||||
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.rvec, right * speed * frame_time);
|
||||
vm_vec_scale_add2(&cam_pos, &cam_orient.vec.uvec, up * speed * frame_time);
|
||||
|
||||
photo_mode->set_rotation(&cam_orient);
|
||||
photo_mode->set_position(&cam_pos);
|
||||
}
|
||||
|
||||
void photo_mode_maybe_render_hud()
|
||||
{
|
||||
if (!Photo_mode_active || Photo_mode_screenshot_queued_this_frame || gr_is_screenshot_requested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Photo_mode_allowed) {
|
||||
photo_mode_set_active(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto photo_mode = Photo_mode_id.getCamera();
|
||||
if (photo_mode == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec3d cam_pos = vmd_zero_vector;
|
||||
matrix cam_orient = vmd_identity_matrix;
|
||||
photo_mode->get_info(&cam_pos, &cam_orient);
|
||||
|
||||
const auto toggle_keybind = format_photo_mode_keybind(TOGGLE_PHOTO_MODE);
|
||||
const auto prev_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_PREV);
|
||||
const auto next_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_NEXT);
|
||||
const auto reset_filter_keybind = format_photo_mode_keybind(PHOTO_MODE_FILTER_RESET);
|
||||
const auto decrease_param_keybind = format_photo_mode_keybind(PHOTO_MODE_PARAM_DECREASE);
|
||||
const auto increase_param_keybind = format_photo_mode_keybind(PHOTO_MODE_PARAM_INCREASE);
|
||||
gr_set_color_fast(&Color_silver);
|
||||
const auto old_font = font::get_current_fontnum();
|
||||
font::set_font(font::FONT1);
|
||||
const int line_height = gr_get_font_height();
|
||||
const int num_param_lines = static_cast<int>(Photo_mode_params.size());
|
||||
const int panel_padding_h = line_height / 2;
|
||||
const int panel_padding_w = Photo_mode_panel_padding_w;
|
||||
const int panel_width = Photo_mode_panel_width;
|
||||
const int panel_height = panel_padding_h * 2 + line_height * (15 + num_param_lines);
|
||||
const int panel_x = gr_screen.center_offset_x + (gr_screen.center_w / 4);
|
||||
const int panel_y = gr_screen.center_offset_y + gr_screen.center_h - panel_height - (gr_screen.center_h / 6);
|
||||
|
||||
gr_line(panel_x, panel_y, panel_x + panel_width, panel_y, GR_RESIZE_NONE);
|
||||
gr_line(panel_x, panel_y + panel_height, panel_x + panel_width, panel_y + panel_height, GR_RESIZE_NONE);
|
||||
gr_line(panel_x, panel_y, panel_x, panel_y + panel_height, GR_RESIZE_NONE);
|
||||
gr_line(panel_x + panel_width, panel_y, panel_x + panel_width, panel_y + panel_height, GR_RESIZE_NONE);
|
||||
gr_line(panel_x,
|
||||
panel_y + line_height + panel_padding_h + 1,
|
||||
panel_x + panel_width,
|
||||
panel_y + line_height + panel_padding_h + 1,
|
||||
GR_RESIZE_NONE);
|
||||
|
||||
bool grid_enabled = false;
|
||||
for (const auto& param : Photo_mode_params) {
|
||||
if (param.role == photo_mode_param_role::GRID_OVERLAY) {
|
||||
grid_enabled = param.bool_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (grid_enabled) {
|
||||
const int x1 = gr_screen.center_offset_x + gr_screen.center_w / 3;
|
||||
const int x2 = gr_screen.center_offset_x + (gr_screen.center_w * 2) / 3;
|
||||
const int y1 = gr_screen.center_offset_y + gr_screen.center_h / 3;
|
||||
const int y2 = gr_screen.center_offset_y + (gr_screen.center_h * 2) / 3;
|
||||
gr_line(x1, gr_screen.center_offset_y, x1, gr_screen.center_offset_y + gr_screen.center_h, GR_RESIZE_NONE);
|
||||
gr_line(x2, gr_screen.center_offset_y, x2, gr_screen.center_offset_y + gr_screen.center_h, GR_RESIZE_NONE);
|
||||
gr_line(gr_screen.center_offset_x, y1, gr_screen.center_offset_x + gr_screen.center_w, y1, GR_RESIZE_NONE);
|
||||
gr_line(gr_screen.center_offset_x, y2, gr_screen.center_offset_x + gr_screen.center_w, y2, GR_RESIZE_NONE);
|
||||
}
|
||||
|
||||
int line = panel_y + panel_padding_h;
|
||||
const int text_x = panel_x + panel_padding_w;
|
||||
gr_printf_no_resize(text_x, line, "%s", XSTR("Photo Mode", 1892));
|
||||
line += line_height;
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, "%s", XSTR("Controls", 1893));
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Toggle: %s", 1894), toggle_keybind.c_str());
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Previous Filter: %s", 1895), prev_filter_keybind.c_str());
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Next Filter: %s", 1896), next_filter_keybind.c_str());
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Reset Filters: %s", 1897), reset_filter_keybind.c_str());
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Decrease Parameter: %s", 1898), decrease_param_keybind.c_str());
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Increase Parameter: %s", 1899), increase_param_keybind.c_str());
|
||||
line += line_height;
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, "%s", XSTR("Status", 1900));
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x, line, XSTR("Time Compression: %.2fx", 1901), f2fl(Game_time_compression));
|
||||
line += line_height;
|
||||
gr_printf_no_resize(text_x,
|
||||
line,
|
||||
XSTR("Cam Pos: X %.1f Y %.1f Z %.1f", 1902),
|
||||
cam_pos.xyz.x,
|
||||
cam_pos.xyz.y,
|
||||
cam_pos.xyz.z);
|
||||
line += line_height;
|
||||
line += line_height;
|
||||
gr_set_color_fast(&Color_silver);
|
||||
gr_printf_no_resize(text_x, line, "%s", XSTR("Effects", 1914));
|
||||
line += line_height;
|
||||
for (int i = 0; i < static_cast<int>(Photo_mode_params.size()); ++i) {
|
||||
const auto& param = Photo_mode_params[i];
|
||||
gr_set_color_fast(Photo_mode_selected_parameter == i ? &Color_bright_white : &Color_silver);
|
||||
|
||||
if (param.type == photo_mode_param_type::INT_RANGE) {
|
||||
gr_printf_no_resize(text_x, line, "%s: %d", XSTR(param.label, param.xstr_id), param.value);
|
||||
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
|
||||
gr_printf_no_resize(text_x, line, "%s: %s", XSTR(param.label, param.xstr_id),
|
||||
param.bool_value ? XSTR("On", 1285) : XSTR("Off", 1286));
|
||||
}
|
||||
|
||||
line += line_height;
|
||||
}
|
||||
|
||||
font::set_font(old_font);
|
||||
}
|
||||
|
||||
void photo_mode_clear_screenshot_queued_flag()
|
||||
{
|
||||
Photo_mode_screenshot_queued_this_frame = false;
|
||||
}
|
||||
|
||||
void photo_mode_set_screenshot_queued_flag()
|
||||
{
|
||||
Photo_mode_screenshot_queued_this_frame = true;
|
||||
}
|
||||
|
||||
void game_toggle_photo_mode()
|
||||
{
|
||||
photo_mode_set_active(!Photo_mode_active);
|
||||
}
|
||||
|
||||
void game_set_photo_mode_allowed(bool allowed)
|
||||
{
|
||||
Photo_mode_allowed = allowed && ((Game_mode & GM_MULTIPLAYER) == 0);
|
||||
|
||||
if (!Photo_mode_allowed && Photo_mode_active) {
|
||||
photo_mode_set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool game_get_photo_mode_allowed()
|
||||
{
|
||||
return Photo_mode_allowed && ((Game_mode & GM_MULTIPLAYER) == 0);
|
||||
}
|
||||
|
||||
bool game_is_photo_mode_active()
|
||||
{
|
||||
return Photo_mode_active;
|
||||
}
|
||||
|
||||
void game_cycle_photo_mode_filter(int direction)
|
||||
{
|
||||
if (!Photo_mode_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
Photo_mode_selected_parameter = std::clamp(Photo_mode_selected_parameter + direction, 0, static_cast<int>(Photo_mode_params.size()) - 1);
|
||||
}
|
||||
|
||||
void game_reset_photo_mode_filters()
|
||||
{
|
||||
if (!Photo_mode_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& param : Photo_mode_params) {
|
||||
if (param.type == photo_mode_param_type::INT_RANGE) {
|
||||
param.value = param.saved_value;
|
||||
} else if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
|
||||
param.bool_value = false;
|
||||
}
|
||||
}
|
||||
photo_mode_apply_parameter_values();
|
||||
}
|
||||
|
||||
void game_adjust_photo_mode_filter_parameter(int delta)
|
||||
{
|
||||
if (!Photo_mode_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& param = Photo_mode_params[Photo_mode_selected_parameter];
|
||||
|
||||
if (param.type == photo_mode_param_type::BOOL_TOGGLE) {
|
||||
param.bool_value = (delta > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
param.value = std::clamp(param.value + delta, param.min_val, param.max_val);
|
||||
photo_mode_apply_parameter_values();
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void photo_mode_set_active(bool active);
|
||||
void photo_mode_do_frame(float frame_time);
|
||||
void photo_mode_maybe_render_hud();
|
||||
void photo_mode_clear_screenshot_queued_flag();
|
||||
void photo_mode_set_screenshot_queued_flag();
|
||||
|
||||
// mission-level permission to allow/disallow Photo Mode
|
||||
void game_toggle_photo_mode();
|
||||
void game_set_photo_mode_allowed(bool allowed);
|
||||
bool game_get_photo_mode_allowed();
|
||||
bool game_is_photo_mode_active();
|
||||
void game_cycle_photo_mode_filter(int direction);
|
||||
void game_reset_photo_mode_filters();
|
||||
void game_adjust_photo_mode_filter_parameter(int delta);
|
||||
+151
-18
@@ -20,10 +20,12 @@
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h> /* needed for memory mapping of file functions */
|
||||
#endif
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <glob.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
@@ -52,7 +54,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
// Root must be index 1!!
|
||||
{ CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT },
|
||||
{ CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT },
|
||||
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
|
||||
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm .lua", CF_TYPE_DATA },
|
||||
@@ -66,26 +68,26 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .ktx .sdr .vert .frag .glsl", CF_TYPE_DATA },
|
||||
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
|
||||
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", /* DON'T add pilot files here!! */ CF_TYPE_DATA },
|
||||
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
|
||||
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html .qch .css .png .jpg", CF_TYPE_DATA }
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -106,6 +108,12 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type, size_t offset, size_t size);
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const char* original_filename, const void* data, size_t size, int dir_type);
|
||||
|
||||
#if defined _WIN32
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, HANDLE hFile, int type);
|
||||
#elif defined SCP_UNIX
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type);
|
||||
#endif
|
||||
|
||||
static void cf_chksum_long_init();
|
||||
|
||||
static void dump_opened_files()
|
||||
@@ -186,7 +194,6 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
char buf[CFILE_ROOT_DIRECTORY_LEN];
|
||||
|
||||
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
|
||||
buf[CFILE_ROOT_DIRECTORY_LEN - 1] = '\0';
|
||||
|
||||
// are we in a root directory?
|
||||
@@ -625,13 +632,18 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
// parameters: *filepath ==> name of file to open (may be path+name)
|
||||
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
|
||||
// passing NULL to mode triggers an assert and returns NULL
|
||||
// type ==> one of: CFILE_NORMAL
|
||||
// CFILE_MEMORY_MAPPED
|
||||
// dir_type => override extension check, value is one of CF_TYPE* #defines
|
||||
//
|
||||
// NOTE: type parameter is an optional parameter. The default value is CFILE_NORMAL
|
||||
//
|
||||
//
|
||||
// returns: success ==> address of CFILE structure
|
||||
// error ==> NULL
|
||||
//
|
||||
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int dir_type,
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
|
||||
bool /* localize */, uint32_t location_flags)
|
||||
{
|
||||
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
|
||||
@@ -647,6 +659,12 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
// Check that all the parameters make sense
|
||||
Assert(file_path && strlen(file_path));
|
||||
Assert( mode != NULL );
|
||||
|
||||
// Can only open read-only binary files in memory mapped mode.
|
||||
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") != 0 ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
// If in write mode, just try to open the file straight off
|
||||
@@ -671,6 +689,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
|
||||
cf_create_default_path_string(longname, dir_type, file_path, location_flags);
|
||||
}
|
||||
Assert( !(type & CFILE_MEMORY_MAPPED) );
|
||||
|
||||
// JOHN: TODO, you should create the path if it doesn't exist.
|
||||
|
||||
@@ -721,11 +740,35 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
auto find_res = cf_find_file_location(file_path, dir_type, location_flags);
|
||||
|
||||
if ( find_res.found ) {
|
||||
|
||||
// Fount it, now create a cfile out of it
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
|
||||
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, find_res, mode, dir_type);
|
||||
if ( type & CFILE_MEMORY_MAPPED ) {
|
||||
|
||||
// Can't open memory mapped files out of pack or memory files
|
||||
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
|
||||
#if defined _WIN32
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, file_path, hFile, dir_type);
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
|
||||
if (fp) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, file_path, fp, dir_type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} else {
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, find_res, mode, dir_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -850,7 +893,27 @@ int cfclose( CFILE * cfile )
|
||||
Assert(cfile != NULL);
|
||||
|
||||
result = 0;
|
||||
if ( cfile->fp != nullptr ) {
|
||||
if ( cfile->data && cfile->mem_mapped ) {
|
||||
// close memory mapped file
|
||||
#if defined _WIN32
|
||||
result = UnmapViewOfFile((void*)cfile->data);
|
||||
Assert(result);
|
||||
result = CloseHandle(cfile->hInFile);
|
||||
Assert(result); // Ensure file handle is closed properly
|
||||
result = CloseHandle(cfile->hMapFile);
|
||||
Assert(result); // Ensure file handle is closed properly
|
||||
result = 0;
|
||||
#elif defined SCP_UNIX
|
||||
// FIXME: result is wrong after munmap() but it is successful
|
||||
//result = munmap(cfile->data, cfile->data_length);
|
||||
//Assert(result);
|
||||
// This const_cast is safe since the pointer returned by mmap was also non-const
|
||||
munmap(const_cast<void*>(cfile->data), cfile->data_length);
|
||||
if ( cfile->fp != nullptr)
|
||||
result = fclose(cfile->fp);
|
||||
#endif
|
||||
|
||||
} else if ( cfile->fp != nullptr ) {
|
||||
Assert(cfile->fp != nullptr);
|
||||
result = fclose(cfile->fp);
|
||||
} else {
|
||||
@@ -895,6 +958,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
} else {
|
||||
CFILE *cfp = &Cfile_block_list[cfile_block_index];
|
||||
cfp->data = nullptr;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->fp = fp;
|
||||
cfp->dir_type = type;
|
||||
cfp->max_read_len = 0;
|
||||
@@ -903,7 +967,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
cfp->source_file = source;
|
||||
cfp->line_num = line;
|
||||
|
||||
auto pos = ftell(fp);
|
||||
int pos = ftell(fp);
|
||||
if(pos == -1L)
|
||||
pos = 0;
|
||||
cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)), 0 );
|
||||
@@ -933,6 +997,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
|
||||
|
||||
cfp->data = nullptr;
|
||||
cfp->fp = fp;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->dir_type = type;
|
||||
cfp->max_read_len = 0;
|
||||
|
||||
@@ -947,6 +1012,70 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cf_open_mapped_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
|
||||
// for the case of a file being opened by cf_open_mapped();
|
||||
//
|
||||
// returns: ptr CFILE structure.
|
||||
//
|
||||
#if defined _WIN32
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, HANDLE hFile, int type)
|
||||
#elif defined SCP_UNIX
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type)
|
||||
#endif
|
||||
{
|
||||
int cfile_block_index;
|
||||
|
||||
cfile_block_index = cfget_cfile_block();
|
||||
if ( cfile_block_index == -1 ) {
|
||||
#ifdef SCP_UNIX
|
||||
fclose(fp);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
CFILE *cfp = &Cfile_block_list[cfile_block_index];
|
||||
|
||||
cfp->max_read_len = 0;
|
||||
cfp->fp = nullptr;
|
||||
cfp->mem_mapped = true;
|
||||
#if defined _WIN32
|
||||
cfp->hInFile = hFile;
|
||||
#endif
|
||||
cfp->dir_type = type;
|
||||
|
||||
cfp->original_filename = original_filename;
|
||||
cfp->source_file = source;
|
||||
cfp->line_num = line;
|
||||
|
||||
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
|
||||
|
||||
#if defined _WIN32
|
||||
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (cfp->hMapFile == NULL) {
|
||||
nprintf(("Error", "Could not create file-mapping object.\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfp->data = (ubyte*)MapViewOfFile(cfp->hMapFile, FILE_MAP_READ, 0, 0, 0);
|
||||
Assert( cfp->data != NULL );
|
||||
#elif defined SCP_UNIX
|
||||
cfp->fp = fp;
|
||||
cfp->data_length = filelength(fileno(fp));
|
||||
cfp->data = mmap(nullptr, // start
|
||||
cfp->data_length, // length
|
||||
PROT_READ, // prot
|
||||
MAP_SHARED, // flags
|
||||
fileno(fp), // fd
|
||||
0); // offset
|
||||
Assert(cfp->data != nullptr);
|
||||
#endif
|
||||
|
||||
return cfp;
|
||||
}
|
||||
}
|
||||
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const char* original_filename, const void* data, size_t size, int dir_type)
|
||||
{
|
||||
int cfile_block_index;
|
||||
@@ -960,6 +1089,7 @@ static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const ch
|
||||
|
||||
cfp->max_read_len = 0;
|
||||
cfp->fp = nullptr;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->dir_type = dir_type;
|
||||
|
||||
cfp->original_filename = original_filename;
|
||||
@@ -1203,6 +1333,9 @@ int cfwrite_string_len(const char *buf, CFILE *file)
|
||||
int cfilelength(CFILE* cfile) {
|
||||
Assert(cfile != NULL);
|
||||
|
||||
// TODO: return length of memory mapped file
|
||||
Assert(!cfile->mem_mapped);
|
||||
|
||||
// cfile->size gets set at cfopen
|
||||
|
||||
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
|
||||
@@ -1595,7 +1728,7 @@ int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_t
|
||||
*chksum = 0;
|
||||
|
||||
// attempt to open the file
|
||||
cfile = cfopen(filename,"rt",cf_type);
|
||||
cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
|
||||
if(cfile == NULL){
|
||||
return 0;
|
||||
}
|
||||
@@ -1645,7 +1778,7 @@ int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type
|
||||
*chksum = 0;
|
||||
|
||||
// attempt to open the file
|
||||
cfile = cfopen(filename,"rt",cf_type);
|
||||
cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
|
||||
if(cfile == NULL){
|
||||
return 0;
|
||||
}
|
||||
|
||||
+5
-2
@@ -85,6 +85,10 @@ typedef struct {
|
||||
// TRUE if type is specified and valid
|
||||
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
|
||||
|
||||
// #define's for the type parameter in cfopen.
|
||||
#define CFILE_NORMAL 0 // open file normally
|
||||
#define CFILE_MEMORY_MAPPED (1<<0) // open file as a memory-mapped file
|
||||
|
||||
#define CF_SORT_NONE 0
|
||||
#define CF_SORT_NAME 1
|
||||
#define CF_SORT_TIME 2
|
||||
@@ -177,7 +181,7 @@ int cf_get_dir_type(const CFILE *cfile);
|
||||
|
||||
// Opens the file. If no path is given, use the extension to look into the
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode,
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
|
||||
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
@@ -373,7 +377,6 @@ struct CFileLocation {
|
||||
SCP_string full_name;
|
||||
size_t size = 0;
|
||||
size_t offset = 0;
|
||||
time_t m_time = 0;
|
||||
const void* data_ptr = nullptr;
|
||||
|
||||
explicit CFileLocation(bool found_in = false) : found(found_in) {}
|
||||
|
||||
@@ -149,6 +149,9 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
if (cfile->compression_info.header != 0)
|
||||
return comp_fseek(cfile, offset, where);
|
||||
|
||||
// TODO: seek to offset in memory mapped file
|
||||
Assert( !cfile->mem_mapped );
|
||||
|
||||
size_t goal_position;
|
||||
|
||||
switch( where ) {
|
||||
|
||||
@@ -38,6 +38,13 @@ struct CFILE {
|
||||
int dir_type; // directory location
|
||||
FILE* fp; // File pointer if opening an individual file
|
||||
const void* data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
|
||||
#ifdef _WIN32
|
||||
HANDLE hInFile; // Handle from CreateFile()
|
||||
HANDLE hMapFile; // Handle from CreateFileMapping()
|
||||
#else
|
||||
size_t data_length; // length of data for mmap
|
||||
#endif
|
||||
size_t lib_offset;
|
||||
size_t raw_position;
|
||||
size_t size; // for packed files
|
||||
|
||||
@@ -143,7 +143,7 @@ void lz41_load_offsets(CFILE* cf)
|
||||
int* offsets_ptr = cf->compression_info.offsets;
|
||||
|
||||
/* Seek to the first offset position, remember to consider the trailing ints */
|
||||
fso_fseek(cf, static_cast<int>( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
|
||||
fso_fseek(cf, ( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
|
||||
for (block = 0; block < cf->compression_info.num_offsets; ++block)
|
||||
{
|
||||
auto bytes_read = fread(offsets_ptr++, sizeof(int), 1, cf->fp);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <windows.h>
|
||||
#include <winbase.h> /* needed for memory mapping of file functions */
|
||||
#include <shlwapi.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
@@ -532,7 +531,7 @@ void cf_build_pack_list( cf_root *root )
|
||||
s_root.roottype = CF_ROOTTYPE_PACK;
|
||||
s_root.cf_type = i;
|
||||
|
||||
temp_roots_sort.push_back(std::move(s_root));
|
||||
temp_roots_sort.push_back(s_root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +595,7 @@ static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
|
||||
|
||||
cf_root* root = cf_create_root();
|
||||
|
||||
root->path = std::move(rootPath);
|
||||
root->path = rootPath;
|
||||
if (primary) {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
} else {
|
||||
@@ -827,8 +826,7 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
|
||||
}
|
||||
|
||||
// this log message occurs in the middle of an existing line, hence the extra new lines
|
||||
// critical files and files in same root are always logged, files in different root are behind a filter
|
||||
nprintf(((critical || !root->path.compare(r->path)) ? "General" : "CFileSystem", "\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
critical ? "critical " : "",
|
||||
newfile.c_str(), curfile.c_str()));
|
||||
|
||||
@@ -1083,7 +1081,7 @@ void cf_search_root_pack(int root_index)
|
||||
file.pathtype = path_type;
|
||||
file.offset = find.offset;
|
||||
|
||||
files.push_back(std::move(file));
|
||||
files.push_back(file);
|
||||
|
||||
//mprintf(( "Found pack file '%s'\n", find.filename ));
|
||||
}
|
||||
@@ -1238,22 +1236,6 @@ static bool sub_path_match(const SCP_string &search, const SCP_string &index)
|
||||
return !stricmp(search.c_str(), index.c_str());
|
||||
}
|
||||
|
||||
static time_t get_mtime(int fd)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _stat buf;
|
||||
#define fstat _fstat
|
||||
#else
|
||||
struct stat buf;
|
||||
#endif
|
||||
|
||||
if (fstat(fd, &buf) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a file.
|
||||
*
|
||||
@@ -1288,7 +1270,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
if (fp) {
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength(fileno(fp)));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@@ -1351,12 +1332,11 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
if (fp) {
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
res.offset = 0;
|
||||
res.full_name = std::move(longname);
|
||||
res.full_name = longname;
|
||||
res.name_ext = filespec;
|
||||
|
||||
return res;
|
||||
@@ -1408,7 +1388,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
res.name_ext = f->name_ext;
|
||||
res.m_time = f->write_time;
|
||||
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
@@ -1544,13 +1523,12 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
res.offset = 0;
|
||||
res.full_name = std::move(longname);
|
||||
res.name_ext = std::move(filespec_ext);
|
||||
res.full_name = longname;
|
||||
res.name_ext = filespec_ext;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1633,7 +1611,6 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
res.name_ext = f->name_ext;
|
||||
res.m_time = f->write_time;
|
||||
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
@@ -2437,9 +2414,7 @@ int cf_create_default_path_string(SCP_string& path, int pathtype, const char* fi
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
if (filename == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
Assert( filename != NULL );
|
||||
path.assign(filename);
|
||||
return 1;
|
||||
}
|
||||
@@ -2482,7 +2457,7 @@ void cfile_spew_pack_file_crcs()
|
||||
my_time = time(NULL);
|
||||
|
||||
memset( datetime, 0, sizeof(datetime) );
|
||||
snprintf(datetime, sizeof(datetime), "%s", ctime(&my_time));
|
||||
snprintf(datetime, sizeof(datetime)-1, "%s", ctime(&my_time));
|
||||
// ctime() adds a newline char, so we have to strip it off
|
||||
datetime[strlen(datetime)-1] = '\0';
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ void parse_cheat_table(const char* filename) {
|
||||
}
|
||||
|
||||
if (shipSpawn) {
|
||||
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, std::move(msg), requireCheats, std::move(shipClass), std::move(shipName)));
|
||||
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, msg, requireCheats, shipClass, shipName));
|
||||
|
||||
if(customCheats.count(code) == 1) {
|
||||
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
||||
@@ -144,7 +144,7 @@ void parse_cheat_table(const char* filename) {
|
||||
customCheats.emplace(code, std::move(shipCheat));
|
||||
}
|
||||
} else {
|
||||
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, std::move(msg), requireCheats));
|
||||
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, msg, requireCheats));
|
||||
|
||||
if(customCheats.count(code) == 1) {
|
||||
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
||||
|
||||
@@ -35,7 +35,7 @@ class SpawnShipCheat : public CustomCheat {
|
||||
SCP_string shipName;
|
||||
public:
|
||||
|
||||
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(std::move(cheat_code), std::move(cheat_msg), require_cheats_enabled),
|
||||
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(cheat_code, cheat_msg, require_cheats_enabled),
|
||||
shipClassName(std::move(class_name)),
|
||||
shipName(std::move(ship_name)) { }
|
||||
|
||||
|
||||
+72
-92
@@ -165,9 +165,11 @@ Flag exe_params[] =
|
||||
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nonormal" },
|
||||
{ "-emissive_light", "Enable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-emissive_light" },
|
||||
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noheight" },
|
||||
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
|
||||
{ "-no_post_process", "Disable post-processing", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_post_process" },
|
||||
{ "-soft_particles", "Enable soft particles", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-soft_particles" },
|
||||
{ "-aa", "Enable Post-process anti-aliasing", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-aa" },
|
||||
{ "-nolightshafts", "Disable lightshafts", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nolightshafts"},
|
||||
{ "-fb_explosions", "Enable Framebuffer Shockwaves", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_explosions", },
|
||||
{ "-fb_thrusters", "Enable Framebuffer Thrusters", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
|
||||
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
|
||||
@@ -191,10 +193,13 @@ Flag exe_params[] =
|
||||
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
{ "-3dwarp", "Enable 3D warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
|
||||
{ "-warp_flash", "Enable flash upon warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
|
||||
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
|
||||
{ "-no_screenshake", "Disable screen shaking", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
|
||||
{ "-vr", "Enable Virtual Reality Mode", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vr", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
{ "-orig_speedx_range", "Restrict speedup/slowdown (1x to 4x)", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-orig_speedx_range", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
|
||||
@@ -237,8 +242,6 @@ Flag exe_params[] =
|
||||
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
|
||||
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
|
||||
{ "-no_bsp_align", "Disable pof BSP data alignment", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bsp_align", },
|
||||
{ "-no_large_shaders", "Split large shader into smaller shaders", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_large_shaders", },
|
||||
|
||||
#ifdef WIN32
|
||||
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
|
||||
#endif
|
||||
@@ -261,7 +264,6 @@ Flag exe_params[] =
|
||||
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
|
||||
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
|
||||
{ "-output_script_json", "Output scripting doc to scripting.json", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_json", },
|
||||
{ "-output_script_lua", "Output scripting doc to scripting.lua", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_luastub", },
|
||||
{ "-controlconfig_tbl", "Save control presets to table", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-controlconfig_tbl", },
|
||||
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
|
||||
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
|
||||
@@ -316,6 +318,7 @@ int Cmdline_cd_check = 1;
|
||||
int Cmdline_closed_game = 0;
|
||||
int Cmdline_freespace_no_music = 0;
|
||||
int Cmdline_freespace_no_sound = 0;
|
||||
int Cmdline_gimme_all_medals = 0;
|
||||
int Cmdline_mouse_coords = 0;
|
||||
int Cmdline_multi_log = 0;
|
||||
int Cmdline_multi_stream_chat_to_file = 0;
|
||||
@@ -339,12 +342,15 @@ cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all a
|
||||
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // semi-deprecated but still functional
|
||||
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
|
||||
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
|
||||
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
|
||||
cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE); // Cmdline_noscalevid -- disable video scaling that fits to window
|
||||
cmdline_parm spec_arg("-nospec", NULL, AT_NONE); // Cmdline_spec --
|
||||
cmdline_parm normal_arg("-nonormal", NULL, AT_NONE); // Cmdline_normal -- disable normal mapping
|
||||
cmdline_parm height_arg("-noheight", NULL, AT_NONE); // Cmdline_height -- enable support for parallax mapping
|
||||
cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
|
||||
cmdline_parm softparticles_arg("-soft_particles", NULL, AT_NONE);
|
||||
cmdline_parm no_postprocess_arg("-no_post_process", "Disables post-processing", AT_NONE);
|
||||
cmdline_parm bloom_intensity_arg("-bloom_intensity", "Set bloom intensity, requires post-processing", AT_INT);
|
||||
cmdline_parm post_process_aa_arg("-aa", "Enables post-process antialiasing", AT_NONE);
|
||||
cmdline_parm post_process_aa_preset_arg("-aa_preset", "Sets the AA effect to use. See the wiki for details", AT_INT);
|
||||
cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
|
||||
@@ -354,6 +360,7 @@ cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), req
|
||||
cmdline_parm msaa_enabled_arg("-msaa", nullptr, AT_INT);
|
||||
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
|
||||
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
|
||||
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
|
||||
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
|
||||
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
|
||||
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
|
||||
@@ -371,7 +378,10 @@ int Cmdline_spec = 1;
|
||||
int Cmdline_emissive = 0;
|
||||
int Cmdline_normal = 1;
|
||||
int Cmdline_height = 1;
|
||||
int Cmdline_enable_3d_shockwave = 0;
|
||||
int Cmdline_softparticles = 0;
|
||||
int Cmdline_bloom_intensity = 25;
|
||||
bool Cmdline_force_lightshaft_off = false;
|
||||
int Cmdline_no_deferred_lighting = 0;
|
||||
bool Cmdline_deferred_lighting_cockpit = false;
|
||||
int Cmdline_aniso_level = 0;
|
||||
@@ -382,7 +392,7 @@ cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NO
|
||||
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
|
||||
|
||||
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
|
||||
bool Cmdline_no_vsync = false;
|
||||
int Cmdline_no_vsync = 0;
|
||||
|
||||
// HUD related
|
||||
cmdline_parm ballistic_gauge("-ballistic_gauge", NULL, AT_NONE); // Cmdline_ballistic_gauge
|
||||
@@ -397,16 +407,22 @@ int Cmdline_orb_radar = 0;
|
||||
int Cmdline_rearm_timer = 0;
|
||||
|
||||
// Gameplay related
|
||||
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
|
||||
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
|
||||
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
|
||||
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
|
||||
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
|
||||
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
|
||||
cmdline_parm vr("-vr", nullptr, AT_NONE);
|
||||
cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
|
||||
int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
bool Cmdline_stretch_menu = false;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
int Cmdline_deadzone = -1;
|
||||
bool Cmdline_enable_vr = false;
|
||||
|
||||
@@ -418,10 +434,8 @@ int Cmdline_no_enhanced_sound = 0;
|
||||
|
||||
// MOD related
|
||||
cmdline_parm mod_arg("-mod", "List of folders to overwrite/add-to the default data", AT_STRING, true); // Cmdline_mod -- DTP modsupport
|
||||
cmdline_parm campaign_arg("-campaign", "Set current campaign", AT_STRING); // Cmdline_campaign
|
||||
|
||||
char *Cmdline_mod = NULL; //DTP for mod argument
|
||||
char *Cmdline_campaign = nullptr; // for campaign argument
|
||||
|
||||
// Multiplayer/Network related
|
||||
cmdline_parm almission_arg("-almission", "Autoload multiplayer mission", AT_STRING); // Cmdline_almission -- DTP for autoload Multi mission
|
||||
@@ -465,7 +479,6 @@ cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
|
||||
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
|
||||
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
|
||||
cmdline_parm no_bsp_align_arg("-no_bsp_align", nullptr, AT_NONE);
|
||||
cmdline_parm no_large_shaders("-no_large_shaders", NULL, AT_NONE);
|
||||
#ifdef WIN32
|
||||
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
#endif
|
||||
@@ -489,7 +502,6 @@ bool Cmdline_prefer_ipv4 = false;
|
||||
bool Cmdline_prefer_ipv6 = false;
|
||||
bool Cmdline_dump_packet_type = false;
|
||||
bool Cmdline_no_bsp_align = false;
|
||||
bool Cmdline_no_large_shaders = false;
|
||||
#ifdef WIN32
|
||||
bool Cmdline_alternate_registry_path = false;
|
||||
#endif
|
||||
@@ -518,7 +530,6 @@ cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_f
|
||||
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
|
||||
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
|
||||
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
|
||||
cmdline_parm retail_time_compression_range_arg("-orig_speedx_range", NULL, AT_NONE); //Cmdline_retail_time_compression_range
|
||||
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
|
||||
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
|
||||
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
|
||||
@@ -534,7 +545,6 @@ cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmd
|
||||
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
|
||||
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
|
||||
cmdline_parm vulkan("-vulkan", nullptr, AT_NONE);
|
||||
cmdline_parm multithreading("-threads", nullptr, AT_INT);
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
int Cmdline_dis_collisions = 0;
|
||||
@@ -549,16 +559,15 @@ int Cmdline_bmpman_usage = 0;
|
||||
int Cmdline_show_pos = 0;
|
||||
int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
bool Cmdline_window = false;
|
||||
bool Cmdline_fullscreen_window = false;
|
||||
std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = std::nullopt;
|
||||
int Cmdline_window = 0;
|
||||
int Cmdline_fullscreen_window = 0;
|
||||
tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = tl::nullopt;
|
||||
char *Cmdline_res = 0;
|
||||
char *Cmdline_center_res = 0;
|
||||
int Cmdline_verify_vps = 0;
|
||||
int Cmdline_reparse_mainhall = 0;
|
||||
bool Cmdline_profile_write_file = false;
|
||||
bool Cmdline_no_unfocus_pause = false;
|
||||
bool Cmdline_retail_time_compression_range = false;
|
||||
bool Cmdline_benchmark_mode = false;
|
||||
const char *Cmdline_pilot = nullptr;
|
||||
bool Cmdline_noninteractive = false;
|
||||
@@ -573,14 +582,12 @@ bool Cmdline_lua_devmode = false;
|
||||
bool Cmdline_override_data = false;
|
||||
bool Cmdline_show_imgui_debug = false;
|
||||
bool Cmdline_vulkan = false;
|
||||
int Cmdline_multithreading = 1;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
|
||||
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
|
||||
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
|
||||
cmdline_parm output_script_json_arg("-output_script_json", nullptr, AT_NONE); // m!m
|
||||
cmdline_parm output_script_luastub_arg("-output_script_lua", nullptr, AT_NONE); // mjnmixael
|
||||
cmdline_parm generate_controlconfig_arg("-controlconfig_tbl", nullptr, AT_NONE);
|
||||
|
||||
// Deprecated flags - CommanderDJ
|
||||
@@ -603,13 +610,6 @@ cmdline_parm deprecated_spec_tube_arg("-spec_tube", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_ambient_factor_arg("-ambient_factor", "Deprecated", AT_NONE); //
|
||||
cmdline_parm deprecated_ship_choice_3d_arg("-ship_choice_3d", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_weapon_choice_3d_arg("-weapon_choice_3d", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_no_screenshake("-no_screenshake", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_bloom_intensity_arg("-bloom_intensity", "Deprecated", AT_INT);
|
||||
cmdline_parm deprecated_nomotiondebris_arg("-nomotiondebris", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_flightshaftsoff_arg("-nolightshafts", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_use_warp_flash("-warp_flash", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_use_3dwarp("-3dwarp", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_enable_3d_shockwave_arg("-3dshockwave", "Deprecated", AT_NONE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
|
||||
@@ -645,8 +645,8 @@ void cmdline_debug_print_cmdline()
|
||||
}
|
||||
#endif
|
||||
|
||||
// builds simple cmdline
|
||||
SCP_string cmdline_build_string()
|
||||
// prints simple cmdline to multi.log
|
||||
void cmdline_print_cmdline_multi()
|
||||
{
|
||||
cmdline_parm *parmp;
|
||||
int found = 0;
|
||||
@@ -665,18 +665,10 @@ SCP_string cmdline_build_string()
|
||||
}
|
||||
|
||||
if ( !found ) {
|
||||
return "";
|
||||
cmdline << " <none>";
|
||||
}
|
||||
|
||||
return cmdline.str();
|
||||
}
|
||||
|
||||
// prints simple cmdline to multi.log
|
||||
void cmdline_print_cmdline_multi()
|
||||
{
|
||||
auto str = cmdline_build_string();
|
||||
|
||||
ml_printf("Command line:%s", str.empty() ? " <none>" : str.c_str());
|
||||
ml_printf("Command line:%s", cmdline.str().c_str());
|
||||
}
|
||||
|
||||
// Return true if this character is an extra char (white space and quotes)
|
||||
@@ -685,6 +677,7 @@ int is_extra_space(char ch)
|
||||
return ((ch == ' ') || (ch == '\t') || (ch == 0x0a) || (ch == '\'') || (ch == '\"'));
|
||||
}
|
||||
|
||||
|
||||
// eliminates all leading and trailing extra chars from a string. Returns pointer passed in.
|
||||
char *drop_extra_chars(char *str)
|
||||
{
|
||||
@@ -1322,7 +1315,7 @@ static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ",")) {
|
||||
SCP_string path = get_real_mod_path(cur_mod);
|
||||
mod_paths.push_back(std::move(path));
|
||||
mod_paths.push_back(path);
|
||||
}
|
||||
|
||||
// create new char[] to replace modlist
|
||||
@@ -1414,7 +1407,7 @@ static json_t* json_get_v1() {
|
||||
auto voices = speech_enumerate_voices();
|
||||
|
||||
for (auto& voice : voices) {
|
||||
json_array_append_new(voices_array, json_string(voice.second.c_str()));
|
||||
json_array_append_new(voices_array, json_string(voice.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(root, "voices", voices_array);
|
||||
@@ -1592,12 +1585,6 @@ bool SetCmdlineParams()
|
||||
{
|
||||
//getcwd(FreeSpace_Directory, 256); // set the directory to our fs2 root
|
||||
|
||||
// DO THIS BEFORE get_flags, as portable_mode can change the value of pref_path printed in the json
|
||||
if (portable_mode.found())
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
}
|
||||
|
||||
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
|
||||
if ( get_flags_arg.found() ) {
|
||||
write_flags();
|
||||
@@ -1778,14 +1765,14 @@ bool SetCmdlineParams()
|
||||
if(window_arg.found()) {
|
||||
// We need to set both values since we don't know if we are going to use the new config system
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
|
||||
Cmdline_window = true;
|
||||
Cmdline_window = 1;
|
||||
}
|
||||
|
||||
if ( fullscreen_window_arg.found( ) )
|
||||
{
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
|
||||
Cmdline_fullscreen_window = true;
|
||||
Cmdline_window = false; /* Make sure no-one sets both */
|
||||
Cmdline_fullscreen_window = 1;
|
||||
Cmdline_window = 0; /* Make sure no-one sets both */
|
||||
}
|
||||
|
||||
if(render_res_arg.found() || deprecated_res_arg.found()){
|
||||
@@ -1880,14 +1867,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_mod = modlist;
|
||||
}
|
||||
|
||||
if(campaign_arg.found()) {
|
||||
Cmdline_campaign = campaign_arg.str();
|
||||
|
||||
// strip off blank space if it's there
|
||||
if ( Cmdline_campaign[strlen(Cmdline_campaign)-1] == ' ' ) {
|
||||
Cmdline_campaign[strlen(Cmdline_campaign)-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (fps_arg.found())
|
||||
{
|
||||
@@ -1904,6 +1883,10 @@ bool SetCmdlineParams()
|
||||
Cmdline_show_pos = 1;
|
||||
}
|
||||
|
||||
if ( nomotiondebris_arg.found() ) {
|
||||
Motion_debris_enabled = false;
|
||||
}
|
||||
|
||||
if( mipmap_arg.found() ) {
|
||||
Cmdline_mipmap = 1;
|
||||
}
|
||||
@@ -1936,25 +1919,6 @@ bool SetCmdlineParams()
|
||||
if (fov_arg.found() || fov_cockpit_arg.found()) {
|
||||
Warning(LOCATION, "FoV Command line settings found. VR-Mode will override these with the HMD's native FoV...");
|
||||
}
|
||||
|
||||
// enable other settings to allow VR to work more seamlessly
|
||||
mprintf(("VR-Mode enabled, so forcing on the following settings: capture_mouse, window_res 1000x1000, window, no_vsync \n"));
|
||||
|
||||
// ensure ingame resolution is set to sensible values in VR mode,
|
||||
// which will exceed the resolution otherwise shown and is not dependent on the monitor resolution
|
||||
Cmdline_capture_mouse = true;
|
||||
Cmdline_window_res.emplace(static_cast<uint16_t>(1000), static_cast<uint16_t>(1000));
|
||||
|
||||
Cmdline_fullscreen_window = false;
|
||||
Cmdline_window = true; /* Make sure no-one sets both */
|
||||
removeWindowModeOption();
|
||||
|
||||
// Turn off VSync, since we definitely don't want to be capped by the main monitor
|
||||
// the OpenXR runtime should have a buffered wait which will behave, effectively,
|
||||
// as a VSync to VR goggle driver
|
||||
Gr_enable_vsync = false;
|
||||
removeVSyncOption();
|
||||
|
||||
openxr_prepare();
|
||||
}
|
||||
|
||||
@@ -1963,16 +1927,28 @@ bool SetCmdlineParams()
|
||||
Cmdline_orb_radar = 1;
|
||||
}
|
||||
|
||||
if ( use_3dwarp.found() ) {
|
||||
Fireball_use_3d_warp = true;
|
||||
}
|
||||
|
||||
if ( use_warp_flash.found() ) {
|
||||
Fireball_warp_flash = true;
|
||||
}
|
||||
|
||||
if ( allow_autpilot_interrupt.found() ) {
|
||||
Cmdline_autopilot_interruptable = 0;
|
||||
}
|
||||
|
||||
if ( no_screenshake.found() ) {
|
||||
Cmdline_no_screenshake = 1;
|
||||
}
|
||||
|
||||
if ( deadzone.found() ) {
|
||||
Cmdline_deadzone = deadzone.get_int();
|
||||
}
|
||||
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = true;
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
|
||||
if ( capture_mouse.found() ) {
|
||||
@@ -2079,9 +2055,6 @@ bool SetCmdlineParams()
|
||||
if (output_script_json_arg.found() )
|
||||
Output_scripting_json = true;
|
||||
|
||||
if (output_script_luastub_arg.found())
|
||||
Output_scripting_luastub = true;
|
||||
|
||||
if (output_sexp_arg.found() ) {
|
||||
Cmdline_output_sexp_info = true;
|
||||
}
|
||||
@@ -2129,6 +2102,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_noshadercache = true;
|
||||
}
|
||||
|
||||
if (portable_mode.found())
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
}
|
||||
|
||||
if (lang_arg.found())
|
||||
{
|
||||
Cmdline_lang = lang_arg.str();
|
||||
@@ -2137,10 +2115,6 @@ bool SetCmdlineParams()
|
||||
if (no_bsp_align_arg.found()) {
|
||||
Cmdline_no_bsp_align = true;
|
||||
}
|
||||
|
||||
if (no_large_shaders.found()) {
|
||||
Cmdline_no_large_shaders = true;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (fix_registry.found()) {
|
||||
@@ -2183,6 +2157,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_ati_color_swap = 1;
|
||||
}
|
||||
|
||||
if ( enable_3d_shockwave_arg.found() )
|
||||
{
|
||||
Cmdline_enable_3d_shockwave = 1;
|
||||
}
|
||||
|
||||
if ( softparticles_arg.found() )
|
||||
{
|
||||
Cmdline_softparticles = 1;
|
||||
@@ -2203,6 +2182,16 @@ bool SetCmdlineParams()
|
||||
Gr_post_processing_enabled = false;
|
||||
}
|
||||
|
||||
if ( bloom_intensity_arg.found() )
|
||||
{
|
||||
Cmdline_bloom_intensity = bloom_intensity_arg.get_int();
|
||||
}
|
||||
|
||||
if ( flightshaftsoff_arg.found() )
|
||||
{
|
||||
Cmdline_force_lightshaft_off = true;
|
||||
}
|
||||
|
||||
if( reparse_mainhall_arg.found() )
|
||||
{
|
||||
Cmdline_reparse_mainhall = 1;
|
||||
@@ -2268,11 +2257,6 @@ bool SetCmdlineParams()
|
||||
{
|
||||
Cmdline_no_unfocus_pause = true;
|
||||
}
|
||||
|
||||
if (retail_time_compression_range_arg.found())
|
||||
{
|
||||
Cmdline_retail_time_compression_range = true;
|
||||
}
|
||||
|
||||
if (benchmark_mode_arg.found())
|
||||
{
|
||||
@@ -2409,10 +2393,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if (multithreading.found()) {
|
||||
Cmdline_multithreading = abs(multithreading.get_int());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+13
-14
@@ -12,7 +12,7 @@
|
||||
#ifndef FS_CMDLINE_HEADER_FILE
|
||||
#define FS_CMDLINE_HEADER_FILE
|
||||
|
||||
#include <optional>
|
||||
#include <tl/optional.hpp>
|
||||
|
||||
int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
@@ -34,6 +34,7 @@ extern int Cmdline_cd_check;
|
||||
extern int Cmdline_closed_game;
|
||||
extern int Cmdline_freespace_no_music;
|
||||
extern int Cmdline_freespace_no_sound;
|
||||
extern int Cmdline_gimme_all_medals;
|
||||
extern int Cmdline_mouse_coords;
|
||||
extern int Cmdline_multi_log;
|
||||
extern int Cmdline_multi_stream_chat_to_file;
|
||||
@@ -43,10 +44,10 @@ extern int Cmdline_spew_pof_info;
|
||||
extern int Cmdline_start_netgame;
|
||||
extern int Cmdline_timeout;
|
||||
extern int Cmdline_use_last_pilot;
|
||||
extern bool Cmdline_window;
|
||||
extern bool Cmdline_fullscreen_window;
|
||||
extern int Cmdline_window;
|
||||
extern int Cmdline_fullscreen_window;
|
||||
extern char *Cmdline_res;
|
||||
extern std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
|
||||
extern tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
|
||||
extern char *Cmdline_center_res;
|
||||
|
||||
|
||||
@@ -62,7 +63,10 @@ extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
|
||||
extern int Cmdline_spec;
|
||||
extern int Cmdline_normal;
|
||||
extern int Cmdline_height;
|
||||
extern int Cmdline_enable_3d_shockwave;
|
||||
extern int Cmdline_softparticles;
|
||||
extern int Cmdline_bloom_intensity;
|
||||
extern bool Cmdline_force_lightshaft_off;
|
||||
extern int Cmdline_no_deferred_lighting;
|
||||
extern bool Cmdline_deferred_lighting_cockpit;
|
||||
extern int Cmdline_emissive;
|
||||
@@ -71,7 +75,7 @@ extern int Cmdline_msaa_enabled;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_NoFPSCap;
|
||||
extern bool Cmdline_no_vsync;
|
||||
extern int Cmdline_no_vsync;
|
||||
|
||||
// HUD related
|
||||
extern int Cmdline_ballistic_gauge;
|
||||
@@ -80,9 +84,12 @@ extern int Cmdline_orb_radar;
|
||||
extern int Cmdline_rearm_timer;
|
||||
|
||||
// Gameplay related
|
||||
extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern bool Cmdline_stretch_menu;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_no_screenshake;
|
||||
extern int Cmdline_deadzone;
|
||||
extern bool Cmdline_enable_vr;
|
||||
|
||||
@@ -92,7 +99,6 @@ extern int Cmdline_no_enhanced_sound;
|
||||
|
||||
// MOD related
|
||||
extern char *Cmdline_mod; // DTP for mod support
|
||||
extern char *Cmdline_campaign; // for campaign support
|
||||
// Multiplayer/Network related
|
||||
extern char *Cmdline_almission; // DTP for autoload mission (for multi only)
|
||||
extern int Cmdline_ingamejoin;
|
||||
@@ -124,7 +130,6 @@ extern bool Cmdline_noshadercache;
|
||||
extern bool Cmdline_prefer_ipv4;
|
||||
extern bool Cmdline_prefer_ipv6;
|
||||
extern bool Cmdline_dump_packet_type;
|
||||
extern bool Cmdline_no_large_shaders;
|
||||
#ifdef WIN32
|
||||
extern bool Cmdline_alternate_registry_path;
|
||||
#endif
|
||||
@@ -144,7 +149,6 @@ extern int Cmdline_verify_vps;
|
||||
extern int Cmdline_reparse_mainhall;
|
||||
extern bool Cmdline_profile_write_file;
|
||||
extern bool Cmdline_no_unfocus_pause;
|
||||
extern bool Cmdline_retail_time_compression_range;
|
||||
extern bool Cmdline_benchmark_mode;
|
||||
extern const char *Cmdline_pilot;
|
||||
extern bool Cmdline_noninteractive;
|
||||
@@ -159,14 +163,9 @@ extern bool Cmdline_lua_devmode;
|
||||
extern bool Cmdline_override_data;
|
||||
extern bool Cmdline_show_imgui_debug;
|
||||
extern bool Cmdline_vulkan;
|
||||
extern int Cmdline_multithreading;
|
||||
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
extern WeaponSpewType Cmdline_spew_weapon_stats;
|
||||
|
||||
extern void removeVSyncOption();
|
||||
extern void removeWindowModeOption();
|
||||
extern void removeResolutionOption();
|
||||
extern void removeResolutionVROption();
|
||||
|
||||
#endif
|
||||
+12
-26
@@ -25,33 +25,18 @@ const float CMEASURE_DETONATE_DISTANCE = 40.0f;
|
||||
|
||||
//Used to set a countermeasure velocity after being launched from a ship as a countermeasure
|
||||
//ie not as a primary or secondary.
|
||||
void cmeasure_set_ship_launch_vel(object* objp, object* parent_objp, int arand)
|
||||
void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
|
||||
{
|
||||
vec3d vel;
|
||||
vec3d rand_vec;
|
||||
vec3d world_dir;
|
||||
vec3d vel, rand_vec;
|
||||
|
||||
weapon* wp = &Weapons[objp->instance];
|
||||
auto* wip = &Weapon_info[wp->weapon_info_index];
|
||||
//Get cmeasure rear velocity in world
|
||||
vm_vec_scale_add(&vel, &parent_objp->phys_info.vel, &parent_objp->orient.vec.fvec, -25.0f);
|
||||
|
||||
// Start with parent velocity
|
||||
vel = parent_objp->phys_info.vel;
|
||||
//Get random velocity vector
|
||||
static_randvec(arand+1, &rand_vec);
|
||||
|
||||
// Normalize direction
|
||||
vec3d local_dir = wip->cm_launch_vec;
|
||||
if (vm_vec_mag_squared(&local_dir) > 0.0f) {
|
||||
vm_vec_normalize(&local_dir);
|
||||
}
|
||||
|
||||
// Convert from ship to world space
|
||||
vm_vec_unrotate(&world_dir, &local_dir, &parent_objp->orient);
|
||||
|
||||
// Apply launch impulse
|
||||
vm_vec_scale_add2(&vel, &world_dir, wip->cm_launch_speed);
|
||||
|
||||
// Add random variance
|
||||
static_randvec(arand + 1, &rand_vec);
|
||||
vm_vec_scale_add2(&vel, &rand_vec, wip->cm_launch_variance);
|
||||
//Add it to the rear velocity
|
||||
vm_vec_scale_add2(&vel, &rand_vec, 2.0f);
|
||||
|
||||
objp->phys_info.vel = vel;
|
||||
|
||||
@@ -59,16 +44,17 @@ void cmeasure_set_ship_launch_vel(object* objp, object* parent_objp, int arand)
|
||||
vm_vec_zero(&objp->phys_info.rotvel);
|
||||
vm_vec_zero(&objp->phys_info.max_vel);
|
||||
vm_vec_zero(&objp->phys_info.max_rotvel);
|
||||
|
||||
|
||||
// blow out his reverse thrusters. Or drag, same thing.
|
||||
objp->phys_info.rotdamp = 10000.0f;
|
||||
objp->phys_info.side_slip_time_const = 10000.0f;
|
||||
|
||||
// Desired velocity should align with launch direction, not hardcoded backward
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &world_dir, wip->cm_launch_speed);
|
||||
objp->phys_info.max_vel.xyz.z = -25.0f;
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
|
||||
|
||||
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
|
||||
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
|
||||
weapon* wp = &Weapons[objp->instance];
|
||||
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
|
||||
wp->trail_ptr->vel[0] = objp->phys_info.vel;
|
||||
wp->trail_ptr->vel[1] = objp->phys_info.vel;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
|
||||
|
||||
#include "camera/photomode.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
@@ -142,9 +141,6 @@ SCP_vector<cc_line> Cc_lines;
|
||||
// Backups for use when user closes the config menu without saving
|
||||
SCP_vector<CCI> Control_config_backup;
|
||||
|
||||
// The current preset that the user is working on and will likely want to save to
|
||||
static SCP_string Current_preset_name;
|
||||
|
||||
// Undo system
|
||||
Undo_system Undo_controls;
|
||||
|
||||
@@ -621,11 +617,6 @@ void control_config_conflict_check()
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip conflict check between items in different conflict groups
|
||||
if ((item_i.conflict_groups & item_j.conflict_groups) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item_i.disabled && (item_i.has_first_conflict(item_j) || item_i.has_second_conflict(item_j))) {
|
||||
// item_i conflicts with item_j and is disabled. Silently clear item_i
|
||||
item_i.clear();
|
||||
@@ -1300,12 +1291,11 @@ bool control_config_accept(bool API_Access)
|
||||
char* cstr; // Must be a char *, because popup_input may return nullptr and std::string don't like it
|
||||
|
||||
retry:;
|
||||
SCP_string default_string = (Current_preset_name.empty()) ? Player->callsign : Current_preset_name;
|
||||
cstr = popup_input(flags,
|
||||
XSTR( "Confirm new custom preset name.\n\nThe name must not be empty or a default preset.\n\n Press [Enter] to accept, [Esc] to abort to config menu.", 1867),
|
||||
"Confirm new custom preset name.\n\nThe name must not be empty.\n\n Press [Enter] to accept, [Esc] to "
|
||||
"abort to config menu.",
|
||||
32 - 6,
|
||||
default_string.c_str(),
|
||||
"-_");
|
||||
Player->callsign);
|
||||
if (cstr == nullptr) {
|
||||
// Abort
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
@@ -1326,13 +1316,14 @@ bool control_config_accept(bool API_Access)
|
||||
});
|
||||
|
||||
if (it != Control_config_presets.end()) {
|
||||
popup(flags | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
|
||||
popup(flags, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists. If so, prompt the user
|
||||
CFILE* fp = cfopen((str + ".json").c_str(),
|
||||
"r",
|
||||
CFILE_NORMAL,
|
||||
CF_TYPE_PLAYER_BINDS,
|
||||
false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
@@ -1340,11 +1331,11 @@ bool control_config_accept(bool API_Access)
|
||||
cfclose(fp);
|
||||
int n = popup(flags,
|
||||
2,
|
||||
POPUP_CANCEL,
|
||||
POPUP_OK,
|
||||
POPUP_CANCEL,
|
||||
"'%s'\n Already exists!\n Press OK to overwrite existing preset, or CANCEL to input another name",
|
||||
str.c_str());
|
||||
if ((n == 0) || (n == -1)) {
|
||||
if ((n == 1) || (n == -1)) {
|
||||
// If Cancel button was pressed, or popup dismissed:
|
||||
// retry
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
@@ -1354,7 +1345,7 @@ bool control_config_accept(bool API_Access)
|
||||
|
||||
// Pack the current bindings into a preset, then save the file
|
||||
CC_preset preset;
|
||||
preset.name = std::move(str);
|
||||
preset.name = str;
|
||||
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
|
||||
Control_config_presets.push_back(preset);
|
||||
save_preset_file(preset, true);
|
||||
@@ -1363,19 +1354,11 @@ bool control_config_accept(bool API_Access)
|
||||
// consistant ordering
|
||||
Control_config_presets.resize(1);
|
||||
load_preset_files();
|
||||
|
||||
// finally, save the new preset so that changes will get saved to this preset
|
||||
Current_preset_name = preset.name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
|
||||
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
|
||||
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', true)));
|
||||
}
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
@@ -1391,8 +1374,8 @@ void control_config_cancel_exit(bool API_Access)
|
||||
// Check if any changes were made
|
||||
if (!API_Access && (control_config_get_current_preset() == Control_config_presets.end())) {
|
||||
// Changes were made, prompt the user first.
|
||||
int flags = PF_TITLE_WHITE | PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON;
|
||||
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, XSTR( "You have unsaved changes.\n\n\n Do you wish to continue without saving?", 1866));
|
||||
int flags = PF_TITLE_WHITE;
|
||||
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, "You have unsaved changes.\n\n\n Do you wish to continue without saving?");
|
||||
|
||||
switch (choice) {
|
||||
case -1: // Aborted
|
||||
@@ -1413,11 +1396,6 @@ void control_config_cancel_exit(bool API_Access)
|
||||
// Restore all bindings with the backup
|
||||
std::move(Control_config_backup.begin(), Control_config_backup.end(), Control_config.begin());
|
||||
|
||||
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
|
||||
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
|
||||
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', false)));
|
||||
}
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
}
|
||||
@@ -1559,11 +1537,9 @@ void control_config_init(bool API_Access)
|
||||
// Init preset cycling system
|
||||
auto preset_it = control_config_get_current_preset();
|
||||
if (preset_it == Control_config_presets.end()) {
|
||||
Current_preset_name.clear();
|
||||
Defaults_cycle_pos = 0;
|
||||
|
||||
} else {
|
||||
Current_preset_name = preset_it->name;
|
||||
Defaults_cycle_pos = static_cast<unsigned int>(std::distance(Control_config_presets.begin(), preset_it));
|
||||
}
|
||||
|
||||
@@ -1675,9 +1651,6 @@ void control_config_close(bool API_Access)
|
||||
Cc_lines.clear();
|
||||
Conflicts.clear();
|
||||
Undo_controls.clear();
|
||||
|
||||
// Clear this, just to be tidy
|
||||
Current_preset_name.clear();
|
||||
}
|
||||
|
||||
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic) {
|
||||
@@ -1773,7 +1746,7 @@ bool control_config_delete_preset(CC_preset preset) {
|
||||
return delete_preset_file(preset);
|
||||
}
|
||||
|
||||
bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
bool control_config_create_new_preset(SCP_string newName)
|
||||
{
|
||||
|
||||
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
|
||||
@@ -1786,14 +1759,13 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists.
|
||||
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
|
||||
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pack the current bindings into a preset, then save the file
|
||||
CC_preset preset;
|
||||
preset.name = newName;
|
||||
preset.type = Preset_t::pst;
|
||||
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
|
||||
|
||||
// Done with the file
|
||||
@@ -1822,7 +1794,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
return false; //should be unreachable, but just in case
|
||||
}
|
||||
|
||||
bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newName, bool overwrite) {
|
||||
bool control_config_clone_preset(CC_preset preset, SCP_string newName) {
|
||||
|
||||
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
|
||||
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
|
||||
@@ -1834,7 +1806,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists.
|
||||
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
|
||||
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1924,7 +1896,7 @@ int control_config_draw_list(int select_tease_line) {
|
||||
char buf[256]; // c_str buffer
|
||||
int font_height = gr_get_font_height();
|
||||
|
||||
for (line = Scroll_offset; cc_line_query_visible(line) && (line - Scroll_offset < LIST_BUTTONS_MAX); ++line) {
|
||||
for (line = Scroll_offset; cc_line_query_visible(line); ++line) {
|
||||
z = Cc_lines[line].cc_index;
|
||||
|
||||
// screen coordinate y = list box origin y + (this item's relative y - topmost item's relative y)
|
||||
@@ -2091,6 +2063,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
|
||||
if (!done && bind) {
|
||||
if (!Axis_override.empty()) {
|
||||
control_config_bind(ctrl, Axis_override, item, API_Access);
|
||||
control_config_bind(ctrl, Axis_override, item, API_Access);
|
||||
done = true;
|
||||
strcpy_s(bound_string, Axis_override.textify().c_str());
|
||||
@@ -2118,7 +2091,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
}
|
||||
|
||||
if ((ctrl == BANK_WHEN_PRESSED || ctrl == GLIDE_WHEN_PRESSED) && (Last_key >= 0) && (k <= 0) &&
|
||||
!key_is_pressed(Last_key)) {
|
||||
!keyd_pressed[Last_key]) {
|
||||
// If the selected cc_item is BANK_WHEN_PRESSED or GLIDE_WHEN_PRESSED, and
|
||||
// If the polled key is a modifier, and
|
||||
// k was consumed, and
|
||||
@@ -2150,12 +2123,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
if (!done && (j < JOY_TOTAL_BUTTONS)) {
|
||||
// Bind the joy button
|
||||
Assert(!Control_config[ctrl].is_axis());
|
||||
control_config_bind(ctrl, CC_bind(static_cast<CID>(joy), j), item, API_Access);
|
||||
|
||||
CC_bind joy_bind(static_cast<CID>(joy), j);
|
||||
|
||||
control_config_bind(ctrl, joy_bind, item, API_Access);
|
||||
|
||||
strcpy_s(bound_string, joy_bind.textify().c_str());
|
||||
strcpy_s(bound_string, Joy_button_text[j]);
|
||||
done = true;
|
||||
}
|
||||
|
||||
@@ -2189,10 +2159,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
|
||||
if (mouse_down(mouse_bind)) {
|
||||
Assert(!Control_config[ctrl].is_axis());
|
||||
|
||||
control_config_bind(ctrl, mouse_bind, item, API_Access);
|
||||
|
||||
strcpy_s(bound_string, mouse_bind.textify().c_str());
|
||||
strcpy_s(bound_string, Joy_button_text[i]);
|
||||
done = true;
|
||||
|
||||
break;
|
||||
@@ -2724,7 +2693,8 @@ void control_config_do_frame(float frametime)
|
||||
strcpy_s(buf, Control_config[i].text.c_str());
|
||||
}
|
||||
|
||||
w = font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
|
||||
font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
|
||||
gr_get_string_size(&w, NULL, buf);
|
||||
gr_printf_menu(x - w / 2, y, "%s", buf);
|
||||
|
||||
} else if (*bound_string) {
|
||||
@@ -2807,22 +2777,8 @@ void control_check_indicate()
|
||||
Control_check_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a control is being used by the player this frame by checking the bound control input bindings.
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
* @param[in] key DO NOT USE. Key combination acquired from game_poll(), or -1 to check against a previous poll
|
||||
*
|
||||
* @returns 0 If the control was disabled by a mod, or
|
||||
* @returns 0 If locked by a script, or
|
||||
* @returns 0 If controls need to be ignored for multiplayer, or
|
||||
* @returns 0 If the control wasn't used, or
|
||||
* @returns 1 If the control was used
|
||||
*/
|
||||
int check_control_used(int id, int key)
|
||||
{
|
||||
// Make sure mouse_down() is only called once during any logic path,
|
||||
// or the mousewheel may be decayed multiple times!!
|
||||
int mask;
|
||||
static int last_key = 0;
|
||||
auto & item = Control_config[id];
|
||||
@@ -2842,19 +2798,12 @@ int check_control_used(int id, int key)
|
||||
if (item.disabled || item.locked)
|
||||
return 0;
|
||||
|
||||
// Filter actions based on conflict groups and current mode
|
||||
{
|
||||
int active_group = game_is_photo_mode_active() ? CONFLICT_GROUP_PHOTO_MODE : CONFLICT_GROUP_DEFAULT;
|
||||
if (!(item.conflict_groups & active_group))
|
||||
return 0;
|
||||
}
|
||||
|
||||
short z = item.get_btn(CID_KEYBOARD); // Get the key that's bound to this control
|
||||
|
||||
if (item.type == CC_TYPE_CONTINUOUS) {
|
||||
|
||||
// this is awful, need to make a reverse lookup table to do
|
||||
// button -> control instead of this control -> button nonsense.
|
||||
// this is awful, need to make a reverse lookup table to do button -> control instead of this control -> button
|
||||
// nonsense.
|
||||
if ((joy_down(item.first) || joy_down_count(item.first, 1)) ||
|
||||
(joy_down(item.second) || joy_down_count(item.second, 1))) {
|
||||
// Joy button bound to this control was pressed, control activated
|
||||
@@ -2864,19 +2813,19 @@ int check_control_used(int id, int key)
|
||||
|
||||
if ((mouse_down(item.first) || mouse_down_count(item.first, 1)) ||
|
||||
(mouse_down(item.second) || mouse_down_count(item.second, 1))) {
|
||||
// Mouse button bound to this control was pressed, control activated
|
||||
// Joy button bound to this control was pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check what current modifiers are pressed
|
||||
mask = 0;
|
||||
if (key_is_pressed(KEY_LSHIFT, true) || key_is_pressed(KEY_RSHIFT, true)) {
|
||||
if (keyd_pressed[KEY_LSHIFT] || key_down_count(KEY_LSHIFT) || keyd_pressed[KEY_RSHIFT] || key_down_count(KEY_RSHIFT)) {
|
||||
// Any shift key is pressed, add KEY_SHIFTED mask
|
||||
mask |= KEY_SHIFTED;
|
||||
}
|
||||
|
||||
if (key_is_pressed(KEY_LALT, true) || key_is_pressed(KEY_RALT, true)) {
|
||||
if (keyd_pressed[KEY_LALT] || key_down_count(KEY_LALT) || keyd_pressed[KEY_RALT] || key_down_count(KEY_RALT)) {
|
||||
// Any alt key is pressed, add KEY_ALTED to the mask
|
||||
mask |= KEY_ALTED;
|
||||
}
|
||||
@@ -2892,7 +2841,7 @@ int check_control_used(int id, int key)
|
||||
|
||||
z &= KEY_MASK;
|
||||
|
||||
if (key_is_pressed(z, true)) {
|
||||
if (keyd_pressed[z] || key_down_count(z)) {
|
||||
// Key combo is pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
@@ -2910,15 +2859,6 @@ int check_control_used(int id, int key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// special case to allow actual mouse wheel to work with trigger controls --wookieejedi
|
||||
if (item.type == CC_TYPE_TRIGGER) {
|
||||
if ( mouse_down(item.first, true) || mouse_down(item.second, true) ) {
|
||||
// Mouse wheel bound to this trigger control was pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +36,8 @@ enum Joy_axis_index : short {
|
||||
JOY_RX_AXIS,
|
||||
JOY_RY_AXIS,
|
||||
JOY_RZ_AXIS,
|
||||
JOY_U_AXIS,
|
||||
JOY_V_AXIS,
|
||||
|
||||
JOY_NUM_AXES //!< Max number of joy axes that FSO can handle. Must be last enum in Joy_axis_index.
|
||||
JOY_NUM_AXES // Number of axes a joystick may have. Must be last enum in Joy_axis_index.
|
||||
};
|
||||
|
||||
// Aliases for mouse axes. Really should unify this...
|
||||
@@ -297,24 +295,8 @@ enum IoActionId : int {
|
||||
JOY_ABS_THROTTLE_AXIS = 127,
|
||||
JOY_REL_THROTTLE_AXIS = 128,
|
||||
|
||||
//!< @n
|
||||
//! Communication menu controls
|
||||
//! ----------------------------
|
||||
COMMS_MENU_MOVE_UP,
|
||||
COMMS_MENU_MOVE_DOWN,
|
||||
COMMS_MENU_SELECT,
|
||||
|
||||
TOGGLE_HUD_SHADOWS,
|
||||
|
||||
CYCLE_PRIMARY_WEAPON_PATTERN,
|
||||
|
||||
TOGGLE_PHOTO_MODE,
|
||||
PHOTO_MODE_FILTER_PREV,
|
||||
PHOTO_MODE_FILTER_NEXT,
|
||||
PHOTO_MODE_FILTER_RESET,
|
||||
PHOTO_MODE_PARAM_DECREASE,
|
||||
PHOTO_MODE_PARAM_INCREASE,
|
||||
|
||||
/*!
|
||||
* This must always be below the last defined item
|
||||
*/
|
||||
@@ -575,7 +557,7 @@ class CC_preset {
|
||||
public:
|
||||
SCP_vector<CCB> bindings;
|
||||
SCP_string name;
|
||||
Preset_t type = Preset_t::hardcode;
|
||||
Preset_t type;
|
||||
|
||||
public:
|
||||
CC_preset() = default;
|
||||
@@ -592,10 +574,6 @@ public:
|
||||
* Control configuration item type.
|
||||
* @detail Contains binding info, documentation, behavior, etc. for a single control
|
||||
*/
|
||||
// Conflict group bitmasks. Bindings only conflict if their groups overlap (bitwise AND != 0).
|
||||
static const int CONFLICT_GROUP_DEFAULT = (1 << 0); //!< Standard gameplay bindings
|
||||
static const int CONFLICT_GROUP_PHOTO_MODE = (1 << 1); //!< Bindings used within photo mode
|
||||
|
||||
class CCI : public CCB {
|
||||
public:
|
||||
// Inherited from CCB
|
||||
@@ -604,7 +582,6 @@ public:
|
||||
|
||||
// Items Set in menu
|
||||
char tab; //!< what tab (category) it belongs in
|
||||
int conflict_groups = CONFLICT_GROUP_DEFAULT; //!< Bitmask of conflict groups. Bindings only conflict with others sharing at least one group.
|
||||
int indexXSTR; //!< what string index we should use to translate this with an XSTR 0 = None, 1= Use item index + CONTROL_CONFIG_XSTR, 2 <= use CCI::indexXSTR directly
|
||||
SCP_string text; //!< describes the action in the config screen
|
||||
|
||||
@@ -677,7 +654,7 @@ public:
|
||||
* If the type is CC_TYPE_TRIGGER or CC_TYPE_CONTINOUS, the primary is assumed to be a key combo and secondary is assumed to be a joy button.
|
||||
* If the type is CC_TYPE_AXIS_ABS, CC_TYPE_AXIS_REL, CC_TYPE_AXIS_BTN_POS, or CC_TYPE_AXIS_BTN_NEG, the primary is a Joy0 axis and the secondary is a Mouse axis
|
||||
*/
|
||||
CCI_builder& operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled = false, int conflict_groups = CONFLICT_GROUP_DEFAULT);
|
||||
CCI_builder& operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled = false);
|
||||
|
||||
private:
|
||||
CCI_builder(); // Only one builder per Control Config, so a default constructor is useless
|
||||
@@ -706,6 +683,7 @@ extern SCP_vector<conflict> Conflicts; //!< Stores conflict data for the keybind
|
||||
|
||||
extern SCP_vector<CCI> Control_config; //!< Stores the keyboard configuration
|
||||
extern SCP_vector<CC_preset> Control_config_presets; // tabled control presets; pointers to config_item arrays
|
||||
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
|
||||
|
||||
extern bool Generate_controlconfig_table;
|
||||
|
||||
@@ -864,7 +842,7 @@ bool control_config_delete_preset(CC_preset preset);
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_clone_preset(const CC_preset& preset, const SCP_string& name, bool overwrite);
|
||||
bool control_config_clone_preset(CC_preset preset, SCP_string name);
|
||||
|
||||
/*!
|
||||
* @brief Saves a preset with the current controls
|
||||
@@ -872,7 +850,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& name
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_create_new_preset(const SCP_string& name, bool overwrite);
|
||||
bool control_config_create_new_preset(SCP_string name);
|
||||
|
||||
/*!
|
||||
* Returns the IoActionId (index within Control_config[]) of a control bound to the given key
|
||||
@@ -930,18 +908,7 @@ const char *textify_scancode(int code);
|
||||
*/
|
||||
const char *textify_scancode_universal(int code);
|
||||
|
||||
/**
|
||||
* @brief Creates a button label based on btn index and locale settings.
|
||||
*
|
||||
* @param[in] btn The btn to textify
|
||||
*
|
||||
* @return The text representation of the btn
|
||||
*
|
||||
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
|
||||
*/
|
||||
const char* textify_button(int btn);
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* @brief Checks how long a control has been active
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
@@ -956,12 +923,8 @@ float check_control_timef(int id);
|
||||
* @brief Wrapper for check_control_used. Allows the game to ignore the key if told to do so by the ignore-key SEXP.
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
* @param[in] key DO NOT USE OUTSIDE OF THE MAIN LOOP. Key combination acquired from game_poll(), or -1 to check against a previous poll
|
||||
* @param[in] key The key combo to check against the control. If -1, re-check the last key passed to this function
|
||||
*
|
||||
* @returns 0 If the control was disabled by a mod, or
|
||||
* @returns 0 If locked by a script, or
|
||||
* @returns 0 If controls need to be ignored for multiplayer, or
|
||||
* @returns 0 If a script is handling the control execution, or
|
||||
* @returns 0 If the control wasn't used, or
|
||||
* @returns 1 If the control was used
|
||||
*
|
||||
|
||||
@@ -45,7 +45,6 @@ int Failed_key_index;
|
||||
// Joystick configuration
|
||||
int Joy_dead_zone_size = 10;
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
|
||||
std::pair<const char*, int>{"Deadzone", 1377},
|
||||
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
|
||||
@@ -60,7 +59,6 @@ auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
|
||||
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
|
||||
std::pair<const char*, int>{"Sensitivity", 1745},
|
||||
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
|
||||
@@ -138,12 +136,12 @@ void control_config_common_init_bindings() {
|
||||
(TARGET_PREV_BOMB, KEY_SHIFTED | KEY_B, -1, TARGET_TAB, 1, "Target Previous Hostile Bomb or Bomber", CC_TYPE_TRIGGER)
|
||||
|
||||
// flight controls (Rotation)
|
||||
(BANK_LEFT, KEY_PAD7, -1, SHIP_TAB, 1, "Bank Left", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(BANK_RIGHT, KEY_PAD9, -1, SHIP_TAB, 1, "Bank Right", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PITCH_FORWARD, KEY_PAD8, -1, SHIP_TAB, 1, "Pitch Forward", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PITCH_BACK, KEY_PAD2, -1, SHIP_TAB, 1, "Pitch Backward", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(YAW_LEFT, KEY_PAD4, -1, SHIP_TAB, 1, "Yaw Left", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(YAW_RIGHT, KEY_PAD6, -1, SHIP_TAB, 1, "Yaw Right", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(BANK_LEFT, KEY_PAD7, -1, SHIP_TAB, 1, "Bank Left", CC_TYPE_CONTINUOUS)
|
||||
(BANK_RIGHT, KEY_PAD9, -1, SHIP_TAB, 1, "Bank Right", CC_TYPE_CONTINUOUS)
|
||||
(PITCH_FORWARD, KEY_PAD8, -1, SHIP_TAB, 1, "Pitch Forward", CC_TYPE_CONTINUOUS)
|
||||
(PITCH_BACK, KEY_PAD2, -1, SHIP_TAB, 1, "Pitch Backward", CC_TYPE_CONTINUOUS)
|
||||
(YAW_LEFT, KEY_PAD4, -1, SHIP_TAB, 1, "Yaw Left", CC_TYPE_CONTINUOUS)
|
||||
(YAW_RIGHT, KEY_PAD6, -1, SHIP_TAB, 1, "Yaw Right", CC_TYPE_CONTINUOUS)
|
||||
|
||||
// flight controls (Throttle)
|
||||
(ZERO_THROTTLE, KEY_BACKSP, -1, SHIP_TAB, 1, "Set Throttle to Zero", CC_TYPE_TRIGGER)
|
||||
@@ -154,16 +152,16 @@ void control_config_common_init_bindings() {
|
||||
(MINUS_5_PERCENT_THROTTLE, KEY_MINUS, -1, SHIP_TAB, 1, "Decrease Throttle 5 Percent", CC_TYPE_TRIGGER)
|
||||
|
||||
// flight controls (Thrust)
|
||||
(FORWARD_THRUST, KEY_A, -1, SHIP_TAB, 1, "Forward Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(REVERSE_THRUST, KEY_Z, -1, SHIP_TAB, 1, "Reverse Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(RIGHT_SLIDE_THRUST, KEY_SHIFTED | KEY_3, -1, SHIP_TAB, 1, "Right Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(LEFT_SLIDE_THRUST, KEY_SHIFTED | KEY_1, -1, SHIP_TAB, 1, "Left Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(UP_SLIDE_THRUST, KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, 1, "Up Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(DOWN_SLIDE_THRUST, KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, 1, "Down Thrust", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(FORWARD_THRUST, KEY_A, -1, SHIP_TAB, 1, "Forward Thrust", CC_TYPE_CONTINUOUS)
|
||||
(REVERSE_THRUST, KEY_Z, -1, SHIP_TAB, 1, "Reverse Thrust", CC_TYPE_CONTINUOUS)
|
||||
(RIGHT_SLIDE_THRUST, KEY_SHIFTED | KEY_3, -1, SHIP_TAB, 1, "Right Thrust", CC_TYPE_CONTINUOUS)
|
||||
(LEFT_SLIDE_THRUST, KEY_SHIFTED | KEY_1, -1, SHIP_TAB, 1, "Left Thrust", CC_TYPE_CONTINUOUS)
|
||||
(UP_SLIDE_THRUST, KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, 1, "Up Thrust", CC_TYPE_CONTINUOUS)
|
||||
(DOWN_SLIDE_THRUST, KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, 1, "Down Thrust", CC_TYPE_CONTINUOUS)
|
||||
|
||||
// flight controls (flight modes)
|
||||
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
|
||||
@@ -180,7 +178,6 @@ void control_config_common_init_bindings() {
|
||||
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_PATTERN, KEY_ALTED | KEY_O, -1, WEAPON_TAB, 1859, "Cycle Primary Weapon Firing Pattern", CC_TYPE_TRIGGER)
|
||||
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
|
||||
@@ -212,10 +209,10 @@ void control_config_common_init_bindings() {
|
||||
(VIEW_DIST_INCREASE, KEY_PADPLUS, -1, COMPUTER_TAB, 1, "Increase View Distance", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_DIST_DECREASE, KEY_PADMINUS, -1, COMPUTER_TAB, 1, "Decrease View Distance", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_CENTER, KEY_PAD5, -1, COMPUTER_TAB, 1, "Center View", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_UP, -1, iHAT_UP, COMPUTER_TAB, 1, "View Up", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_DOWN, -1, iHAT_DOWN, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, iHAT_LEFT, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, iHAT_RIGHT, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_UP, -1, 33, COMPUTER_TAB, 1, "View Up", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
|
||||
@@ -267,12 +264,6 @@ void control_config_common_init_bindings() {
|
||||
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_PHOTO_MODE, KEY_ALTED | KEY_1, -1, COMPUTER_TAB, 1908, "Toggle Photo Mode", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_DEFAULT | CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PHOTO_MODE_FILTER_PREV, KEY_UP, -1, COMPUTER_TAB, 1909, "Photo Mode Previous Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PHOTO_MODE_FILTER_NEXT, KEY_DOWN, -1, COMPUTER_TAB, 1910, "Photo Mode Next Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PHOTO_MODE_FILTER_RESET, KEY_ALTED | KEY_2, -1, COMPUTER_TAB, 1911, "Photo Mode Reset Parameters", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PHOTO_MODE_PARAM_DECREASE, KEY_LEFT, -1, COMPUTER_TAB, 1912, "Photo Mode Decrease Selected Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
|
||||
(PHOTO_MODE_PARAM_INCREASE, KEY_RIGHT, -1, COMPUTER_TAB, 1913, "Photo Mode Increase Selected Parameter", CC_TYPE_TRIGGER, false, CONFLICT_GROUP_PHOTO_MODE)
|
||||
|
||||
// Custom Controls
|
||||
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 1784, "Custom Control 1", CC_TYPE_TRIGGER, true)
|
||||
@@ -280,13 +271,6 @@ void control_config_common_init_bindings() {
|
||||
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 1786, "Custom Control 3", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 1787, "Custom Control 4", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 1788, "Custom Control 5", CC_TYPE_TRIGGER, true)
|
||||
|
||||
|
||||
//Comms Controls
|
||||
(COMMS_MENU_MOVE_UP, -1, -1, COMPUTER_TAB, 1883, "Communication Menu Move Up", CC_TYPE_TRIGGER)
|
||||
(COMMS_MENU_MOVE_DOWN, -1, -1, COMPUTER_TAB, 1884, "Communication Menu Move Down", CC_TYPE_TRIGGER)
|
||||
(COMMS_MENU_SELECT, -1, -1, COMPUTER_TAB, 1885, "Communication Menu Select", CC_TYPE_TRIGGER)
|
||||
|
||||
.end(); // Builder
|
||||
|
||||
// init default preset
|
||||
@@ -440,12 +424,6 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Up Thrust", UP_SLIDE_THRUST},
|
||||
{"Down Thrust", DOWN_SLIDE_THRUST},
|
||||
{"Toggle HUD Wireframe Target View", HUD_TARGETBOX_TOGGLE_WIREFRAME},
|
||||
{"Toggle Photo Mode", TOGGLE_PHOTO_MODE},
|
||||
{"Photo Mode Previous Parameter", PHOTO_MODE_FILTER_PREV},
|
||||
{"Photo Mode Next Parameter", PHOTO_MODE_FILTER_NEXT},
|
||||
{"Photo Mode Reset Parameters", PHOTO_MODE_FILTER_RESET},
|
||||
{"Photo Mode Decrease Selected Parameter", PHOTO_MODE_PARAM_DECREASE},
|
||||
{"Photo Mode Increase Selected Parameter", PHOTO_MODE_PARAM_INCREASE},
|
||||
{"Top-Down View", VIEW_TOPDOWN},
|
||||
{"Target Padlock View", VIEW_TRACK_TARGET},
|
||||
|
||||
@@ -453,49 +431,74 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Cycle Nav Points", NAV_CYCLE},
|
||||
{"Toggle Gliding", TOGGLE_GLIDING},
|
||||
{"Cycle Primary Weapon Firing Rate", CYCLE_PRIMARY_WEAPON_SEQUENCE},
|
||||
{"Cycle Primary Weapon Firing Pattern", CYCLE_PRIMARY_WEAPON_PATTERN},
|
||||
{"Custom Control 1", CUSTOM_CONTROL_1},
|
||||
{"Custom Control 2", CUSTOM_CONTROL_2},
|
||||
{"Custom Control 3", CUSTOM_CONTROL_3},
|
||||
{"Custom Control 4", CUSTOM_CONTROL_4},
|
||||
{"Custom Control 5", CUSTOM_CONTROL_5},
|
||||
{"Communication Menu Move Up", COMMS_MENU_MOVE_UP},
|
||||
{"Communication Menu Move Down", COMMS_MENU_MOVE_DOWN},
|
||||
{"Communication Menu Select", COMMS_MENU_SELECT},
|
||||
};
|
||||
|
||||
// Localization strings for hat positions. Back[0], Forward[1], Left[2], Right[3]
|
||||
// This ordering is used to follow the same logic as hatBtnToEnum in joy-sdl.cpp
|
||||
const char* Joy_hat_text_german_u[JOY_NUM_HAT_POS] = {
|
||||
"Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
const char* Joy_button_text_german_u[] = {
|
||||
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
|
||||
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
|
||||
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
|
||||
"Knopf 19", "Knopf 20", "Knopf 21", "Knopf 22", "Knopf 23", "Knopf 24",
|
||||
"Knopf 25", "Knopf 26", "Knopf 27", "Knopf 28", "Knopf 29", "Knopf 30",
|
||||
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_french_u[JOY_NUM_HAT_POS] = {
|
||||
("Chapeau Arri\xc3\xa8""re"), "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
const char* Joy_button_text_french_u[] = {
|
||||
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
|
||||
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
"Bouton 19", "Bouton 20", "Bouton 21", "Bouton 22", "Bouton 23", "Bouton 24",
|
||||
"Bouton 25", "Bouton 26", "Bouton 27", "Bouton 28", "Bouton 29", "Bouton 30",
|
||||
"Bouton 31", "Bouton 32", ("Chapeau Arri\xc3\xa8""re"), "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_polish_u[JOY_NUM_HAT_POS] = {
|
||||
"Hat Ty\xc5\x82", ("Hat Prz\xc3\xb3""d"), "Hat Lewo", "Hat Prawo"
|
||||
const char* Joy_button_text_polish_u[] = {
|
||||
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
|
||||
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
"Przyc.19", "Przyc.20", "Przyc.21", "Przyc.22", "Przyc.23", "Przyc.24",
|
||||
"Przyc.25", "Przyc.26", "Przyc.27", "Przyc.28", "Przyc.29", "Przyc.30",
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xc5\x82", ("Hat Prz\xc3\xb3""d"), "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_english_u[JOY_NUM_HAT_POS] = {
|
||||
"Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
const char* Joy_button_text_english_u[] = {
|
||||
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
|
||||
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
|
||||
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
|
||||
"Button 19", "Button 20", "Button 21", "Button 22", "Button 23", "Button 24",
|
||||
"Button 25", "Button 26", "Button 27", "Button 28", "Button 29", "Button 30",
|
||||
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_german[JOY_NUM_HAT_POS] = {
|
||||
"Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
const char* Joy_button_text_german[] = {
|
||||
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
|
||||
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
|
||||
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
|
||||
"Knopf 19", "Knopf 20", "Knopf 21", "Knopf 22", "Knopf 23", "Knopf 24",
|
||||
"Knopf 25", "Knopf 26", "Knopf 27", "Knopf 28", "Knopf 29", "Knopf 30",
|
||||
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_french[JOY_NUM_HAT_POS] = {
|
||||
"Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
const char* Joy_button_text_french[] = {
|
||||
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
|
||||
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
"Bouton 19", "Bouton 20", "Bouton 21", "Bouton 22", "Bouton 23", "Bouton 24",
|
||||
"Bouton 25", "Bouton 26", "Bouton 27", "Bouton 28", "Bouton 29", "Bouton 30",
|
||||
"Bouton 31", "Bouton 32", "Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_polish[JOY_NUM_HAT_POS] = {
|
||||
"Hat Ty\xB3", "Hat Prz\xF3\x64", "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_english[JOY_NUM_HAT_POS] = {
|
||||
"Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
const char* Joy_button_text_polish[] = {
|
||||
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
|
||||
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
"Przyc.19", "Przyc.20", "Przyc.21", "Przyc.22", "Przyc.23", "Przyc.24",
|
||||
"Przyc.25", "Przyc.26", "Przyc.27", "Przyc.28", "Przyc.29", "Przyc.30",
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xB3", "Hat Prz\xF3\x64", "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
//English scancodes are still needed eclusively for the scripting API, as we need to give generic and stable scan code names to the API that are neither translated nor localized to keyboard layout.
|
||||
@@ -541,6 +544,17 @@ const char *Scan_code_text_english[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
const char* Joy_button_text_english[] = {
|
||||
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
|
||||
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
|
||||
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
|
||||
"Button 19", "Button 20", "Button 21", "Button 22", "Button 23", "Button 24",
|
||||
"Button 25", "Button 26", "Button 27", "Button 28", "Button 29", "Button 30",
|
||||
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
};
|
||||
|
||||
const char **Joy_button_text = Joy_button_text_english;
|
||||
|
||||
bool Generate_controlconfig_table = false;
|
||||
|
||||
int sections_read = 0; // Number of sections read within the controlconfigdefaults.tbl
|
||||
@@ -709,69 +723,7 @@ const char *textify_scancode_universal(int code)
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
const char* textify_button(int btn) {
|
||||
static char text[BTN_MSG_LEN];
|
||||
|
||||
if ((btn < 0) || (btn >= JOY_TOTAL_BUTTONS))
|
||||
return "None";
|
||||
|
||||
text[0] = '\0';
|
||||
|
||||
if (btn < JOY_NUM_BUTTONS) {
|
||||
// Is a button.
|
||||
if (Lcl_gr) {
|
||||
sprintf(text, "Knopf %i", btn);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
sprintf(text, "Bouton %i", btn);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
sprintf(text, "Przyc.%i", btn);
|
||||
|
||||
} else {
|
||||
sprintf(text, "Button %i", btn);
|
||||
}
|
||||
|
||||
} else {
|
||||
//is Hat
|
||||
btn -= JOY_NUM_BUTTONS;
|
||||
Assertion(btn <= JOY_NUM_HAT_POS, "Invalid btn value '%i' after hat position translation.", btn);
|
||||
|
||||
if (Unicode_text_mode) {
|
||||
// use unicode character maps
|
||||
if (Lcl_gr) {
|
||||
strcpy_s(text, Joy_hat_text_german_u[btn]);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
strcpy_s(text, Joy_hat_text_french_u[btn]);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
strcpy_s(text, Joy_hat_text_polish_u[btn]);
|
||||
|
||||
} else {
|
||||
strcpy_s(text, Joy_hat_text_english_u[btn]);
|
||||
}
|
||||
} else {
|
||||
// use ascii character maps
|
||||
if (Lcl_gr) {
|
||||
strcpy_s(text, Joy_hat_text_german[btn]);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
strcpy_s(text, Joy_hat_text_french[btn]);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
strcpy_s(text, Joy_hat_text_polish[btn]);
|
||||
|
||||
} else {
|
||||
strcpy_s(text, Joy_hat_text_english[btn]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
//XSTR:ON
|
||||
//XSTR:ON
|
||||
|
||||
void control_config_common_load_overrides();
|
||||
|
||||
@@ -804,6 +756,36 @@ void control_config_common_init()
|
||||
// load player presets
|
||||
load_preset_files();
|
||||
|
||||
// Init control label localization
|
||||
if (Unicode_text_mode) {
|
||||
if (Lcl_gr) {
|
||||
Joy_button_text = Joy_button_text_german_u;
|
||||
}
|
||||
else if (Lcl_fr) {
|
||||
Joy_button_text = Joy_button_text_french_u;
|
||||
}
|
||||
else if (Lcl_pl) {
|
||||
Joy_button_text = Joy_button_text_polish_u;
|
||||
}
|
||||
else {
|
||||
Joy_button_text = Joy_button_text_english_u;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Lcl_gr) {
|
||||
Joy_button_text = Joy_button_text_german;
|
||||
}
|
||||
else if (Lcl_fr) {
|
||||
Joy_button_text = Joy_button_text_french;
|
||||
}
|
||||
else if (Lcl_pl) {
|
||||
Joy_button_text = Joy_button_text_polish;
|
||||
}
|
||||
else {
|
||||
Joy_button_text = Joy_button_text_english;
|
||||
}
|
||||
}
|
||||
|
||||
// Old XSTR indices have been put beside their corresponding label in case we use them again
|
||||
Axis_text[0] = vm_strdup(XSTR("X Axis", 1647)); // XSTR 1021 - "Joystick/Mouse X Axis"
|
||||
Axis_text[1] = vm_strdup(XSTR("Y Axis", 1648)); // XSTR 1022 - "Joystick/Mouse Y Axis"
|
||||
@@ -811,8 +793,6 @@ void control_config_common_init()
|
||||
Axis_text[3] = vm_strdup(XSTR("rX Axis", 1650)); // XSTR 1024 - "Joystick rX Axis"
|
||||
Axis_text[4] = vm_strdup(XSTR("rY Axis", 1651)); // XSTR 1025 - "Joystick rY Axis"
|
||||
Axis_text[5] = vm_strdup(XSTR("rZ Axis", 1652)); // XSTR 1026 - "Joystick rZ Axis"
|
||||
Axis_text[6] = vm_strdup(XSTR("U Axis", 1860));
|
||||
Axis_text[7] = vm_strdup(XSTR("V Axis", 1861));
|
||||
|
||||
Mouse_button_text[0] = vm_strdup(XSTR("Left Button", 1027));
|
||||
Mouse_button_text[1] = vm_strdup(XSTR("Right Button", 1028));
|
||||
@@ -1165,12 +1145,6 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(UP_SLIDE_THRUST)
|
||||
ADD_ENUM_TO_ACTION_MAP(DOWN_SLIDE_THRUST)
|
||||
ADD_ENUM_TO_ACTION_MAP(HUD_TARGETBOX_TOGGLE_WIREFRAME)
|
||||
ADD_ENUM_TO_ACTION_MAP(TOGGLE_PHOTO_MODE)
|
||||
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_PREV)
|
||||
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_NEXT)
|
||||
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_FILTER_RESET)
|
||||
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_PARAM_DECREASE)
|
||||
ADD_ENUM_TO_ACTION_MAP(PHOTO_MODE_PARAM_INCREASE)
|
||||
ADD_ENUM_TO_ACTION_MAP(VIEW_TOPDOWN)
|
||||
ADD_ENUM_TO_ACTION_MAP(VIEW_TRACK_TARGET)
|
||||
|
||||
@@ -1180,7 +1154,6 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(TOGGLE_GLIDING)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(CYCLE_PRIMARY_WEAPON_SEQUENCE)
|
||||
ADD_ENUM_TO_ACTION_MAP(CYCLE_PRIMARY_WEAPON_PATTERN)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(CUSTOM_CONTROL_1)
|
||||
ADD_ENUM_TO_ACTION_MAP(CUSTOM_CONTROL_2)
|
||||
@@ -1194,10 +1167,6 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(JOY_ABS_THROTTLE_AXIS)
|
||||
ADD_ENUM_TO_ACTION_MAP(JOY_REL_THROTTLE_AXIS)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_MOVE_UP)
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_MOVE_DOWN)
|
||||
ADD_ENUM_TO_ACTION_MAP(COMMS_MENU_SELECT)
|
||||
|
||||
|
||||
#undef ADD_ENUM_TO_ACTION_MAP
|
||||
|
||||
@@ -1237,8 +1206,6 @@ void LoadEnumsIntoAxisMap() {
|
||||
mAxisNameToVal["RX_AXIS"] = JOY_RX_AXIS;
|
||||
mAxisNameToVal["RY_AXIS"] = JOY_RY_AXIS;
|
||||
mAxisNameToVal["RZ_AXIS"] = JOY_RZ_AXIS;
|
||||
mAxisNameToVal["U_AXIS"] = JOY_U_AXIS;
|
||||
mAxisNameToVal["V_AXIS"] = JOY_V_AXIS;
|
||||
}
|
||||
|
||||
void LoadEnumsIntoHatMap() {
|
||||
@@ -1990,7 +1957,7 @@ int control_config_common_write_tbl(bool overwrite = false, bool all = false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CFILE* cfile = cfopen("controlconfigdefaults.tbl", "w", CF_TYPE_TABLES);
|
||||
CFILE* cfile = cfopen("controlconfigdefaults.tbl", "w", CFILE_NORMAL, CF_TYPE_TABLES);
|
||||
if (cfile == nullptr) {
|
||||
// Could not open. Bail.
|
||||
return 1;
|
||||
@@ -2683,21 +2650,22 @@ SCP_string CC_bind::textify() const {
|
||||
SCP_string prefix;
|
||||
SCP_string retval;
|
||||
|
||||
// TODO: XSTR the Mouse/Joy prefix
|
||||
switch (cid) {
|
||||
case CID_MOUSE:
|
||||
prefix = XSTR("Mouse ", 1868);
|
||||
prefix = "Mouse ";
|
||||
break;
|
||||
case CID_JOY0:
|
||||
prefix = XSTR("Joy-0 ", 1869);
|
||||
prefix = "Joy-0 ";
|
||||
break;
|
||||
case CID_JOY1:
|
||||
prefix = XSTR("Joy-1 ", 1870);
|
||||
prefix = "Joy-1 ";
|
||||
break;
|
||||
case CID_JOY2:
|
||||
prefix = XSTR("Joy-2 ", 1871);
|
||||
prefix = "Joy-2 ";
|
||||
break;
|
||||
case CID_JOY3:
|
||||
prefix = XSTR("Joy-3 ", 1872);
|
||||
prefix = "Joy-3 ";
|
||||
break;
|
||||
case CID_NONE:
|
||||
case CID_KEYBOARD:
|
||||
@@ -2709,7 +2677,7 @@ SCP_string CC_bind::textify() const {
|
||||
if (flags & CCF_AXIS) {
|
||||
// Is Axis
|
||||
if (cid == CID_NONE) {
|
||||
retval = XSTR("None", 1873);
|
||||
retval = "None";
|
||||
} else {
|
||||
Assert((btn >= 0) && (btn < NUM_AXIS_TEXT));
|
||||
retval = SCP_string(Axis_text[btn]);
|
||||
@@ -2732,12 +2700,12 @@ SCP_string CC_bind::textify() const {
|
||||
case CID_JOY2:
|
||||
case CID_JOY3:
|
||||
Assert((btn >= 0) && (btn < JOY_TOTAL_BUTTONS));
|
||||
retval = SCP_string(textify_button(btn));
|
||||
retval = SCP_string(Joy_button_text[btn]);
|
||||
break;
|
||||
|
||||
case CID_NONE:
|
||||
default:
|
||||
retval = XSTR("None", 1873);
|
||||
retval = "None";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2816,12 +2784,10 @@ bool CCB::operator!=(const CCB& A) const {
|
||||
}
|
||||
|
||||
bool CCB::has_first_conflict(const CCB& A) const {
|
||||
// coverity[copy_paste_error:FALSE]
|
||||
return !first.empty() && (first.conflicts_with(A.first) || first.conflicts_with(A.second));
|
||||
}
|
||||
|
||||
bool CCB::has_second_conflict(const CCB& A) const {
|
||||
// coverity[copy_paste_error:FALSE]
|
||||
return !second.empty() && (second.conflicts_with(A.first) || second.conflicts_with(A.second));
|
||||
}
|
||||
|
||||
@@ -2838,7 +2804,6 @@ CCI& CCI::operator=(const CCI& A) {
|
||||
locked = A.locked;
|
||||
scriptEnabledByDefault = A.scriptEnabledByDefault;
|
||||
continuous_ongoing = A.continuous_ongoing;
|
||||
conflict_groups = A.conflict_groups;
|
||||
|
||||
return *this;
|
||||
};
|
||||
@@ -2921,7 +2886,7 @@ CCI_builder& CCI_builder::start() {
|
||||
|
||||
void CCI_builder::end() {};
|
||||
|
||||
CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled, int conflict_groups) {
|
||||
CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled) {
|
||||
Assert(action_id < CCFG_MAX);
|
||||
CCI& item = ControlConfig[action_id];
|
||||
|
||||
@@ -2959,9 +2924,6 @@ CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short
|
||||
item.disabled = false;
|
||||
}
|
||||
|
||||
// Assign the conflict group
|
||||
item.conflict_groups = conflict_groups;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
#include "controlconfig/presets.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "libs/jansson.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "popup/popup.h"
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
@@ -45,7 +43,7 @@ void load_preset_files(SCP_string clone) {
|
||||
std::unique_ptr<PresetFileHandler> handler = nullptr;
|
||||
|
||||
for (const auto &file : filelist) {
|
||||
CFILE* fp = cfopen((file + ".json").c_str(), "r", CF_TYPE_PLAYER_BINDS, false,
|
||||
CFILE* fp = cfopen((file + ".json").c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if (!fp) {
|
||||
@@ -135,12 +133,8 @@ void load_preset_files(SCP_string clone) {
|
||||
Control_config_presets.push_back(preset);
|
||||
|
||||
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
|
||||
if (gameseq_get_state() == GS_STATE_CONTROL_CONFIG) {
|
||||
popup(PF_TITLE_WHITE | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
} else {
|
||||
// Complain and ignore if the preset names or the type differs
|
||||
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
}
|
||||
// Complain and ignore if the preset names or the type differs
|
||||
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
|
||||
} // else, silent ignore
|
||||
}
|
||||
@@ -190,7 +184,7 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
|
||||
std::unique_ptr<PresetFileHandler> handler = nullptr;
|
||||
|
||||
// Check if there's a file already
|
||||
CFILE* fp = cfopen(filename.c_str(), "r", CF_TYPE_PLAYER_BINDS, false,
|
||||
CFILE* fp = cfopen(filename.c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if ((fp != nullptr) && !overwrite) {
|
||||
@@ -199,7 +193,7 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
|
||||
}
|
||||
|
||||
// Try opening file for write
|
||||
fp = cfopen(filename.c_str(), "w", CF_TYPE_PLAYER_BINDS, false,
|
||||
fp = cfopen(filename.c_str(), "w", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if (!fp) {
|
||||
|
||||
@@ -354,25 +354,32 @@ static const char* Text_lines[MAX_TEXT_LINES];
|
||||
|
||||
void cutscenes_screen_play()
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Cutscene_list, Selected_line), "Selected line %d is out of range!", Selected_line);
|
||||
int which_cutscene = Cutscene_list[Selected_line];
|
||||
char name[MAX_FILENAME_LEN]; // *full_name
|
||||
int which_cutscene;
|
||||
|
||||
Assert((Selected_line >= 0) && (Selected_line < (int) Cutscene_list.size()));
|
||||
which_cutscene = Cutscene_list[Selected_line];
|
||||
|
||||
strcpy_s(name, Cutscenes[which_cutscene].filename);
|
||||
// full_name = cf_add_ext(name, NOX(".mve"));
|
||||
|
||||
main_hall_stop_music(true);
|
||||
main_hall_stop_ambient();
|
||||
auto rval = movie::play(Cutscenes[which_cutscene].filename, true);
|
||||
auto rval = movie::play(name);
|
||||
main_hall_start_music();
|
||||
|
||||
if (!rval)
|
||||
{
|
||||
SCP_string str;
|
||||
char str[256];
|
||||
|
||||
if (Cmdline_nomovies)
|
||||
str = XSTR("Movies are currently disabled.", 1574);
|
||||
strcpy_s(str, XSTR("Movies are currently disabled.", 1574));
|
||||
else
|
||||
sprintf(str, XSTR("Unable to play movie %s.", 204), Cutscenes[which_cutscene].name);
|
||||
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str.c_str());
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cutscenes_screen_scroll_line_up()
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace {
|
||||
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
|
||||
const int OUT_SAMPLE_RATE = 48000;
|
||||
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
|
||||
const int OUT_NUM_CHANNELS = av_popcount64(OUT_CH_LAYOUT);
|
||||
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
|
||||
|
||||
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
|
||||
|
||||
|
||||
@@ -69,11 +69,7 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
paras.height = stream->codecpar->height;
|
||||
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 36, 255)
|
||||
paras.channel_layout = stream->codecpar->ch_layout.u.mask;
|
||||
#else
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
#endif
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
|
||||
}
|
||||
|
||||
SubtitleFramePtr frame(new SubtitleFrame());
|
||||
frame->text = std::move(processed_text);
|
||||
frame->text = processed_text;
|
||||
|
||||
frame->displayStartTime = start_time;
|
||||
frame->displayEndTime = end_time;
|
||||
|
||||
@@ -12,10 +12,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
videoCodec = nullptr;
|
||||
|
||||
if (videoCodecCtx != nullptr) {
|
||||
avcodec_close(videoCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&videoCodecCtx);
|
||||
#else
|
||||
avcodec_close(videoCodecCtx);
|
||||
#endif
|
||||
videoCodecCtx = nullptr;
|
||||
}
|
||||
@@ -25,10 +24,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
audioCodec = nullptr;
|
||||
|
||||
if (audioCodecCtx != nullptr) {
|
||||
avcodec_close(audioCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&audioCodecCtx);
|
||||
#else
|
||||
avcodec_close(audioCodecCtx);
|
||||
#endif
|
||||
audioCodecCtx = nullptr;
|
||||
}
|
||||
@@ -38,10 +36,9 @@ DecoderStatus::~DecoderStatus() {
|
||||
subtitleCodec = nullptr;
|
||||
|
||||
if (subtitleCodecCtx != nullptr) {
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&subtitleCodecCtx);
|
||||
#else
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#endif
|
||||
subtitleCodecCtx = nullptr;
|
||||
}
|
||||
|
||||
+8
-33
@@ -30,7 +30,6 @@
|
||||
#include "io/key.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
#include "network/multi.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
|
||||
extern int Game_mode;
|
||||
extern int Is_standalone;
|
||||
@@ -46,7 +45,6 @@ struct PlaybackState {
|
||||
vec2d posBottomRight;
|
||||
|
||||
int subtitle_font = -1;
|
||||
color subtitle_color = Color_bright_white;
|
||||
};
|
||||
|
||||
void processEvents()
|
||||
@@ -104,7 +102,7 @@ void displayVideo(Player* player, PlaybackState* state) {
|
||||
|
||||
auto subtitle = player->getCurrentSubtitle();
|
||||
if (!subtitle.empty() && state->subtitle_font >= 0) {
|
||||
gr_set_color_fast(&state->subtitle_color);
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
font::set_font(state->subtitle_font);
|
||||
|
||||
int width;
|
||||
@@ -181,20 +179,7 @@ void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
|
||||
if ((Movie_subtitle_rgba[0] >= 0 && Movie_subtitle_rgba[0] <= 255) &&
|
||||
(Movie_subtitle_rgba[1] >= 0 && Movie_subtitle_rgba[1] <= 255) &&
|
||||
(Movie_subtitle_rgba[2] >= 0 && Movie_subtitle_rgba[2] <= 255) &&
|
||||
(Movie_subtitle_rgba[3] >= 0 && Movie_subtitle_rgba[3] <= 255))
|
||||
{
|
||||
gr_init_alphacolor(&state->subtitle_color,
|
||||
Movie_subtitle_rgba[0],
|
||||
Movie_subtitle_rgba[1],
|
||||
Movie_subtitle_rgba[2],
|
||||
Movie_subtitle_rgba[3]);
|
||||
}
|
||||
|
||||
}
|
||||
else if (font::FontManager::numberOfFonts() > 0) {
|
||||
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
|
||||
@@ -273,22 +258,12 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
|
||||
namespace movie {
|
||||
// Play one movie
|
||||
bool play(const char* filename, bool via_tech_room = false)
|
||||
{
|
||||
if (scripting::hooks::OnMovieAboutToPlay->isActive())
|
||||
{
|
||||
auto paramList = scripting::hook_param_list(scripting::hook_param("Filename", 's', filename), scripting::hook_param("ViaTechRoom", 'b', via_tech_room));
|
||||
bool skip = scripting::hooks::OnMovieAboutToPlay->isOverride(paramList);
|
||||
scripting::hooks::OnMovieAboutToPlay->run(std::move(paramList));
|
||||
if (skip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool play(const char* name) {
|
||||
// mark the movie as viewable to the player when in a campaign
|
||||
// do this before anything else so that we're sure the movie is available
|
||||
// to the player even if it's not going to play right now
|
||||
if (Game_mode & GM_CAMPAIGN_MODE) {
|
||||
cutscene_mark_viewable(filename);
|
||||
cutscene_mark_viewable(name);
|
||||
}
|
||||
|
||||
if (Cmdline_nomovies || Is_standalone) {
|
||||
@@ -317,7 +292,7 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
// clear third buffer (may not be one, but that's ok)
|
||||
gr_clear();
|
||||
|
||||
auto player = cutscene::Player::newPlayer(filename);
|
||||
auto player = cutscene::Player::newPlayer(name);
|
||||
if (player) {
|
||||
PlaybackState state;
|
||||
initialize_player_state(player.get(), &state);
|
||||
@@ -327,7 +302,7 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
player->stopPlayback();
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", filename));
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
}
|
||||
|
||||
Movie_active = false;
|
||||
@@ -338,9 +313,9 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
return true;
|
||||
}
|
||||
|
||||
void play_two(const char* filename1, const char* filename2) {
|
||||
if (play(filename1)) {
|
||||
play(filename2);
|
||||
void play_two(const char* name1, const char* name2) {
|
||||
if (play(name1)) {
|
||||
play(name2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
namespace movie {
|
||||
|
||||
bool play(const char* filename, bool via_tech_room = false);
|
||||
bool play(const char* name);
|
||||
|
||||
void play_two(const char* filename1, const char* filename2);
|
||||
void play_two(const char* name1, const char* name2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+178
-372
@@ -2,21 +2,7 @@
|
||||
#include "ddsutils/ddsutils.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "osapi/osregistry.h"
|
||||
#ifdef USE_OPENGL_ES
|
||||
#include "graphics/opengl/es_compatibility.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
#include <glad/glad.h>
|
||||
#else
|
||||
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
||||
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
|
||||
#endif
|
||||
|
||||
#define BCDEC_IMPLEMENTATION 1
|
||||
PUSH_SUPPRESS_WARNINGS
|
||||
#include "ddsutils/bcdec.h"
|
||||
POP_SUPPRESS_WARNINGS
|
||||
|
||||
/* Currently supported formats:
|
||||
* DXT1a (compressed)
|
||||
@@ -26,9 +12,12 @@ POP_SUPPRESS_WARNINGS
|
||||
* uncompressed 1555 (16-bit, 1-bit being alpha)
|
||||
* uncompressed 8888 (32-bit)
|
||||
* uncompressed 888 (24-bit, no alpha)
|
||||
* uncompressed R8 (8-bit, Red channel as luminance)
|
||||
* paletted 8-bit (256 colors)
|
||||
*/
|
||||
|
||||
|
||||
int Texture_compression_available = 0;
|
||||
int Use_compressed_textures = 0;
|
||||
|
||||
// power of two check, to verify that a given DDS will always be usable since
|
||||
// some may not be power-of-2
|
||||
@@ -37,237 +26,39 @@ static inline int is_power_of_two(int w, int h)
|
||||
return ( (w && !(w & (w-1))) && (h && !(h & (h-1))) );
|
||||
}
|
||||
|
||||
static bool valid_dx10_format(const DDS_HEADER_DXT10 &header)
|
||||
// This function is used to verify that the file format specified in the DX10 Header
|
||||
// is supported by the OpenGL extensions
|
||||
bool dds_read_dx10_header(CFILE* dds_file, DDS_HEADER_DXT10* header)
|
||||
{
|
||||
switch (header.dxgiFormat) {
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
|
||||
return true;
|
||||
header->dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(dds_file));
|
||||
header->resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(dds_file));
|
||||
header->miscFlag = cfread_uint(dds_file);
|
||||
header->arraySize = cfread_uint(dds_file);
|
||||
header->miscFlags2 = cfread_uint(dds_file);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool conversion_needed(const DDS_HEADER &dds_header)
|
||||
{
|
||||
if ((dds_header.ddspf.dwFlags & DDPF_FOURCC) != DDPF_FOURCC) {
|
||||
switch (header->dxgiFormat) {
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DXT1:
|
||||
case FOURCC_DXT3:
|
||||
case FOURCC_DXT5:
|
||||
return !GLAD_GL_EXT_texture_compression_s3tc;
|
||||
|
||||
case FOURCC_DX10:
|
||||
// anything other than BC7 will end up invalid
|
||||
return !GLAD_GL_ARB_texture_compression_bptc;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// anything not specifically listed should end up invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
// Memory usage for uncompressed textures is quite high. Some MVP assets can
|
||||
// require well over a GB of VRAM for a single ship after conversion. To help
|
||||
// alleviate this we need to resize those textures where possible. At 1024x1024
|
||||
// the memory requirement is reduced to about 36 MB per ship with a full set
|
||||
// of textures.
|
||||
//
|
||||
// NOTE: modifies header!!
|
||||
//
|
||||
// returns: number of mipmap levels to skip
|
||||
static uint conversion_resize(DDS_HEADER &dds_header)
|
||||
{
|
||||
const size_t MAX_SIZE = 1024;
|
||||
uint width, height, depth, offset = 0;
|
||||
|
||||
if (dds_header.dwMipMapCount <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
width = dds_header.dwWidth;
|
||||
height = dds_header.dwHeight;
|
||||
depth = dds_header.dwDepth;
|
||||
|
||||
// drop levels until we get to an appropriate size, but make sure we have
|
||||
// at least 1 mipmap level remaining at the end (in case there's not a full chain)
|
||||
while (((width > MAX_SIZE) || (height > MAX_SIZE)) && (offset < dds_header.dwMipMapCount-1)) {
|
||||
// this shouldn't happen, but catch the obscure case (like 8192x4)
|
||||
if ((width <= 4) || (height <= 4)) {
|
||||
break;
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
depth >>= 1;
|
||||
|
||||
++offset;
|
||||
}
|
||||
|
||||
// no change needed
|
||||
if ( !offset ) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
// update header with new values
|
||||
dds_header.dwWidth = std::max(1U, width);
|
||||
dds_header.dwHeight = std::max(1U, height);
|
||||
dds_header.dwDepth = std::max(1U, depth);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_DXT10 *dds_header_dx10 = nullptr)
|
||||
{
|
||||
DDS_HEADER_DXT10 dx10_header;
|
||||
|
||||
// read the code
|
||||
int code = cfread_int(ddsfile);
|
||||
|
||||
// check it
|
||||
if (code != DDS_FILECODE) {
|
||||
return DDS_ERROR_BAD_HEADER;
|
||||
}
|
||||
|
||||
// read header variables
|
||||
dds_header.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.dwHeight = cfread_uint(ddsfile);
|
||||
dds_header.dwWidth = cfread_uint(ddsfile);
|
||||
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
|
||||
dds_header.dwDepth = cfread_uint(ddsfile);
|
||||
dds_header.dwMipMapCount = cfread_uint(ddsfile);
|
||||
|
||||
// skip over the crap we don't care about
|
||||
cfseek(ddsfile, 11*4, CF_SEEK_CUR);
|
||||
|
||||
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
|
||||
|
||||
dds_header.dwCaps = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps2 = cfread_uint(ddsfile);
|
||||
|
||||
// Unused but need them checked for later
|
||||
dds_header.dwCaps3 = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps4 = cfread_uint(ddsfile);
|
||||
dds_header.dwReserved2 = cfread_uint(ddsfile);
|
||||
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
|
||||
dx10_header.dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(ddsfile));
|
||||
dx10_header.resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(ddsfile));
|
||||
dx10_header.miscFlag = cfread_uint(ddsfile);
|
||||
dx10_header.arraySize = cfread_uint(ddsfile);
|
||||
dx10_header.miscFlags2 = cfread_uint(ddsfile);
|
||||
|
||||
if (dds_header_dx10) {
|
||||
memcpy(dds_header_dx10, &dx10_header, sizeof(DDS_HEADER_DXT10));
|
||||
}
|
||||
}
|
||||
|
||||
// sanitize values
|
||||
dds_header.dwDepth = std::max(1U, dds_header.dwDepth);
|
||||
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (dds_header.dwDepth > 1) {
|
||||
Assertion(dds_header.dwFlags & DDSD_DEPTH, "ERROR: Volume texture missing proper flags!!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// set pitch manually (per MS docs)
|
||||
dds_header.dwFlags &= ~DDSD_LINEARSIZE;
|
||||
dds_header.dwFlags |= DDSD_PITCH;
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
int block_size = (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16;
|
||||
dds_header.dwPitchOrLinearSize = std::max(1U, (dds_header.dwWidth+3)/4) * block_size;
|
||||
} else {
|
||||
// this isn't technically correct, but it's only wrong for formats we don't support
|
||||
dds_header.dwPitchOrLinearSize = (dds_header.dwWidth * dds_header.ddspf.dwRGBBitCount + 7) / 8;
|
||||
}
|
||||
|
||||
return DDS_ERROR_NONE;
|
||||
}
|
||||
|
||||
static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = false)
|
||||
{
|
||||
const uint block_sz = 4;
|
||||
uint d_width = 0, d_height = 0, d_depth = 0;
|
||||
size_t d_size = 0;
|
||||
|
||||
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
|
||||
d_width = std::max(1U, dds_header.dwWidth >> i);
|
||||
d_height = std::max(1U, dds_header.dwHeight >> i);
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> i);
|
||||
|
||||
// When converting we need to pad a bit to compensate for the decompression
|
||||
// size on smaller mipmap levels. We need to ensure there is always enough
|
||||
// room to decode an entire 4x4 block in rgba space
|
||||
if (converting) {
|
||||
auto sz = std::min(d_width, d_height);
|
||||
|
||||
if (sz < block_sz) {
|
||||
d_size += ((block_sz * block_sz) - (sz * sz)) * d_depth * 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
} else {
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes valid cubemap (should be checked elsewhere)
|
||||
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
Assertion(d_size > 0, "ERROR: DDS size computed to 0!!");
|
||||
|
||||
return d_size;
|
||||
}
|
||||
|
||||
static int get_bit_count(const DDS_HEADER &dds_header)
|
||||
{
|
||||
if (dds_header.ddspf.dwFlags & DDPF_RGB) {
|
||||
return dds_header.ddspf.dwRGBBitCount;
|
||||
} else if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
|
||||
return 24;
|
||||
} else {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size)
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size, ubyte *palette)
|
||||
{
|
||||
DDS_HEADER dds_header;
|
||||
DDS_HEADER_DXT10 dds_header_dx10;
|
||||
int code = 0;
|
||||
CFILE *ddsfile;
|
||||
char real_name[MAX_FILENAME_LEN];
|
||||
int retval = DDS_ERROR_NONE;
|
||||
int ct = DDS_UNCOMPRESSED;
|
||||
int is_cubemap = 0;
|
||||
bool convert = false;
|
||||
int bits = 0;
|
||||
int i, is_cubemap = 0;
|
||||
uint32_t d_width = 0, d_height = 0, d_depth = 0;
|
||||
size_t d_size = 0;
|
||||
|
||||
|
||||
if (img_cfp == NULL) {
|
||||
@@ -290,36 +81,113 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
ddsfile = img_cfp;
|
||||
}
|
||||
|
||||
retval = _dds_read_header(ddsfile, dds_header, &dds_header_dx10);
|
||||
// read the code
|
||||
code = cfread_int(ddsfile);
|
||||
|
||||
if (retval != DDS_ERROR_NONE) {
|
||||
// check it
|
||||
if (code != DDS_FILECODE) {
|
||||
retval = DDS_ERROR_BAD_HEADER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// check for valid cubemap (we require all 6 faces)
|
||||
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
// read header variables
|
||||
dds_header.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.dwHeight = cfread_uint(ddsfile);
|
||||
dds_header.dwWidth = cfread_uint(ddsfile);
|
||||
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
|
||||
dds_header.dwDepth = cfread_uint(ddsfile);
|
||||
dds_header.dwMipMapCount = cfread_uint(ddsfile);
|
||||
|
||||
// skip over the crap we don't care about
|
||||
for (i = 0; i < 11; i++)
|
||||
cfread_uint(ddsfile);
|
||||
|
||||
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
|
||||
|
||||
dds_header.dwCaps = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps2 = cfread_uint(ddsfile);
|
||||
|
||||
// Unused but need them checked for later
|
||||
dds_header.dwCaps3 = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps4 = cfread_uint(ddsfile);
|
||||
dds_header.dwReserved2 = cfread_uint(ddsfile);
|
||||
|
||||
// sanity
|
||||
if (dds_header.dwDepth == 0)
|
||||
dds_header.dwDepth = 1;
|
||||
|
||||
if (dds_header.dwMipMapCount < 1)
|
||||
dds_header.dwMipMapCount = 1;
|
||||
|
||||
d_width = dds_header.dwWidth;
|
||||
d_height = dds_header.dwHeight;
|
||||
d_depth = dds_header.dwDepth;
|
||||
|
||||
// calculate the type and size of the data
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// did I mention lately that I hate Microsoft?
|
||||
// this is here to fix the situation where Microsoft doesn't follow their own docs
|
||||
if ( !(dds_header.dwFlags & (DDSD_LINEARSIZE | DDSD_PITCH) ) || dds_header.dwPitchOrLinearSize <= 0 ) {
|
||||
// calculate the block size, mult by 8 for DXT1, 16 for DXT3 & 5
|
||||
d_size = ((dds_header.dwWidth + 3)/4) * ((dds_header.dwHeight + 3)/4) * ((dds_header.dwDepth + 3)/4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
} else {
|
||||
d_size = dds_header.dwPitchOrLinearSize;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
}
|
||||
// if we have mipmaps then compute them into the final size too
|
||||
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
|
||||
// reduce size by half for the next pass
|
||||
d_width /= 2;
|
||||
d_height /= 2;
|
||||
|
||||
if (d_width <= 0)
|
||||
d_width = 1;
|
||||
|
||||
if (d_height <= 0)
|
||||
d_height = 1;
|
||||
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
}
|
||||
|
||||
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
Assert( d_size > 0 );
|
||||
*size = d_size;
|
||||
|
||||
// determine and verify the type of data for internal use
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DXT1:
|
||||
bits = 24;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT1 : DDS_DXT1;
|
||||
break;
|
||||
|
||||
case FOURCC_DXT3:
|
||||
bits = 32;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT3 : DDS_DXT3;
|
||||
break;
|
||||
|
||||
case FOURCC_DXT5:
|
||||
bits = 32;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT5 : DDS_DXT5;
|
||||
break;
|
||||
|
||||
@@ -332,8 +200,9 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
break;
|
||||
|
||||
case FOURCC_DX10:
|
||||
if (valid_dx10_format(dds_header_dx10)) {
|
||||
if (dds_read_dx10_header(ddsfile, &dds_header_dx10)) {
|
||||
// Currently only BC7 is supported
|
||||
bits = 32;
|
||||
ct = DDS_BC7;
|
||||
} else {
|
||||
retval = DDS_ERROR_UNSUPPORTED;
|
||||
@@ -349,7 +218,46 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
goto Done;
|
||||
break;
|
||||
}
|
||||
} else if (dds_header.ddspf.dwFlags & DDPF_RGB) {
|
||||
} else if ( dds_header.ddspf.dwFlags & (DDPF_RGB | DDPF_PALETTEINDEXED8) ) {
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
|
||||
// calculate full data size for all mipmap levels
|
||||
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
|
||||
d_width /= 2;
|
||||
d_height /= 2;
|
||||
d_depth /= 2;
|
||||
|
||||
if (d_width < 1)
|
||||
d_width = 1;
|
||||
|
||||
if (d_height < 1)
|
||||
d_height = 1;
|
||||
|
||||
if (d_depth < 1)
|
||||
d_depth = 1;
|
||||
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
}
|
||||
|
||||
Assert( d_size > 0 );
|
||||
|
||||
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
*size = d_size;
|
||||
|
||||
bits = dds_header.ddspf.dwRGBBitCount;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
|
||||
} else {
|
||||
// it's not a readable format
|
||||
@@ -357,35 +265,21 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// maybe do conversion if format not supported
|
||||
convert = conversion_needed(dds_header);
|
||||
|
||||
if (convert) {
|
||||
// switch to uncompressed format and reset vars
|
||||
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
|
||||
dds_header.ddspf.dwFlags |= DDPF_RGB;
|
||||
|
||||
dds_header.ddspf.dwRGBBitCount = 32;
|
||||
|
||||
// NOTE: modifies header and returns offset for mipmap count
|
||||
dds_header.dwMipMapCount -= conversion_resize(dds_header);
|
||||
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
|
||||
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
|
||||
}
|
||||
|
||||
// we don't support compressed, non-power-of-2 images
|
||||
if ( (ct != DDS_UNCOMPRESSED) && (!is_power_of_two(dds_header.dwWidth, dds_header.dwHeight)) ) {
|
||||
retval = DDS_ERROR_NON_POWER_OF_2;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// stuff important info
|
||||
if (size)
|
||||
*size = compute_dds_size(dds_header, convert);
|
||||
// make sure that the video card can handle compressed textures before using them
|
||||
if ( !Use_compressed_textures && (ct != DDS_UNCOMPRESSED) && (ct != DDS_DXT_INVALID) ) {
|
||||
retval = DDS_ERROR_NO_COMPRESSION;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// stuff important info
|
||||
if (bpp)
|
||||
*bpp = get_bit_count(dds_header);
|
||||
*bpp = bits;
|
||||
|
||||
if (compression_type)
|
||||
*compression_type = ct;
|
||||
@@ -399,6 +293,12 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
if (levels)
|
||||
*levels = dds_header.dwMipMapCount;
|
||||
|
||||
if (palette && (bits == 8)) {
|
||||
cfseek(ddsfile, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
cfread(palette, 1, 1024, ddsfile);
|
||||
}
|
||||
|
||||
|
||||
Done:
|
||||
if (img_cfp == NULL) {
|
||||
// close file and return
|
||||
@@ -409,17 +309,15 @@ Done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void (*decompress_dds)(const void *in, void *out, int pitch) = nullptr;
|
||||
static uint32_t BLOCK_SIZE = 0;
|
||||
|
||||
//reads pixel info from a dds file
|
||||
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
{
|
||||
int retval;
|
||||
int w,h,ct,lvl;
|
||||
size_t size = 0;
|
||||
int bits = 0;
|
||||
CFILE *cfp;
|
||||
char real_name[MAX_FILENAME_LEN];
|
||||
DDS_HEADER dds_header;
|
||||
|
||||
// this better not happen.. ever
|
||||
Assert(filename != NULL);
|
||||
@@ -431,120 +329,28 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
strcat_s(real_name, ".dds");
|
||||
|
||||
// open it up and go to the data section
|
||||
cfp = cfopen(real_name, "rb", cf_type);
|
||||
cfp = cfopen(real_name, "rb", CFILE_NORMAL, cf_type);
|
||||
|
||||
// just in case
|
||||
if (cfp == nullptr)
|
||||
if (cfp == NULL)
|
||||
return DDS_ERROR_INVALID_FILENAME;
|
||||
|
||||
// read the header -- if its at this stage, it should be legal.
|
||||
retval = _dds_read_header(cfp, dds_header);
|
||||
retval = dds_read_header(real_name, cfp, &w, &h, &bits, &ct, &lvl, &size);
|
||||
Assert(retval == DDS_ERROR_NONE);
|
||||
|
||||
// this really shouldn't be needed but better safe than sorry
|
||||
if (retval != DDS_ERROR_NONE) {
|
||||
cfclose(cfp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
cfseek(cfp, (dds_header.ddspf.dwFourCC == FOURCC_DX10) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
|
||||
size = compute_dds_size(dds_header); // don't add padding on this one!!
|
||||
cfseek(cfp, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
|
||||
// read in the data
|
||||
if ( !conversion_needed(dds_header) ) {
|
||||
cfread(data, 1, (int)size, cfp);
|
||||
} else {
|
||||
// Compression format not supported, convert to BGRA
|
||||
ubyte *comp_data = (ubyte*)vm_malloc(size);
|
||||
|
||||
cfread(comp_data, 1, (int)size, cfp);
|
||||
|
||||
ubyte *src = comp_data;
|
||||
ubyte *dst = data;
|
||||
|
||||
uint d_width, d_height, d_depth;
|
||||
size_t data_offset = 0;
|
||||
|
||||
// NOTE: this alters the width, height, and depth values in the header,
|
||||
// so we have to jump through some hoops to get the proper values
|
||||
const uint mipmap_offset = conversion_resize(dds_header);
|
||||
|
||||
const int num_faces = (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) ? 6 : 1;
|
||||
const bool has_depth = (dds_header.dwFlags & DDSD_DEPTH) == DDSD_DEPTH;
|
||||
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DX10:
|
||||
decompress_dds = bcdec_bc7;
|
||||
BLOCK_SIZE = BCDEC_BC7_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT5:
|
||||
decompress_dds = bcdec_bc3;
|
||||
BLOCK_SIZE = BCDEC_BC3_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT1:
|
||||
decompress_dds = bcdec_bc1;
|
||||
BLOCK_SIZE = BCDEC_BC1_BLOCK_SIZE;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
decompress_dds = bcdec_bc2;
|
||||
BLOCK_SIZE = BCDEC_BC2_BLOCK_SIZE;
|
||||
break;
|
||||
default:
|
||||
Error(LOCATION, "Invalid FourCC (%d) for DDS decompression!", dds_header.ddspf.dwFourCC);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int f = 0; f < num_faces; ++f) {
|
||||
// if we resized then skip over all of that data (altering values to match pre-resize)
|
||||
for (uint x = 0; x < mipmap_offset; ++x) {
|
||||
d_width = std::max(1U, dds_header.dwWidth << (mipmap_offset - x));
|
||||
d_height = std::max(1U, dds_header.dwHeight << (mipmap_offset - x));
|
||||
d_depth = has_depth ? std::max(1U, dds_header.dwDepth << (mipmap_offset - x)) : 1U;
|
||||
|
||||
src += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * BLOCK_SIZE;
|
||||
}
|
||||
|
||||
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
|
||||
// width/height/depth at post-resize mipmap sizes, so compensate here
|
||||
d_width = std::max(1U, dds_header.dwWidth >> (m - mipmap_offset));
|
||||
d_height = std::max(1U, dds_header.dwHeight >> (m - mipmap_offset));
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> (m - mipmap_offset));
|
||||
|
||||
for (uint d = 0; d < d_depth; ++d) {
|
||||
auto depth_offset = d * d_width * d_height * 4;
|
||||
|
||||
for (uint i = 0; i < d_height; i += 4) {
|
||||
for (uint j = 0; j < d_width; j += 4) {
|
||||
dst = data + data_offset + depth_offset + ((i * d_width + j) * 4);
|
||||
|
||||
decompress_dds(src, dst, d_width * 4);
|
||||
src += BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need it in bgra, XOR to the rescue
|
||||
for (size_t x = data_offset; x < (data_offset + (d_width * d_height * d_depth * 4)); x += 4) {
|
||||
data[x] ^= data[x+2], data[x+2] ^= data[x], data[x] ^= data[x+2];
|
||||
}
|
||||
|
||||
// bump data offset to next layer
|
||||
data_offset += (d_width * d_height * d_depth * 4);
|
||||
}
|
||||
}
|
||||
|
||||
vm_free(comp_data);
|
||||
comp_data = nullptr;
|
||||
|
||||
// switch to uncompressed format and reset vars (needed below to get correct bit count)
|
||||
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
|
||||
dds_header.ddspf.dwFlags |= DDPF_RGB;
|
||||
dds_header.ddspf.dwRGBBitCount = 32;
|
||||
}
|
||||
cfread(data, 1, (int)size, cfp);
|
||||
|
||||
if (bpp)
|
||||
*bpp = (ubyte)get_bit_count(dds_header);
|
||||
*bpp = (ubyte)bits;
|
||||
|
||||
// we look done here
|
||||
cfclose(cfp);
|
||||
@@ -597,7 +403,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
|
||||
strcat_s(real_filename, ".dds");
|
||||
}
|
||||
|
||||
CFILE *image = cfopen( real_filename, "wb", CF_TYPE_CACHE );
|
||||
CFILE *image = cfopen( real_filename, "wb", CFILE_NORMAL, CF_TYPE_CACHE );
|
||||
|
||||
if (image == NULL) {
|
||||
mprintf(("Unable to open DDS image for saving!!\n"));
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#define DDSD_HEIGHT 0x00000002
|
||||
#define DDSD_CAPS 0x00000001
|
||||
#define DDSD_MIPMAPCOUNT 0x00020000
|
||||
#define DDSD_DEPTH 0x00800000
|
||||
|
||||
#define DDSCAPS_COMPLEX 0x00000008
|
||||
#define DDSCAPS_PRIMARYSURFACE 0x00000200
|
||||
@@ -279,7 +278,7 @@ typedef struct {
|
||||
//reads a dds header
|
||||
//returns one of the error values
|
||||
//'compression_type' comes back as one of the DDS_DXTC* defines
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0);
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0, ubyte *palette = NULL);
|
||||
|
||||
//reads bitmap
|
||||
//size of the data it stored in size
|
||||
@@ -291,4 +290,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
|
||||
//returns a string from a DDS error code
|
||||
const char *dds_error_string(int code);
|
||||
|
||||
extern int Texture_compression_available;
|
||||
extern int Use_compressed_textures;
|
||||
|
||||
#endif //__DDS_H
|
||||
+107
-222
@@ -22,8 +22,7 @@
|
||||
#include "object/objcollide.h"
|
||||
#include "object/objectsnd.h"
|
||||
#include "particle/particle.h"
|
||||
#include "particle/ParticleEffect.h"
|
||||
#include "particle/volumes/LegacyAACuboidVolume.h"
|
||||
#include "radar/radar.h"
|
||||
#include "radar/radarsetup.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
@@ -37,6 +36,7 @@
|
||||
#include "utils/Random.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
constexpr int MIN_RADIUS_FOR_PERSISTENT_DEBRIS = 50; // ship radius at which debris from it becomes persistant
|
||||
constexpr int DEBRIS_SOUND_DELAY = 2000; // time to start debris sound after created
|
||||
|
||||
int Num_hull_pieces; // number of hull pieces in existence
|
||||
@@ -54,59 +54,32 @@ int Debris_model = -1;
|
||||
int Debris_vaporize_model = -1;
|
||||
int Debris_num_submodels = 0;
|
||||
|
||||
particle::ParticleEffectHandle Debris_hit_particle;
|
||||
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
|
||||
|
||||
// Find the first available arc slot. If none is available, and no_create is false, add one.
|
||||
debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create);
|
||||
|
||||
/**
|
||||
* Start the sequence of a piece of debris writhing in unholy agony!!!
|
||||
*/
|
||||
static void debris_start_death_roll(object *debris_obj, debris *debris_p, vec3d *hitpos = nullptr)
|
||||
{
|
||||
auto sip = &Ship_info[debris_p->ship_info_index];
|
||||
if (debris_p->is_hull) {
|
||||
// tell everyone else to blow up the piece of debris
|
||||
if( MULTIPLAYER_MASTER )
|
||||
send_debris_update_packet(debris_obj,DEBRIS_UPDATE_NUKE);
|
||||
|
||||
if (sip->debris_end_particles.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(sip->debris_end_particles);
|
||||
|
||||
// Use the position since the object is going to be invalid soon
|
||||
auto host = std::make_unique<EffectHostVector>(debris_obj->pos, debris_obj->orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->setNormal(debris_obj->orient.vec.uvec);
|
||||
source->finishCreation();
|
||||
} else {
|
||||
int fireball_type = fireball_ship_explosion_type(sip);
|
||||
if(fireball_type < 0) {
|
||||
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
|
||||
}
|
||||
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
|
||||
int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]);
|
||||
if(fireball_type < 0) {
|
||||
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
|
||||
}
|
||||
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
|
||||
|
||||
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
|
||||
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
|
||||
auto snd_id = sip->debris_explosion_sound;
|
||||
auto snd_id = Ship_info[debris_p->ship_info_index].debris_explosion_sound;
|
||||
if (snd_id.isValid()) {
|
||||
snd_play_3d( gamesnd_get_game_sound(snd_id), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (sip->shrapnel_end_particles.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(sip->shrapnel_end_particles);
|
||||
|
||||
// Use the position since the object is going to be invalid soon
|
||||
auto host = std::make_unique<EffectHostVector>(debris_obj->pos, debris_obj->orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->setNormal(debris_obj->orient.vec.uvec);
|
||||
source->finishCreation();
|
||||
}
|
||||
}
|
||||
|
||||
if (scripting::hooks::OnDebrisDeath->isActive()) {
|
||||
@@ -139,36 +112,6 @@ void debris_init()
|
||||
Debris.reserve(SOFT_LIMIT_DEBRIS_PIECES);
|
||||
|
||||
Num_hull_pieces = 0;
|
||||
|
||||
Debris_hit_particle = particle::ParticleManager::get()->addEffect(particle::ParticleEffect(
|
||||
"", //Name
|
||||
::util::UniformFloatRange(10.f), //Particle num
|
||||
particle::ParticleEffect::Duration::ONETIME, //Single Particle Emission
|
||||
::util::UniformFloatRange(), //No duration
|
||||
::util::UniformFloatRange (-1.f), //Single particle only
|
||||
particle::ParticleEffect::ShapeDirection::ALIGNED, //Particle direction
|
||||
::util::UniformFloatRange(1.f), //Velocity Inherit
|
||||
false, //Velocity Inherit absolute?
|
||||
std::make_unique<particle::LegacyAACuboidVolume>(0.3f, 1.f, true), //Velocity volume
|
||||
::util::UniformFloatRange(0.f, 10.f), //Velocity volume multiplier
|
||||
particle::ParticleEffect::VelocityScaling::NONE, //Velocity directional scaling
|
||||
std::nullopt, //Orientation-based velocity
|
||||
std::nullopt, //Position-based velocity
|
||||
nullptr, //Position volume
|
||||
particle::ParticleEffectHandle::invalid(), //Trail
|
||||
1.f, //Chance
|
||||
true, //Affected by detail
|
||||
1.f, //Culling range multiplier
|
||||
true, //Disregard Animation Length. Must be true for everything using particle::Anim_bitmap_X
|
||||
false, //Don't reverse animation
|
||||
false, //parent local
|
||||
false, //ignore velocity inherit if parented
|
||||
false, //position velocity inherit absolute?
|
||||
std::nullopt, //Local velocity offset
|
||||
std::nullopt, //Local offset
|
||||
::util::UniformFloatRange(0.25f, 0.75f), //Lifetime
|
||||
::util::UniformFloatRange(0.2f, 0.4f), //Radius
|
||||
particle::Anim_bitmap_id_fire)); //Bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,14 +121,14 @@ void debris_page_in()
|
||||
{
|
||||
uint i;
|
||||
|
||||
Debris_model = model_load( NOX("debris01.pof") );
|
||||
Debris_model = model_load( NOX("debris01.pof"), 0, NULL );
|
||||
if (Debris_model >= 0) {
|
||||
polymodel * pm;
|
||||
pm = model_get(Debris_model);
|
||||
Debris_num_submodels = pm->n_models;
|
||||
}
|
||||
|
||||
Debris_vaporize_model = model_load( NOX("debris02.pof") );
|
||||
Debris_vaporize_model = model_load( NOX("debris02.pof"), 0, NULL );
|
||||
|
||||
for (i=0; i<Species_info.size(); i++ )
|
||||
{
|
||||
@@ -248,7 +191,6 @@ void debris_delete( object * obj )
|
||||
|
||||
if (db->model_instance_num >= 0) {
|
||||
model_delete_instance(db->model_instance_num);
|
||||
db->model_instance_num = -1;
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
@@ -300,48 +242,56 @@ void debris_process_post(object * obj, float frame_time)
|
||||
return; // If arc_frequency <= 0, this piece has no arcs on it
|
||||
}
|
||||
|
||||
if ( !timestamp_elapsed(db->arc_timeout) && timestamp_elapsed(db->arc_next_time)) {
|
||||
if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball)) {
|
||||
|
||||
db->arc_next_time = _timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->next_fireball = _timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->arc_frequency += 100;
|
||||
|
||||
if (db->is_hull) {
|
||||
|
||||
int n_arcs = Random::next(1, 3); // Create 1-3 sparks
|
||||
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
|
||||
|
||||
vec3d v1 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v2 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v3 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v4 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
|
||||
n = 0;
|
||||
|
||||
int lifetime = Random::next(100, 1000);
|
||||
|
||||
// Create the spark effects
|
||||
for (int n = 0; n < n_arcs; n++) {
|
||||
auto arc = debris_find_or_create_electrical_arc_slot(db, db->electrical_arcs.size() >= MAX_DEBRIS_ARCS);
|
||||
if (arc) {
|
||||
arc->timestamp = _timestamp(lifetime); // live up to a second
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( !db->arc_timestamp[i].isValid() ) {
|
||||
|
||||
db->arc_timestamp[i] = _timestamp(lifetime); // live up to a second
|
||||
|
||||
switch( n ) {
|
||||
case 0:
|
||||
arc->endpoint_1 = v1;
|
||||
arc->endpoint_2 = v2;
|
||||
db->arc_pts[i][0] = v1;
|
||||
db->arc_pts[i][1] = v2;
|
||||
break;
|
||||
case 1:
|
||||
arc->endpoint_1 = v2;
|
||||
arc->endpoint_2 = v3;
|
||||
db->arc_pts[i][0] = v2;
|
||||
db->arc_pts[i][1] = v3;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
arc->endpoint_1 = v2;
|
||||
arc->endpoint_2 = v4;
|
||||
db->arc_pts[i][0] = v2;
|
||||
db->arc_pts[i][1] = v4;
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE("Unhandled case %d for electrical arc creation in debris_process_post()!", n);
|
||||
Int3();
|
||||
}
|
||||
|
||||
n++;
|
||||
if ( n == n_arcs )
|
||||
break; // Don't need to create anymore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// rotate v2 out of local coordinates into world.
|
||||
// Use v2 since it is used in every bolt. See above switch().
|
||||
vec3d snd_pos;
|
||||
@@ -368,20 +318,16 @@ void debris_process_post(object * obj, float frame_time)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &arc: db->electrical_arcs) {
|
||||
if (arc.timestamp.isValid()) {
|
||||
if (timestamp_elapsed(arc.timestamp)) {
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
if ( timestamp_elapsed( db->arc_timestamp[i] ) ) {
|
||||
// Kill off the spark
|
||||
arc.timestamp = TIMESTAMP::invalid();
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
} else {
|
||||
// Maybe move a vertex.... 20% of the time maybe?
|
||||
int mr = Random::next();
|
||||
if ( mr < Random::MAX_VALUE/5 ) {
|
||||
auto pt = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
if (mr % 2 == 0)
|
||||
arc.endpoint_1 = pt;
|
||||
else
|
||||
arc.endpoint_2 = pt;
|
||||
db->arc_pts[i][mr % 2] = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,7 +376,7 @@ MONITOR(NumHullDebris)
|
||||
* @param exp_force Explosion force, used to assign velocity to pieces. 1.0f assigns velocity like before. 2.0f assigns twice as much to non-inherited part of velocity
|
||||
* @param source_subsys The subsystem this debris came from, if any
|
||||
*/
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, const vec3d *pos, const vec3d *exp_center, bool hull_flag, float exp_force, const ship_subsys* source_subsys)
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
int parent_objnum;
|
||||
object *obj;
|
||||
@@ -450,38 +396,12 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, const
|
||||
{
|
||||
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force, source_subsys);
|
||||
debris_create_fire_hook(obj, source_obj);
|
||||
const auto& sip = Ship_info[Ships[source_obj->instance].ship_info_index];
|
||||
particle::ParticleEffectHandle flame_effect;
|
||||
if (source_subsys != nullptr) {
|
||||
if (hull_flag) {
|
||||
if (source_subsys->system_info->debris_flame_particles.isValid()) {
|
||||
flame_effect = source_subsys->system_info->debris_flame_particles;
|
||||
} else {
|
||||
flame_effect = sip.default_subsys_debris_flame_particles;
|
||||
}
|
||||
} else {
|
||||
if (source_subsys->system_info->shrapnel_flame_particles.isValid()) {
|
||||
flame_effect = source_subsys->system_info->shrapnel_flame_particles;
|
||||
} else {
|
||||
flame_effect = sip.default_subsys_shrapnel_flame_particles;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flame_effect = hull_flag ? sip.debris_flame_particles : sip.shrapnel_flame_particles;
|
||||
}
|
||||
if (flame_effect.isValid()) {
|
||||
auto source = particle::ParticleManager::get()->createSource(flame_effect);
|
||||
source->setHost(std::make_unique<EffectHostObject>(obj, vmd_zero_vector));
|
||||
source->setTriggerRadius(source_obj->radius);
|
||||
source->setTriggerVelocity(vm_vec_mag_quick(&source_obj->phys_info.vel));
|
||||
source->finishCreation();
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, const vec3d *pos, const matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx)
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx)
|
||||
{
|
||||
int objnum;
|
||||
object *obj;
|
||||
@@ -529,7 +449,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
// non-hull debris has no relation to its parent orientation
|
||||
vec3d rand;
|
||||
vm_vec_rand_vec(&rand);
|
||||
vm_vector_2_matrix_norm(&orient_buf, &rand);
|
||||
vm_vector_2_matrix(&orient_buf, &rand);
|
||||
orient = &orient_buf;
|
||||
}
|
||||
}
|
||||
@@ -608,10 +528,22 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
}
|
||||
|
||||
// Create Debris piece n!
|
||||
if ( hull_flag ) {
|
||||
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
else {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
} else {
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
}
|
||||
|
||||
//WMC - Oh noes, we may need to change lifeleft
|
||||
if(hull_flag)
|
||||
{
|
||||
// set lifeleft based on tabled entries if they are not negative
|
||||
// coded originally by WMC then clean-up added by wookieejedi
|
||||
if(sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
|
||||
{
|
||||
db->lifeleft = (( sip->debris_max_lifetime - sip->debris_min_lifetime ) * frand()) + sip->debris_min_lifetime;
|
||||
@@ -626,22 +558,6 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
if(db->lifeleft > sip->debris_max_lifetime)
|
||||
db->lifeleft = sip->debris_max_lifetime;
|
||||
}
|
||||
// By default, make some pieces blow up shortly after explosion.
|
||||
else if (Random::next() < (Random::MAX_VALUE / 6))
|
||||
{
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
}
|
||||
|
||||
// increase lifetime for vaporized debris
|
||||
@@ -655,13 +571,15 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
db->ship_info_index = parent_ship_class;
|
||||
db->team = team;
|
||||
db->ambient_sound = (sip == nullptr) ? gamesnd_id(-1) : sip->debris_ambient_sound;
|
||||
db->arc_timeout = TIMESTAMP::never(); // if not changed, timestamp_elapsed() will return false
|
||||
db->fire_timeout = TIMESTAMP::never(); // if not changed, timestamp_elapsed() will return false
|
||||
db->time_started = Missiontime;
|
||||
db->species = (sip == nullptr) ? -1 : sip->species;
|
||||
db->parent_alt_name = alt_type_index;
|
||||
db->damage_mult = 1.0f;
|
||||
|
||||
db->electrical_arcs.clear();
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) { // NOLINT
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
// Percent of debris pieces with arcs controlled via table (default 50%)
|
||||
@@ -674,7 +592,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
db->arc_frequency = 0;
|
||||
}
|
||||
|
||||
db->arc_next_time = _timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
db->next_fireball = _timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
|
||||
flagset<Object::Object_Flags> default_flags;
|
||||
default_flags.set(Object::Object_Flags::Renders);
|
||||
@@ -692,11 +610,6 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
|
||||
db->model_instance_num = hull_flag ? model_create_instance(objnum, db->model_num) : -1;
|
||||
|
||||
// ensure that any texture replace on parent ship gets copied to debris --wookieejedi
|
||||
int parent_model_instance_num;
|
||||
if ((db->model_instance_num >= 0) && (parent_objnum >= 0) && ((parent_model_instance_num = object_get_model_instance_num(&Objects[parent_objnum])) >= 0))
|
||||
model_get_instance(db->model_instance_num)->texture_replace = model_get_instance(parent_model_instance_num)->texture_replace;
|
||||
|
||||
// assign the network signature. The signature will be 0 for non-hull pieces, but since that
|
||||
// is our invalid signature, it should be okay.
|
||||
obj->net_signature = 0;
|
||||
@@ -708,25 +621,19 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
obj->hull_strength = hull_strength;
|
||||
|
||||
if (hull_flag) {
|
||||
float min_hp = sip->debris_min_hitpoints;
|
||||
float max_hp = sip->debris_max_hitpoints;
|
||||
if (sip->debris_hitpoints_radius_multi >= 0.0f) {
|
||||
min_hp *= sip->debris_hitpoints_radius_multi * radius;
|
||||
max_hp *= sip->debris_hitpoints_radius_multi * radius;
|
||||
}
|
||||
if (min_hp >= 0.0f && max_hp >= 0.0f)
|
||||
if(sip->debris_min_hitpoints >= 0.0f && sip->debris_max_hitpoints >= 0.0f)
|
||||
{
|
||||
obj->hull_strength = ((max_hp - min_hp) * frand()) + min_hp;
|
||||
obj->hull_strength = (( sip->debris_max_hitpoints - sip->debris_min_hitpoints ) * frand()) + sip->debris_min_hitpoints;
|
||||
}
|
||||
else if(min_hp >= 0.0f)
|
||||
else if(sip->debris_min_hitpoints >= 0.0f)
|
||||
{
|
||||
if (obj->hull_strength < min_hp)
|
||||
obj->hull_strength = min_hp;
|
||||
if(obj->hull_strength < sip->debris_min_hitpoints)
|
||||
obj->hull_strength = sip->debris_min_hitpoints;
|
||||
}
|
||||
else if(max_hp >= 0.0f)
|
||||
else if(sip->debris_max_hitpoints >= 0.0f)
|
||||
{
|
||||
if (obj->hull_strength > max_hp)
|
||||
obj->hull_strength = max_hp;
|
||||
if(obj->hull_strength > sip->debris_max_hitpoints)
|
||||
obj->hull_strength = sip->debris_max_hitpoints;
|
||||
}
|
||||
db->damage_mult = sip->debris_damage_mult;
|
||||
|
||||
@@ -735,23 +642,21 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
// limit the amount of time that fireballs appear
|
||||
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
|
||||
if (spark_timeout >= 0) {
|
||||
db->arc_timeout = _timestamp(spark_timeout);
|
||||
db->fire_timeout = _timestamp(spark_timeout);
|
||||
} else if (parent_objnum >= 0) {
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + (fl2i(1000*3*Objects[parent_objnum].radius) == 0 ? 0 : Random::next(fl2i(1000*3*Objects[parent_objnum].radius)));
|
||||
db->arc_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
} else {
|
||||
db->arc_timeout = TIMESTAMP::immediate();
|
||||
db->fire_timeout = TIMESTAMP::immediate();
|
||||
}
|
||||
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].radius >= Min_radius_for_persistent_debris) {
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].radius >= MIN_RADIUS_FOR_PERSISTENT_DEBRIS) {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
} else {
|
||||
debris_add_to_hull_list(db);
|
||||
}
|
||||
}
|
||||
|
||||
db->max_hull = obj->hull_strength;
|
||||
|
||||
if (hull_flag) {
|
||||
MONITOR_INC(NumHullDebris,1);
|
||||
} else {
|
||||
@@ -761,7 +666,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debris_create_set_velocity(const debris *db, const ship *source_shipp, const vec3d *exp_center, float exp_force, const ship_subsys* source_subsys)
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
auto obj = &Objects[db->objnum];
|
||||
auto source_obj = (source_shipp == nullptr) ? nullptr : &Objects[source_shipp->objnum];
|
||||
@@ -871,18 +776,30 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
|
||||
debris *debris_p = &Debris[debris_obj->instance];
|
||||
|
||||
// Do a little particle spark shower to show we hit
|
||||
if (Debris_hit_particle.isValid()){ // Where the particles emit from
|
||||
{
|
||||
particle::particle_emitter pe;
|
||||
|
||||
pe.pos = *hitpos; // Where the particles emit from
|
||||
pe.vel = debris_obj->phys_info.vel; // Initial velocity of all the particles
|
||||
|
||||
vec3d tmp_norm;
|
||||
vm_vec_sub( &tmp_norm, hitpos, &debris_obj->pos );
|
||||
vm_vec_normalize_safe(&tmp_norm);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix_norm(&orient, &tmp_norm);
|
||||
|
||||
pe.normal = tmp_norm; // What normal the particle emit around
|
||||
pe.normal_variance = 0.3f; // How close they stick to that normal 0=good, 1=360 degree
|
||||
pe.min_rad = 0.20f; // Min radius
|
||||
pe.max_rad = 0.40f; // Max radius
|
||||
|
||||
auto source = particle::ParticleManager::get()->createSource(Debris_hit_particle);
|
||||
auto host = std::make_unique<EffectHostVector>(*hitpos, orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->finishCreation();
|
||||
// Sparks for first time at this spot
|
||||
pe.num_low = 10; // Lowest number of particles to create
|
||||
pe.num_high = 10; // Highest number of particles to create
|
||||
pe.normal_variance = 0.3f; // How close they stick to that normal 0=good, 1=360 degree
|
||||
pe.min_vel = 0.0f; // How fast the slowest particle can move
|
||||
pe.max_vel = 10.0f; // How fast the fastest particle can move
|
||||
pe.min_life = 0.25f; // How long the particles live
|
||||
pe.max_life = 0.75f; // How long the particles live
|
||||
particle::emit( &pe, particle::PARTICLE_FIRE, 0 );
|
||||
}
|
||||
|
||||
// multiplayer clients bail here
|
||||
@@ -1031,9 +948,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
model_get_moving_submodel_list(submodel_vector, heavy_obj);
|
||||
|
||||
// turn off all moving submodels, collide against only 1 at a time.
|
||||
mc.collision_checked.assign(pm->n_models, 0);
|
||||
// turn off collision detection for all moving submodels
|
||||
for (auto submodel : submodel_vector) {
|
||||
mc.collision_checked[submodel] = true;
|
||||
pmi->submodel[submodel].collision_checked = true;
|
||||
}
|
||||
|
||||
// Only check single submodel now, since children of moving submodels are handled as moving as well
|
||||
@@ -1045,8 +962,10 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
|
||||
// check each submodel in turn
|
||||
for (auto submodel: submodel_vector) {
|
||||
auto smi = &pmi->submodel[submodel];
|
||||
|
||||
// turn on just one submodel for collision test
|
||||
mc.collision_checked[submodel] = false;
|
||||
smi->collision_checked = false;
|
||||
|
||||
// find the start and end positions of the sphere in submodel RF
|
||||
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
|
||||
@@ -1080,11 +999,8 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
}
|
||||
|
||||
// Don't look at this submodel again
|
||||
mc.collision_checked[submodel] = true;
|
||||
smi->collision_checked = true;
|
||||
}
|
||||
|
||||
// Clear collision_checked before base model pass so it auto-inits fresh
|
||||
mc.collision_checked.clear();
|
||||
}
|
||||
|
||||
// Now complete base model collision checks that do not take into account rotating submodels.
|
||||
@@ -1189,7 +1105,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
/**
|
||||
* Return the team field for a debris object
|
||||
*/
|
||||
int debris_get_team(const object *objp)
|
||||
int debris_get_team(object *objp)
|
||||
{
|
||||
Assert( objp->type == OBJ_DEBRIS );
|
||||
Assert( objp->instance >= 0 && objp->instance < (int)Debris.size() );
|
||||
@@ -1229,7 +1145,7 @@ void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs,
|
||||
*/
|
||||
void debris_render(object * obj, model_draw_list *scene)
|
||||
{
|
||||
int num, swapped;
|
||||
int i, num, swapped;
|
||||
debris *db;
|
||||
|
||||
swapped = -1;
|
||||
@@ -1264,9 +1180,9 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
|
||||
// Only render electrical arcs if within 500m of the eye (for a 10m piece)
|
||||
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
|
||||
for (auto &arc: db->electrical_arcs) {
|
||||
if ( arc.timestamp.isValid() ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &arc.endpoint_1, &arc.endpoint_2, nullptr, MARC_TYPE_DAMAGED );
|
||||
for (i=0; i<MAX_DEBRIS_ARCS; i++ ) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_DAMAGED );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1281,9 +1197,6 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
// render_info.set_flags(MR_NO_LIGHTING);
|
||||
}
|
||||
|
||||
if (db->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(db->model_instance_num)->texture_replace);
|
||||
|
||||
submodel_render_queue( &render_info, scene, pm, pmi, db->submodel_num, &obj->orient, &obj->pos );
|
||||
|
||||
if (tbase != NULL && (swapped!=-1) && pm) {
|
||||
@@ -1291,56 +1204,28 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
}
|
||||
}
|
||||
|
||||
bool debris_is_generic(const debris *db)
|
||||
bool debris_is_generic(debris *db)
|
||||
{
|
||||
return db->model_num == Debris_model;
|
||||
}
|
||||
|
||||
bool debris_is_vaporized(const debris *db)
|
||||
bool debris_is_vaporized(debris *db)
|
||||
{
|
||||
return db->model_num == Debris_vaporize_model;
|
||||
}
|
||||
|
||||
void create_generic_debris(object* ship_objp, const vec3d* pos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris)
|
||||
{
|
||||
void create_generic_debris(object* ship_objp, vec3d* pos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris) {
|
||||
Assertion(ship_objp->type == OBJ_SHIP, "create_generic_debris called for a non-ship, only ships can spew debris!");
|
||||
if (ship_objp->type != OBJ_SHIP)
|
||||
return;
|
||||
|
||||
// determine if using custom or non-custom generic debris
|
||||
int model_num = use_ship_debris ? Ship_info[Ships[ship_objp->instance].ship_info_index].generic_debris_model_num : -1;
|
||||
|
||||
// if using non-custom generic debris, then bail early if that kind of debris is not allowed --wookeejedi
|
||||
if ( (model_num < 0) && (Disable_all_noncustom_generic_debris) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
float num_debris = frand_range(min_num_debris, max_num_debris);
|
||||
|
||||
num_debris *= (Detail.num_small_debris + 0.5f) / 4.5f;
|
||||
|
||||
vec3d create_pos = *pos;
|
||||
for (int i = 0; i < num_debris; i++) {
|
||||
debris_create(ship_objp, model_num, -1, &create_pos, pos, false, speed_mult);
|
||||
int model_num = use_ship_debris ? Ship_info[Ships[ship_objp->instance].ship_info_index].generic_debris_model_num : -1;
|
||||
debris_create(ship_objp, model_num, -1, &create_pos, pos, 0, speed_mult);
|
||||
}
|
||||
}
|
||||
|
||||
debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto& ii : db->electrical_arcs)
|
||||
{
|
||||
if (!ii.timestamp.isValid())
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == db->electrical_arcs.size())
|
||||
{
|
||||
if (no_create)
|
||||
return nullptr;
|
||||
db->electrical_arcs.emplace_back();
|
||||
}
|
||||
|
||||
return &db->electrical_arcs[i];
|
||||
}
|
||||
Loaded 100 of 2030 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user