Compare commits

..
Author SHA1 Message Date
Tyler Blount 0945dee99e Update test-pull_request.yaml 2025-06-09 09:51:29 -07:00
Tyler Blount 9e8003bd8a Update build-test.yaml 2025-06-09 09:50:22 -07:00
Tyler Blount 47d77aa9d5 Update build-release.yaml 2025-06-09 09:49:15 -07:00
Tyler Blount 2b49a0d780 Update nightly build to use windows 2022 2025-06-09 09:47:05 -07:00
1581 changed files with 72686 additions and 137257 deletions

No files matched your search

-2
View File
@@ -48,7 +48,5 @@ CheckOptions:
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'
...
+20 -38
View File
@@ -23,13 +23,10 @@ jobs:
runs-on: ${{ matrix.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
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,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@v4
with:
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -62,26 +59,23 @@ 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
strategy:
matrix:
arch: [x86_64, arm64]
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@v4
with:
name: linux-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug-${{ matrix.arch }}
path: builds
@@ -112,13 +106,10 @@ jobs:
name: Windows
runs-on: windows-2022
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
@@ -164,13 +155,13 @@ jobs:
-DFSO_USE_VOICEREC="ON" -DFORCED_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_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 +179,7 @@ jobs:
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
@@ -196,27 +187,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@v4
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -261,14 +249,11 @@ 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]
with:
@@ -317,7 +302,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@v4
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
@@ -325,27 +310,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@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
+24 -42
View File
@@ -52,15 +52,12 @@ jobs:
runs-on: ${{ matrix.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
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 +82,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@v4
# 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.
@@ -102,29 +99,26 @@ 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
strategy:
matrix:
arch: [x86_64, arm64]
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@v4
with:
name: linux-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
# Grab the debug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug-${{ matrix.arch }}
path: builds
@@ -141,7 +135,7 @@ jobs:
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@v4
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
@@ -163,15 +157,12 @@ jobs:
name: Windows
runs-on: windows-2022
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
@@ -220,13 +211,13 @@ jobs:
-DFSO_USE_VOICEREC="ON" -DFORCED_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_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 +235,7 @@ jobs:
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
@@ -253,7 +244,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 +252,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@v4
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -292,13 +280,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@v4
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@v4
with:
name: ${{ steps.generate_package.outputs.debug_name }}
path: ${{ steps.generate_package.outputs.debug_path }}
@@ -336,15 +324,12 @@ 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]
with:
@@ -387,7 +372,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@v4
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
@@ -395,27 +380,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@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
@@ -431,7 +413,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@v4
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
+20 -38
View File
@@ -17,13 +17,10 @@ jobs:
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
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@v4
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@v4
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: linux-FastDebug
path: builds
@@ -104,13 +98,10 @@ jobs:
name: Windows
runs-on: windows-2022
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: |
@@ -162,13 +153,13 @@ jobs:
-DFSO_USE_VOICEREC="ON" -DFORCED_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_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@v4
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@v4
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -260,14 +248,11 @@ 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]
with:
@@ -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@v4
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@v4
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: mac-FastDebug-${{ matrix.arch }}
path: builds
+1 -6
View File
@@ -27,15 +27,10 @@ jobs:
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
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:
+2 -6
View File
@@ -33,7 +33,6 @@ env:
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
FORUM_SECRET: ${{ secrets.FORUM_SECRET }}
RELEASE_TAG: ${{ inputs.releaseTag }}
jobs:
@@ -46,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
@@ -70,7 +67,6 @@ jobs:
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ inputs.releaseTag }}
FORUM_SECRET: ${{ secrets.FORUM_SECRET }}
run: python ci/post/main.py release
- name: Post Builds (Manual trigger)
+8 -19
View File
@@ -30,16 +30,11 @@ jobs:
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
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,7 +76,7 @@ jobs:
build_windows:
strategy:
matrix:
configuration: [Debug, FastDebug, Release]
configuration: [Debug, Release]
compiler: [MSVC]
arch: [Win32, x64]
name: Windows
@@ -89,13 +84,10 @@ jobs:
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
@@ -147,12 +139,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 ..
-DFORCED_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 ..
-DFORCED_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,14 +197,11 @@ 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:
+1 -4
View File
@@ -29,12 +29,9 @@ jobs:
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"
# pipe results of wget to a log file because it's very verbose and rarely fails
- name: Install Coverity
-3
View File
@@ -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
+16 -33
View File
@@ -1,5 +1,5 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.21)
CMAKE_MINIMUM_REQUIRED(VERSION 3.9)
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.")
@@ -57,16 +57,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 +70,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 +105,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.")
@@ -127,25 +121,10 @@ 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)
IF(NOT APPLE)
SET(OPENXR_BUILD_DEFAULT ON)
ELSE()
SET(OPENXR_BUILD_DEFAULT OFF)
@@ -173,11 +152,15 @@ 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,8 +171,7 @@ 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)
@@ -245,7 +227,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}")
@@ -259,6 +243,5 @@ 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}")
+1 -1
View File
@@ -26,5 +26,5 @@ git diff -U0 --no-color "$BASE_COMMIT..$2" | \
-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)' \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+1 -1
View File
@@ -42,7 +42,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
+4 -39
View File
@@ -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
+6 -8
View File
@@ -33,14 +33,12 @@ class ForumAPI:
print("Post failed! No API or API_KEY given!")
return
resp = requests.post(self.config["hlp"]["api"],
headers={"X-HLP-Bot": os.environ["FORUM_SECRET"]},
data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
resp = requests.post(self.config["hlp"]["api"], data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
if resp.status_code != 200:
print("Post failed! Response: %s" %resp.text)
-5
View File
@@ -18,7 +18,6 @@
# Credentials into hard-light.net for forum post
# HLP_API:
# HLP_KEY:
# FORUM_SECRET:
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
@@ -125,10 +124,6 @@ def get_source_version(date_version: datetime, tag_name: str) -> semantic_versio
def main():
if "FORUM_SECRET" not in os.environ or not os.environ["FORUM_SECRET"]:
print(" ERROR: FORUM_SECRET environment variable not set")
sys.exit(1)
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
# Aggregate configuration data in a dictionary
+2 -2
View File
@@ -1,3 +1,3 @@
Mako==1.3.12
requests==2.33.0
Mako==1.2.2
requests==2.32.0
semantic-version==2.8.5
File renamed without changes.
File renamed without changes.
+21
View File
@@ -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")
+4054
View File
File diff suppressed because it is too large. Load diff
-2
View File
@@ -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()
+1 -6
View File
@@ -9,19 +9,14 @@ else()
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()
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()
@@ -38,6 +33,6 @@ else()
endif()
set(IS_X86 FALSE)
if (NOT IS_ARM64 AND NOT IS_RISCV AND NOT IS_ARMV7A)
if (NOT IS_ARM64 AND NOT IS_RISCV)
set(IS_X86 TRUE)
endif()
+1 -1
View File
@@ -15,4 +15,4 @@ 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_DEBUG "-O0 -g -Wshadow")
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
+2 -2
View File
@@ -119,14 +119,14 @@ 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 ("${CXX_OPT_FLAG}" STREQUAL "")
set(CXX_OPT_FLAG_RELEASE "-O3")
set(CXX_OPT_FLAG_DEBUG "-O0")
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_DEBUG "-Og")
else()
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
+2 -2
View File
@@ -161,14 +161,14 @@ 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 ("${CXX_OPT_FLAG}" STREQUAL "")
set(CXX_OPT_FLAG_RELEASE "-O3")
set(CXX_OPT_FLAG_DEBUG "-O0")
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_DEBUG "-Og")
else()
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
+17 -8
View File
@@ -71,19 +71,27 @@ 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
@@ -114,7 +122,8 @@ if(IS_X86)
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
+21 -11
View File
@@ -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()
+3 -3
View File
@@ -6,9 +6,9 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 26)
set_if_not_defined(FSO_VERSION_MINOR 0)
set_if_not_defined(FSO_VERSION_BUILD 1)
set_if_not_defined(FSO_VERSION_MAJOR 24)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
set_if_not_defined(FSO_VERSION_REVISION 0)
+1 -1
View File
@@ -59,7 +59,7 @@ endif()
target_link_libraries(code PUBLIC libRocket)
target_link_libraries(code PUBLIC pcpnatpmp)
target_link_libraries(code PUBLIC pcp)
target_link_libraries(code PUBLIC parsers)
+1 -1
View File
@@ -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>()));
}
};
+1 -1
View File
@@ -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;
}
+2 -2
View File
@@ -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
+8 -8
View File
@@ -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)));
const auto xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
const auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
const 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;
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -70,7 +70,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
+2 -2
View File
@@ -61,7 +61,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
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->setHost(make_unique<EffectHostObject>(locals.host.objp(), local_pos, orientation, true));
source->finishCreation();
return ActionResult::Finished;
@@ -69,7 +69,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
std::unique_ptr<Action> ParticleEffectAction::clone() const
{
return std::make_unique<ParticleEffectAction>(*this);
return std::unique_ptr<Action>(new ParticleEffectAction(*this));
}
} // namespace types
+1 -1
View File
@@ -57,7 +57,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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+4 -5
View File
@@ -42,7 +42,6 @@ typedef struct 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)
@@ -528,7 +527,7 @@ 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);
@@ -560,7 +559,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,7 +596,7 @@ 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);
@@ -618,7 +617,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);
+1 -23
View File
@@ -44,15 +44,12 @@ namespace AI {
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
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
};
@@ -132,7 +129,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,
@@ -146,7 +142,6 @@ namespace AI {
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,
Require_exact_los,
Improved_missile_avoidance,
@@ -175,11 +170,6 @@ namespace AI {
Debris_respects_big_damage,
Dont_limit_change_in_speed_due_to_physics_whack,
Guards_ignore_protected_attackers,
Fix_standard_strafe,
Fix_ai_target_recovery, // a) strafing ships that lose their target re-process their orders, like chasing ships already do
// b) ships parked in AIM_NONE while holding a standing chase order (attack-any etc.) re-process their orders;
// c) target selection skips ships outside the attacker's actively-pursues list, and self-chosen targets
// outside that list are dropped rather than held forever
Standard_strafe_used_more,
Unify_usage_ai_shield_manage_delay,
Fix_AI_shield_management_bug,
@@ -188,18 +178,6 @@ namespace AI {
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,
Kamikaze_no_collision_avoidance,
Fix_big_ship_waypoint_completion, // a) big ships complete a waypoint within their radius rather than sqrt(radius);
// b) completion no longer requires moving 0.1m in a single frame (framerate-dependent)
Fix_shockwave_expire_before_do_damage, // shockwaves whose lifetime is shorter than one frame apply their area damage at least once before expiring
Fix_small_ai_recover_after_engines_repaired, // ensure small ship AI can switch back to useful AI modes if engines get repaired
NUM_VALUES
};
+1 -75
View File
@@ -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*);
@@ -478,9 +477,6 @@ 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:")) {
@@ -592,8 +588,6 @@ void parse_ai_profiles_tbl(const char *filename)
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:")) {
@@ -675,10 +669,6 @@ void parse_ai_profiles_tbl(const char *filename)
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, "$fix ai target recovery:", AI::Profile_Flags::Fix_ai_target_recovery);
set_flag(profile, "$standard strafe used more:", AI::Profile_Flags::Standard_strafe_used_more);
if (optional_string("$standard strafe triggers under this speed:")) {
@@ -693,14 +683,6 @@ void parse_ai_profiles_tbl(const char *filename)
stuff_float(&profile->strafe_max_unhit_time);
}
if (optional_string("$strafe retreat collide time:")) {
stuff_float(&profile->strafe_retreat_collide_time);
}
if (optional_string("$strafe retreat collide distance:")) {
stuff_float(&profile->strafe_retreat_collide_distance);
}
if (optional_string("$guard uses big-orbit for target radius above:")) {
stuff_float(&profile->guard_big_orbit_above_target_radius);
}
@@ -715,10 +697,6 @@ void parse_ai_profiles_tbl(const char *filename)
}
}
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);
@@ -733,39 +711,6 @@ void parse_ai_profiles_tbl(const char *filename)
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);
set_flag(profile, "$no collision avoidance for kamikaze fighters:", AI::Profile_Flags::Kamikaze_no_collision_avoidance);
set_flag(profile, "$fix big ship waypoint completion:", AI::Profile_Flags::Fix_big_ship_waypoint_completion);
set_flag(profile, "$fix shockwave expiring before dealing damage:", AI::Profile_Flags::Fix_shockwave_expire_before_do_damage);
set_flag(profile, "$fix fighter/bomber AI recovers after engines repaired:", AI::Profile_Flags::Fix_small_ai_recover_after_engines_repaired);
// end of options ----------------------------------------
@@ -834,7 +779,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))
@@ -858,7 +803,6 @@ void ai_profile_t::reset()
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;
@@ -866,14 +810,9 @@ void ai_profile_t::reset()
standard_strafe_when_below_speed = 3.0f;
strafe_retreat_box_dist = 300.0f;
strafe_max_unhit_time = 20.0f;
strafe_retreat_collide_time = 2.0f;
strafe_retreat_collide_distance = 100.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;
@@ -988,18 +927,5 @@ void ai_profile_t::reset()
}
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);
}
if (mod_supports_version(26, 2, 0)) {
flags.set(AI::Profile_Flags::Kamikaze_no_collision_avoidance);
flags.set(AI::Profile_Flags::Fix_big_ship_waypoint_completion);
flags.set(AI::Profile_Flags::Fix_shockwave_expire_before_do_damage);
flags.set(AI::Profile_Flags::Fix_small_ai_recover_after_engines_repaired);
flags.set(AI::Profile_Flags::Fix_standard_strafe);
flags.set(AI::Profile_Flags::Fix_ai_target_recovery);
}
}
+2 -13
View File
@@ -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
@@ -102,9 +101,6 @@ public:
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;
@@ -143,18 +139,11 @@ public:
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
float strafe_retreat_collide_time; // When anticipated collision time is less than this, begin retreat from strafe
float strafe_retreat_collide_distance; // When perpendicular distance to *surface* is less than this, begin retreat from strafe
// 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();
};
@@ -163,10 +152,10 @@ extern int Num_ai_profiles;
extern int Default_ai_profile;
extern ai_profile_t Ai_profiles[MAX_AI_PROFILES];
#define AI_PROFILES_INDEX(ai_p) (static_cast<int>((ai_p)-Ai_profiles))
#define AI_PROFILES_INDEX(ai_p) ((int)((ai_p) - Ai_profiles))
void ai_profiles_init();
int ai_profile_lookup(const char *name);
int ai_profile_lookup(char *name);
#endif
+84 -110
View File
@@ -40,6 +40,9 @@
// 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 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
@@ -59,9 +62,9 @@
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);
@@ -143,10 +146,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]
@@ -348,10 +347,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;
@@ -865,7 +864,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);
@@ -1195,78 +1194,70 @@ void ai_big_chase()
}
// If a collision is expected, pull out!
if (!(The_mission.ai_profile->flags[AI::Profile_Flags::Kamikaze_no_collision_avoidance] && aip->ai_flags[AI::AI_Flags::Kamikaze])) {
float dist_normal_to_enemy;
float dist_normal_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
else // I'm fairly sure this retail code VVV meant to use / instead of *
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
}
else {
// don;t have normal so use a conservative value here
dist_normal_to_enemy = 0.3f * dist_to_enemy;
}
// float time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed * fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
// if (Framecount % 30 == 1) {
// mprintf(("normal dist; %.1f, time: %.1f\n", dist_normal_to_enemy, time_to_enemy));
// }
// since we're not in strafe and we may get a bad normal, cap dist_normal_to_enemy as MIN(0.3*dist_to_enemy, self)
// this will allow us to get closer on a bad normal
dist_normal_to_enemy = MAX(0.3f * dist_to_enemy, dist_normal_to_enemy);
if (dist_to_enemy < ATTACK_COLLIDE_BASE_DIST) {
// within 50m or 1sec
float time_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
}
else {
// a big time
time_to_enemy = 100.0f;
}
}
else {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed;
}
else {
// a big time
time_to_enemy = 100.0f;
}
}
float speed_dist = MAX(0.0f, (Pl_objp->phys_info.speed - 50) * 2);
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME)) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
}
else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME)) {
// slow down
accelerate_ship(aip, -1.0f);
}
}
/*
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)) {
if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, (aip->targeted_subsys == NULL)*2.0f + 1.5f)) {
if ((Missiontime - aip->last_hit_time > F1_0*4) && (dist_to_enemy < Pl_objp->radius*2 + En_objp->radius*2)) {
accelerate_ship(aip, -1.0f);
} else {
aip->submode = SM_AVOID;
aip->submode_start_time = Missiontime;
}
}
} */
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
else // I'm fairly sure this retail code VVV meant to use / instead of *
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
} else {
// don;t have normal so use a conservative value here
dist_normal_to_enemy = 0.3f * dist_to_enemy;
}
// float time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed * fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
// if (Framecount % 30 == 1) {
// mprintf(("normal dist; %.1f, time: %.1f\n", dist_normal_to_enemy, time_to_enemy));
// }
// since we're not in strafe and we may get a bad normal, cap dist_normal_to_enemy as MIN(0.3*dist_to_enemy, self)
// this will allow us to get closer on a bad normal
dist_normal_to_enemy = MAX(0.3f*dist_to_enemy, dist_normal_to_enemy);
if (dist_to_enemy < ATTACK_COLLIDE_BASE_DIST) {
// within 50m or 1sec
float time_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
} else {
// a big time
time_to_enemy = 100.0f;
}
} else {
if (Pl_objp->phys_info.speed > 0.1) {
time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed;
} else {
// a big time
time_to_enemy = 100.0f;
}
}
float speed_dist = MAX(0.0f, (Pl_objp->phys_info.speed-50) * 2);
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
// slow down
accelerate_ship(aip, -1.0f);
}
}
/*
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)) {
if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, (aip->targeted_subsys == NULL)*2.0f + 1.5f)) {
if ((Missiontime - aip->last_hit_time > F1_0*4) && (dist_to_enemy < Pl_objp->radius*2 + En_objp->radius*2)) {
accelerate_ship(aip, -1.0f);
} else {
aip->submode = SM_AVOID;
aip->submode_start_time = Missiontime;
}
}
} */
}
switch (aip->submode) {
@@ -1425,7 +1416,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];
@@ -1433,42 +1424,25 @@ 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) < (The_mission.ai_profile->strafe_retreat_collide_time);
collide_distance = dist_to_target < ((The_mission.ai_profile->strafe_retreat_collide_distance) + 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) < (The_mission.ai_profile->strafe_retreat_collide_time);
collide_distance = dist_normal_to_target < ((The_mission.ai_profile->strafe_retreat_collide_distance) + 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
// 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);
@@ -1512,7 +1486,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);
@@ -1632,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.
+116 -424
View File
File diff suppressed because it is too large. Load diff
View File
Whitespace-only changes.
+116 -274
View File
@@ -40,43 +40,28 @@ struct ship_registry_entry;
// dynamic goals are not handled here.
// defines for player issued goal priorities
constexpr int PLAYER_PRIORITY_MIN = 90;
constexpr int PLAYER_PRIORITY_SHIP = 100;
constexpr int PLAYER_PRIORITY_WING = 95;
constexpr int PLAYER_PRIORITY_SUPPORT_LOW = 10;
#define PLAYER_PRIORITY_MIN 90
#define PLAYER_PRIORITY_SHIP 100
#define PLAYER_PRIORITY_WING 95
#define PLAYER_PRIORITY_SUPPORT_LOW 10
constexpr int MAX_GOAL_PRIORITY = 200;
constexpr int MIN_GOAL_PRIORITY = 1;
// note: "purging" is not the same as "clearing" here
// purging: any goal that no longer makes sense (i.e. is "invalid") in light of a new goal is removed
// clearing: every goal is removed, including, ironically, the goal that caused the clearing
#define MAX_GOAL_PRIORITY 200
// define for which goals cause other goals to get purged
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
[[nodiscard]] bool causes_invalid_goal_purge_all_ships(ai_goal_mode ai_mode)
inline bool purge_goals_all_ships(ai_goal_mode ai_mode)
{
return ai_mode == AI_GOAL_IGNORE || ai_mode == AI_GOAL_DISABLE_SHIP || ai_mode == AI_GOAL_DISARM_SHIP;
}
[[nodiscard]] bool causes_invalid_goal_purge_one_ship(ai_goal_mode ai_mode)
inline bool purge_goals_one_ship(ai_goal_mode ai_mode)
{
return ai_mode == AI_GOAL_IGNORE_NEW;
}
// function for which goals cause other goals to be cleared -- see comments above on purging vs clearing
// NOTE: this function is only evaluated in ai_add_goal_sub_player() and ai_add_goal_sub_scripting(); for
// ai_add_goal_sub_sexp(), the goal clearing is integrated into the logic of the relevant sexp operators
[[nodiscard]] bool causes_goal_clearing(ai_goal_mode ai_mode)
{
return ((ai_mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still])
|| (ai_mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing])
|| (ai_mode == AI_GOAL_PLAY_DEAD));
}
// goals given from the player to other ships in the game are also handled in this
// code
@@ -115,7 +100,6 @@ ai_goal_list Ai_goal_names[] =
{ "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
{ "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
{ "Attack ship class", AI_GOAL_CHASE_SHIP_CLASS, 0 },
{ "Attack ship type", AI_GOAL_CHASE_SHIP_TYPE, 0 },
};
int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
@@ -130,7 +114,6 @@ const char *Ai_goal_text(ai_goal_mode goal, int submode)
case AI_GOAL_CHASE:
case AI_GOAL_CHASE_WING:
case AI_GOAL_CHASE_SHIP_CLASS:
case AI_GOAL_CHASE_SHIP_TYPE:
return XSTR( "attack ", 474);
case AI_GOAL_DOCK:
return XSTR( "dock ", 475);
@@ -212,15 +195,12 @@ void ai_maybe_add_form_goal(wing* wingp)
return;
}
// we may simply not want the mission to do this
if (The_mission.ai_profile->flags[AI::Profile_Flags::Dont_form_on_wing_at_mission_start]) {
return;
}
int j;
// iterate through the ship_index list of this wing and check for orders. We will do
// this for all ships in the wing instead of on a wing only basis in case some ships
// in the wing actually have different orders than others
for (int j = 0; j < wingp->current_count; j++) {
for (j = 0; j < wingp->current_count; j++) {
ai_info* aip;
Assert(wingp->ship_index[j] != -1); // get Allender
@@ -232,8 +212,7 @@ void ai_maybe_add_form_goal(wing* wingp)
}
// need to add a form on my wing goal here. Ships are always forming on the player's wing.
// it is sufficient enough to check the first goal entry to see if it has a valid goal.
// Note: Although the player didn't explicitly order this, it is treated as a player-issued order
// it is sufficient enough to check the first goal entry to see if it has a valid goal
if (aip->goals[0].ai_mode == AI_GOAL_NONE) {
// Need to have a more specific target in multi, or they may end up trying to target standalone placeholder.
// So form on their team leader. In dogfight, all player-slot ai die, so just exclude.
@@ -534,25 +513,13 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
if ( purge_goal->target_name == NULL )
continue;
// goals operating on ship classes and ship types are handled slightly differently
// goals operating on ship classes are handled slightly differently
if ( purge_ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
// if the target of the purge goal is the same class of ship we are concerned about, then we have a match;
// if it is not, then we can continue (see standard ship check below)
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) != 0 )
continue;
}
else if (purge_ai_mode == AI_GOAL_CHASE_SHIP_TYPE) {
// Get the ship type of the ship we're concerned about
int ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
// If the ship type is invalid, we can't match it, so continue
if (ship_type < 0)
continue;
// Check if the target name of the purge goal matches the ship type name
if (stricmp(purge_goal->target_name, Ship_types[ship_type].name) != 0)
continue;
}
// standard goals operating on either wings or ships
else {
// determine if the purge goal is acting either on the ship or the ship's wing.
@@ -621,8 +588,8 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
int i;
ship_obj *sop;
// only purge goals if a new goal is one of the types that require purging
if (!causes_invalid_goal_purge_all_ships(aigp->ai_mode))
// only purge goals if a new goal is one of the types in next statement
if (!purge_goals_all_ships(aigp->ai_mode))
return;
for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
@@ -765,14 +732,12 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
// from the mission goals (i.e. those goals which come from events) in that we don't
// use sexpressions for goals from the player...so we enumerate all the parameters
void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *target_name, ai_goal *aigp, int int_data, float float_data, const ai_lua_parameters& lua_target )
void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
{
Assert ( (type == ai_goal_type::PLAYER_WING) || (type == ai_goal_type::PLAYER_SHIP) );
ai_goal_reset(aigp, true, mode, submode, type);
aigp->int_data = int_data;
aigp->float_data = float_data;
aigp->lua_ai_target = lua_target;
if ( mode == AI_GOAL_WARP ) {
@@ -790,18 +755,6 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
if ( target_name != NULL )
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
// set up the clear-goals flag for certain goals
if (causes_goal_clearing(mode))
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
aigp->flags.set(AI::Goal_Flags::Want_override);
// generally, players want ships to form-on-wing only until they need to do something else
if (mode == AI_GOAL_FORM_ON_WING && The_mission.ai_profile->flags[AI::Profile_Flags::Purge_player_issued_form_on_wing_after_subsequent_order])
aigp->flags.set(AI::Goal_Flags::Purge_when_new_goal_added);
if (The_mission.ai_profile->flags[AI::Profile_Flags::Player_orders_afterburn_hard])
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
@@ -813,6 +766,10 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
if ( (mode == AI_GOAL_STAY_NEAR_SHIP) || (mode == AI_GOAL_KEEP_SAFE_DISTANCE) )
aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;
// Goober5000 - same with form-on-wing, since it's a type of staying near
else if ( mode == AI_GOAL_FORM_ON_WING )
aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;
else if ( aigp->type == ai_goal_type::PLAYER_WING ) // NOLINT(readability-braces-around-statements)
aigp->priority = PLAYER_PRIORITY_WING; // player wing goals not as high as ship goals
else
@@ -825,25 +782,19 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
// friendlies want to rearm at the same time. The support ship forgets what it's doing and flies
// off to repair somebody while still docked. I reproduced this with retail, so it's not a bug in
// my new docking code. :)
// Note that this function is now where Purge_when_new_goal_added is checked to set the Purge flag.
int ai_goal_allocate_slot( ai_goal *goals, int active_goal )
int ai_goal_find_empty_slot( ai_goal *goals, int active_goal )
{
int oldest_index = -1, first_empty_index = -1;
int gindex, oldest_index;
for ( int gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
oldest_index = -1;
for ( gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
{
// get the index for the first unused goal
if (goals[gindex].ai_mode == AI_GOAL_NONE)
{
if (first_empty_index < 0)
first_empty_index = gindex;
}
// if any goal needs to be purged when we add a goal, set the flag
else if (goals[gindex].flags[AI::Goal_Flags::Purge_when_new_goal_added])
goals[gindex].flags.set(AI::Goal_Flags::Purge);
return gindex;
// if this is the active goal, and a real goal, don't consider it for pre-emption!!
if (gindex == active_goal && goals[gindex].ai_mode != AI_GOAL_NONE)
// if this is the active goal, don't consider it for pre-emption!!
if (gindex == active_goal)
continue;
// store the index of the oldest goal
@@ -853,10 +804,6 @@ int ai_goal_allocate_slot( ai_goal *goals, int active_goal )
oldest_index = gindex;
}
// try to use the first empty slot
if (first_empty_index >= 0)
return first_empty_index;
// if we didn't find an empty slot, use the oldest goal's slot
return oldest_index;
}
@@ -889,26 +836,9 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
if ( target_name != NULL )
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
// set up the clear-goals flag for certain goals
if (causes_goal_clearing(mode))
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
// also set up the override, since it's no longer done automatically in ai_mission_goal_achievable
if (mode == AI_GOAL_FORM_ON_WING && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing])
aigp->flags.set(AI::Goal_Flags::Want_override);
aigp->priority = priority;
aigp->int_data = int_data;
aigp->float_data = float_data;
// range check
if ( aigp->priority > MAX_GOAL_PRIORITY ) {
nprintf (("AI", "bashing scripting priority of goal %d from %d to %d.\n", mode, aigp->priority, MAX_GOAL_PRIORITY));
aigp->priority = MAX_GOAL_PRIORITY;
} else if ( aigp->priority < MIN_GOAL_PRIORITY ) {
nprintf (("AI", "bashing scripting priority of goal %d from %d to %d.\n", mode, aigp->priority, MIN_GOAL_PRIORITY));
aigp->priority = MIN_GOAL_PRIORITY;
}
}
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)
@@ -916,7 +846,7 @@ void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, co
int empty_index;
ai_goal *aigp;
empty_index = ai_goal_allocate_slot(aip->goals, aip->active_goal);
empty_index = ai_goal_find_empty_slot(aip->goals, aip->active_goal);
aigp = &aip->goals[empty_index];
ai_add_goal_sub_scripting(ai_goal_type::PLAYER_SHIP, mode, submode, priority, shipname, aigp, int_data, float_data);
@@ -935,14 +865,14 @@ void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, co
// is issued to ship or wing (from player), mode is AI_GOAL_*. submode is the submode the
// ship should go into. shipname is the object of the action. aip is the ai_info pointer
// of the ship receiving the order
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, float float_data, const ai_lua_parameters& lua_target)
void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
{
int empty_index;
ai_goal *aigp;
empty_index = ai_goal_allocate_slot( aip->goals, aip->active_goal );
empty_index = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
aigp = &aip->goals[empty_index];
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, int_data, float_data, lua_target );
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, lua_target );
// if the goal is to dock, then we must determine which dock points on the two ships to use.
// If the target of the dock is a cargo type container, then we should use DOCK_TYPE_CARGO
@@ -956,7 +886,7 @@ void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
// adds a goal from the player to the given wing (which in turn will add it to the proper
// ships in the wing
void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, int wingnum, int int_data, float float_data, const ai_lua_parameters& lua_target)
void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char *shipname, int wingnum, const ai_lua_parameters& lua_target)
{
int i, empty_index;
wing *wingp = &Wings[wingnum];
@@ -967,15 +897,15 @@ void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
int num = wingp->ship_index[i];
if ( num == -1 ) // ship must have been destroyed or departed
continue;
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index], int_data, float_data, lua_target );
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index], lua_target );
}
}
// add the sexpression index into the wing's list of goal sexpressions if
// there are more waves to come. We use the same method here as when adding a goal to
// a ship -- find the first empty entry. If none exists, take the oldest entry and replace it.
empty_index = ai_goal_allocate_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index], int_data, float_data, lua_target );
empty_index = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index], lua_target );
}
@@ -1008,9 +938,11 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
// for achievability.
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
aigp->ai_mode = (op == OP_AI_WAYPOINTS_ONCE) ? AI_GOAL_WAYPOINTS_ONCE : AI_GOAL_WAYPOINTS;
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
aigp->ai_mode = AI_GOAL_WAYPOINTS;
if ( op == OP_AI_WAYPOINTS_ONCE )
aigp->ai_mode = AI_GOAL_WAYPOINTS_ONCE;
if (CDDDDR(node) < 0)
aigp->int_data = 0; // handle optional node separately because we don't subtract 1 here
else
@@ -1089,27 +1021,10 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
}
case OP_AI_STAY_STILL:
{
int n = CDR(node);
aigp->target_name = ai_get_goal_target_name(CTEXT(n), &aigp->target_name_index); // waypoint path name;
n = CDR(n);
aigp->priority = eval_num(n, priority_is_nan, priority_is_nan_forever);
n = CDR(n);
bool clear_goals = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_stay_still];
if (n >= 0)
{
clear_goals = is_sexp_true(n);
n = CDR(n);
}
if (clear_goals)
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
aigp->ai_mode = AI_GOAL_STAY_STILL;
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
break;
}
case OP_AI_DOCK:
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
@@ -1127,12 +1042,13 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
break;
case OP_AI_PLAY_DEAD:
// we don't clear out ship goals for the "persistent" goal variant
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
FALLTHROUGH;
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
aigp->ai_mode = AI_GOAL_PLAY_DEAD;
break;
case OP_AI_PLAY_DEAD_PERSISTENT:
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
aigp->ai_mode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
aigp->ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
break;
case OP_AI_KEEP_SAFE_DISTANCE:
@@ -1168,53 +1084,14 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
}
case OP_AI_FORM_ON_WING:
{
int n = CDR(node);
aigp->target_name = ai_get_goal_target_name(CTEXT(n), &aigp->target_name_index);
n = CDR(n);
if (n >= 0)
{
aigp->priority = eval_num(n, priority_is_nan, priority_is_nan_forever);
n = CDR(n);
}
else
aigp->priority = The_mission.ai_profile->default_form_on_wing_priority;
bool clear_goals = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_running_form_on_wing];
if (n >= 0)
{
clear_goals = is_sexp_true(n);
n = CDR(n);
}
if (clear_goals)
aigp->flags.set(AI::Goal_Flags::Clear_all_goals_first);
bool set_override = !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_set_override_when_assigning_form_on_wing];
if (n >= 0)
{
set_override = is_sexp_true(n);
n = CDR(n);
}
if (set_override)
aigp->flags.set(AI::Goal_Flags::Want_override);
if (n >= 0)
{
if (is_sexp_true(n))
aigp->flags.set(AI::Goal_Flags::Purge_when_new_goal_added);
n = CDR(n);
}
aigp->priority = 99;
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
aigp->ai_mode = AI_GOAL_FORM_ON_WING;
break;
}
case OP_AI_CHASE:
case OP_AI_CHASE_WING:
case OP_AI_CHASE_SHIP_CLASS:
case OP_AI_CHASE_SHIP_TYPE:
case OP_AI_GUARD:
case OP_AI_GUARD_WING:
case OP_AI_EVADE_SHIP:
@@ -1246,8 +1123,6 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
aigp->ai_mode = AI_GOAL_CHASE_WING;
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
} else if (op == OP_AI_CHASE_SHIP_TYPE) {
aigp->ai_mode = AI_GOAL_CHASE_SHIP_TYPE;
} else if ( op == OP_AI_IGNORE ) {
aigp->ai_mode = AI_GOAL_IGNORE;
} else if ( op == OP_AI_IGNORE_NEW ) {
@@ -1289,13 +1164,10 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
} else if ( aigp->priority > MAX_GOAL_PRIORITY ) {
nprintf (("AI", "bashing add-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, aigp->priority, MAX_GOAL_PRIORITY));
aigp->priority = MAX_GOAL_PRIORITY;
} else if ( aigp->priority < MIN_GOAL_PRIORITY ) {
nprintf (("AI", "bashing add-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, aigp->priority, MIN_GOAL_PRIORITY));
aigp->priority = MIN_GOAL_PRIORITY;
}
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
if (op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_CHASE_SHIP_TYPE
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
if (is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
@@ -1320,7 +1192,6 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
if (op == OP_AI_CHASE ||
op == OP_AI_CHASE_WING ||
op == OP_AI_CHASE_SHIP_CLASS ||
op == OP_AI_CHASE_SHIP_TYPE ||
op == OP_AI_DISABLE_SHIP ||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
op == OP_AI_DISARM_SHIP ||
@@ -1404,11 +1275,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
nprintf(("AI", "bashing remove-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, _priority, MAX_GOAL_PRIORITY));
_priority = MAX_GOAL_PRIORITY;
}
else if (_priority < MIN_GOAL_PRIORITY)
{
nprintf(("AI", "bashing remove-goal sexpression priority of goal %s from %d to %d.\n", Sexp_nodes[CAR(sexp)].text, _priority, MIN_GOAL_PRIORITY));
_priority = MIN_GOAL_PRIORITY;
}
if (n >= 0)
{
@@ -1429,9 +1295,12 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
/* We now need to determine what the mode and submode values are*/
switch( op )
{
case OP_AI_WAYPOINTS:
case OP_AI_WAYPOINTS_ONCE:
goalmode = (op == OP_AI_WAYPOINTS_ONCE) ? AI_GOAL_WAYPOINTS_ONCE : AI_GOAL_WAYPOINTS;
goalmode = AI_GOAL_WAYPOINTS_ONCE;
priority = eval_priority_et_seq(CDDR(node));
break;
case OP_AI_WAYPOINTS:
goalmode = AI_GOAL_WAYPOINTS;
priority = eval_priority_et_seq(CDDR(node));
break;
case OP_AI_DESTROY_SUBSYS:
@@ -1509,10 +1378,6 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
priority = eval_priority_et_seq(CDDR(node));
goalmode = AI_GOAL_CHASE_SHIP_CLASS;
break;
case OP_AI_CHASE_SHIP_TYPE:
priority = eval_priority_et_seq(CDDR(node));
goalmode = AI_GOAL_CHASE_SHIP_TYPE;
break;
case OP_AI_EVADE_SHIP:
priority = eval_priority_et_seq(CDDR(node));
goalmode = AI_GOAL_EVADE_SHIP;
@@ -1527,7 +1392,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
break;
case OP_AI_FORM_ON_WING:
priority = eval_priority_et_seq(CDDR(node), The_mission.ai_profile->default_form_on_wing_priority);
priority = eval_priority_et_seq(-1, 99);
goalmode = AI_GOAL_FORM_ON_WING;
break;
case OP_AI_FLY_TO_SHIP:
@@ -1614,7 +1479,7 @@ void ai_add_ship_goal_sexp( int sexp, ai_goal_type type, ai_info *aip )
{
int gindex;
gindex = ai_goal_allocate_slot( aip->goals, aip->active_goal );
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
ai_add_goal_sub_sexp( sexp, type, aip, &aip->goals[gindex], Ships[aip->shipnum].ship_name );
}
@@ -1638,7 +1503,7 @@ void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp)
if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running) {
int gindex;
gindex = ai_goal_allocate_slot( wingp->ai_goals, -1 );
gindex = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_sexp( sexp, type, nullptr, &wingp->ai_goals[gindex], wingp->name );
}
}
@@ -1661,7 +1526,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
Assertion(strcmp(name, Ships[aip->shipnum].ship_name) != 0, "The goals apply to the actor in ai_add_goal_ship_internal for ship %s, please report to the SCP!", name);
// find an empty slot to put this goal in.
gindex = ai_goal_allocate_slot( aip->goals, aip->active_goal );
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
aigp = &(aip->goals[gindex]);
ai_goal_reset(aigp, true);
@@ -1790,7 +1655,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (!target_ship_entry || !target_ship_entry->has_shipp())
return ai_achievability::NOT_ACHIEVABLE;
// the override flag is now set in the calling function, validate_mission_goals
aigp->flags.set(AI::Goal_Flags::Goal_override);
return ai_achievability::ACHIEVABLE;
}
@@ -1822,20 +1687,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
return ai_achievability::NOT_KNOWN;
}
// and similarly for chasing all ships of a certain ship type
if (aigp->ai_mode == AI_GOAL_CHASE_SHIP_TYPE) {
for (auto so : list_range(&Ship_obj_list)) {
auto type_objp = &Objects[so->objnum];
if (type_objp->type != OBJ_SHIP || type_objp->flags[Object::Object_Flags::Should_be_dead])
continue;
int ship_info_idx = Ships[type_objp->instance].ship_info_index;
int class_type = Ship_info[ship_info_idx].class_type;
if (class_type >= 0 && !strcmp(aigp->target_name, Ship_types[class_type].name)) {
return ai_achievability::ACHIEVABLE;
}
}
return ai_achievability::NOT_KNOWN;
}
return_val = ai_achievability::SATISFIED;
@@ -2065,15 +1917,15 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags[AI::Goal_Flags::Goals_purged]))
{
if (causes_invalid_goal_purge_all_ships(aigp->ai_mode)) {
if (purge_goals_all_ships(aigp->ai_mode)) {
ai_goal_purge_all_invalid_goals(aigp);
aigp->flags.set(AI::Goal_Flags::Goals_purged);
}
else if (causes_invalid_goal_purge_one_ship(aigp->ai_mode)) {
else if (purge_goals_one_ship(aigp->ai_mode)) {
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
aigp->flags.set(AI::Goal_Flags::Goals_purged);
}
}
}
// if we are docking, validate the docking indices on both ships. We might have to change names to indices.
// only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
@@ -2373,10 +2225,6 @@ void validate_mission_goals(int objnum, ai_info *aip)
continue;
}
// if the status is achievable, and we want to set the override, set it
if ( (state == ai_achievability::ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Want_override]))
aigp->flags.set(AI::Goal_Flags::Goal_override);
// if the status is achievable, and the on_hold flag is set, clear the flagb
if ( (state == ai_achievability::ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
aigp->flags.remove(AI::Goal_Flags::Goal_on_hold);
@@ -2426,7 +2274,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
object *objp = &Objects[objnum];
object *other_obj;
ai_goal *current_goal;
int wingnum;
int wingnum, shipnum;
int original_signature;
/* if (!stricmp(Ships[objp->instance].ship_name, "gtt comet")) {
@@ -2501,34 +2349,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
}
std::unique_ptr<ai_goal> current_goal_backup;
auto current_goal_target_ship = current_goal->target_name ? ship_registry_get(current_goal->target_name) : nullptr;
if (current_goal->flags[AI::Goal_Flags::Clear_all_goals_first]) {
// save the current goal before we wipe it out by clearing everything
current_goal_backup.reset(new ai_goal(*current_goal));
current_goal = current_goal_backup.get();
// stay-still, form-on-wing, and play-dead all clear their goals here...
//
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
// then we need to clear everything out since there is not a real way to get rid of this goal
//
// for form on wing, we need to clear out all goals for this ship, and then call the form on wing AI code
//
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
//
// clearing out goals is okay here since we are now what mode to set this AI object to.
ai_clear_ship_goals(aip);
}
switch ( current_goal->ai_mode ) {
case AI_GOAL_CHASE:
if (current_goal->target_name) {
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
if ( current_goal->target_name ) {
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
other_obj = &Objects[Ships[shipnum].objnum];
} else
other_obj = NULL; // we get this case when we tell ship to engage enemy!
@@ -2545,8 +2373,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
case AI_GOAL_GUARD:
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
other_obj = &Objects[Ships[shipnum].objnum];
// shipnum and other_obj are the shipnumber and object pointer of the object that you should
// guard.
if (objp != other_obj) {
@@ -2577,8 +2406,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
}
case AI_GOAL_DOCK: {
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
other_obj = &Objects[Ships[shipnum].objnum];
// be sure that we have indices for docking points here! If we ever had names, they should
// get fixed up in goal_achievable so that the points can be checked there for validity
@@ -2588,22 +2418,24 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
}
case AI_GOAL_UNDOCK:
// try to find the object with which this object is docked. Use that object as the
// try to find the object which which this object is docked with. Use that object as the
// "other object" for the undocking proceedure. If "other object" isn't found, then the undock
// goal cannot continue. Spit out a warning and remove the goal.
// Goober5000 - do we have a specific ship to undock from?
if (current_goal->target_name)
if ( current_goal->target_name != NULL )
{
shipnum = ship_name_lookup( current_goal->target_name );
// hmm, perhaps he was destroyed
if (!current_goal_target_ship || !current_goal_target_ship->has_objp())
if (shipnum == -1)
{
other_obj = NULL;
}
// he exists... let's undock from him
else
{
other_obj = current_goal_target_ship->objp();
other_obj = &Objects[Ships[shipnum].objnum];
}
}
// no specific ship
@@ -2656,15 +2488,16 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL: {
Assert(current_goal_target_ship && current_goal_target_ship->has_objp());
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_attack_object( objp, other_obj);
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
// don't protect-ship for tactical goals
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
if (aip->target_objnum != -1) {
int class_type = Ship_info[current_goal_target_ship->shipp()->ship_info_index].class_type;
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
@@ -2688,20 +2521,10 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// chase-ship-class is chase-any but restricted to a subset of ships
case AI_GOAL_CHASE_SHIP_CLASS:
{
int ship_info_index = ship_info_lookup(current_goal->target_name);
Assertion(ship_info_index >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!");
ai_attack_object(objp, nullptr, ship_info_index);
shipnum = ship_info_lookup( current_goal->target_name );
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
ai_attack_object( objp, nullptr, shipnum );
break;
}
// similarly for chase-ship-type
case AI_GOAL_CHASE_SHIP_TYPE:
{
int class_type = ship_type_name_lookup(current_goal->target_name);
Assertion(class_type >= 0, "The target of AI_GOAL_CHASE_SHIP_TYPE must refer to a valid ship type!");
ai_attack_object(objp, nullptr, -1, class_type);
break;
}
case AI_GOAL_WARP: {
mission_do_departure( objp, true );
@@ -2709,29 +2532,46 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
}
case AI_GOAL_EVADE_SHIP:
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_evade_object( objp, other_obj);
break;
case AI_GOAL_STAY_STILL:
// NOTE: goal clearing moved above this enclosing switch block
// for now, ignore any other parameters!!!!
// clear out the object's goals. Seems to me that if a ship is staying still for a purpose
// then we need to clear everything out since there is not a real way to get rid of this goal
// clearing out goals is okay here since we are now what mode to set this AI object to.
ai_clear_ship_goals( aip );
ai_stay_still( objp, NULL );
break;
case AI_GOAL_PLAY_DEAD:
// if a ship is playing dead, MWA says that it shouldn't try to do anything else.
// clearing out goals is okay here since we are now what mode to set this AI object to.
ai_clear_ship_goals( aip );
aip->mode = AIM_PLAY_DEAD;
aip->submode = -1;
aip->submode_start_time = Missiontime;
break;
case AI_GOAL_PLAY_DEAD_PERSISTENT:
// NOTE: goal clearing moved above this enclosing switch block
// same as above, but we don't clear out ship goals
aip->mode = AIM_PLAY_DEAD;
aip->submode = -1;
aip->submode_start_time = Missiontime;
break;
case AI_GOAL_FORM_ON_WING:
// NOTE: goal clearing moved above this enclosing switch block
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
// get the ship first, since we're going to wipe it out next
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
// for form on wing, we need to clear out all goals for this ship, and then call the form
// on wing AI code
// clearing out goals is okay here since we are now what mode to set this AI object to.
ai_clear_ship_goals( aip );
ai_form_on_wing( objp, other_obj );
break;
@@ -2740,8 +2580,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
case AI_GOAL_STAY_NEAR_SHIP:
case AI_GOAL_FLY_TO_SHIP:
{
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
ai_do_stay_near(objp, other_obj, dist, additional_data);
@@ -2756,8 +2597,9 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
case AI_GOAL_REARM_REPAIR:
Assert(current_goal_target_ship && current_goal_target_ship->has_objp()); // shouldn't get here if this is false!!!!
other_obj = current_goal_target_ship->objp();
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_rearm_repair( objp, current_goal->docker.index, other_obj, current_goal->dockee.index );
break;
+6 -13
View File
@@ -47,9 +47,9 @@ enum class ai_goal_type
enum ai_goal_mode : uint8_t
{
AI_GOAL_NONE = 0,
AI_GOAL_SCHROEDINGER, // used for FRED when multiple ships are selected with different orders
AI_GOAL_PLACEHOLDER_1,
AI_GOAL_CHASE,
AI_GOAL_CHASE, // per the original #define list, AI_GOAL_CHASE started at 2 (1<<1)
AI_GOAL_DOCK, // used for undocking as well
AI_GOAL_WAYPOINTS,
AI_GOAL_WAYPOINTS_ONCE,
@@ -80,8 +80,7 @@ enum ai_goal_mode : uint8_t
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_PLAY_DEAD_PERSISTENT,
AI_GOAL_LUA,
AI_GOAL_DISARM_SHIP_TACTICAL,
AI_GOAL_DISABLE_SHIP_TACTICAL,
@@ -104,11 +103,7 @@ inline bool ai_goal_is_disable_or_disarm(ai_goal_mode ai_mode)
}
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;
}
inline bool ai_goal_is_standing_chase(ai_goal_mode ai_mode)
{
return ai_mode == AI_GOAL_CHASE_ANY;
return ai_mode == AI_GOAL_CHASE || ai_mode == AI_GOAL_CHASE_WING || ai_mode == AI_GOAL_CHASE_SHIP_CLASS;
}
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
@@ -157,8 +152,6 @@ typedef struct 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);
// 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;
@@ -192,8 +185,8 @@ extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
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(ai_goal_type type, ai_goal_mode 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(ai_goal_type type, ai_goal_mode 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 );
+103 -61
View File
@@ -350,18 +350,6 @@ const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
return &Weapon_info[wi_index];
}
// similar to the above, since "weapon_num" is a bank index over multiple banks
static std::pair<int, int> get_turret_weapon_bank(int weapon_num)
{
int pbank = -1;
int sbank = -1;
if (weapon_num >= MAX_SHIP_PRIMARY_BANKS)
sbank = weapon_num - MAX_SHIP_PRIMARY_BANKS;
else
pbank = weapon_num;
return { pbank, sbank };
}
int get_turret_weapon_next_fire_stamp(const ship_weapon *swp, int weapon_num)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
@@ -491,12 +479,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;
}
@@ -1107,12 +1089,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) {
// The parent's target can be a weapon or an asteroid, so make sure it's a ship before indexing Ships[]
ship* target_shipp = (Objects[target_objnum].type == OBJ_SHIP) ? &Ships[Objects[target_objnum].instance] : nullptr;
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;
}
}
@@ -1580,9 +1559,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
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);
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]++;
@@ -1682,7 +1659,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);
@@ -1741,7 +1718,6 @@ bool turret_fire_weapon(int weapon_num,
auto wip = get_turret_weapon_wip(&turret->weapons, weapon_num);
if (!wip)
return false;
auto [turret_pbank, turret_sbank] = get_turret_weapon_bank(weapon_num);
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
@@ -1768,7 +1744,7 @@ bool turret_fire_weapon(int weapon_num,
parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
parent_ship = &Ships[Objects[parent_objnum].instance];
int turret_weapon_class = WEAPON_INFO_INDEX(wip);
int turret_weapon_class = weapon_info_get_index(wip);
#ifndef NDEBUG
// moved here from check_ok_to_fire
@@ -1852,7 +1828,6 @@ bool turret_fire_weapon(int weapon_num,
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.bank = turret_pbank;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
@@ -1865,6 +1840,7 @@ bool turret_fire_weapon(int weapon_num,
fire_info.target_pos1 = turret->last_aim_enemy_pos;
}
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
@@ -1890,53 +1866,113 @@ bool turret_fire_weapon(int weapon_num,
}
// don't fire swam, but set up swarm info instead
else if ((wip->wi_flags[Weapon::Info_Flags::Swarm]) || (wip->wi_flags[Weapon::Info_Flags::Corkscrew])) {
// swarm and corkscrew are not restricted to missiles, so check whichever bank is actually firing
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo])) {
bool has_ammo = (turret_pbank >= 0)
? swp->primary_bank_ammo[turret_pbank] > 0
: ship_secondary_has_ammo(swp, turret_sbank);
if (!has_ammo)
return false;
if (swp->current_secondary_bank < 0) {
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::Use_multiple_guns])) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
}
return false;
} else {
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_pbank, turret_sbank, in_lab);
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
}
}
// 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);
// note that wip is reassigned to the created weapon's class inside the loop, so any
// property of the bank's own weapon must be read before we get there
bool no_ammo_needed = (turret_sbank >= 0) && Weapon_info[swp->secondary_bank_weapons[turret_sbank]].wi_flags[Weapon::Info_Flags::SecondaryNoAmmo];
for (int i = 0; i < shots; i++) {
if (!in_lab && turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
if (turret_pbank >= 0) {
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
if (wip->subtype == WP_LASER) {
int points;
if (swp->num_primary_banks <= 0) {
return false;
}
if (swp->current_primary_bank < 0){
swp->current_primary_bank = 0;
return false;
}
int num_primary_banks = swp->num_primary_banks;
Assert(num_primary_banks > 0);
if (num_primary_banks < 1){
return false;
}
bank_to_fire = swp->current_primary_bank;
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo]) {
points = turret->system_info->turret_num_firing_points;
points = num_slots;
} else {
points = 1;
}
if (swp->primary_bank_ammo[turret_pbank] >= points) {
swp->primary_bank_ammo[turret_pbank] -= points;
} else if ((swp->primary_bank_ammo[turret_pbank] >= 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
if (swp->primary_bank_ammo[bank_to_fire] >= points) {
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if ((swp->primary_bank_ammo[bank_to_fire] >= 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->primary_bank_ammo[turret_pbank] -= points;
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
swp->current_primary_bank++;
if (swp->current_primary_bank >= swp->num_primary_banks) {
swp->current_primary_bank = 0;
}
return false;
} else {
return false;
}
}
else if (turret_sbank >= 0) {
if (!no_ammo_needed) {
if (swp->secondary_bank_ammo[turret_sbank] > 0) {
swp->secondary_bank_ammo[turret_sbank]--;
} else if ((swp->secondary_bank_ammo[turret_sbank] == 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
else if (wip->subtype == WP_MISSILE) {
if (swp->num_secondary_banks <= 0) {
return false;
}
if (swp->current_secondary_bank < 0){
swp->current_secondary_bank = 0;
return false;
}
bank_to_fire = swp->current_secondary_bank;
int start_slot, end_slot;
start_slot = swp->secondary_next_slot[bank_to_fire];
end_slot = start_slot;
for (int j = start_slot; j <= end_slot; j++) {
swp->secondary_next_slot[bank_to_fire]++;
if (Weapon_info[swp->secondary_bank_weapons[bank_to_fire]].wi_flags[Weapon::Info_Flags::SecondaryNoAmmo])
continue;
if (swp->secondary_next_slot[bank_to_fire] > (num_slots - 1)){
swp->secondary_next_slot[bank_to_fire] = 0;
}
if (swp->secondary_bank_ammo[bank_to_fire] > 0) {
swp->secondary_bank_ammo[bank_to_fire]--;
} else if ((swp->secondary_bank_ammo[bank_to_fire] == 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->secondary_bank_ammo[turret_sbank]--;
swp->secondary_bank_ammo[bank_to_fire]--;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
swp->current_secondary_bank = 0;
}
return false;
} else {
return false;
}
@@ -1951,7 +1987,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, swp, turret_pbank, turret_sbank, launch_curve_data);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, 0.0f, turret, launch_curve_data);
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));
@@ -2002,11 +2038,14 @@ bool turret_fire_weapon(int weapon_num,
}
//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->setHost(make_unique<EffectHostTurret>(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos));
particleSource->setTriggerRadius(objp->radius * radius_mult);
particleSource->setTriggerVelocity(vm_vec_mag_quick(&objp->phys_info.vel));
particleSource->finishCreation();
}
else 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.
if ( MULTIPLAYER_MASTER && (weapon_objnum != -1) ) {
@@ -2094,7 +2133,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
};
// create weapon and homing info
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, &tsi->turret->weapons, tsi->swp_pbank, tsi->swp_sbank, launch_curve_data);
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_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
// do other cool stuff if weapon is created.
@@ -2123,10 +2162,13 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
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->setHost(make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1));
particleSource->setTriggerRadius(Objects[weapon_objnum].radius);
particleSource->finishCreation();
}
else 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
if ( Weapon_info[tsi->weapon_class].launch_snd.isValid() ) {
+10 -18
View File
@@ -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;
}
+79 -157
View File
@@ -32,9 +32,8 @@
#include "object/objcollide.h"
#include "object/object.h"
#include "parse/parselo.h"
#include "particle/ParticleEffect.h"
#include "scripting/global_hooks.h"
#include "particle/hosts/EffectHostVector.h"
#include "particle/particle.h"
#include "render/3d.h"
#include "ship/ship.h"
#include "ship/shipfx.h"
@@ -64,7 +63,8 @@ asteroid Asteroids[MAX_ASTEROIDS];
asteroid_field Asteroid_field;
static particle::ParticleEffectHandle Asteroid_impact_explosion_ani;
static int Asteroid_impact_explosion_ani;
static float Asteroid_impact_explosion_radius;
char Asteroid_icon_closeup_model[NAME_LENGTH];
vec3d Asteroid_icon_closeup_position;
float Asteroid_icon_closeup_zoom;
@@ -648,30 +648,24 @@ void asteroid_create_all()
int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_VALUE-Detail.asteroid_density)));
int num_debris_types = 0;
int num_valid = 0; // count of valid (non-(-1)) entries written into shipDebrisOddsTable
// get number of debris types
if (Asteroid_field.debris_genre == DG_DEBRIS) {
num_debris_types = static_cast<int>(Asteroid_field.field_debris_type.size());
// Calculate the odds table; skip invalid entries (field_debris_type[idx] == -1 means
// missionparse invalidated the entry because the type no longer exists in Asteroid_info)
// Calculate the odds table
for (idx=0; idx<num_debris_types; idx++) {
if (Asteroid_field.field_debris_type[idx] == -1)
continue;
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
shipDebrisOddsTable[num_valid].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[num_valid].debris_type = Asteroid_field.field_debris_type[idx];
shipDebrisOddsTable[idx].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[idx].debris_type = Asteroid_field.field_debris_type[idx];
max_weighted_range += debris_weight;
num_valid++;
}
}
// Load Asteroid/debris models
if (Asteroid_field.debris_genre == DG_DEBRIS) {
for (idx=0; idx<num_debris_types; idx++) {
if (Asteroid_field.field_debris_type[idx] != -1)
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
}
} else {
for (const auto& subtype : Asteroid_field.field_asteroid_type) {
@@ -696,7 +690,7 @@ void asteroid_create_all()
float rand_choice = frand() * max_weighted_range;
for (idx = 0; idx < num_valid; idx++) {
for (idx = 0; idx < static_cast<int>(Asteroid_field.field_debris_type.size()); idx++) {
// for ship debris, choose type according to odds table
if (rand_choice < shipDebrisOddsTable[idx].random_threshold) {
asteroid_create(&Asteroid_field, shipDebrisOddsTable[idx].debris_type, 0);
@@ -830,7 +824,18 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
*/
void asteroid_level_init()
{
Asteroid_field = {};
Asteroid_field.num_initial_asteroids = 0; // disable asteroid field by default.
Asteroid_field.speed = 0.0f;
vm_vec_make(&Asteroid_field.min_bound, -1000.0f, -1000.0f, -1000.0f);
vm_vec_make(&Asteroid_field.max_bound, 1000.0f, 1000.0f, 1000.0f);
vm_vec_make(&Asteroid_field.inner_min_bound, -500.0f, -500.0f, -500.0f);
vm_vec_make(&Asteroid_field.inner_max_bound, 500.0f, 500.0f, 500.0f);
Asteroid_field.has_inner_bound = false;
Asteroid_field.field_type = FT_ACTIVE;
Asteroid_field.debris_genre = DG_ASTEROID;
Asteroid_field.field_debris_type.clear();
Asteroid_field.field_asteroid_type.clear();
Asteroid_field.target_names.clear();
if (!Fred_running)
{
@@ -1083,10 +1088,8 @@ void asteroid_delete( object * obj )
asp = &Asteroids[num];
if (asp->model_instance_num >= 0) {
if (asp->model_instance_num >= 0)
model_delete_instance(asp->model_instance_num);
asp->model_instance_num = -1;
}
if (asp->target_objnum >= 0) {
for (asteroid_target& target : Asteroid_targets) {
@@ -1323,9 +1326,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
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
@@ -1333,8 +1336,10 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// 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);
@@ -1366,12 +1371,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
}
// 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.
@@ -1616,13 +1618,8 @@ static float asteroid_create_explosion(object *objp)
}
fireball_scale_multiplier = asteroid_get_fireball_scale_multiplier(objp->instance);
auto fireball_radius = objp->radius * fireball_scale_multiplier;
if (Zero_radius_explosions_skip_fireballs && fl_near_zero(fireball_radius))
fireball_objnum = -1;
else
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), fireball_radius, false, &objp->phys_info.vel );
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, false, &objp->phys_info.vel );
if ( fireball_objnum > -1 ) {
explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
} else {
@@ -1708,57 +1705,37 @@ static void asteroid_do_area_effect(object *asteroid_objp)
*/
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force )
{
asteroid *asp = &Asteroids[pasteroid_obj->instance];
asteroid_info *asip = &Asteroid_info[Asteroids[pasteroid_obj->instance].asteroid_type];
float explosion_life;
asteroid *asp;
asp = &Asteroids[pasteroid_obj->instance];
if (pasteroid_obj->flags[Object::Object_Flags::Should_be_dead]){
return;
}
if ( MULTIPLAYER_MASTER ){
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage, force );
}
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_asteroids]) {
vec3d rel_hit_pos = *hitpos - pasteroid_obj->pos;
physics_calculate_and_apply_whack(force, &rel_hit_pos, &pasteroid_obj->phys_info, &pasteroid_obj->orient, &pasteroid_obj->phys_info.I_body_inv);
pasteroid_obj->phys_info.desired_vel = pasteroid_obj->phys_info.vel;
}
pasteroid_obj->hull_strength -= damage;
if (pasteroid_obj->hull_strength < 0.0f) {
if ( !asp->final_death_time.isValid() ) {
int play_loud_collision = 0;
float explosion_life = 1.f;
int breakup_timestamp;
Assertion(!asip->end_particles.isValid() || asip->breakup_delay.has_value(), "Asteroid %s has end particles but no breakup delay. Parsing should not have allowed this!", asip->name);
if (asip->end_particles.isValid()) {
auto source = particle::ParticleManager::get()->createSource(asip->end_particles);
// Use the position since the asteroid is going to be invalid soon
auto host = std::make_unique<EffectHostVector>(pasteroid_obj->pos, pasteroid_obj->orient, pasteroid_obj->phys_info.vel);
host->setRadius(pasteroid_obj->radius);
source->setHost(std::move(host));
source->setNormal(pasteroid_obj->orient.vec.uvec);
source->finishCreation();
} else {
explosion_life = asteroid_create_explosion(pasteroid_obj);
}
if (asip->breakup_delay.has_value()) {
breakup_timestamp = fl2i(*asip->breakup_delay * MILLISECONDS_PER_SECOND);
} else {
breakup_timestamp = fl2i((explosion_life * MILLISECONDS_PER_SECOND) / 5.f);
}
explosion_life = asteroid_create_explosion(pasteroid_obj);
asteroid_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
asteroid_do_area_effect(pasteroid_obj);
asp->final_death_time = _timestamp( breakup_timestamp ); // Wait till 20% of vclip time before breaking the asteroid up, or use the specified delay
asp->final_death_time = _timestamp( fl2i(explosion_life*MILLISECONDS_PER_SECOND)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
if ( hitpos ) {
asp->death_hit_pos = *hitpos;
} else {
@@ -1774,10 +1751,8 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
weapon_info *wip;
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
// If the weapon didn't play any impact animation, play custom asteroid impact animation
if (!wip->impact_weapon_expl_effect.isValid() && Asteroid_impact_explosion_ani.isValid()) {
auto source = particle::ParticleManager::get()->createSource(Asteroid_impact_explosion_ani);
source->setHost(std::make_unique<EffectHostVector>(*hitpos, vmd_identity_matrix, vmd_zero_vector));
source->finishCreation();
if (!wip->impact_weapon_expl_effect.isValid()) {
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, Asteroid_impact_explosion_ani );
}
}
}
@@ -2234,7 +2209,7 @@ static void asteroid_parse_section()
}
return;
}
asteroid_list.push_back(std::move(asteroid_t));
asteroid_list.push_back(asteroid_t);
asteroid_p = &asteroid_list[asteroid_list.size() - 1];
}
@@ -2332,13 +2307,13 @@ static void asteroid_parse_section()
thisType.type_name.c_str(),
asteroid_p->name);
} else {
asteroid_p->subtypes.push_back(std::move(thisType));
asteroid_p->subtypes.push_back(thisType);
}
}
}
if (optional_string("$Detail distance:")) {
asteroid_p->num_detail_levels = sz2i(stuff_int_list(asteroid_p->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, ParseLookupType::RAW_INTEGER_TYPE));
asteroid_p->num_detail_levels = (int)stuff_int_list(asteroid_p->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, RAW_INTEGER_TYPE);
}
if (optional_string("$Max Speed:")) {
@@ -2355,25 +2330,13 @@ static void asteroid_parse_section()
asteroid_p->damage_type_idx_sav = damage_type_add(buf);
asteroid_p->damage_type_idx = asteroid_p->damage_type_idx_sav;
}
if (optional_string("$Explosion Effect:")) {
asteroid_p->end_particles = particle::util::parseEffect(asteroid_p->name);
} else {
if(optional_string("$Explosion Animations:")){
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
}
if (optional_string("$Explosion Radius Mult:")) {
stuff_float(&asteroid_p->fireball_radius_multiplier);
}
if(optional_string("$Explosion Animations:")){
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
}
if (optional_string("$Breakup Delay:")) {
stuff_float(&asteroid_p->breakup_delay.emplace());
}
if (asteroid_p->end_particles.isValid() && !asteroid_p->breakup_delay.has_value()) {
error_display(0, "Asteroid %s has an explosion effect but no breakup delay!", asteroid_p->name);
if (optional_string("$Explosion Radius Mult:")) {
stuff_float(&asteroid_p->fireball_radius_multiplier);
}
if (optional_string("$Expl inner rad:")){
@@ -2498,52 +2461,18 @@ static void asteroid_parse_tbl(const char* filename)
required_string("#End");
if (optional_string("$Impact Explosion Effect:")) {
Asteroid_impact_explosion_ani = particle::util::parseEffect();
if (optional_string("$Impact Explosion:")) {
char impact_ani_file[MAX_FILENAME_LEN];
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
if (VALID_FNAME(impact_ani_file)) {
int num_frames;
Asteroid_impact_explosion_ani = bm_load_animation(impact_ani_file, &num_frames, nullptr, nullptr, nullptr, true);
}
}
else {
char impact_ani_file[MAX_FILENAME_LEN] = {0};
float Asteroid_impact_explosion_radius = 0.0f;
int num_frames;
if (optional_string("$Impact Explosion:")) {
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
}
if (optional_string("$Impact Explosion Radius:")) {
stuff_float(&Asteroid_impact_explosion_radius);
}
if(VALID_FNAME(impact_ani_file)) {
Asteroid_impact_explosion_ani = particle::ParticleManager::get()->addEffect(particle::ParticleEffect(
"", //Name
::util::UniformFloatRange(1.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(), //Velocity Inherit
false, //Velocity Inherit absolute?
nullptr, //Velocity volume
::util::UniformFloatRange(), //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
false, //Affected by detail
-1.f, //Culling range multiplier
false, //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(-1.f), //Lifetime
::util::UniformFloatRange(Asteroid_impact_explosion_radius), //Radius
bm_load_animation(impact_ani_file, &num_frames, nullptr, nullptr, nullptr, true))); //Bitmap
}
if (optional_string("$Impact Explosion Radius:")) {
stuff_float(&Asteroid_impact_explosion_radius);
}
if (optional_string("$Briefing Icon Closeup Model:")) {
@@ -2578,21 +2507,24 @@ int get_asteroid_index(const char* asteroid_name)
return -1;
}
// Returns the list of unique asteroid subtype names.
// List is cached after the first call since Asteroid_info cannot change during an engine instance.
const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes()
// For FRED. Gets a list of unique asteroid subtype names
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes()
{
static SCP_vector<SCP_string> list;
SCP_vector<SCP_string> list;
if (list.empty()) {
for (const auto& this_asteroid : Asteroid_info) {
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
for (const auto& subtype : this_asteroid.subtypes) {
// Only add unique names
if (std::find(list.begin(), list.end(), subtype.type_name) == list.end()) {
list.push_back(subtype.type_name);
for (const auto& this_asteroid : Asteroid_info) {
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
for (const auto& subtype : this_asteroid.subtypes) {
bool exists = false;
for (const auto& entry : list) {
if (subtype.type_name == entry) {
exists = true;
}
}
if (!exists) {
list.push_back(subtype.type_name);
}
}
}
}
@@ -2600,7 +2532,6 @@ const SCP_vector<SCP_string>& get_list_valid_asteroid_subtypes()
return list;
}
static void verify_asteroid_splits()
{
@@ -2621,7 +2552,7 @@ static void verify_asteroid_splits()
}
// Replace splits with only valid splits
Asteroid_info[i].split_info = std::move(splits_t);
Asteroid_info[i].split_info = splits_t;
}
}
@@ -2649,11 +2580,6 @@ static void verify_asteroid_list()
if (found)
continue;
if (asteroid_list.empty()) {
mprintf(("%s asteroid not found and no fallback available in asteroid_list.\n", asteroid_size[i].c_str()));
continue;
}
//Left this as a log print instead of a Warning because of retail-Mjn
mprintf(("%s asteroid not found. Using asteroid %s\n", asteroid_size[i].c_str(), asteroid_list[0].name));
asteroid_list[0].type = i;
@@ -2696,7 +2622,8 @@ static void verify_asteroid_list()
*/
void asteroid_init()
{
Asteroid_impact_explosion_ani = particle::ParticleEffectHandle::invalid();
Asteroid_impact_explosion_ani = -1;
Asteroid_impact_explosion_radius = 20.0; // retail value
Asteroid_icon_closeup_model[0] = '\0';
vm_vec_make(&Asteroid_icon_closeup_position, 0.0f, 0.0f, -334.0f); // magic numbers from retail
Asteroid_icon_closeup_zoom = 0.5f; // magic number from retail
@@ -2708,10 +2635,8 @@ void asteroid_init()
parse_modular_table("*-ast.tbm", asteroid_parse_tbl);
//No asteroids defined. Bail!
if (asteroid_list.empty()) {
mprintf(("No asteroids defined in asteroid.tbl or any modular tables. Asteroid fields will not function.\n"));
if (asteroid_list.empty())
return;
}
// now verify the asteroids were found and put them in the correct order
verify_asteroid_list();
@@ -2719,11 +2644,8 @@ void asteroid_init()
// now that Asteroid_info is filled in we can verify the asteroid splits and set their indecies
verify_asteroid_splits();
if (!Asteroid_impact_explosion_ani.isValid()) {
// this will always be missing on a standalone
if ( !Is_standalone ) {
Error(LOCATION, "Missing valid asteroid impact explosion definition in asteroid.tbl!");
}
if (Asteroid_impact_explosion_ani == -1) {
Error(LOCATION, "Missing valid asteroid impact explosion definition in asteroid.tbl!");
}
if (Asteroid_icon_closeup_model[0] == '\0')
+5 -27
View File
@@ -16,8 +16,6 @@
#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;
@@ -81,9 +79,7 @@ public:
float initial_asteroid_strength; // starting strength of asteroid
SCP_vector< asteroid_split_info > split_info;
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;
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 debris
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
float gravity_const; // multiplier for mission gravity
@@ -94,7 +90,7 @@ public:
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 = "";
@@ -134,7 +130,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;
@@ -151,24 +147,7 @@ struct asteroid_field {
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];
@@ -200,8 +179,7 @@ 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);
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
// extern for the lab
void asteroid_load(int asteroid_info_index, int asteroid_subtype);
+9 -10
View File
@@ -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;
+30 -150
View File
@@ -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 };
@@ -83,12 +82,7 @@ static bool bm_inited = false;
static uint Bm_next_signature = 0x1234;
static int Bm_low_mem = 0;
struct bm_lookup_cache_entry {
ubyte* data;
int width;
int height;
};
SCP_map<int, bm_lookup_cache_entry> bm_lookup_cache;
SCP_map<int,ubyte*> bm_lookup_cache;
/**
* How much RAM bmpman can use for textures.
@@ -149,31 +143,30 @@ bitmap_slot* bm_get_slot(int handle, bool separate_ani_frames) {
// Declaration of private functions and templates(declared as static type func(type param);)
bitmap_lookup::bitmap_lookup(int bitmap_num):
Bitmap_data(nullptr),
Width(0),
Height(0),
Num_channels(3)
Bitmap_data(NULL)
{
if ( !bm_is_valid(bitmap_num) ) return;
Num_channels = 3;
if ( bm_has_alpha_channel(bitmap_num) ) {
Num_channels = 4;
}
bitmap_entry *be = bm_get_entry(bitmap_num);
Width = be->bm.w;
Height = be->bm.h;
auto cache_search = bm_lookup_cache.find(bitmap_num);
if (cache_search == bm_lookup_cache.end()) {
// The texture in graphics memory may be smaller than the bitmap itself, e.g. when mipmap levels
// are culled at lower texture detail settings, so the readback reports the dimensions of the
// data it actually returns.
Bitmap_data = gr_get_bitmap_from_texture(bitmap_num, &Width, &Height);
Bitmap_data = (ubyte*)vm_malloc(Width * Height * Num_channels * sizeof(ubyte));
if (Bitmap_data != nullptr) {
bm_lookup_cache.insert({bitmap_num, {Bitmap_data, Width, Height}});
}
gr_get_bitmap_from_texture((void*)Bitmap_data, bitmap_num);
bm_lookup_cache.insert({bitmap_num, Bitmap_data});
} else {
Bitmap_data = cache_search->second.data;
Width = cache_search->second.width;
Height = cache_search->second.height;
Bitmap_data = cache_search->second;
}
}
@@ -196,11 +189,6 @@ float bitmap_lookup::get_channel_alpha(float u, float v)
{
Assert( Bitmap_data != NULL );
// without an alpha channel there is nothing to look up, and indexing channel 3 would read out of bounds
if ( Num_channels < 4 ) {
return 1.0f;
}
int x = fl2i(map_texture_address(u) * (Width-1));
int y = fl2i(map_texture_address(v) * (Height-1));
@@ -209,7 +197,7 @@ float bitmap_lookup::get_channel_alpha(float u, float v)
void clear_bm_lookup_cache() {
for(auto &iter: bm_lookup_cache) {
vm_free(iter.second.data);
free(iter.second);
}
bm_lookup_cache.clear();
}
@@ -217,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
@@ -651,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
@@ -913,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;
@@ -1067,24 +1055,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;
}
@@ -1178,16 +1148,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);
@@ -1401,8 +1361,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;
@@ -1432,7 +1390,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;
@@ -1524,10 +1482,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;
@@ -1987,7 +1941,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!");
@@ -2084,7 +2038,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;
@@ -2210,7 +2164,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);
@@ -2260,7 +2214,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;
@@ -2324,7 +2278,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;
@@ -2371,7 +2325,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];
@@ -2416,7 +2370,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;
@@ -2461,7 +2415,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];
@@ -2520,7 +2474,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
@@ -2813,21 +2767,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;
}
@@ -2873,21 +2812,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;
}
@@ -3508,47 +3432,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
View File
@@ -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.
+19 -45
View File
@@ -56,10 +56,6 @@ APPLY_TO_FOV_T(-, sub)
// Used to set the default value for in-game options
static float fov_default = DEFAULT_FOV;
static float cockpit_fov_default = DEFAULT_FOV;
static bool cockpit_fov_toggle_default = false;
bool Use_cockpit_fov = false;
static SCP_string fov_display(float val)
{
@@ -77,22 +73,6 @@ static void parse_fov_func()
fov_default = value;
}
static void parse_cockpit_fov_func()
{
float value;
stuff_float(&value);
CLAMP(value, 0.436332f, 1.5708f);
cockpit_fov_default = value;
}
static void parse_cockpit_fov_toggle_func()
{
bool value;
stuff_boolean(&value);
cockpit_fov_toggle_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})
@@ -109,7 +89,24 @@ auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
.parser(parse_fov_func)
.finish();
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
bool Use_cockpit_fov = false;
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})
.category(std::make_pair("Graphics", 1825))
.default_val(false)
.change_listener([](bool val, bool) {
if (!val) {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true; // This option will always persist so we never return false
})
.level(options::ExpertLevel::Advanced)
.bind_to(&Use_cockpit_fov)
.importance(61)
.finish();
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})
@@ -124,28 +121,9 @@ auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
return true;
})
.display(fov_display)
.default_func([]() { return cockpit_fov_default; })
.default_val(fov_default)
.level(options::ExpertLevel::Advanced)
.importance(62)
.parser(parse_cockpit_fov_func)
.finish();
// 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})
.category(std::make_pair("Graphics", 1825))
.default_func([]() {return cockpit_fov_toggle_default;})
.change_listener([](bool val, bool) {
if (!val) {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true; // This option will always persist so we never return false
})
.level(options::ExpertLevel::Advanced)
.bind_to(&Use_cockpit_fov)
.importance(61)
.parser(parse_cockpit_fov_toggle_func)
.finish();
//*************************CLASS: camera*************************
@@ -754,7 +732,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();
}
@@ -1317,9 +1294,6 @@ float cam_get_bbox_dist(const object* viewer_obj, float preferred_distance, cons
return preferred_distance;
polymodel* pm = object_get_model(viewer_obj);
if (pm == nullptr)
return preferred_distance;
vec3d adjusted_bbox;
const vec3d* cam_vec = &cam_orient->vec.fvec;
-609
View File
@@ -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", 1286));
}
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();
}
-16
View File
@@ -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);
+11 -12
View File
@@ -52,7 +52,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 +66,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
@@ -186,7 +186,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?
@@ -903,7 +902,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 );
+1 -1
View File
@@ -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);
+7 -9
View File
@@ -532,7 +532,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);
}
}
@@ -1083,7 +1083,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 ));
}
@@ -1356,7 +1356,7 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
fclose(fp);
res.offset = 0;
res.full_name = std::move(longname);
res.full_name = longname;
res.name_ext = filespec;
return res;
@@ -1549,8 +1549,8 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
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;
}
@@ -2437,9 +2437,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 +2480,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';
+2 -2
View File
@@ -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());
+1 -1
View File
@@ -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)) { }
+2 -8
View File
@@ -534,7 +534,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;
@@ -573,7 +572,6 @@ 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);
@@ -1322,7 +1320,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 +1412,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);
@@ -2409,10 +2407,6 @@ bool SetCmdlineParams()
}
}
if (multithreading.found()) {
Cmdline_multithreading = abs(multithreading.get_int());
}
return true;
}
-1
View File
@@ -159,7 +159,6 @@ 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;
+12 -26
View File
@@ -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;
+7 -42
View File
@@ -10,7 +10,6 @@
#include "camera/photomode.h"
#include "cfile/cfile.h"
#include "cmdline/cmdline.h"
#include "controlconfig/controlsconfig.h"
@@ -621,11 +620,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();
@@ -1304,8 +1298,7 @@ bool control_config_accept(bool API_Access)
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),
32 - 6,
default_string.c_str(),
"-_");
default_string.c_str());
if (cstr == nullptr) {
// Abort
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
@@ -2091,6 +2084,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());
@@ -2724,7 +2718,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 +2802,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 +2823,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,7 +2838,7 @@ 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;
}
@@ -2910,15 +2884,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;
}
+2 -25
View File
@@ -297,24 +297,10 @@ 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
*/
@@ -592,10 +578,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 +586,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 +658,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
@@ -956,12 +937,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
*
+14 -52
View File
@@ -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)
@@ -267,12 +265,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 +272,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 +425,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},
@@ -459,9 +438,6 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
{"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]
@@ -1165,12 +1141,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)
@@ -1194,10 +1164,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
@@ -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;
}
+3 -6
View File
@@ -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;
}
+1 -1
View File
@@ -279,7 +279,7 @@ bool play(const char* filename, bool via_tech_room = false)
{
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));
scripting::hooks::OnMovieAboutToPlay->run(paramList);
if (skip)
return false;
}
+30 -190
View File
@@ -1,4 +1,4 @@
/* bcdec.h - v0.97
/* bcdec.h - v0.96
provides functions to decompress blocks of BC compressed images
written by Sergii "iOrange" Kudlai in 2022
@@ -23,10 +23,6 @@
For more info, issues and suggestions please visit https://github.com/iOrange/bcdec
Configuration:
#define BCDEC_BC4BC5_PRECISE:
enables more precise but slower BC4/BC5 decoding + signed/unsigned mode
CREDITS:
Aras Pranckevicius (@aras-p) - BC1/BC3 decoders optimizations (up to 3x the speed)
- BC6H/BC7 bits pulling routines optimizations
@@ -34,11 +30,6 @@
- Split BC6H decompression function into 'half' and
'float' variants
Michael Schmidt (@RunDevelopment) - Found better "magic" coefficients for integer interpolation
of reference colors in BC1 color block, that match with
the floating point interpolation. This also made it faster
than integer division by 3!
bugfixes:
@linkmauve
@@ -48,9 +39,6 @@
#ifndef BCDEC_HEADER_INCLUDED
#define BCDEC_HEADER_INCLUDED
#define BCDEC_VERSION_MAJOR 0
#define BCDEC_VERSION_MINOR 98
/* if BCDEC_STATIC causes problems, try defining BCDECDEF to 'inline' or 'static inline' */
#ifndef BCDECDEF
#ifdef BCDEC_STATIC
@@ -102,20 +90,12 @@
BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
#ifndef BCDEC_BC4BC5_PRECISE
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
#else
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
BCDECDEF void bcdec_bc4_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
BCDECDEF void bcdec_bc5_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
#endif
BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned);
BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch);
#endif /* BCDEC_HEADER_INCLUDED */
#ifdef BCDEC_IMPLEMENTATION
@@ -130,44 +110,35 @@ static void bcdec__color_block(const void* compressedBlock, void* decompressedBl
c0 = ((unsigned short*)compressedBlock)[0];
c1 = ((unsigned short*)compressedBlock)[1];
/* Unpack 565 ref colors */
r0 = (c0 >> 11) & 0x1F;
g0 = (c0 >> 5) & 0x3F;
b0 = c0 & 0x1F;
r1 = (c1 >> 11) & 0x1F;
g1 = (c1 >> 5) & 0x3F;
b1 = c1 & 0x1F;
/* Expand 565 ref colors to 888 */
r = (r0 * 527 + 23) >> 6;
g = (g0 * 259 + 33) >> 6;
b = (b0 * 527 + 23) >> 6;
refColors[0] = 0xFF000000 | (b << 16) | (g << 8) | r;
r0 = (((c0 >> 11) & 0x1F) * 527 + 23) >> 6;
g0 = (((c0 >> 5) & 0x3F) * 259 + 33) >> 6;
b0 = ((c0 & 0x1F) * 527 + 23) >> 6;
refColors[0] = 0xFF000000 | (b0 << 16) | (g0 << 8) | r0;
r = (r1 * 527 + 23) >> 6;
g = (g1 * 259 + 33) >> 6;
b = (b1 * 527 + 23) >> 6;
refColors[1] = 0xFF000000 | (b << 16) | (g << 8) | r;
r1 = (((c1 >> 11) & 0x1F) * 527 + 23) >> 6;
g1 = (((c1 >> 5) & 0x3F) * 259 + 33) >> 6;
b1 = ((c1 & 0x1F) * 527 + 23) >> 6;
refColors[1] = 0xFF000000 | (b1 << 16) | (g1 << 8) | r1;
if (c0 > c1 || onlyOpaqueMode) { /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */
/* color_2 = 2/3*color_0 + 1/3*color_1
color_3 = 1/3*color_0 + 2/3*color_1 */
r = ((2 * r0 + r1) * 351 + 61) >> 7;
g = ((2 * g0 + g1) * 2763 + 1039) >> 11;
b = ((2 * b0 + b1) * 351 + 61) >> 7;
r = (2 * r0 + r1 + 1) / 3;
g = (2 * g0 + g1 + 1) / 3;
b = (2 * b0 + b1 + 1) / 3;
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
r = ((r0 + r1 * 2) * 351 + 61) >> 7;
g = ((g0 + g1 * 2) * 2763 + 1039) >> 11;
b = ((b0 + b1 * 2) * 351 + 61) >> 7;
r = (r0 + 2 * r1 + 1) / 3;
g = (g0 + 2 * g1 + 1) / 3;
b = (b0 + 2 * b1 + 1) / 3;
refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r;
} else { /* Quite rare BC1A mode */
/* color_2 = 1/2*color_0 + 1/2*color_1;
color_3 = 0; */
r = ((r0 + r1) * 1053 + 125) >> 8;
g = ((g0 + g1) * 4145 + 1019) >> 11;
b = ((b0 + b1) * 1053 + 125) >> 8;
r = (r0 + r1 + 1) >> 1;
g = (g0 + g1 + 1) >> 1;
b = (b0 + b1 + 1) >> 1;
refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
refColors[3] = 0x00000000;
@@ -219,19 +190,19 @@ static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompr
if (alpha[0] > alpha[1]) {
/* 6 interpolated alpha values. */
alpha[2] = (6 * alpha[0] + alpha[1]) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */
alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */
alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */
alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */
alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */
alpha[7] = ( alpha[0] + 6 * alpha[1]) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */
alpha[2] = (6 * alpha[0] + alpha[1] + 1) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */
alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 1) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */
alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 1) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */
alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 1) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */
alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 1) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */
alpha[7] = ( alpha[0] + 6 * alpha[1] + 1) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */
}
else {
/* 4 interpolated alpha values. */
alpha[2] = (4 * alpha[0] + alpha[1]) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */
alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */
alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */
alpha[5] = ( alpha[0] + 4 * alpha[1]) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */
alpha[2] = (4 * alpha[0] + alpha[1] + 1) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */
alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 1) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */
alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 1) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */
alpha[5] = ( alpha[0] + 4 * alpha[1] + 1) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */
alpha[6] = 0x00;
alpha[7] = 0xFF;
}
@@ -247,117 +218,6 @@ static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompr
}
}
#ifdef BCDEC_BC4BC5_PRECISE
static void bcdec__bc4_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize, int isSigned) {
signed char* sblock;
unsigned char* ublock;
int alpha[8];
int i, j;
unsigned long long block, indices;
static int aWeights4[4] = { 13107, 26215, 39321, 52429 };
static int aWeights6[6] = { 9363, 18724, 28086, 37450, 46812, 56173 };
block = *(unsigned long long*)compressedBlock;
if (isSigned) {
alpha[0] = (char)(block & 0xFF);
alpha[1] = (char)((block >> 8) & 0xFF);
if (alpha[0] < -127) alpha[0] = -127; /* -128 clamps to -127 */
if (alpha[1] < -127) alpha[1] = -127; /* -128 clamps to -127 */
} else {
alpha[0] = block & 0xFF;
alpha[1] = (block >> 8) & 0xFF;
}
if (alpha[0] > alpha[1]) {
/* 6 interpolated alpha values. */
alpha[2] = (aWeights6[5] * alpha[0] + aWeights6[0] * alpha[1] + 32768) >> 16; /* 6/7*alpha_0 + 1/7*alpha_1 */
alpha[3] = (aWeights6[4] * alpha[0] + aWeights6[1] * alpha[1] + 32768) >> 16; /* 5/7*alpha_0 + 2/7*alpha_1 */
alpha[4] = (aWeights6[3] * alpha[0] + aWeights6[2] * alpha[1] + 32768) >> 16; /* 4/7*alpha_0 + 3/7*alpha_1 */
alpha[5] = (aWeights6[2] * alpha[0] + aWeights6[3] * alpha[1] + 32768) >> 16; /* 3/7*alpha_0 + 4/7*alpha_1 */
alpha[6] = (aWeights6[1] * alpha[0] + aWeights6[4] * alpha[1] + 32768) >> 16; /* 2/7*alpha_0 + 5/7*alpha_1 */
alpha[7] = (aWeights6[0] * alpha[0] + aWeights6[5] * alpha[1] + 32768) >> 16; /* 1/7*alpha_0 + 6/7*alpha_1 */
} else {
/* 4 interpolated alpha values. */
alpha[2] = (aWeights4[3] * alpha[0] + aWeights4[0] * alpha[1] + 32768) >> 16; /* 4/5*alpha_0 + 1/5*alpha_1 */
alpha[3] = (aWeights4[2] * alpha[0] + aWeights4[1] * alpha[1] + 32768) >> 16; /* 3/5*alpha_0 + 2/5*alpha_1 */
alpha[4] = (aWeights4[1] * alpha[0] + aWeights4[2] * alpha[1] + 32768) >> 16; /* 2/5*alpha_0 + 3/5*alpha_1 */
alpha[5] = (aWeights4[0] * alpha[0] + aWeights4[3] * alpha[1] + 32768) >> 16; /* 1/5*alpha_0 + 4/5*alpha_1 */
alpha[6] = isSigned ? -127 : 0;
alpha[7] = isSigned ? 127 : 255;
}
indices = block >> 16;
if (isSigned) {
sblock = (char*)decompressedBlock;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
sblock[j * pixelSize] = (char)alpha[indices & 0x07];
indices >>= 3;
}
sblock += destinationPitch;
}
} else {
ublock = (unsigned char*)decompressedBlock;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
ublock[j * pixelSize] = (unsigned char)alpha[indices & 0x07];
indices >>= 3;
}
ublock += destinationPitch;
}
}
}
static void bcdec__bc4_block_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize, int isSigned) {
float* decompressed;
float alpha[8];
int i, j;
unsigned long long block, indices;
block = *(unsigned long long*)compressedBlock;
decompressed = (float*)decompressedBlock;
if (isSigned) {
alpha[0] = (float)((char)(block & 0xFF)) / 127.0f;
alpha[1] = (float)((char)((block >> 8) & 0xFF)) / 127.0f;
if (alpha[0] < -1.0f) alpha[0] = -1.0f; /* -128 clamps to -127 */
if (alpha[1] < -1.0f) alpha[1] = -1.0f; /* -128 clamps to -127 */
} else {
alpha[0] = (float)(block & 0xFF) / 255.0f;
alpha[1] = (float)((block >> 8) & 0xFF) / 255.0f;
}
if (alpha[0] > alpha[1]) {
/* 6 interpolated alpha values. */
alpha[2] = (6.0f * alpha[0] + alpha[1]) / 7.0f; /* 6/7*alpha_0 + 1/7*alpha_1 */
alpha[3] = (5.0f * alpha[0] + 2.0f * alpha[1]) / 7.0f; /* 5/7*alpha_0 + 2/7*alpha_1 */
alpha[4] = (4.0f * alpha[0] + 3.0f * alpha[1]) / 7.0f; /* 4/7*alpha_0 + 3/7*alpha_1 */
alpha[5] = (3.0f * alpha[0] + 4.0f * alpha[1]) / 7.0f; /* 3/7*alpha_0 + 4/7*alpha_1 */
alpha[6] = (2.0f * alpha[0] + 5.0f * alpha[1]) / 7.0f; /* 2/7*alpha_0 + 5/7*alpha_1 */
alpha[7] = ( alpha[0] + 6.0f * alpha[1]) / 7.0f; /* 1/7*alpha_0 + 6/7*alpha_1 */
} else {
/* 4 interpolated alpha values. */
alpha[2] = (4.0f * alpha[0] + alpha[1]) / 5.0f; /* 4/5*alpha_0 + 1/5*alpha_1 */
alpha[3] = (3.0f * alpha[0] + 2.0f * alpha[1]) / 5.0f; /* 3/5*alpha_0 + 2/5*alpha_1 */
alpha[4] = (2.0f * alpha[0] + 3.0f * alpha[1]) / 5.0f; /* 2/5*alpha_0 + 3/5*alpha_1 */
alpha[5] = ( alpha[0] + 4.0f * alpha[1]) / 5.0f; /* 1/5*alpha_0 + 4/5*alpha_1 */
alpha[6] = isSigned ? -1.0f : 0.0f;
alpha[7] = 1.0f;
}
indices = block >> 16;
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
decompressed[j * pixelSize] = alpha[indices & 0x07];
indices >>= 3;
}
decompressed += destinationPitch;
}
}
#endif /* BCDEC_BC4BC5_PRECISE */
typedef struct bcdec__bitstream {
unsigned long long low;
unsigned long long high;
@@ -410,37 +270,15 @@ BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, in
bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4);
}
#ifndef BCDEC_BC4BC5_PRECISE
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 1);
#else
BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
bcdec__bc4_block(compressedBlock, decompressedBlock, destinationPitch, 1, isSigned);
#endif
}
#ifndef BCDEC_BC4BC5_PRECISE
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 2);
bcdec__smooth_alpha_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2);
#else
BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
bcdec__bc4_block(compressedBlock, decompressedBlock, destinationPitch, 2, isSigned);
bcdec__bc4_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2, isSigned);
#endif
}
#ifdef BCDEC_BC4BC5_PRECISE
BCDECDEF void bcdec_bc4_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
bcdec__bc4_block_float(compressedBlock, decompressedBlock, destinationPitch, 1, isSigned);
}
BCDECDEF void bcdec_bc5_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) {
bcdec__bc4_block_float(compressedBlock, decompressedBlock, destinationPitch, 2, isSigned);
bcdec__bc4_block_float(((char*)compressedBlock) + 8, ((float*)decompressedBlock) + 1, destinationPitch, 2, isSigned);
}
#endif /* BCDEC_BC4BC5_PRECISE */
/* http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend */
static int bcdec__extend_sign(int val, int bits) {
return (val << (32 - bits)) >> (32 - bits);
@@ -1431,6 +1269,8 @@ BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, in
#endif /* BCDEC_IMPLEMENTATION */
#endif /* BCDEC_HEADER_INCLUDED */
/* LICENSE:
This software is available under 2 licenses -- choose whichever you prefer.
+20 -59
View File
@@ -2,9 +2,6 @@
#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>
@@ -99,11 +96,6 @@ static uint conversion_resize(DDS_HEADER &dds_header)
// 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;
@@ -202,10 +194,9 @@ static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_D
return DDS_ERROR_NONE;
}
static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = false)
static size_t compute_dds_size(const DDS_HEADER &dds_header)
{
const uint block_sz = 4;
uint d_width = 0, d_height = 0, d_depth = 0;
uint d_width, d_height, d_depth;
size_t d_size = 0;
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
@@ -213,17 +204,6 @@ static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = f
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);
@@ -267,7 +247,6 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
int retval = DDS_ERROR_NONE;
int ct = DDS_UNCOMPRESSED;
int is_cubemap = 0;
bool convert = false;
if (img_cfp == NULL) {
@@ -358,9 +337,7 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
}
// maybe do conversion if format not supported
convert = conversion_needed(dds_header);
if (convert) {
if (conversion_needed(dds_header)) {
// switch to uncompressed format and reset vars
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
dds_header.ddspf.dwFlags |= DDPF_RGB;
@@ -382,7 +359,7 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
// stuff important info
if (size)
*size = compute_dds_size(dds_header, convert);
*size = compute_dds_size(dds_header);
if (bpp)
*bpp = get_bit_count(dds_header);
@@ -409,9 +386,6 @@ 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)
{
@@ -449,7 +423,7 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
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!!
size = compute_dds_size(dds_header);
// read in the data
if ( !conversion_needed(dds_header) ) {
@@ -473,28 +447,6 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
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) {
@@ -502,7 +454,7 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
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;
src += (d_width * d_height * d_depth);
}
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
@@ -512,14 +464,23 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
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);
dst = data + data_offset + ((i * d_width + j) * 4);
decompress_dds(src, dst, d_width * 4);
src += BLOCK_SIZE;
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
bcdec_bc7(src, dst, d_width * 4);
src += BCDEC_BC7_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT5) {
bcdec_bc3(src, dst, d_width * 4);
src += BCDEC_BC3_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
bcdec_bc1(src, dst, d_width * 4);
src += BCDEC_BC1_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT3) {
bcdec_bc2(src, dst, d_width * 4);
src += BCDEC_BC2_BLOCK_SIZE;
}
}
}
}
+78 -172
View File
@@ -37,6 +37,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
@@ -56,57 +57,32 @@ int Debris_num_submodels = 0;
particle::ParticleEffectHandle Debris_hit_particle;
#define DEBRIS_INDEX(dp) (static_cast<int>((dp)-Debris.data()))
#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()) {
@@ -143,13 +119,10 @@ void debris_init()
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
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
@@ -160,12 +133,6 @@ void debris_init()
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
@@ -248,7 +215,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 +266,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 +342,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);
}
}
}
@@ -450,32 +420,6 @@ 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;
@@ -608,10 +552,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 +582,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 +595,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 +616,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);
@@ -708,25 +650,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 +671,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 {
@@ -1031,9 +965,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 +979,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 +1016,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.
@@ -1229,7 +1162,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 +1197,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 );
}
}
}
@@ -1307,40 +1240,13 @@ void create_generic_debris(object* ship_objp, const vec3d* pos, float min_num_de
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];
}
+5 -11
View File
@@ -20,7 +20,7 @@ class object;
struct CFILE;
class model_draw_list;
#define MAX_DEBRIS_ARCS 8
#define MAX_DEBRIS_ARCS 8 // Must be less than MAX_ARC_EFFECTS in model.h
FLAG_LIST(Debris_Flags) {
Used,
@@ -30,12 +30,6 @@ FLAG_LIST(Debris_Flags) {
NUM_VALUES
};
struct debris_electrical_arc
{
vec3d endpoint_1;
vec3d endpoint_2;
TIMESTAMP timestamp; // When this times out, the spark goes away. Invalid is not used
};
typedef struct debris {
flagset<Debris_Flags> flags; // See DEBRIS_??? defines
@@ -49,15 +43,15 @@ typedef struct debris {
int model_num; // What model this uses
int model_instance_num; // What model instance this uses - needed for arcs
int submodel_num; // What submodel this uses
TIMESTAMP arc_next_time; // When the next damage/emp arc will be created.
TIMESTAMP next_fireball; // When to start a fireball
bool is_hull; // indicates whether this is a collideable, destructable piece of debris from the model, or just a generic debris fragment
float max_hull;
int species; // What species this is from. -1 if don't care.
TIMESTAMP arc_timeout; // timestamp that holds time for arcs to stop appearing
TIMESTAMP fire_timeout; // timestamp that holds time for fireballs to stop appearing
TIMESTAMP sound_delay; // timestamp to signal when sound should start
fix time_started; // time when debris was created
SCP_vector<debris_electrical_arc> electrical_arcs;
vec3d arc_pts[MAX_DEBRIS_ARCS][2]; // The endpoints of each arc
TIMESTAMP arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. Invalid is not used
int arc_frequency; // Starts at 1000, gets bigger
int parent_alt_name;
+1 -1
View File
@@ -467,7 +467,7 @@ void dc_putc(char c)
*/
temp_str = line_str->substr(lastwhite);
line_str->resize(lastwhite);
dc_buffer.push_back(std::move(temp_str));
dc_buffer.push_back(temp_str);
line_str = &dc_buffer.back();
if ((dc_buffer.size() > DROWS) && (dc_scroll_y < SCROLL_Y_MAX)) {
+2 -2
View File
@@ -1083,7 +1083,7 @@ void dc_stuff_int(int *i)
value_l = dc_parse_long(token.c_str(), DCT_INT);
if ((value_l < INT_MAX) && (value_l > INT_MIN)) {
*i = static_cast<int>(value_l);
*i = value_l;
} else {
throw errParse(token.c_str(), DCT_INT);
@@ -1101,7 +1101,7 @@ void dc_stuff_uint(uint *i)
value_l = dc_parse_long(Cp, DCT_INT);
if (value_l < UINT_MAX) {
*i = static_cast<uint>(value_l);
*i = value_l;
} else {
throw errParse(token.c_str(), DCT_INT);
+90 -123
View File
@@ -181,61 +181,66 @@ void parse_decals_table(const char* filename) {
}
}
Decal::Decal() {
vm_vec_make(&scale, 1.f, 1.f, 1.f);
}
struct Decal {
int definition_handle = -1;
object_h object;
int orig_obj_type = OBJ_NONE;
int submodel = -1;
void Decal::markForDeletion() {
orig_obj_type = OBJ_NONE;
}
float creation_time = -1.0f; //!< The mission time at which this decal was created
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
bool Decal::isValid() const {
if (!object.isValid()) {
return false;
}
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
return false;
vec3d position = vmd_zero_vector;
vec3d scale;
matrix orientation = vmd_identity_matrix;
Decal() {
vm_vec_make(&scale, 1.f, 1.f, 1.f);
}
if (orig_obj_type == OBJ_NONE) {
//Decal should be cleared
return false;
}
if (orig_obj_type != object.objp()->type) {
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
return false;
}
if (lifetime > 0.0f) {
if (f2fl(Missiontime) >= creation_time + lifetime) {
// Decal has expired
bool isValid() const {
if (!object.isValid()) {
return false;
}
}
auto objp = object.objp();
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models,
"Invalid submodel number detected!");
auto smi = &model_instance->submodel[submodel];
if (smi->blown_off) {
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
return false;
}
} else {
Assertion(false, "Only ships are currently supported for decals!");
return false;
if (orig_obj_type != object.objp()->type) {
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
return false;
}
if (lifetime > 0.0f) {
if (f2fl(Missiontime) >= creation_time + lifetime) {
// Decal has expired
return false;
}
}
auto objp = object.objp();
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models,
"Invalid submodel number detected!");
auto smi = &model_instance->submodel[submodel];
if (smi->blown_off) {
return false;
}
} else {
Assertion(false, "Only ships are currently supported for decals!");
return false;
}
return true;
}
};
return true;
}
SCP_vector<Decal> active_decals, active_single_frame_decals;
SCP_vector<Decal> active_decals;
bool required_string_if_new(const char* token, bool new_entry) {
if (!new_entry) {
@@ -365,11 +370,7 @@ void initializeMission() {
active_decals.clear();
}
// Discard any fragments where the angle to the direction to greater than 45°
const float DECAL_ANGLE_CUTOFF = fl_radians(45.f);
const float DECAL_ANGLE_FADE_START = fl_radians(30.f);
static matrix4 getDecalTransform(const Decal& decal, float alpha) {
matrix4 getDecalTransform(Decal& decal) {
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
auto objp = decal.object.objp();
@@ -404,62 +405,11 @@ static matrix4 getDecalTransform(const Decal& decal, float alpha) {
matrix4 mat4;
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
// This is currently a constant but in the future this may be configurable by the decals table
mat4.a2d[0][3] = DECAL_ANGLE_CUTOFF;
mat4.a2d[1][3] = DECAL_ANGLE_FADE_START;
mat4.a2d[2][3] = alpha;
return mat4;
}
inline static void renderDecal(graphics::decal_draw_list& draw_list, const Decal& decal) {
auto mission_time = f2fl(Missiontime);
int diffuse_bm = -1;
int glow_bm = -1;
int normal_bm = -1;
auto decal_time = mission_time - decal.creation_time;
auto progress = decal_time / decal.lifetime;
float alpha = 1.0f;
if (progress > 0.8) {
// Fade the decal out for the last 20% of its lifetime
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
}
if (std::holds_alternative<int>(decal.definition_handle)) {
int definition_handle = std::get<int>(decal.definition_handle);
Assertion(definition_handle >= 0 && definition_handle < (int) DecalDefinitions.size(),
"Invalid decal handle detected!");
auto &decalDef = DecalDefinitions[definition_handle];
if (decalDef.getDiffuseBitmap() >= 0) {
diffuse_bm = decalDef.getDiffuseBitmap()
+
bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
}
if (decalDef.getGlowBitmap() >= 0) {
glow_bm = decalDef.getGlowBitmap()
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
}
if (decalDef.getNormalBitmap() >= 0) {
normal_bm = decalDef.getNormalBitmap()
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
}
}
else {
std::tie(diffuse_bm, glow_bm, normal_bm) = std::get<std::tuple<int, int, int>>(decal.definition_handle);
}
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha));
}
void renderAll() {
if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) {
if (!Decal_system_active || !Decal_option_active) {
return;
}
@@ -482,21 +432,51 @@ void renderAll() {
++iter;
}
if (active_decals.empty() && active_single_frame_decals.empty()) {
if (active_decals.empty()) {
return;
}
auto mission_time = f2fl(Missiontime);
graphics::decal_draw_list draw_list(active_decals.size());
for (auto& decal : active_decals) {
graphics::decal_draw_list draw_list;
for (auto& decal : active_decals)
renderDecal(draw_list, decal);
for (auto& decal : active_single_frame_decals)
renderDecal(draw_list, decal);
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(),
"Invalid decal handle detected!");
auto& decalDef = DecalDefinitions[decal.definition_handle];
int diffuse_bm = -1;
int glow_bm = -1;
int normal_bm = -1;
auto decal_time = mission_time - decal.creation_time;
auto progress = decal_time / decal.lifetime;
float alpha = 1.0f;
if (progress > 0.8) {
// Fade the decal out for the last 20% of its lifetime
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
}
if (decalDef.getDiffuseBitmap() >= 0) {
diffuse_bm = decalDef.getDiffuseBitmap()
+ bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
}
if (decalDef.getGlowBitmap() >= 0) {
glow_bm = decalDef.getGlowBitmap()
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
}
if (decalDef.getNormalBitmap() >= 0) {
normal_bm = decalDef.getNormalBitmap()
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
}
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal), alpha);
}
draw_list.render();
active_single_frame_decals.clear();
}
void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
@@ -541,17 +521,4 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d
active_decals.push_back(newDecal);
}
void addSingleFrameDecal(Decal&& info) {
active_single_frame_decals.push_back(info);
}
void invalidateForShip(const ship* shipp) {
int objnum = shipp->objnum;
for (Decal& decal : active_decals) {
if (decal.object.objnum == objnum) {
decal.markForDeletion();
}
}
}
}
-25
View File
@@ -50,27 +50,6 @@ class DecalDefinition {
bool isNormalLooping() const;
};
struct Decal {
//DecalDefinition idx vs immediate diffuse/glow/normal
std::variant<int, std::tuple<int, int, int>> definition_handle = -1;
object_h object;
int orig_obj_type = OBJ_NONE;
int submodel = -1;
float creation_time = -1.0f; //!< The mission time at which this decal was created
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
vec3d position = vmd_zero_vector;
vec3d scale;
matrix orientation = vmd_identity_matrix;
Decal();
void markForDeletion();
bool isValid() const;
};
extern SCP_vector<DecalDefinition> DecalDefinitions;
extern bool Decal_system_active;
extern bool Decal_option_active;
@@ -160,8 +139,4 @@ void addDecal(creation_info& info,
const vec3d& local_pos,
const matrix& local_orient);
void addSingleFrameDecal(Decal&& info);
void invalidateForShip(const ship* shipp);
}
+5 -8
View File
@@ -65,7 +65,7 @@ $Max Player Attackers: 2, 3, 4, 5, 99
;; maximum number of active (i.e. 'thrown') asteroids that can be
;; heading toward a friendly ship at any given time
$Max Incoming Asteroids: 3, 4, 5, 7, 10
$Max Incoming Asteroids: 3, 4, 5, 7, 10
;; factor applied to damage suffered by the player
$Player Damage Factor: 0.25, 0.5, 0.65, 0.85, 1
@@ -181,8 +181,9 @@ $Player Autoaim FOV: 0, 0, 0, 0, 0
$Detail Distance Multiplier: 0.125, 0.25, 1.0, 4.0, 8.0
;; General AI-related flags. These were previously all lumped together
;; under the New AI mission flag.
;; under the New AI mission flag.
;; if set, big ships can attack a beam turret that's firing on them
;; from a ship that they don't currently have targeted.
$big ships can attack beam turrets on untargeted ships: NO
@@ -353,10 +354,6 @@ $no warp camera: NO
;; If set, this flag overrides the retail behavior whereby a ship
;; assigned to guard a ship in a wing will instead guard the entire wing
$ai guards specific ship in wing: NO
;; maximum number of allies allowed to be rearming at the same time
;; before the AI will hold off on requesting support
$max allies rearming threshold: 2
$ai guards specific ship in wing: NO
#End
+23 -11
View File
@@ -10,12 +10,6 @@ out vec4 fragOut0; // Diffuse buffer
out vec4 fragOut1; // Normal buffer
out vec4 fragOut2; // Emissive buffer
flat in mat4 invModelMatrix;
flat in vec3 decalDirection;
flat in float normal_angle_cutoff;
flat in float angle_fade_start;
flat in float alpha_scale;
uniform sampler2D gDepthBuffer;
uniform sampler2D gNormalBuffer;
@@ -29,15 +23,24 @@ layout (std140) uniform decalGlobalData {
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
int diffuse_blend_mode;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
@@ -74,7 +77,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
#endif
//Calculate angle between surface normal and decal direction
float angle = acos(dot(normal, decalDirection));
float angle = acos(dot(normal, decal_direction));
if (angle > normal_angle_cutoff) {
// The angle between surface normal and decal direction is too big
@@ -88,7 +91,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
}
vec2 getDecalTexCoord(vec3 view_pos, inout float alpha) {
vec4 object_pos = invModelMatrix * invViewMatrix * vec4(view_pos, 1.0);
vec4 object_pos = inv_model_matrix * invViewMatrix * vec4(view_pos, 1.0);
bvec3 invalidComponents = greaterThan(abs(object_pos.xyz), vec3(0.5));
bvec4 nanComponents = isnan(object_pos); // nan can happen some times if we have an infinite depth value
@@ -108,7 +111,6 @@ void main() {
vec3 frag_position = computeViewPosition(gl_FragCoord.xy);
float alpha = alpha_scale;
vec2 tex_coord = getDecalTexCoord(frag_position, alpha);
vec3 binormal;
@@ -132,6 +134,16 @@ void main() {
// Additive blending
diffuse_out = vec4(color.rgb * alpha, 1.0);
}
// The main model shader applies ambient lighting by drawing the ambient part of the texture into the emissive
// texture. We do the same here to make sure the decal material is applied correctly
if (glow_blend_mode == 0) {
// Normal alpha blending
emissive_out = vec4(color.rgb * ambientLight, color.a * alpha);
} else {
// Additive blending
emissive_out = vec4(alpha * color.rgb * ambientLight, 1.0);
}
}
if (glow_index >= 0) {
+12 -21
View File
@@ -1,12 +1,5 @@
in vec4 vertPosition;
in mat4 vertModelMatrix;
flat out mat4 invModelMatrix;
flat out vec3 decalDirection;
flat out float normal_angle_cutoff;
flat out float angle_fade_start;
flat out float alpha_scale;
layout (std140) uniform decalGlobalData {
mat4 viewMatrix;
@@ -14,29 +7,27 @@ layout (std140) uniform decalGlobalData {
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
int diffuse_blend_mode;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
void main() {
normal_angle_cutoff = vertModelMatrix[0][3];
angle_fade_start = vertModelMatrix[1][3];
alpha_scale = vertModelMatrix[2][3];
mat4 modelMatrix = vertModelMatrix;
modelMatrix[0][3] = 0.0;
modelMatrix[1][3] = 0.0;
modelMatrix[2][3] = 0.0;
invModelMatrix = inverse(modelMatrix);
decalDirection = mat3(viewMatrix) * modelMatrix[2].xyz;
gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition;
gl_Position = projMatrix * viewMatrix * model_matrix * vertPosition;
}
@@ -7,7 +7,7 @@ out vec4 fragOut5;
void main()
{
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
fragOut1 = vec4(0.0, 0.0, -1000000.0, 0.0); // position
fragOut1 = vec4(0.0, 0.0, -1000000.0, 1.0); // position
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
+27 -95
View File
@@ -1,8 +1,7 @@
//? #version 150
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "shadows.sdr" //! #include "shadows.sdr"
#include "z-compress.sdr" //! #include "z-compress.sdr"
out vec4 fragOut0;
@@ -12,11 +11,6 @@ uniform sampler2D PositionBuffer;
uniform sampler2D SpecBuffer;
uniform sampler2DArray shadow_map;
#ifdef ENV_MAP
uniform samplerCube sEnvmap;
uniform samplerCube sIrrmap;
#endif
layout (std140) uniform globalDeferredData {
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
@@ -103,7 +97,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
discard;
}
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
}
else if (lightType == LT_TUBE) { // Tube light
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
vec3 beamDir = normalize(beamVec);
@@ -144,7 +138,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
discard;
}
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
}
else if (lightType == LT_CONE) {
lightDirOut = lightPosition - position.xyz;
float coneDot = dot(normalize(-lightDirOut), coneDir);
@@ -171,108 +165,46 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
}
}
#ifdef ENV_MAP
void ComputeEnvLight(float alpha, float ao, vec3 light_dir, vec3 eyeDir, vec3 normal, vec4 baseColor, vec4 specColor, out vec3 envLight) {
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
// to determine the mip bias.
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
// so let s = (2/alpha^2 - 2)
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
float alphaSqr = alpha * alpha;
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
float mip_bias = REZ_BIAS - rough_bias;
// Sample light, using mip bias to blur it.
vec3 env_light_dir = vec3(modelViewMatrix * vec4(light_dir, 0.0));
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
vec3 halfVec = normal;
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
// or properly calculating IBL levels.
// Fresnel calculation as with standard lights.
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
// Pseudo-IBL, so use k_IBL
float k = alpha * alpha/ 2.0f;
float NdotL = max(dot(light_dir, normal),0);
float g1vNL = GeometrySchlickGGX(NdotL, k);
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
vec3 kD = vec3(1.0)-fresnel;
kD *= (vec3(1.0) - specColor.rgb);
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(modelViewMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * ao;
envLight = (specEnvLighting + diffEnvLighting) * baseColor.a;
}
#endif
void main()
{
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
vec4 position_buffer = texture(PositionBuffer, screenPos);
vec3 position = vec3(position_buffer.xy, uncompress_depth_value(position_buffer.z));
vec3 position = texture(PositionBuffer, screenPos).xyz;
if(abs(dot(position, position)) < nearPlane * nearPlane)
discard;
vec4 diffuse = texture(ColorBuffer, screenPos);
vec3 diffColor = diffuse.rgb;
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
vec4 normalData = texture(NormalBuffer, screenPos);
vec4 specColor = texture(SpecBuffer, screenPos);
// The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer
vec3 normal = normalize(normalData.xyz);
float gloss = normalData.a;
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
float alpha = roughness * roughness;
float fresnel = specColor.a;
vec3 eyeDir = normalize(-position);
vec3 lightDir;
float attenuation;
float area_normalisation;
vec3 reflectDir = reflect(-eyeDir, normal);
vec4 specColor = texture(SpecBuffer, screenPos);
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
if (enable_shadows) {
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
vec4 fragShadowUV[4];
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
neardist, veryneardist);
}
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
vec4 fragmentColor = vec4(1.0);
if (lightType == LT_AMBIENT) {
float ao = position_buffer.w;
fragmentColor.rgb = diffuseLightColor * diffColor * ao;
#ifdef ENV_MAP
vec3 envLight;
ComputeEnvLight(alpha, ao, reflectDir, eyeDir, normal, diffuse, specColor, envLight);
fragmentColor.rgb += envLight;
#endif
}
else {
float fresnel = specColor.a;
vec3 lightDir;
float attenuation;
float area_normalisation;
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
if (enable_shadows) {
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
vec4 fragShadowUV[4];
fragShadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, fragShadowPos);
fragShadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, fragShadowPos);
fragShadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, fragShadowPos);
fragShadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, fragShadowPos);
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowPos.z, fragShadowUV, fardist, middist,
neardist, veryneardist);
}
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
}
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
fragOut0 = max(fragmentColor, vec4(0.0));
}
+1 -1
View File
@@ -29,7 +29,7 @@ layout (std140) uniform lightData {
void main()
{
if (lightType == LT_DIRECTIONAL || lightType == LT_AMBIENT) {
if (lightType == LT_DIRECTIONAL) {
gl_Position = vec4(vertPosition.xyz, 1.0);
} else {
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
+1 -2
View File
@@ -1,6 +1,5 @@
#include "gamma.sdr"
#include "z-compress.sdr"
in float fragRadius;
in vec4 fragPosition;
@@ -39,7 +38,7 @@ void main()
float sceneDepthLinear;
float fragDepthLinear;
if ( linear_depth == 1 ) {
sceneDepthLinear = -uncompress_depth_value(sceneDepth.z);
sceneDepthLinear = -sceneDepth.z;
fragDepthLinear = -fragPosition.z;
} else {
sceneDepthLinear = ( 2.0 * farZ * nearZ ) / ( farZ + nearZ - sceneDepth.x * (farZ-nearZ) );
-6
View File
@@ -15,9 +15,6 @@ layout (std140) uniform genericData {
float fog_density;
float zNear;
float zFar;
float clip_inf_dist;
float clip_dist;
};
void main()
@@ -31,9 +28,6 @@ void main()
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
float skybox_compat_fake = step(1.0, depth_val);
view_depth = clamp(view_depth, 0.0, mix(clip_dist, clip_inf_dist, skybox_compat_fake));
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
-1
View File
@@ -3,7 +3,6 @@ const int LT_DIRECTIONAL = 0; // A light like a sun
const int LT_POINT = 1; // A point light, like an explosion
const int LT_TUBE = 2; // A tube light, like a fluorescent light
const int LT_CONE = 3; // A cone light, like a flood light
const int LT_AMBIENT = 4; // Directionless ambient light
const float SPEC_FACTOR_NO_SPEC_MAP = 0.1;
const float GLOW_MAP_INTENSITY = 1.5;
+79 -23
View File
@@ -2,7 +2,6 @@
#include "shadows.sdr" //! #include "shadows.sdr"
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "z-compress.sdr" //! #include "z-compress.sdr"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
@@ -33,14 +32,15 @@ layout (std140) uniform modelData {
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float outlineWidth;
float fogNear;
float fogDensity;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
@@ -50,7 +50,6 @@ layout (std140) uniform modelData {
int n_lights;
float defaultGloss;
//EXCLUSIVELY used for non-deferred rendering
vec3 ambientFactor;
int desaturate;
@@ -86,16 +85,22 @@ layout (std140) uniform modelData {
float fardist;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
float alphaMult;
int flags;
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
@@ -121,6 +126,10 @@ uniform sampler2DArray sGlowmap;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
uniform sampler2DArray sSpecmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
uniform samplerCube sEnvmap;
uniform samplerCube sIrrmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
uniform sampler2DArray sNormalmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
@@ -178,7 +187,7 @@ void GetLightInfo(int i, out vec3 lightDir, out float attenuation)
vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor)
{
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
vec3 lightAmbient = ambientFactor * aoFactor;
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactor; // ambientFactor^2 due to legacy OpenGL compatibility behavior
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
#pragma optionNV unroll all
@@ -333,7 +342,19 @@ void main()
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
// Ambient lighting still needs to be done since that counts as an "emissive" color
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
emissiveColor.rgb += baseColor.rgb * lightAmbient;
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
float shadow = 1.0;
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
@@ -347,6 +368,54 @@ void main()
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
// to determine the mip bias.
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
// so let s = (2/alpha^2 - 2)
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
float mip_bias = REZ_BIAS - rough_bias;
// Sample light, using mip bias to blur it.
vec3 light_dir = reflect(-eyeDir, normal);
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
vec3 halfVec = normal;
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
// or properly calculating IBL levels.
// Fresnel calculation as with standard lights.
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
// Pseudo-IBL, so use k_IBL
float k = alpha * alpha/ 2.0f;
float NdotL = max(dot(light_dir, normal),0);
float g1vNL = GeometrySchlickGGX(NdotL, k);
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
vec3 kD = vec3(1.0)-fresnel;
kD *= (vec3(1.0) - specColor.rgb);
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
@@ -376,10 +445,9 @@ void main()
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
// color.
float fogDensityFinal = clamp(1 - pow(fogDensity, vertIn.fogDist) , 0.0, 1.0);
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, fogDensityFinal);
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
specColor.rgb *= fogDensityFinal;
specColor.rgb *= vertIn.fogDist;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
@@ -415,22 +483,10 @@ void main()
baseColor.rgb += emissiveColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
glossData = 0;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
// If there is no lighting then we copy the color data so far into the emissive.
emissiveColor.rgb += baseColor.rgb;
aoFactors.x = 0;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
fragOut0 = baseColor;
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xy, compress_depth_value(vertIn.position.z), aoFactors.x);
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
+22 -2
View File
@@ -39,14 +39,15 @@ layout (std140) uniform modelData {
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float outlineWidth;
float fogNear;
float fogDensity;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
@@ -102,6 +103,10 @@ layout (std140) uniform modelData {
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
@@ -126,6 +131,10 @@ in VertexOutput {
} vertIn[];
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
@@ -163,12 +172,19 @@ out VertexOutput {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
vertOut.position = gl_in[vert].gl_Position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
vertOut.envReflect = vertIn[vert].envReflect;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
@@ -223,6 +239,10 @@ out VertexOutput {
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
vertOut.envReflect = vertIn[vert].envReflect;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
+14 -3
View File
@@ -34,14 +34,15 @@ layout (std140) uniform modelData {
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float outlineWidth;
float fogNear;
float fogDensity;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
@@ -101,6 +102,10 @@ uniform samplerBuffer transform_tex;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
@@ -188,8 +193,14 @@ void main()
vec3 b = cross(normal, t) * vertTangent.w;
vertOut.tangentMatrix = mat3(t, b, normal);
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
// Environment mapping reflection vector.
vec3 envReflect = reflect(normalize(position.xyz), normal);
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vertOut.fogDist = gl_Position.z - fogNear;
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
@@ -14,21 +14,22 @@ SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false)
SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false)
SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false)
SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false)
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 6) , false)
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 7) , false)
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 8) , false)
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 9), false)
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 10), false)
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 11), false)
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 12), false)
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 13), false)
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 14), false)
SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false)
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false)
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false)
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false)
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false)
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false)
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false)
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false)
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false)
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false)
#ifndef MODEL_SDR_FLAG_MODE_GLSL
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 15), true)
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 16), true)
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true)
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true)
#endif
+5 -11
View File
@@ -1,5 +1,3 @@
#include "z-compress.sdr"
in vec4 fragTexCoord;
out vec4 fragOut0;
out vec4 fragOut1;
@@ -34,7 +32,7 @@ float getMedianDist(ivec2 texel) {
float dists[4];
for(int i = 0; i < 4; i++) {
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 2)
@@ -53,7 +51,7 @@ float getMedianDist(ivec2 texel) {
float dists[8];
for(int i = 0; i < 8; i++) {
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 4)
@@ -84,7 +82,7 @@ float getMedianDist(ivec2 texel) {
float dists[16];
for(int i = 0; i < 16; i++) {
dists[i] = uncompress_depth_value(texelFetch(texPos, texel, i).z);
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 1)
@@ -147,7 +145,7 @@ float getMedianDist(ivec2 texel) {
float getMedianDist(ivec2 texel) {
float minDist = -1000000;
for(int i = 0; i < samples; i++) {
minDist = max(minDist, uncompress_depth_value(texelFetch(texPos, texel, i).z));
minDist = max(minDist, texelFetch(texPos, texel, i).z);
}
return minDist;
}
@@ -175,7 +173,6 @@ void main()
for(int i = 0; i < samples; i++) {
vec4 localPos = texelFetch(texPos, texel, i);
localPos.z = uncompress_depth_value(localPos.z);
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
//However, if the median distance is 0, only deal with current texel if it's local distance is 0 as well
float localWeight = max(step(-0.001, dist) * step(-0.001, localPos.z),
@@ -192,11 +189,8 @@ void main()
weight += localWeight;
}
pos /= weight;
pos.z = compress_depth_value(pos.z);
fragOut0 = color / weight;
fragOut1 = pos;
fragOut1 = pos / weight;
fragOut2 = vec4(normalize(normal.xyz), normal.a / weight);
fragOut3 = specular / weight;
fragOut4 = emissive / weight;
-8
View File
@@ -18,14 +18,6 @@ layout (std140) uniform genericData {
vec3 tint;
float dither;
// these are blank, valid slots for modders to create custom effects
// that can be defined in post_processing.tbl and coded below
vec3 custom_effect_vec3_a;
float custom_effect_float_a;
vec3 custom_effect_vec3_b;
float custom_effect_float_b;
};
void main()
+37 -44
View File
@@ -26,45 +26,48 @@ float sampleNoPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec
return computeShadowFactor(shadowDepth, sampleShadowMap(shadow_map, shadowUV[cascade].xy, vec2(0.0, 0.0), cascade, 1.0/1024.0), 0.05);
}
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4], bool cockpit_shadow_bias)
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4])
{
if(cascade > 3 || cascade < 0) return 1.0;
vec2 poissonDisc[16] = vec2[](
vec2(-0.76275, -0.3432573),
vec2(-0.5226235, -0.8277544),
vec2(-0.3780261, 0.01528688),
vec2(-0.7742821, 0.4245702),
vec2(0.04196143, -0.02622231),
vec2(-0.2974772, -0.4722782),
vec2(-0.516093, 0.71495),
vec2(-0.3257416, 0.3910343),
vec2(0.2705966, 0.6670476),
vec2(0.4918377, 0.1853267),
vec2(0.4428544, -0.6251478),
vec2(-0.09204347, 0.9267113),
vec2(0.391505, -0.2558275),
vec2(0.05605913, -0.7570801),
vec2(0.81772, -0.02475523),
vec2(0.6890262, 0.5191521)
);
vec2 poissonDisc[16];
poissonDisc[0] = vec2(-0.76275, -0.3432573);
poissonDisc[1] = vec2(-0.5226235, -0.8277544);
poissonDisc[2] = vec2(-0.3780261, 0.01528688);
poissonDisc[3] = vec2(-0.7742821, 0.4245702);
poissonDisc[4] = vec2(0.04196143, -0.02622231);
poissonDisc[5] = vec2(-0.2974772, -0.4722782);
poissonDisc[6] = vec2(-0.516093, 0.71495);
poissonDisc[7] = vec2(-0.3257416, 0.3910343);
poissonDisc[8] = vec2(0.2705966, 0.6670476);
poissonDisc[9] = vec2(0.4918377, 0.1853267);
poissonDisc[10] = vec2(0.4428544, -0.6251478);
poissonDisc[11] = vec2(-0.09204347, 0.9267113);
poissonDisc[12] = vec2(0.391505, -0.2558275);
poissonDisc[13] = vec2(0.05605913, -0.7570801);
poissonDisc[14] = vec2(0.81772, -0.02475523);
poissonDisc[15] = vec2(0.6890262, 0.5191521);
float maxUVOffset[4];
maxUVOffset[0] = 1.0/300.0;
maxUVOffset[1] = 1.0/250.0;
maxUVOffset[2] = 1.0/200.0;
maxUVOffset[3] = 1.0/200.0;
// default external shadows
// bias is a bit larger to only pick up larger geometry
// favors light over shadow to avoid flickering/spotty shadows
// compute Chebyshev per-sample to avoid halos from moment-averaging at occluder edges
float visibility = 0.0f;
for (int i=0; i<16; i++) {
vec2 shadow_sample = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[i], cascade, maxUVOffset[cascade]);
visibility += computeShadowFactor(shadowDepth, shadow_sample, cockpit_shadow_bias ? 0.01f : 0.1f);
}
return visibility * (1.0f/16.0f);
vec2 sum = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[0], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[1], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[2], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[3], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[4], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[5], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[6], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[7], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[8], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[9], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[10], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[11], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[12], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[13], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[14], cascade, maxUVOffset[cascade])*(1.0/16.0);
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[15], cascade, maxUVOffset[cascade])*(1.0/16.0);
return computeShadowFactor(shadowDepth, sum, 0.1);
}
float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth, vec4 shadowUV[4], float fardist,
@@ -83,20 +86,10 @@ float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth,
cascade_start_dist[3] = middist;
cascade_start_dist[4] = fardist;
if(cascade > 3 || cascade < 0) return 1.0;
bool cockpit_shadow_bias;
if (fardist < 50.0f) {
// internal cockpit shadows
cockpit_shadow_bias = true;
} else {
// default external shadows
cockpit_shadow_bias = false;
}
float dist_threshold = (cascade_start_dist[cascade+1] - cascade_start_dist[cascade])*0.2;
if(cascade_start_dist[cascade+1] - dist_threshold > depth)
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, cockpit_shadow_bias);
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, cockpit_shadow_bias), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV, cockpit_shadow_bias),
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV);
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV),
smoothstep(cascade_start_dist[cascade+1] - dist_threshold, cascade_start_dist[cascade+1], depth));
}
+6 -4
View File
@@ -100,6 +100,8 @@ void main()
vec3 sampleposition = position / nebSize + 0.5;
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
float stepsize_current = min(max(stepsize, volume_sample.x * udfScale), mintMax - stept);
#ifdef DO_EDGE_SMOOTHING
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
float stepcolor_alpha = volume_sample.a;
@@ -119,8 +121,6 @@ void main()
float stepcolor_alpha = volume_sample.a;
#endif
float stepsize_current = min(max(stepsize, step(stepcolor_alpha, 0.01) * volume_sample.x * udfScale), mintMax - stept);
float stepalpha = -(pow(alphalim, 1.0 / (opacitydistance / stepsize_current)) - 1.0f) * stepcolor_alpha;
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
if(stepcolor_alpha > 0.01)
@@ -151,7 +151,7 @@ void main()
//Emissive
cumnebdist += stepcolor_alpha * stepsize_current;
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0, 1);
vec3 stepcolor_emissive = emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity;
//Step finish
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
@@ -165,5 +165,7 @@ void main()
break;
}
fragOut0 = vec4(cumOMAlpha * color_in.rgb + ((1.0 - cumOMAlpha) * cumcolor), 1);
cumcolor += cumOMAlpha * color_in.rgb;
fragOut0 = vec4(cumcolor, 1);
}
@@ -1,89 +0,0 @@
float compress_depth_value(float linear) {
float linear_mult;
float exponent_mult;
float offset;
linear = max(-linear, 0.0);
if(linear < 10.0) {
//Special handling for very close values. For smooth shadows at very close distances, equidistant steps get too inaccurate.
//Scaling this down linearly will push more accuracy to closer distances. Due to the scaling, this does not lose accuracy
//at any point over the worse of uncompressed / z-compress, but it does trade the gained accuracy from compression at 10m
//distance for accuracy lost due to compression below 0.5m (roughly)
return linear * 0.01;
}
else if (linear < 100.0) {
linear_mult = 0.05550473078;
exponent_mult = 0.08493173544;
offset = 0.0;
}
else if (linear < 1570.0) {
linear_mult = 11.53589613947;
exponent_mult = 0.00793869919;
offset = 0.0;
}
else if (linear < 3000.0) {
linear_mult = -0.10000000000;
exponent_mult = 0.00928910863;
offset = 3000.0;
}
else if (linear < 10000.0) {
linear_mult = -0.10000000000;
exponent_mult = 0.00094912231;
offset = 3000.0;
}
else if (linear < 100000.0) {
linear_mult = -6.98947320727;
exponent_mult = 0.00007382062;
offset = 3000.0;
}
else {
linear_mult = -1000.0;
exponent_mult = log2(1000.0 / 65000.0) / (100000.0 - GLOBAL_FAR_Z);
offset = 100000.0;
}
return linear_mult * pow(2.0, (linear - offset) * exponent_mult);
}
float uncompress_depth_value(float compressed) {
float linear_mult;
float exponent_mult;
float offset;
if(compressed < -1000.0) {
linear_mult = -1000.0;
exponent_mult = log2(1000.0 / 65000.0) / (100000.0 - GLOBAL_FAR_Z);
offset = 100000.0;
}
else if (compressed < -10.0) {
linear_mult = -6.98947320727;
exponent_mult = 0.00007382062;
offset = 3000.0;
}
else if (compressed < -0.1) {
linear_mult = -0.10000000000;
exponent_mult = 0.00094912231;
offset = 3000.0;
}
else if (compressed < 0.0) {
linear_mult = -0.10000000000;
exponent_mult = 0.00928910863;
offset = 3000.0;
}
else if (compressed < 0.1) {
return compressed * -100.0;
}
else if (compressed < 20.0) {
linear_mult = 0.05550473078;
exponent_mult = 0.08493173544;
offset = 0.0;
}
else {
linear_mult = 11.53589613947;
exponent_mult = 0.00793869919;
offset = 0.0;
}
return -(log2(compressed / linear_mult) / exponent_mult + offset);
}
@@ -84,21 +84,3 @@ setmetatable(Globals, mt)
Globals.nullVec = ba.createVector(0, 0, 0)
Globals.zeroVec = Globals.nullVec
Globals.identityOrient = ba.createOrientationFromVectors(ba.createVector(0, 0, 1), ba.createVector(0, 1, 0), ba.createVector(1, 0, 0))
Globals.FSOObjectsTableMetatable = {
__newindex = function(tbl, key, value)
for k, v in pairs(tbl) do
if k == key then
rawset(tbl, k, value)
return
end
end
rawset(tbl, key, value)
end,
__index = function(tbl, key)
for k, v in pairs(tbl) do
if k == key then
return v
end
end
end
}
+7 -9
View File
@@ -53,9 +53,8 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Cargo
$Targetable as unscanned: YES
$Scannable by default: YES
$Name: Cargo
$Scannable: YES
$Max Debris Speed: 200
$FF Multiplier: 0.10
$EMP Multiplier: 10.0
@@ -111,9 +110,9 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "attack ship type" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "attack ship type" "depart" "disable subsys" )
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
@@ -139,9 +138,9 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "attack ship type" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "attack ship type" "depart" "disable subsys" )
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
@@ -157,8 +156,6 @@ $Praise Destruction: YES
$On Hotkey List: YES
$Target as Threat: YES
$Show Attack Direction: YES
$Targetable as unscanned: YES
$Scannable by default: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 2.0
@@ -189,6 +186,7 @@ $Praise Destruction: YES
$On Hotkey List: YES
$Target as Threat: YES
$Show Attack Direction: YES
$Scannable: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 1.75
Loaded 100 of 1581 files, more files were not shown because too many files have changed in this diff. Show more