mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a654272ea |
No files matched your search
@@ -5,7 +5,6 @@ modernize-*,\
|
||||
-modernize-make-unique,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-default-member-init,\
|
||||
-modernize-use-nodiscard,\
|
||||
-modernize-use-trailing-return-type,\
|
||||
-modernize-use-using,\
|
||||
performance-*,\
|
||||
|
||||
@@ -13,15 +13,9 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
name: Linux
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -51,18 +45,15 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
linux_zip:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -70,23 +61,17 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release-${{ matrix.arch }}
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug-${{ matrix.arch }}
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
- name: Fix permissions
|
||||
working-directory: ./builds
|
||||
shell: bash
|
||||
run: chmod 755 *.AppImage
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
working-directory: ./builds
|
||||
@@ -104,7 +89,7 @@ jobs:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -135,9 +120,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -152,13 +137,13 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
@@ -179,7 +164,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -199,12 +184,12 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -255,9 +240,9 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
@@ -302,7 +287,7 @@ jobs:
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -322,12 +307,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
|
||||
@@ -41,16 +41,10 @@ jobs:
|
||||
# Run this job for each configuration
|
||||
# The current config running is accesible with `matrix.configuration`
|
||||
configuration: [FastDebug, Release]
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
arch: x86_64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
name: Linux
|
||||
needs: create_release # Don't run this job until create_release is done and successful
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
@@ -82,7 +76,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
# Upload the url file for use with other runners
|
||||
# upload-artifact.inputs:
|
||||
# if-no-files-found=warn What to do if path fails to find any files.
|
||||
@@ -93,16 +87,13 @@ jobs:
|
||||
# 0 Use default retention policy of the repo
|
||||
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
linux_zip:
|
||||
name: Build Linux distribution zip
|
||||
needs: build_linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -112,30 +103,24 @@ jobs:
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release-${{ matrix.arch }}
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
# Grab the debug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug-${{ matrix.arch }}
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
- name: Fix permissions
|
||||
working-directory: ./builds
|
||||
shell: bash
|
||||
run: chmod 755 *.AppImage
|
||||
- name: Create Distribution package
|
||||
# Zip both builds together
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
# Stash the result to artifact filespace
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
@@ -155,7 +140,7 @@ jobs:
|
||||
simd: [SSE2, AVX]
|
||||
needs: create_release
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
# Checkout repo
|
||||
@@ -191,9 +176,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -208,13 +193,13 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
@@ -235,7 +220,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -259,13 +244,13 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -280,13 +265,13 @@ jobs:
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
|
||||
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
- name: Upload debug package
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.debug_name }}
|
||||
path: ${{ steps.generate_package.outputs.debug_path }}
|
||||
@@ -331,9 +316,9 @@ jobs:
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -372,7 +357,7 @@ jobs:
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -392,12 +377,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
@@ -413,7 +398,7 @@ jobs:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -51,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@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -68,12 +68,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
arch: [Win32, x64]
|
||||
simd: [SSE2]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -133,9 +133,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -150,13 +150,13 @@ jobs:
|
||||
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DFORCED_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -198,12 +198,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -254,9 +254,9 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
@@ -300,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@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
@@ -320,12 +320,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -20,15 +20,9 @@ jobs:
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Debug
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
|
||||
- configuration: Release
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=ON
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -80,7 +74,7 @@ jobs:
|
||||
compiler: [MSVC]
|
||||
arch: [Win32, x64]
|
||||
name: Windows
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Prepare Environment
|
||||
run: choco install ninja
|
||||
@@ -113,9 +107,9 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
@@ -139,11 +133,11 @@ 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 16 2019" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFORCED_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
fi
|
||||
@@ -208,9 +202,9 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected].1
|
||||
uses: humbletim/[email protected].0
|
||||
with:
|
||||
vulkan-query-version: 1.4.304.1
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
if: github.repository == 'scp-fs2open/fs2open.github.com'
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -66,8 +66,4 @@ jobs:
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl -X POST -d token=${{ env.coverity_token }} -d email=${{ env.coverity_email }} -d file_name="'cov-scan.tgz'" -d version=${{ github.ref }} -d description="Automatic GHA scan" 'https://scan.coverity.com/projects/870/builds/init' | tee response
|
||||
upload_url=$(jq -r '.url' response)
|
||||
build_id=$(jq -r '.build_id' response)
|
||||
curl -X PUT --header 'Content-Type: application/json' --upload-file cov-scan.tgz $upload_url
|
||||
curl -X PUT -d token=${{ env.coverity_token }} https://scan.coverity.com/projects/870/builds/$build_id/enqueue
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form file=@cov-scan.tgz --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
[submodule "cmake/external/rpavlik-cmake-modules"]
|
||||
path = cmake/external/rpavlik-cmake-modules
|
||||
url = https://github.com/rpavlik/cmake-modules.git
|
||||
url = https://github.com/asarium/cmake-modules.git
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/scp-fs2open/libRocket.git
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
|
||||
+6
-28
@@ -1,5 +1,5 @@
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.9)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.4)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Make sure the source and binary directory are not the sample
|
||||
@@ -47,6 +47,11 @@ endif()
|
||||
|
||||
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
# Check if the external modules exists
|
||||
IF(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules/launcher-templates")
|
||||
message(FATAL_ERROR "External submodules could not be found. Please make sure you have updated your submodules.")
|
||||
@@ -117,28 +122,13 @@ option(FSO_RELEASE_LOGGING "Enable logging output for release builds" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_FFMPEG "Enable the usage of FFmpeg for sound and custscenes" ON)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_DISCORD "Build with Discord support" ON)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
|
||||
IF(NOT APPLE)
|
||||
SET(OPENXR_BUILD_DEFAULT ON)
|
||||
ELSE()
|
||||
SET(OPENXR_BUILD_DEFAULT OFF)
|
||||
ENDIF()
|
||||
OPTION(FSO_BUILD_WITH_OPENXR "Build with OpenXR support" ${OPENXR_BUILD_DEFAULT})
|
||||
IF(FSO_BUILD_WITH_OPENXR AND APPLE)
|
||||
MESSAGE(WARNING "FSO_BUILD_WITH_OPENXR is ON. Not supported on macOS - setting to OFF.")
|
||||
SET(FSO_BUILD_WITH_OPENXR OFF CACHE BOOL "" FORCE)
|
||||
ENDIF()
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENXR_DEBUG "Enables debug option for OpenXR" OFF)
|
||||
|
||||
OPTION(FSO_USE_LTO "Build using LTO (only for release builds)" ON)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
@@ -149,11 +139,9 @@ mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
|
||||
mark_as_advanced(FORCE ENABLE_COTIRE)
|
||||
mark_as_advanced(FORCE FSO_RELEASE_LOGGING)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_FFMPEG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_DISCORD)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_DEBUG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_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/
|
||||
@@ -176,14 +164,6 @@ endif()
|
||||
|
||||
include(clang-tidy)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT LTO_AVAILABLE)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
message("Enabled LTO")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif (CMAKE_BUILD_TYPE STREQUAL "Release" AND FSO_USE_LTO AND LTO_AVAILABLE)
|
||||
|
||||
# This includes source code for some tools, either used in the build or also for something else
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
@@ -241,7 +221,5 @@ message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
message(STATUS "Release logging: ${FSO_RELEASE_LOGGING}")
|
||||
message(STATUS "With FFmpeg: ${FSO_BUILD_WITH_FFMPEG}")
|
||||
message(STATUS "With Discord: ${FSO_BUILD_WITH_DISCORD}")
|
||||
message(STATUS "With OpenGL: ${FSO_BUILD_WITH_OPENGL}")
|
||||
message(STATUS "With Vulkan: ${FSO_BUILD_WITH_VULKAN}")
|
||||
message(STATUS "With OpenXR: ${FSO_BUILD_WITH_OPENXR}")
|
||||
@@ -18,13 +18,8 @@ fi
|
||||
# branch
|
||||
BASE_COMMIT=$(git merge-base $1 $2)
|
||||
|
||||
# Note: Manually passing in the Vulkan flags that are normally provided by cmake (but are not so, here), to ensure
|
||||
# that the source files are checked with the actual configuration used.
|
||||
echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
|
||||
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
|
||||
-extra-arg="-DWITH_VULKAN" \
|
||||
-extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \
|
||||
-extra-arg="-DVK_NO_PROTOTYPES" \
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
@@ -21,13 +21,16 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
else
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2 -DUSE_STATIC_LIBCXX=ON"
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
|
||||
fi
|
||||
|
||||
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
|
||||
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
|
||||
# force clang to silently allow -static-libstdc++ flag
|
||||
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
|
||||
fi
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
|
||||
@@ -8,11 +8,11 @@ OS="$1"
|
||||
source $HERE/dist_functions.sh
|
||||
|
||||
if [ "$OS" = "Linux" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Linux-$ARCH.tar.gz" *
|
||||
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
|
||||
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Windows" ]; then
|
||||
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
|
||||
|
||||
|
||||
+5
-95
@@ -12,61 +12,6 @@ from subprocess import check_output
|
||||
MAX_PAGES = 100 # maximum number of PR pages to go through
|
||||
warnings = 0
|
||||
|
||||
label_scores = {
|
||||
"fred" : 6,
|
||||
"qtfred" : 6,
|
||||
"vr" : 6,
|
||||
"multi" : 6,
|
||||
"Lab" : 6,
|
||||
"pilot file" : 6,
|
||||
"scripting" : 6,
|
||||
"sexps" : 6,
|
||||
"ai" : 6,
|
||||
"controls" : 6,
|
||||
"HUD" : 6,
|
||||
"models" : 6,
|
||||
"sound" : 6,
|
||||
"graphics" : 6,
|
||||
"physics" : 6,
|
||||
"ui" : 6,
|
||||
"localization / translation" : 6,
|
||||
"optimization" : 6,
|
||||
"gameplay" : 5,
|
||||
"general modding" : 4,
|
||||
"fix" : 3,
|
||||
"enhancement" : 2,
|
||||
"backport" : 1,
|
||||
"cleanup" : 0
|
||||
}
|
||||
|
||||
label_to_category = {
|
||||
"fred" : "FRED",
|
||||
"qtfred" : "QtFRED",
|
||||
"vr" : "VR",
|
||||
"multi" : "Multiplayer",
|
||||
"Lab" : "Lab",
|
||||
"pilot file" : "Pilot File",
|
||||
"scripting" : "Scripting",
|
||||
"sexps" : "SEXPs",
|
||||
"ai" : "AI",
|
||||
"controls" : "Controls",
|
||||
"HUD" : "HUD",
|
||||
"models" : "Models",
|
||||
"sound" : "Sound",
|
||||
"graphics" : "Graphics",
|
||||
"physics" : "Physics",
|
||||
"ui" : "UI",
|
||||
"localization / translation" : "Localization",
|
||||
"optimization" : "Optimization",
|
||||
"gameplay" : "Gameplay",
|
||||
"general modding" : "General Modding",
|
||||
"fix" : "Fix",
|
||||
"enhancement" : "Enhancement",
|
||||
"backport" : "Backport",
|
||||
"cleanup" : "Cleanup",
|
||||
"misc" : "Misc."
|
||||
}
|
||||
|
||||
def get_last_page(response: requests.Response) -> int:
|
||||
"""
|
||||
@brief Extract the last page number from the response header
|
||||
@@ -95,33 +40,7 @@ def get_last_page(response: requests.Response) -> int:
|
||||
return MAX_PAGES
|
||||
else:
|
||||
return last_page
|
||||
|
||||
def label_score(label):
|
||||
try:
|
||||
return label_scores[label['name']]
|
||||
except KeyError:
|
||||
return -1
|
||||
|
||||
def get_label(labels) -> str:
|
||||
"""
|
||||
@brief Get the primary label from a list of labels
|
||||
|
||||
@param[in] labels The list of labels from a pull request
|
||||
|
||||
@returns The primary label to be used for sorting in the changelog
|
||||
"""
|
||||
if len(labels) < 1:
|
||||
return "misc"
|
||||
|
||||
# Sort the labels based on their score and grab the highest valued label
|
||||
name = sorted(labels, key=label_score, reverse=True)[0]['name']
|
||||
|
||||
# If a label couldn't be found, toss it into a miscellaneous bin
|
||||
if name not in label_scores:
|
||||
name = "misc"
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Retrieves a log of commit messages and attempts to pretty them into a human-readable format")
|
||||
@@ -219,16 +138,11 @@ def main():
|
||||
print("Found old pull #{} ({}), stopping loop...".format(pull['number'], pull['updated_at']))
|
||||
page = last_page + 1
|
||||
break
|
||||
|
||||
# If a label isn't in the changelog, create a bin for it
|
||||
label = get_label(pull['labels'])
|
||||
if label not in changelog:
|
||||
changelog[label] = {}
|
||||
|
||||
# Add the pull to the changelog, indexed by its pull.number
|
||||
if pull['number'] not in changelog[label]:
|
||||
if pull['number'] not in changelog:
|
||||
# only add if the key isn't there already
|
||||
changelog[label][pull['number']] = {
|
||||
changelog[pull['number']] = {
|
||||
"date": merge_date,
|
||||
"title": pull['title'],
|
||||
"labels": pull['labels'],
|
||||
@@ -244,13 +158,9 @@ def main():
|
||||
# 2021-09-28 | (#3661) Fix homing child weapons in niche circumstances
|
||||
print("Writing to change.log...")
|
||||
str = ''
|
||||
for label, pulls in dict(sorted(changelog.items())).items():
|
||||
str += "[size=18pt]{}[/size]\n".format(label_to_category[label])
|
||||
str += "[list]\n"
|
||||
for key, value in pulls.items():
|
||||
str += "[li](#{}) {} [/li]\n".format(key, value['title'])
|
||||
str += "[/list]\n\n"
|
||||
|
||||
for key, value in changelog.items():
|
||||
str += "{} | (#{}) {} \n".format(value['date'].strftime("%Y-%m-%d"), key, value['title'])
|
||||
|
||||
with open("change.log", "w") as file:
|
||||
file.write(str)
|
||||
|
||||
|
||||
+5
-9
@@ -7,8 +7,7 @@ import requests
|
||||
from file_list import ReleaseFile
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
LINUX_X64_KEY = "Linux-x86_64"
|
||||
LINUX_ARM64_KEY = "Linux-arm64"
|
||||
LINUX_KEY = "Linux"
|
||||
MACOSX_X64_KEY = "Mac-x86_64"
|
||||
MACOSX_ARM64_KEY = "Mac-arm64"
|
||||
WIN32_SSE2_KEY = "Win32-SSE2"
|
||||
@@ -35,8 +34,7 @@ metadata = {
|
||||
}
|
||||
|
||||
platforms = {
|
||||
LINUX_X64_KEY: 'linux',
|
||||
LINUX_ARM64_KEY: 'linux',
|
||||
LINUX_KEY: 'linux',
|
||||
MACOSX_X64_KEY: 'macosx',
|
||||
MACOSX_ARM64_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
@@ -46,8 +44,7 @@ platforms = {
|
||||
}
|
||||
|
||||
envs = {
|
||||
LINUX_X64_KEY: 'linux && x86_64',
|
||||
LINUX_ARM64_KEY: 'linux && arm64',
|
||||
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
|
||||
MACOSX_X64_KEY: 'macosx && x86_64',
|
||||
MACOSX_ARM64_KEY: 'macosx && arm64',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
@@ -116,7 +113,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
'filename': dest_fn
|
||||
})
|
||||
|
||||
if group.startswith('Linux') and fn.endswith('.AppImage'):
|
||||
if group == LINUX_KEY and fn.endswith('.AppImage'):
|
||||
if 'qtfred' in fn:
|
||||
if '-FASTDBG' in fn:
|
||||
label = 'QtFRED Debug'
|
||||
@@ -130,8 +127,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
label = None
|
||||
|
||||
props = {
|
||||
"arm64": "arm64" in fn,
|
||||
"x64": "x64" in fn,
|
||||
"x64": True, # All Linux builds are 64-bit
|
||||
"sse2": True, # Linux builds are forced to compile with SSE2 but not AVX
|
||||
"avx": False,
|
||||
"avx2": False,
|
||||
|
||||
@@ -44,10 +44,9 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
Don't want to deal with that? Use [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 20.04 LTS, GCC 9[/size]
|
||||
[b]x86_64:[/b] ${build(groups["Linux"].subFiles["x86_64"])}
|
||||
[b]arm64:[/b] ${build(groups["Linux"].subFiles["arm64"])}
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
|
||||
${build(groups["Linux"].mainFile)}
|
||||
|
||||
These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
|
||||
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
|
||||
|
||||
+14
-36
@@ -2,72 +2,50 @@
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
// Windows
|
||||
#define cpuid __cpuidex
|
||||
#define xgetbv _xgetbv
|
||||
#define cpuid __cpuid
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// GCC Inline Assembly
|
||||
void cpuid(int CPUInfo[4], int InfoType, int SubType){
|
||||
void cpuid(int CPUInfo[4],int InfoType){
|
||||
__asm__ __volatile__ (
|
||||
"cpuid":
|
||||
"=a" (CPUInfo[0]),
|
||||
"=b" (CPUInfo[1]),
|
||||
"=c" (CPUInfo[2]),
|
||||
"=d" (CPUInfo[3]) :
|
||||
"a" (InfoType),
|
||||
"c" (SubType)
|
||||
"a" (InfoType)
|
||||
);
|
||||
}
|
||||
|
||||
uint64_t xgetbv(uint32_t xcr) {
|
||||
uint32_t lower, higher;
|
||||
__asm__ __volatile__ (
|
||||
"xgetbv":
|
||||
"=a"(lower),
|
||||
"=d"(higher) :
|
||||
"c"(xcr)
|
||||
);
|
||||
return (static_cast<uint64_t>(higher) << static_cast<uint64_t>(32)) | static_cast<uint64_t>(lower);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
bool SSE = false;
|
||||
bool SSE2 = false;
|
||||
bool OSXSAVE = false;
|
||||
bool AVX = false;
|
||||
bool AVX2 = false;
|
||||
int SSE = false;
|
||||
int SSE2 = false;
|
||||
int AVX = false;
|
||||
int AVX2 = false;
|
||||
|
||||
int info[4];
|
||||
cpuid(info, 0, 0);
|
||||
cpuid(info, 0);
|
||||
int nIds = info[0];
|
||||
|
||||
// Detect Instruction Set
|
||||
if (nIds >= 1){
|
||||
cpuid(info, 0x00000001, 0);
|
||||
SSE = (info[3] & ((int)1 << 25)) != 0;
|
||||
SSE2 = (info[3] & ((int)1 << 26)) != 0;
|
||||
OSXSAVE = (info[2] & ((int)1 << 27)) != 0;
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
cpuid(info,0x00000001);
|
||||
SSE = (info[3] & ((int)1 << 25)) != 0;
|
||||
SSE2 = (info[3] & ((int)1 << 26)) != 0;
|
||||
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
}
|
||||
if (nIds >= 7){
|
||||
cpuid(info,0x00000007, 0);
|
||||
cpuid(info,0x00000007);
|
||||
AVX2 = (info[1] & ((int)1 << 5)) != 0;
|
||||
}
|
||||
|
||||
// Detect OS Support
|
||||
if (!OSXSAVE || (xgetbv(0) & 0x6) == 0) {
|
||||
AVX = false;
|
||||
AVX2 = false;
|
||||
}
|
||||
|
||||
if (AVX2)
|
||||
std::cout << "AVX2";
|
||||
else if(AVX)
|
||||
|
||||
@@ -24,19 +24,3 @@ set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
if (FSO_BUILD_WITH_DISCORD)
|
||||
message(WARNING "Discord support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_BUILD_WITH_DISCORD:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_BUILD_FRED2)
|
||||
message(WARNING "FRED2 support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_BUILD_FRED2:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_USE_SPEECH)
|
||||
message(WARNING "Speech support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_USE_SPEECH:BOOL=OFF")
|
||||
endif()
|
||||
|
||||
if (FSO_USE_VOICEREC)
|
||||
message(WARNING "Voice recognition support is not tested for cross-compilation. Here be dragons! To disable, set -DFSO_USE_VOICEREC:BOOL=OFF")
|
||||
endif()
|
||||
+1
-11
@@ -97,19 +97,9 @@ function(handle_embedded_files _target)
|
||||
set(INCLUDE_LIST "${INCLUDE_LIST}\n#include \"${HEADER_FILE}\"")
|
||||
set(ARRAY_ELEMENTS "${ARRAY_ELEMENTS}\n\t{ \"${_pathType}\", \"${FILE_NAME}\" , ${FIELD_NAME} , ${FIELD_NAME}_size },")
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(EMBEDFILE_PATH "EMBEDFILE-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to an embedfile of a cmake build for the host OS")
|
||||
IF(EMBEDFILE_PATH STREQUAL "EMBEDFILE-NOTFOUND")
|
||||
#This could, possibly, be configured to compile an embedfile using host compilation automatically, but that seems to be a challenge.
|
||||
message(FATAL_ERROR "A manual embedfile path must be configured for cross compilation. Set EMBEDFILE_PATH to the location of an embedfile executable, found in the build directories for the host OS.")
|
||||
ENDIF()
|
||||
ELSE(CMAKE_CROSSCOMPILING)
|
||||
SET(EMBEDFILE_PATH "embedfile")
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${ALL_OUTPUTS}
|
||||
COMMAND ${EMBEDFILE_PATH} "${_filePath}" "${_outputBasePath}" "${FIELD_NAME}"
|
||||
COMMAND embedfile "${_filePath}" "${_outputBasePath}" "${FIELD_NAME}"
|
||||
MAIN_DEPENDENCY "${_filePath}"
|
||||
COMMENT "Generating string file for ${_filePath}"
|
||||
)
|
||||
|
||||
@@ -19,20 +19,3 @@ else()
|
||||
set(IS_ARM64 TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IS_RISCV FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(riscv64|RISCV64|riscv32|RISCV32)")
|
||||
set(IS_RISCV TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv64|RISCV64|riscv32|RISCV32)")
|
||||
set(IS_RISCV TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IS_X86 FALSE)
|
||||
if (NOT IS_ARM64 AND NOT IS_RISCV)
|
||||
set(IS_X86 TRUE)
|
||||
endif()
|
||||
@@ -11,8 +11,7 @@ endif()
|
||||
|
||||
target_link_libraries(platform INTERFACE ${COCOA_LIBRARY})
|
||||
|
||||
# To support C++17 we need to target at least 10.13. maybe 10.14 for some rare features
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
|
||||
|
||||
SET(CMAKE_SKIP_RPATH FALSE)
|
||||
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
#cmakedefine01 IS_ARM64
|
||||
#cmakedefine01 IS_RISCV
|
||||
|
||||
#cmakedefine01 SCP_HAVE_STRCASECMP
|
||||
#cmakedefine01 SCP_HAVE_STRNCASECMP
|
||||
|
||||
@@ -13,6 +13,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
@@ -10,41 +10,8 @@ option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
|
||||
option(CLANG_USE_LIBCXX "Use libc++" OFF)
|
||||
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-pipe")
|
||||
set(CXX_BASE_FLAGS "-pipe")
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(CLANG_EXTENSIONS "-march=native")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
set(CLANG_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
|
||||
else ()
|
||||
message( FATAL_ERROR "Unknown instruction set encountered for clang. Update toolchain-clang.cmake!" )
|
||||
endif()
|
||||
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${CLANG_EXTENSIONS}")
|
||||
elseif(IS_ARM)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
|
||||
endif ()
|
||||
elseif(IS_RISCV)
|
||||
# Default C/CXX_BASE_FLAGS are fine for RISC-V
|
||||
endif()
|
||||
|
||||
if (USE_STATIC_LIBCXX)
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++ -Qunused-arguments")
|
||||
set(CLANG_USE_LIBCXX ON)
|
||||
endif()
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CXXFLAGS})
|
||||
@@ -68,6 +35,10 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "argument unused during compilation" when clang is used with ccache.
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Qunused-arguments")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
||||
# Force color diagnostics for Ninja generator
|
||||
@@ -116,16 +87,16 @@ endif()
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
|
||||
@@ -12,49 +12,8 @@ option(GCC_USE_GOLD "Use the gold linker instead of the standard linker" OFF)
|
||||
option(GCC_GENERATE_GDB_INDEX "Adds linker option to generate the gdb index for debug builds" OFF)
|
||||
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-pipe")
|
||||
set(CXX_BASE_FLAGS "-pipe")
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(GCC_EXTENSIONS "-march=native")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(GCC_EXTENSIONS "-march=x86-64")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
set(GCC_EXTENSIONS "-march=x86-64 -msse -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
set(GCC_EXTENSIONS "-march=x86-64 -msse -msse2 -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
set(GCC_EXTENSIONS "-march=x86-64-v2 -msse -msse2 -mavx -mfpmath=sse")
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
set(GCC_EXTENSIONS "-march=x86-64-v3 -msse -msse2 -mavx -mavx2 -mfpmath=sse")
|
||||
else ()
|
||||
message( FATAL_ERROR "Unknown instruction set encountered for GCC. Update toolchain-gcc.cmake!" )
|
||||
endif()
|
||||
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} ${GCC_EXTENSIONS}")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} ${GCC_EXTENSIONS}")
|
||||
|
||||
if (IS_64BIT)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -m64")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -m64")
|
||||
endif()
|
||||
elseif(IS_ARM)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
set(C_BASE_FLAGS "${C_BASE_FLAGS} -march=native")
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -march=native")
|
||||
endif ()
|
||||
elseif(IS_RISCV)
|
||||
# You do not need to pass a -march, passing nothing will make gcc to choose itself.
|
||||
# If you want a specific set of instructions like vectors, set -march in CFLAGS and CXXFLAGS env variables
|
||||
# Example for vectors: -march=rv64gcv
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html
|
||||
# As such, default C/CXX_BASE_FLAGS are sufficient.
|
||||
endif()
|
||||
|
||||
if (USE_STATIC_LIBCXX)
|
||||
set(CXX_BASE_FLAGS "${CXX_BASE_FLAGS} -static-libstdc++")
|
||||
endif()
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CFLAGS})
|
||||
@@ -158,16 +117,16 @@ endif()
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
# If no user-set opt flag, set -O3 and -Og
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O3")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O3")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
|
||||
+38
-20
@@ -95,31 +95,49 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
INCLUDE(MSVCMultipleProcessCompile)
|
||||
|
||||
# Visual Studio supports compiling for multiple vector instruction sets
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
|
||||
if(IS_X86)
|
||||
if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
|
||||
# MSVC has no direct -march=native equivalent, so just use the detected extensions.
|
||||
SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
|
||||
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
|
||||
|
||||
if(FSO_INSTRUCTION_SET STREQUAL "")
|
||||
set(MSVC_SIMD_INSTRUCTIONS "IA32")
|
||||
else()
|
||||
set(MSVC_SIMD_INSTRUCTIONS ${FSO_INSTRUCTION_SET})
|
||||
endif()
|
||||
SET(MSVC_SIMD_INSTRUCTIONS "${MSVC_DETECTED_SIMD_INSTRUCTIONS}" CACHE FILEPATH "The SIMD instructions which will be used, possible values are ${POSSIBLE_INSTUCTION_SETS}")
|
||||
MARK_AS_ADVANCED(FORCE MSVC_SIMD_INSTRUCTIONS)
|
||||
endif()
|
||||
set(FSO_INSTRUCTION_SET ${MSVC_SIMD_INSTRUCTIONS})
|
||||
|
||||
if (NOT (IS_64BIT AND (MSVC_SIMD_INSTRUCTIONS STREQUAL "IA32" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE2")))
|
||||
# 32-Bit and SSE(2) mustn't be set, as these are implied in x86_64 and thus MSVC does not support it for the /arch argument
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:${MSVC_SIMD_INSTRUCTIONS}" COMPILER_SUPPORTS_ARCH)
|
||||
LIST(FIND POSSIBLE_INSTUCTION_SETS "${MSVC_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
|
||||
ELSE()
|
||||
message( FATAL_ERROR "Your version of MSVC does not support the requested instruction set. Consider updating!" )
|
||||
ENDIF()
|
||||
endif()
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An invalid instruction set was specified, defaulting to no special compiler options.")
|
||||
else()
|
||||
IF (NOT SET_INDEX EQUAL 0)
|
||||
SET(FOUND)
|
||||
|
||||
FOREACH(list_index RANGE ${SET_INDEX} 1)
|
||||
list(GET POSSIBLE_INSTUCTION_SETS ${list_index} _simd_set)
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:${_simd_set}" COMPILER_SUPPORTS_ARCH_${_simd_set})
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH_${_simd_set})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${_simd_set}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${_simd_set}")
|
||||
|
||||
SET(FOUND TRUE)
|
||||
BREAK()
|
||||
ENDIF()
|
||||
ENDFOREACH(list_index)
|
||||
|
||||
IF(NOT FOUND)
|
||||
# Don't set anything, it will likely not work
|
||||
MESSAGE(STATUS "Your compiler does not support any optimization flags, defaulting to none")
|
||||
ENDIF(NOT FOUND)
|
||||
ELSE()
|
||||
CHECK_CXX_COMPILER_FLAG("/arch:IA32" COMPILER_SUPPORTS_ARCH_IA32)
|
||||
|
||||
IF(COMPILER_SUPPORTS_ARCH_IA32)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:IA32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:IA32")
|
||||
ENDIF(COMPILER_SUPPORTS_ARCH_IA32)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
|
||||
|
||||
@@ -5,55 +5,6 @@ add_library(compiler INTERFACE)
|
||||
|
||||
target_compile_definitions(compiler INTERFACE "$<$<CONFIG:Release>:NDEBUG>;$<$<CONFIG:Debug>:_DEBUG>;$<$<CONFIG:FastDebug>:_DEBUG>")
|
||||
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS ON CACHE BOOL "Override instruction set detection and compile with the maximum possible instructions for the current system.")
|
||||
IF(IS_X86)
|
||||
SET(POSSIBLE_INSTRUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
message("Cross-Compile cannot detect supported instruction sets. Defaulting to SSE2. Disabling host-optimization.")
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS OFF)
|
||||
set(DETECTED_SIMD_INSTRUCTIONS SSE2)
|
||||
else()
|
||||
detect_simd_instructions(DETECTED_SIMD_INSTRUCTIONS)
|
||||
endif()
|
||||
|
||||
set(FORCED_SIMD_INSTRUCTIONS "" CACHE STRING "Overrides any instruction set settings (including forced-native). Any of ${POSSIBLE_INSTRUCTION_SETS}.")
|
||||
if (NOT FORCED_SIMD_INSTRUCTIONS STREQUAL "")
|
||||
set(FORCED_NATIVE_SIMD_INSTRUCTIONS OFF)
|
||||
LIST(FIND POSSIBLE_INSTRUCTION_SETS "${FORCED_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An invalid instruction set was specified, defaulting to no special compiler options.")
|
||||
set(FSO_INSTRUCTION_SET "")
|
||||
else ()
|
||||
LIST(FIND POSSIBLE_INSTRUCTION_SETS "${DETECTED_SIMD_INSTRUCTIONS}" SET_INDEX)
|
||||
if (SET_INDEX LESS 0)
|
||||
MESSAGE(STATUS "An instruction set was specified which is unsupported on this platform. Compiled binary might not be executable.")
|
||||
endif()
|
||||
|
||||
set(FSO_INSTRUCTION_SET ${FORCED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
else()
|
||||
SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
|
||||
endif()
|
||||
MESSAGE(STATUS "Using instruction set level ${FSO_INSTRUCTION_SET}. Optimizations for host-system specifically: ${FORCED_NATIVE_SIMD_INSTRUCTIONS}.")
|
||||
|
||||
if (FSO_INSTRUCTION_SET STREQUAL "SSE")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "SSE2")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
add_compile_definitions(FSO_SIMD_AVX)
|
||||
elseif (FSO_INSTRUCTION_SET STREQUAL "AVX2")
|
||||
add_compile_definitions(FSO_SIMD_SSE)
|
||||
add_compile_definitions(FSO_SIMD_SSE2)
|
||||
add_compile_definitions(FSO_SIMD_AVX)
|
||||
add_compile_definitions(FSO_SIMD_AVX2)
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
include(toolchain-gcc)
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
+2
-8
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 24)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
@@ -35,13 +35,7 @@ ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
|
||||
ENDIF()
|
||||
|
||||
IF(IS_RISCV)
|
||||
IF(IS_64BIT)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv64")
|
||||
ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv32")
|
||||
ENDIF()
|
||||
ELSEIF(IS_ARM64)
|
||||
IF(IS_ARM64)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
|
||||
ELSEIF(IS_64BIT)
|
||||
# This is a 64-bit builds
|
||||
|
||||
+11
-12
@@ -6,7 +6,7 @@ INCLUDE(voice_rec.cmake)
|
||||
|
||||
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
|
||||
|
||||
target_compile_features(code PUBLIC cxx_std_17)
|
||||
target_compile_features(code PUBLIC cxx_std_11)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(code PUBLIC "PDB_DEBUGGING=1")
|
||||
@@ -25,11 +25,7 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR)
|
||||
add_definitions(-DFS_OPENXR)
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG AND FSO_BUILD_WITH_OPENXR)
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
add_definitions(-DFS_OPENXR_DEBUG)
|
||||
endif()
|
||||
|
||||
@@ -52,10 +48,7 @@ TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
target_link_libraries(code PUBLIC md5)
|
||||
|
||||
if (FSO_BUILD_WITH_DISCORD)
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
add_definitions(-DWITH_DISCORD)
|
||||
endif()
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
|
||||
target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
@@ -74,13 +67,19 @@ ENDIF(FSO_USE_SPEECH)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
|
||||
target_link_libraries(code PUBLIC variant)
|
||||
|
||||
target_link_libraries(code PUBLIC any)
|
||||
|
||||
target_link_libraries(code PUBLIC optional)
|
||||
|
||||
target_link_libraries(code PUBLIC anl)
|
||||
|
||||
target_link_libraries(code PUBLIC hidapi::hidapi)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
IF(FSO_BUILD_WITH_OPENXR)
|
||||
IF(NOT APPLE)
|
||||
target_link_libraries(code PUBLIC OpenXR::openxr_loader)
|
||||
target_include_directories(code PUBLIC OpenXR::Headers)
|
||||
ENDIF()
|
||||
@@ -140,4 +139,4 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[va
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
|
||||
|
||||
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
|
||||
suppress_file_warnings(scripting/lua/bitop/bit.c)
|
||||
suppress_file_warnings(scripting/lua/bitop/bit.c)
|
||||
@@ -122,9 +122,9 @@ class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
}
|
||||
antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext* context) override
|
||||
{
|
||||
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 xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto zExpression = visit(context->expression(2)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto expression = std::make_shared<nodes::VectorConstructorExpression>(context->L_PAREN()->getSymbol(),
|
||||
xExpression,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <variant>
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
@@ -85,10 +85,10 @@ class Value {
|
||||
|
||||
if (currentType == expectedType) {
|
||||
// No conversion necessary
|
||||
return std::get<T>(m_value);
|
||||
return mpark::get<T>(m_value);
|
||||
}
|
||||
|
||||
return std::visit(detail::implicit_conversion<T>{}, m_value);
|
||||
return mpark::visit(detail::implicit_conversion<T>{}, m_value);
|
||||
}
|
||||
|
||||
friend bool operator==(const Value& lhs, const Value& rhs);
|
||||
@@ -97,7 +97,7 @@ class Value {
|
||||
friend std::ostream& operator<<(std::ostream& os, const Value& value);
|
||||
|
||||
private:
|
||||
std::variant<std::monostate, int, float, vec3d, SCP_string> m_value;
|
||||
mpark::variant<mpark::monostate, int, float, vec3d, SCP_string> m_value;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
|
||||
@@ -26,8 +26,10 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
// The calling code should ensure that this never happens
|
||||
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
|
||||
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
const auto destinationSubObject = m_subObjectExpression.execute(locals.variables);
|
||||
@@ -55,7 +57,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
|
||||
// We need to do a linear search for the right subobject
|
||||
for (int i = 0; i < pm->n_models; ++i) {
|
||||
const auto& submodel = pm->submodel[i];
|
||||
const auto submodel = pm->submodel[i];
|
||||
|
||||
if (subsystem_stricmp(destinationSubObject.c_str(), submodel.name) == 0) {
|
||||
// Found something!
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "math/vecmat.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "particle/hosts/EffectHostObject.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
#include <utility>
|
||||
@@ -39,8 +37,10 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
@@ -58,11 +58,11 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
|
||||
matrix orientation;
|
||||
vm_vector_2_matrix_norm(&orientation, &direction); // direction is normalized in SetDirectionAction::execute
|
||||
|
||||
source->setHost(make_unique<EffectHostObject>(locals.host.objp(), local_pos, orientation, true));
|
||||
source->finishCreation();
|
||||
source.moveToObject(locals.host.objp(), &local_pos);
|
||||
source.setOrientationFromNormalizedVec(&direction, true);
|
||||
|
||||
source.finish();
|
||||
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
@@ -26,8 +26,10 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto pmi = object_get_model_instance(locals.host.objp());
|
||||
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
model_instance_local_to_global_point_orient(&local_pos,
|
||||
|
||||
+9
-10
@@ -36,7 +36,7 @@ typedef struct ai_flag_name {
|
||||
|
||||
typedef struct ai_flag_description {
|
||||
AI::AI_Flags flag;
|
||||
const char *flag_desc;
|
||||
SCP_string flag_desc;
|
||||
} ai_flag_description;
|
||||
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
@@ -96,7 +96,6 @@ extern const int Num_ai_flag_names;
|
||||
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
#define AI_ACTIVE_GOAL_NONE -1
|
||||
#define AI_ACTIVE_GOAL_DYNAMIC 999
|
||||
|
||||
typedef struct ai_class {
|
||||
@@ -277,8 +276,8 @@ typedef struct ai_info {
|
||||
int ai_class; // Class. Might be override of default.
|
||||
|
||||
// Probably become obsolete, to be replaced by path_start, path_cur, etc.
|
||||
int wp_list_index; // index of waypoint list being followed
|
||||
int wp_index; // index of waypoint in list
|
||||
waypoint_list *wp_list; // waypoint list being followed
|
||||
int wp_index; // waypoint index in list
|
||||
int wp_flags; // waypoint flags, see WPF_xxxx
|
||||
int waypoint_speed_cap; // -1 no cap, otherwise cap - changed to int by Goober5000
|
||||
|
||||
@@ -318,7 +317,7 @@ typedef struct ai_info {
|
||||
//Unlike the predicted position stuff, also takes into account velocity
|
||||
//Only used against small ships
|
||||
fix next_aim_pos_time;
|
||||
vec3d last_aim_enemy_pos; // Normally this is the position of the enemy a turret is targeting but in the F3 Lab, this is used to pass raw target coordinates to the turret firing methods.
|
||||
vec3d last_aim_enemy_pos;
|
||||
vec3d last_aim_enemy_vel;
|
||||
|
||||
ai_goal goals[MAX_AI_GOALS];
|
||||
@@ -330,7 +329,7 @@ typedef struct ai_info {
|
||||
float time_enemy_near; // SUSHI: amount of time enemy continuously "near" the player
|
||||
fix last_attack_time; // Missiontime of last time this ship attacked its enemy.
|
||||
fix last_hit_time; // Missiontime of last time this ship was hit by anyone.
|
||||
int danger_shield_quadrant; // Shield section AI will prefer to prioritize for recharging, it if possible.
|
||||
int last_hit_quadrant; // Shield section of last hit.
|
||||
fix last_hit_target_time; // Missiontime of last time this ship successfully hit target.
|
||||
int hitter_objnum; // Object index of ship that hit this ship last time.
|
||||
int hitter_signature; // Signature of hitter. Prevents stupidity if hitter gets killed.
|
||||
@@ -485,7 +484,7 @@ typedef struct {
|
||||
#define SUBSYS_PATH_DIST 500.0f
|
||||
|
||||
// Friendly damage defines
|
||||
#define MAX_BURST_DAMAGE 20.0f // max damage that can be done in BURST_DURATION
|
||||
#define MAX_BURST_DAMAGE 20 // max damage that can be done in BURST_DURATION
|
||||
#define BURST_DURATION 500 // decay time over which Player->damage_this_burst falls from MAX_BURST_DAMAGE to 0
|
||||
|
||||
extern int Mission_all_attack; // !0 means all teams attack all teams.
|
||||
@@ -534,8 +533,8 @@ extern void ai_ignore_wing(object *ignorer, int wingnum);
|
||||
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, int wl_index, int wp_flags, int start_index, bool force = false);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, const vec3d *hit_normal);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
|
||||
extern void ai_turn_towards_vector(const vec3d *dest, object *objp, const vec3d *slide_vec, const vec3d *rel_pos, float bank_override, int flags, const vec3d *rvec = nullptr, const vec3d* turnrate_mod = nullptr);
|
||||
@@ -636,6 +635,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
|
||||
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
|
||||
|
||||
|
||||
bool test_line_of_sight(const vec3d* from, const vec3d* to, SCP_unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
|
||||
#endif
|
||||
+3
-16
@@ -43,7 +43,7 @@ namespace AI {
|
||||
Dockee_index_valid, // when set, index field for dockee is valid
|
||||
Goal_on_hold, // when set, this goal cannot currently be satisfied, although it could be in the future
|
||||
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
|
||||
Goal_override, // paired with ai_goal_type::DYNAMIC to mean this goal overrides any other goal
|
||||
Goal_override, // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
|
||||
Purge, // purge this goal next time we process
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
@@ -101,10 +101,6 @@ namespace AI {
|
||||
Fix_heat_seeker_stealth_bug,
|
||||
Fix_linked_primary_bug,
|
||||
Fix_ramming_stationary_targets_bug,
|
||||
Fix_avoid_shockwave_bugs, // a) waiting until a homing weapon actually homes before evading;
|
||||
// b) picking the correct expected impact position for capships;
|
||||
// c) not clearing shockwave_object for ships;
|
||||
// d) checking the explosion damage of the correct ship
|
||||
Force_beam_turret_fov,
|
||||
Free_afterburner_use,
|
||||
Glide_decay_requires_thrust,
|
||||
@@ -141,11 +137,10 @@ namespace AI {
|
||||
All_nonshielded_ships_can_manage_ets,
|
||||
Fightercraft_nonshielded_ships_can_manage_ets,
|
||||
Ships_playing_dead_dont_manage_ets,
|
||||
Better_combat_collision_avoidance,
|
||||
Better_guard_collision_avoidance,
|
||||
Better_collision_avoidance,
|
||||
Require_exact_los,
|
||||
Improved_missile_avoidance,
|
||||
Unify_usage_countermeasure_firechance,
|
||||
Friendlies_use_countermeasure_firechance,
|
||||
Improved_subsystem_attack_pathing,
|
||||
Fixed_ship_weapon_collision,
|
||||
No_shield_damage_from_ship_collisions,
|
||||
@@ -170,14 +165,6 @@ namespace AI {
|
||||
Debris_respects_big_damage,
|
||||
Dont_limit_change_in_speed_due_to_physics_whack,
|
||||
Guards_ignore_protected_attackers,
|
||||
Standard_strafe_used_more,
|
||||
Unify_usage_ai_shield_manage_delay,
|
||||
Fix_AI_shield_management_bug,
|
||||
AI_balances_shields_when_attacked,
|
||||
Disable_ai_transferring_energy,
|
||||
Freespace_1_missile_behavior,
|
||||
ETS_uses_power_output,
|
||||
ETS_energy_same_regardless_of_system_presence,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+4
-76
@@ -377,7 +377,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
|
||||
if (optional_string("$Detail Distance Multiplier:"))
|
||||
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_VALUE + 1);
|
||||
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1);
|
||||
|
||||
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships);
|
||||
|
||||
@@ -582,25 +582,11 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
|
||||
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_combat_collision_avoidance);
|
||||
|
||||
if (optional_string("+combat collision avoidance aggression for fightercraft:")) {
|
||||
stuff_float(&profile->better_collision_avoid_aggression_combat);
|
||||
}
|
||||
|
||||
set_flag(profile, "$better guard collision avoidance for fightercraft:", AI::Profile_Flags::Better_guard_collision_avoidance);
|
||||
|
||||
if (optional_string("+guard collision avoidance aggression for fightercraft:")) {
|
||||
stuff_float(&profile->better_collision_avoid_aggression_guard);
|
||||
}
|
||||
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
|
||||
|
||||
set_flag(profile, "$improved missile avoidance for fightercraft:", AI::Profile_Flags::Improved_missile_avoidance);
|
||||
|
||||
if (optional_string_either("$friendly ships use AI profile countermeasure chance:", "$unify usage of AI profile countermeasure chance:", true) >= 0) {
|
||||
bool val;
|
||||
stuff_boolean(&val);
|
||||
profile->flags.set(AI::Profile_Flags::Unify_usage_countermeasure_firechance, val);
|
||||
}
|
||||
set_flag(profile, "$friendly ships use AI profile countermeasure chance:", AI::Profile_Flags::Friendlies_use_countermeasure_firechance);
|
||||
|
||||
set_flag(profile, "$improved subsystem attack pathing:", AI::Profile_Flags::Improved_subsystem_attack_pathing);
|
||||
|
||||
@@ -667,51 +653,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
|
||||
}
|
||||
|
||||
set_flag(profile, "$fix avoid-shockwave bugs:", AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
|
||||
set_flag(profile, "$standard strafe used more:", AI::Profile_Flags::Standard_strafe_used_more);
|
||||
|
||||
if (optional_string("$standard strafe triggers under this speed:")) {
|
||||
stuff_float(&profile->standard_strafe_when_below_speed);
|
||||
}
|
||||
|
||||
if (optional_string("$strafe distance from target bounding box:")) {
|
||||
stuff_float(&profile->strafe_retreat_box_dist);
|
||||
}
|
||||
|
||||
if (optional_string("$strafe stops after time unhit:")) {
|
||||
stuff_float(&profile->strafe_max_unhit_time);
|
||||
}
|
||||
|
||||
if (optional_string("$guard uses big-orbit for target radius above:")) {
|
||||
stuff_float(&profile->guard_big_orbit_above_target_radius);
|
||||
}
|
||||
|
||||
if (optional_string("$guard with big-orbit uses max speed percent:")) {
|
||||
float max_percent;
|
||||
stuff_float(&max_percent);
|
||||
if (max_percent > 0.0f && max_percent <= 1.0f) {
|
||||
profile->guard_big_orbit_max_speed_percent = max_percent;
|
||||
} else {
|
||||
mprintf(("Warning: \"$guard with big-orbit uses max speed percent:\" should be > 0 and <= 1 (read %f). Value will not be used.\n", max_percent));
|
||||
}
|
||||
}
|
||||
|
||||
set_flag(profile, "$unify usage of AI Shield Manage Delay:", AI::Profile_Flags::Unify_usage_ai_shield_manage_delay);
|
||||
|
||||
set_flag(profile, "$fix AI shield management bug:", AI::Profile_Flags::Fix_AI_shield_management_bug);
|
||||
|
||||
set_flag(profile, "$AI balances shields instead of directs when attacked:", AI::Profile_Flags::AI_balances_shields_when_attacked);
|
||||
|
||||
set_flag(profile, "$disable AI transferring energy:", AI::Profile_Flags::Disable_ai_transferring_energy);
|
||||
|
||||
set_flag(profile, "$enable freespace 1 style missile behavior:", AI::Profile_Flags::Freespace_1_missile_behavior);
|
||||
|
||||
set_flag(profile, "$ETS uses ship class power output:", AI::Profile_Flags::ETS_uses_power_output);
|
||||
|
||||
set_flag(profile, "$ETS energy same regardless of system presence:", AI::Profile_Flags::ETS_energy_same_regardless_of_system_presence);
|
||||
|
||||
|
||||
// end of options ----------------------------------------
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
@@ -804,16 +745,6 @@ void ai_profile_t::reset()
|
||||
turret_target_recheck_time = 2000.0f;
|
||||
rot_fac_multiplier_ply_collisions = 0.0f;
|
||||
|
||||
better_collision_avoid_aggression_combat = 3.5f;
|
||||
better_collision_avoid_aggression_guard = 3.5f;
|
||||
|
||||
standard_strafe_when_below_speed = 3.0f;
|
||||
strafe_retreat_box_dist = 300.0f;
|
||||
strafe_max_unhit_time = 20.0f;
|
||||
|
||||
guard_big_orbit_above_target_radius = 500.0f;
|
||||
guard_big_orbit_max_speed_percent = 1.0f;
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
max_allowed_player_homers[i] = 0;
|
||||
@@ -871,7 +802,7 @@ void ai_profile_t::reset()
|
||||
player_autoaim_fov[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= MAX_DETAIL_VALUE; ++i) {
|
||||
for (int i = 0; i <= MAX_DETAIL_LEVEL; ++i) {
|
||||
detail_distance_mult[i] = 0;
|
||||
}
|
||||
|
||||
@@ -925,7 +856,4 @@ void ai_profile_t::reset()
|
||||
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
|
||||
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
}
|
||||
if (mod_supports_version(25, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_avoid_shockwave_bugs);
|
||||
}
|
||||
}
|
||||
+1
-19
@@ -99,7 +99,7 @@ public:
|
||||
// Player-specific autoaim FOV override
|
||||
float player_autoaim_fov[NUM_SKILL_LEVELS];
|
||||
|
||||
float detail_distance_mult[MAX_DETAIL_VALUE + 1]; //MAX_DETAIL_VALUE really needs to be 4
|
||||
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
|
||||
|
||||
// minimum radius for the line-of-sight (los) detection --wookieejedi
|
||||
float los_min_detection_radius;
|
||||
@@ -126,24 +126,6 @@ public:
|
||||
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
|
||||
float rot_fac_multiplier_ply_collisions;
|
||||
|
||||
// Collision avoidance options --developed by asteroth, exposed by wookieejedi
|
||||
// Velocity / turn rate gives us a vector which represents the minimum 'bug out' distance.
|
||||
// However this will be a significant underestimate, it doesn't take into account acceleration
|
||||
// with regards to its turn speed, nor already existing rotvel, nor the angular distance
|
||||
// to the particular avoidance vector it comes up with.
|
||||
// These would significantly complicate the calculation, so for now, it is all bundled into these magic numbers.
|
||||
float better_collision_avoid_aggression_combat;
|
||||
float better_collision_avoid_aggression_guard;
|
||||
|
||||
// AI strafing options --wookieejedi
|
||||
float standard_strafe_when_below_speed; // Speed at which standard strafing large ships is possibly triggered
|
||||
float strafe_retreat_box_dist; // Distance beyond the bounding box to retreat to strafing point
|
||||
float strafe_max_unhit_time; // Maximum amount of time to stay in strafe mode if not hit
|
||||
|
||||
// AI guard options --wookieejedi
|
||||
float guard_big_orbit_above_target_radius; // Radius of guardee that triggers ai_big_guard()
|
||||
float guard_big_orbit_max_speed_percent; // Max percent of forward speed that is used in ai_big_guard()
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
|
||||
+28
-28
@@ -39,9 +39,10 @@
|
||||
#define MIN_DOT_TO_ATTACK_MOVING_SUBSYS 0.97f
|
||||
|
||||
// AI BIG MAGIC NUMBERS
|
||||
// Select strafing options are now exposed to modders --wookieejedi
|
||||
#define STRAFE_RETREAT_COLLIDE_TIME 2.0 // when anticipated collision time is less than this, begin retreat
|
||||
#define STRAFE_RETREAT_COLLIDE_DIST 100 // when perpendicular distance to *surface* is less than this, begin retreat
|
||||
#define STRAFE_RETREAT_BOX_DIST 300 // distance beyond the bounding box to retreat
|
||||
#define STRAFE_MAX_UNHIT_TIME 20 // Maximum amount of time to stay in strafe mode if not hit
|
||||
|
||||
#define EVADE_BOX_BASE_DISTANCE 300 // standard distance to end evade submode
|
||||
#define EVADE_BOX_MIN_DISTANCE 200 // minimun distance to end evade submode, after long time
|
||||
@@ -66,8 +67,8 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern void compute_desired_rvec(vec3d *rvec, const vec3d *goal_pos, const vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(const object *objp, const object *big_objp, const vec3d *collision_normal);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
|
||||
// Called by ai_big_pick_attack_point.
|
||||
@@ -718,21 +719,19 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since ship is moving slowly and attacking a large ship, scan if enemy fighters are near, if so
|
||||
// then enter strafe mode
|
||||
if ( ai_big_maybe_start_strafe(aip, sip) ) {
|
||||
aip->previous_mode = aip->mode;
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
ai_big_strafe_position();
|
||||
return;
|
||||
}
|
||||
|
||||
} // end if ( Pl_objp->phys_info.speed < 3.0f )
|
||||
|
||||
// if moving slowly and attacking a large ship,
|
||||
// check if need to enter standard strafe mode
|
||||
// including ai_profile flag and if enemy fighters are near
|
||||
if (Pl_objp->phys_info.speed < The_mission.ai_profile->standard_strafe_when_below_speed &&
|
||||
(The_mission.ai_profile->flags[AI::Profile_Flags::Standard_strafe_used_more] || ai_big_maybe_start_strafe(aip, sip))) {
|
||||
aip->previous_mode = aip->mode;
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
ai_big_strafe_position();
|
||||
return;
|
||||
}
|
||||
|
||||
//Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
|
||||
aip->previous_mode = aip->mode;
|
||||
@@ -914,13 +913,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if ( !(En_objp->flags[Object::Object_Flags::Protected]) || ai_goal_is_disable_or_disarm(aip->goals[0].ai_mode) ) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if ( !(En_objp->flags[Object::Object_Flags::Protected]) || (ai_goal_is_disable_or_disarm(aip->goals[0].ai_mode) && swip->wi_flags[Weapon::Info_Flags::Puncture]) ) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
@@ -1440,7 +1439,7 @@ static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
|
||||
//if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f))
|
||||
|
||||
// Inside 2 sec retreat, setting goal point to box point + strafe_retreat_box_dist
|
||||
// Inside 2 sec retreat, setting goal point to box point + 300m
|
||||
// If collision, use std collision resolution.
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (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]) {
|
||||
@@ -1448,13 +1447,13 @@ static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + strafe_retreat_box_dist
|
||||
// too close for comfort so fly to box point + 300
|
||||
aip->submode = AIS_STRAFE_RETREAT1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
int is_inside;
|
||||
vec3d goal_point;
|
||||
get_world_closest_box_point_with_delta(&goal_point, En_objp, &Pl_objp->pos, &is_inside, The_mission.ai_profile->strafe_retreat_box_dist);
|
||||
get_world_closest_box_point_with_delta(&goal_point, En_objp, &Pl_objp->pos, &is_inside, STRAFE_RETREAT_BOX_DIST);
|
||||
|
||||
// set goal point
|
||||
aip->goal_point = goal_point;
|
||||
@@ -1569,7 +1568,8 @@ void ai_big_strafe_attack()
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
fix long_enough = fl2f(The_mission.ai_profile->strafe_max_unhit_time);
|
||||
fix long_enough;
|
||||
long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
|
||||
if ( (last_hit > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
|
||||
ai_big_switch_to_chase_mode(aip);
|
||||
}
|
||||
@@ -1616,11 +1616,11 @@ void ai_big_strafe_glide_attack()
|
||||
//If we haven't chosen the goal point yet, do so now
|
||||
if (aip->submode_parm1 == 0) {
|
||||
//Pick goal point. This should be a random point that passes through the circle whose normal is the vector between attacker and target
|
||||
vec3d targetToAttackerDir;
|
||||
vm_vec_normalized_dir(&targetToAttackerDir, &Pl_objp->pos, &target_objp->pos);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix_norm(&orient, &targetToAttackerDir, nullptr, nullptr);
|
||||
vec3d targetToAttacker;
|
||||
vec3d tangentPoint;
|
||||
vm_vec_sub(&targetToAttacker, &Pl_objp->pos, &target_objp->pos);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix(&orient, &targetToAttacker, NULL, NULL);
|
||||
vm_vec_random_in_circle(&tangentPoint, &target_objp->pos, &orient, target_objp->radius + GLIDE_STRAFE_DISTANCE, true);
|
||||
//Get tangent point in coords relative to ship, scale it up so the actual goal point is far away, then put back in world coords
|
||||
vm_vec_sub2(&tangentPoint, &Pl_objp->pos);
|
||||
@@ -1641,7 +1641,7 @@ void ai_big_strafe_glide_attack()
|
||||
//Keep going until we are too far away.
|
||||
//If we are still on approach but too far away, this will still trigger. This will allow us to reposition the target
|
||||
//point and allow for a "jinking" effect.
|
||||
if (target_ship_dist > (The_mission.ai_profile->strafe_retreat_box_dist + target_objp->radius) &&
|
||||
if (target_ship_dist > (STRAFE_RETREAT_BOX_DIST + target_objp->radius) &&
|
||||
Missiontime - aip->submode_start_time > i2f(GLIDE_STRAFE_MIN_TIME)) {
|
||||
//This checks whether we are moving toward the target or away from it. If moving towards, we reset the stage so that we
|
||||
//pick a new attack vector (jinking). If moving away, we're at the end of a run so do a full reset (possibly allowing a
|
||||
@@ -1691,7 +1691,7 @@ void ai_big_strafe_glide_attack()
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
// (same as ai_big_strafe_attack)
|
||||
fix long_enough = fl2f(The_mission.ai_profile->strafe_max_unhit_time);
|
||||
fix long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
|
||||
if ( (Missiontime - aip->last_hit_time > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
|
||||
ai_big_switch_to_chase_mode(aip);
|
||||
}
|
||||
@@ -1887,7 +1887,7 @@ void ai_big_strafe()
|
||||
{
|
||||
//Re-roll for random sidethrust every 2 seconds
|
||||
if (static_randf((Missiontime + static_rand(aip->shipnum)) >> 17) < aip->ai_random_sidethrust_percent) {
|
||||
do_random_sidethrust(aip, &Ship_info[Ships[aip->shipnum].ship_info_index]);
|
||||
do_random_sidethrust(aip, &Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+105
-234
@@ -185,9 +185,9 @@ object *En_objp;
|
||||
#define REARM_SOUND_DELAY (3*F1_0) // Amount of time to delay rearm/repair after mode start
|
||||
#define REARM_BREAKOFF_DELAY (3*F1_0) // Amount of time to wait after fully rearmed to breakoff.
|
||||
|
||||
// Select guard options are now exposed to modders --wookieejedi
|
||||
#define MIN_DIST_TO_WAYPOINT_GOAL 5.0f
|
||||
#define MAX_GUARD_DIST 250.0f
|
||||
#define BIG_GUARD_RADIUS 500.0f
|
||||
|
||||
#define MAX_EVADE_TIME (15 * 1000) // Max time to evade a weapon.
|
||||
|
||||
@@ -924,8 +924,6 @@ void parse_ai_class()
|
||||
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
|
||||
set_aic_flag(aicp, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
|
||||
set_aic_flag(aicp, "$AI balances shields instead of directs when attacked:", AI::Profile_Flags::AI_balances_shields_when_attacked);
|
||||
}
|
||||
|
||||
void reset_ai_class_names()
|
||||
@@ -1199,7 +1197,7 @@ int ai_is_stealth_visible(const object *viewer_objp, const object *stealth_objp)
|
||||
* Forward vector is the forward vector of the ship.
|
||||
* If from_dot == NULL, don't fill it in.
|
||||
*/
|
||||
float compute_dots(const object *objp, const object *other_objp, float *to_dot, float *from_dot)
|
||||
float compute_dots(object *objp, object *other_objp, float *to_dot, float *from_dot)
|
||||
{
|
||||
vec3d v2o;
|
||||
float dist;
|
||||
@@ -1244,7 +1242,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
ai_info *aip;
|
||||
float old_dist, new_dist;
|
||||
float old_dot, new_dot;
|
||||
object *old_weapon_objp = nullptr;
|
||||
object *old_weapon_objp = NULL;
|
||||
|
||||
// any object number less than 0 is invalid
|
||||
if ((attacked_objnum < 0) || (weapon_objnum < 0)) {
|
||||
@@ -1289,7 +1287,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
}
|
||||
}
|
||||
|
||||
new_dist = compute_dots(weapon_objp, objp, &new_dot, nullptr); // NOLINT(readability-suspicious-call-argument)
|
||||
new_dist = compute_dots(weapon_objp, objp, &new_dot, NULL);
|
||||
|
||||
if (aip->danger_weapon_objnum == -1) {
|
||||
if (new_dist < 1500.0f) {
|
||||
@@ -1299,8 +1297,8 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Assert(old_weapon_objp != nullptr);
|
||||
old_dist = compute_dots(old_weapon_objp, objp, &old_dot, nullptr); // NOLINT(readability-suspicious-call-argument)
|
||||
Assert(old_weapon_objp != NULL);
|
||||
old_dist = compute_dots(old_weapon_objp, objp, &old_dot, NULL);
|
||||
|
||||
if (old_dot < 0.5f) {
|
||||
aip->danger_weapon_objnum = -1;
|
||||
@@ -1484,7 +1482,7 @@ void ai_turn_towards_vector(const vec3d* dest, object* objp, const vec3d* slide_
|
||||
if (rvec != NULL) {
|
||||
matrix goal_orient;
|
||||
|
||||
vm_vector_2_matrix_norm(&goal_orient, &desired_fvec, nullptr, rvec);
|
||||
vm_vector_2_matrix(&goal_orient, &desired_fvec, NULL, rvec);
|
||||
vm_angular_move_matrix(&goal_orient, &curr_orient, &vel_in, delta_time,
|
||||
&out_orient, &vel_out, &vel_limit, &acc_limit, The_mission.ai_profile->flags[AI::Profile_Flags::No_turning_directional_bias]);
|
||||
} else {
|
||||
@@ -2099,7 +2097,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
}
|
||||
else
|
||||
{
|
||||
recharge_scale = ets_power_factor(objp) * Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = sip->afterburner_recover_rate * recharge_scale / (sip->afterburner_burn_rate + sip->afterburner_recover_rate * recharge_scale);
|
||||
lowest_max_av_ab_speed = recharge_scale * (objp->phys_info.afterburner_max_vel.xyz.z - objp->phys_info.max_vel.xyz.z) + objp->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
@@ -2127,7 +2125,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
}
|
||||
else
|
||||
{
|
||||
recharge_scale = ets_power_factor(o) * Energy_levels[oshipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = osip->afterburner_recover_rate * recharge_scale / (osip->afterburner_burn_rate + osip->afterburner_recover_rate * recharge_scale);
|
||||
cur_max = recharge_scale * (o->phys_info.afterburner_max_vel.xyz.z - o->phys_info.max_vel.xyz.z) + o->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
@@ -3517,40 +3515,20 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
|
||||
// flags tells:
|
||||
// WPF_REPEAT Set -> repeat waypoints.
|
||||
// WPF_BACKTRACK Go in reverse.
|
||||
void ai_start_waypoints(object *objp, int wp_list_index, int wp_flags, int start_index, bool force)
|
||||
void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index)
|
||||
{
|
||||
auto aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
ai_info *aip;
|
||||
Assert(wp_list != NULL);
|
||||
|
||||
if (Waypoint_lists.empty())
|
||||
{
|
||||
Warning(LOCATION, "No waypoint lists in mission!");
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
auto wp_list = find_waypoint_list_at_index(wp_list_index);
|
||||
if (!wp_list)
|
||||
{
|
||||
Warning(LOCATION, "wp_list_index %d must be a valid waypoint list index!", wp_list_index);
|
||||
wp_list_index = 0;
|
||||
wp_list = find_waypoint_list_at_index(wp_list_index);
|
||||
}
|
||||
|
||||
if (wp_list->get_waypoints().empty())
|
||||
{
|
||||
Warning(LOCATION, "Waypoint list '%s' is empty!", wp_list->get_name());
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
auto wp = find_waypoint_at_index(wp_list, start_index);
|
||||
if (!wp)
|
||||
if (start_index < 0 || start_index >= (int)wp_list->get_waypoints().size())
|
||||
{
|
||||
Warning(LOCATION, "Starting index for %s on '%s' is out of range!", Ships[objp->instance].ship_name, wp_list->get_name());
|
||||
start_index = (wp_flags & WPF_BACKTRACK) ? (int)wp_list->get_waypoints().size() - 1 : 0;
|
||||
}
|
||||
|
||||
if ( (aip->mode == AIM_WAYPOINTS) && (aip->wp_list_index == wp_list_index) && !force )
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
if ( (aip->mode == AIM_WAYPOINTS) && (aip->wp_list == wp_list) )
|
||||
{
|
||||
if (aip->wp_index == INVALID_WAYPOINT_POSITION)
|
||||
{
|
||||
@@ -3570,7 +3548,7 @@ void ai_start_waypoints(object *objp, int wp_list_index, int wp_flags, int start
|
||||
}
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
|
||||
aip->wp_list_index = wp_list_index;
|
||||
aip->wp_list = wp_list;
|
||||
aip->wp_index = start_index;
|
||||
aip->wp_flags = wp_flags;
|
||||
aip->mode = AIM_WAYPOINTS;
|
||||
@@ -4437,7 +4415,7 @@ float ai_path()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this is not the same thing as CLAMP()! CLAMP() adjusts the value, while this adjusts the bounds.
|
||||
// Only needed because CLAMP() doesn't handle pointers
|
||||
void update_min_max(float val, float *min, float *max)
|
||||
{
|
||||
if (val < *min)
|
||||
@@ -4614,7 +4592,7 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
|
||||
/* I shouldn't be flying to position for what ever called me any more.
|
||||
Set mode to none so that default dynamic behaviour gets started up again. */
|
||||
if ( (aip->active_goal == AI_ACTIVE_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) ) {
|
||||
if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) ) {
|
||||
aip->mode = AIM_NONE;
|
||||
}
|
||||
|
||||
@@ -4661,7 +4639,7 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
// this needs to be done for ALL SHIPS not just capships STOP CHANGING THIS
|
||||
// ----------------------------------------------
|
||||
|
||||
vec3d goal_point;
|
||||
vec3d perp, goal_point;
|
||||
|
||||
bool carry_flag = ((shipp->flags[Ship::Ship_Flags::Navpoint_carry]) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags[Ship::Wing_Flags::Nav_carry])));
|
||||
|
||||
@@ -4684,7 +4662,6 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
&& carry_flag
|
||||
&& ((The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics]) || (Pl_objp != Autopilot_flight_leader)) )
|
||||
{
|
||||
vec3d perp;
|
||||
Assertion( Autopilot_flight_leader != NULL, "When under autopilot there must be a flight leader" );
|
||||
// snap wings into formation
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics]) {
|
||||
@@ -4719,8 +4696,8 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
Pl_objp->pos = goal_point;
|
||||
}
|
||||
|
||||
vm_vec_normalized_dir(&perp, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
|
||||
vm_vector_2_matrix_norm(&Pl_objp->orient, &perp, nullptr, nullptr);
|
||||
vm_vec_sub(&perp, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
|
||||
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
|
||||
} else {
|
||||
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, slop_vec, nullptr, 0.0f, 0, nullptr, &turnrate_mod);
|
||||
@@ -4798,7 +4775,7 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
max_allowed_speed = 0.9f * get_wing_lowest_max_speed(Pl_objp);
|
||||
max_allowed_ab_speed = 0.95f * get_wing_lowest_av_ab_speed(Pl_objp);
|
||||
if (ab_allowed) {
|
||||
float self_ab_scale = ets_power_factor(Pl_objp) * Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
float self_ab_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
self_ab_scale = sip->afterburner_recover_rate * self_ab_scale / (sip->afterburner_burn_rate + sip->afterburner_recover_rate * self_ab_scale);
|
||||
self_ab_speed = 0.95f * (self_ab_scale * (Pl_objp->phys_info.afterburner_max_vel.xyz.z - Pl_objp->phys_info.max_vel.xyz.z) + Pl_objp->phys_info.max_vel.xyz.z);
|
||||
}
|
||||
@@ -4881,10 +4858,12 @@ void ai_fly_to_target_position(const vec3d* target_pos, bool* pl_done_p=NULL, bo
|
||||
// for itself and in a wing, treat the completion as we would a ship
|
||||
treat_as_ship = 1;
|
||||
if ( shipp->wingnum != -1 ) {
|
||||
int type;
|
||||
|
||||
// protect array access from invalid indexes
|
||||
if ((aip->active_goal >= 0) && (aip->active_goal < MAX_AI_GOALS)) {
|
||||
auto type = aip->goals[aip->active_goal].type;
|
||||
if ( (type == ai_goal_type::EVENT_WING) || (type == ai_goal_type::PLAYER_WING) ) {
|
||||
type = aip->goals[aip->active_goal].type;
|
||||
if ( (type == AIG_TYPE_EVENT_WING) || (type == AIG_TYPE_PLAYER_WING) ) {
|
||||
treat_as_ship = 0;
|
||||
} else {
|
||||
treat_as_ship = 1;
|
||||
@@ -4917,15 +4896,19 @@ void ai_waypoints()
|
||||
|
||||
// sanity checking for stuff that should never happen
|
||||
if (aip->wp_index == INVALID_WAYPOINT_POSITION) {
|
||||
UNREACHABLE("Waypoints should have been started already!");
|
||||
ai_start_waypoints(Pl_objp, (aip->wp_list_index < 0) ? 0 : aip->wp_list_index, WPF_REPEAT, 0);
|
||||
if (aip->wp_list == NULL) {
|
||||
UNREACHABLE("Waypoints should have been assigned already!");
|
||||
ai_start_waypoints(Pl_objp, &Waypoint_lists.front(), WPF_REPEAT, 0);
|
||||
} else {
|
||||
UNREACHABLE("Waypoints should have been started already!");
|
||||
ai_start_waypoints(Pl_objp, aip->wp_list, WPF_REPEAT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
auto wp_list = find_waypoint_list_at_index(aip->wp_list_index);
|
||||
Assert(wp_list && !wp_list->get_waypoints().empty()); // What? Is this zero? Probably never got initialized!
|
||||
Assert(!aip->wp_list->get_waypoints().empty()); // What? Is this zero? Probably never got initialized!
|
||||
|
||||
bool done, treat_as_ship;
|
||||
ai_fly_to_target_position(wp_list->get_waypoints()[aip->wp_index].get_pos(), &done, &treat_as_ship);
|
||||
ai_fly_to_target_position(aip->wp_list->get_waypoints()[aip->wp_index].get_pos(), &done, &treat_as_ship);
|
||||
|
||||
if ( done ) {
|
||||
bool reached_end;
|
||||
@@ -4935,7 +4918,7 @@ void ai_waypoints()
|
||||
reached_end = (aip->wp_index == -1);
|
||||
} else {
|
||||
++aip->wp_index;
|
||||
reached_end = (aip->wp_index == static_cast<int>(wp_list->get_waypoints().size()));
|
||||
reached_end = (aip->wp_index == (int)aip->wp_list->get_waypoints().size());
|
||||
}
|
||||
|
||||
if (reached_end) {
|
||||
@@ -4943,7 +4926,7 @@ void ai_waypoints()
|
||||
if ( aip->wp_flags & WPF_REPEAT ) {
|
||||
// go back to the start.
|
||||
if (aip->wp_flags & WPF_BACKTRACK) {
|
||||
aip->wp_index = static_cast<int>(wp_list->get_waypoints().size()) - 1;
|
||||
aip->wp_index = (int)aip->wp_list->get_waypoints().size() - 1;
|
||||
} else {
|
||||
aip->wp_index = 0;
|
||||
}
|
||||
@@ -4961,10 +4944,10 @@ void ai_waypoints()
|
||||
// ai_fly_to_target_position when it marks the AI directive as complete
|
||||
if ( treat_as_ship ) {
|
||||
ai_mission_goal_complete( aip ); // this call should reset the AI mode
|
||||
mission_log_add_entry( LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, wp_list->get_name(), -1 );
|
||||
mission_log_add_entry( LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, aip->wp_list->get_name(), -1 );
|
||||
} else {
|
||||
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
|
||||
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, wp_list->get_name(), -1 );
|
||||
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
|
||||
}
|
||||
// adds scripting hook for 'On Waypoints Done' --wookieejedi
|
||||
if (scripting::hooks::OnWaypointsDone->isActive()) {
|
||||
@@ -4972,7 +4955,7 @@ void ai_waypoints()
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', Pl_objp),
|
||||
scripting::hook_param("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum)),
|
||||
scripting::hook_param("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(wp_list)))
|
||||
scripting::hook_param("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)))
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -5066,7 +5049,7 @@ int maybe_resume_previous_mode(object *objp, ai_info *aip)
|
||||
aip->mode = aip->previous_mode;
|
||||
aip->submode = aip->previous_submode;
|
||||
aip->submode_start_time = Missiontime;
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
aip->mode_time = -1; // Means do forever.
|
||||
return 1;
|
||||
}
|
||||
@@ -5087,7 +5070,7 @@ int maybe_resume_previous_mode(object *objp, ai_info *aip)
|
||||
aip->mode = aip->previous_mode;
|
||||
aip->submode = AIS_GUARD_PATROL;
|
||||
aip->submode_start_time = Missiontime;
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -5747,7 +5730,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < ship_info_size());
|
||||
|
||||
//made it so it only selects puncture weapons if the active goal is to disable something -Bobboau
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && ai_goal_is_disable_or_disarm(Ai_info[shipp->ai_index].goals[0].ai_mode))
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL)))
|
||||
{
|
||||
if (swp->current_primary_bank >= 0)
|
||||
{
|
||||
@@ -5974,9 +5957,9 @@ void set_primary_weapon_linkage(object *objp)
|
||||
|
||||
// AL 2-11-98: If ship has a disarm or disable goal, don't link unless both weapons are
|
||||
// puncture weapons
|
||||
if ( (aip->active_goal != AI_ACTIVE_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
if ( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
{
|
||||
if ( ai_goal_is_disable_or_disarm(aip->goals[aip->active_goal].ai_mode) )
|
||||
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISABLE_SHIP_TACTICAL|AI_GOAL_DISARM_SHIP|AI_GOAL_DISARM_SHIP_TACTICAL) )
|
||||
{
|
||||
// only continue if both primaries are puncture weapons
|
||||
if ( swp->num_primary_banks == 2 ) {
|
||||
@@ -6275,7 +6258,7 @@ int ai_fire_primary_weapon(object *objp)
|
||||
vm_vec_normalized_dir(&v2t, &G_predicted_pos, &G_fire_pos);
|
||||
dot = vm_vec_dot(&v2t, &objp->orient.vec.fvec);
|
||||
if (dot > .998629534f){ // if within 3.0 degrees of desired heading, bash
|
||||
vm_vector_2_matrix_norm(&objp->orient, &v2t, &objp->orient.vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(&objp->orient, &v2t, &objp->orient.vec.uvec, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7257,7 +7240,7 @@ static void ai_chase_eb(ai_info *aip, vec3d *predicted_enemy_pos)
|
||||
// Assumes ship_objp is not moving.
|
||||
// Returns negative time if not going to hit.
|
||||
// This is a very approximate function, but is pretty fast.
|
||||
float ai_endangered_time(const object *ship_objp, const object *weapon_objp)
|
||||
float ai_endangered_time(object *ship_objp, object *weapon_objp)
|
||||
{
|
||||
float to_dot, from_dot, dist;
|
||||
|
||||
@@ -7606,7 +7589,7 @@ void mabs_pick_goal_point(object *objp, object *big_objp, vec3d *collision_point
|
||||
vec3d v2b;
|
||||
|
||||
vm_vec_normalized_dir(&v2b, collision_point, &objp->pos);
|
||||
vm_vector_2_matrix_norm(&mat1, &v2b, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&mat1, &v2b, NULL, NULL);
|
||||
|
||||
int found = 0;
|
||||
|
||||
@@ -7676,7 +7659,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
aip->ai_flags.set(AI::AI_Flags::Avoiding_big_ship);
|
||||
mabs_pick_goal_point(objp, &Objects[ship_num], &collision_point, &aip->avoid_goal_point);
|
||||
float dist = vm_vec_dist_quick(&aip->avoid_goal_point, &objp->pos);
|
||||
next_check_time = fl2i(2000.0f + MIN(1000.0f, (dist * 2.0f)) * time_scale); // Delay until check again is based on distance to avoid point.
|
||||
next_check_time = (int) (2000 + MIN(1000, (dist * 2.0f)) * time_scale); // Delay until check again is based on distance to avoid point.
|
||||
aip->avoid_check_timestamp = timestamp(next_check_time);
|
||||
aip->avoid_ship_num = ship_num;
|
||||
} else {
|
||||
@@ -7710,7 +7693,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
* Set desired right vector for ships flying towards another ship.
|
||||
* Since this is governed only by vector to target, it causes ships to align bank and look less chaotic.
|
||||
*/
|
||||
void compute_desired_rvec(vec3d *rvec, const vec3d *goal_pos, const vec3d *cur_pos)
|
||||
void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos)
|
||||
{
|
||||
vec3d v2e;
|
||||
|
||||
@@ -7720,8 +7703,6 @@ void compute_desired_rvec(vec3d *rvec, const vec3d *goal_pos, const vec3d *cur_p
|
||||
rvec->xyz.z = -v2e.xyz.x;
|
||||
if (vm_vec_mag_squared(rvec) < 0.001f)
|
||||
rvec->xyz.y = 1.0f;
|
||||
|
||||
vm_vec_normalize_safe(rvec); // since messing with the bank will make it un-normalized
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8699,17 +8680,10 @@ void ai_cruiser_chase()
|
||||
|
||||
// kamikaze - ram and explode
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
// point toward the subsystem if we're targeting one; otherwise point toward the center
|
||||
if (aip->targeted_subsys) {
|
||||
get_subsystem_pos(&goal_pos, En_objp, aip->targeted_subsys);
|
||||
} else {
|
||||
goal_pos = En_objp->pos;
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &goal_pos);
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &En_objp->pos);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
@@ -8928,8 +8902,15 @@ void ai_chase()
|
||||
return;
|
||||
}
|
||||
|
||||
if ((The_mission.ai_profile->flags[AI::Profile_Flags::Better_combat_collision_avoidance]) && sip->is_small_ship()) {
|
||||
vec3d collide_vec = Pl_objp->phys_info.vel * (The_mission.ai_profile->better_collision_avoid_aggression_combat / (PI2 / sip->srotation_time));
|
||||
if ((The_mission.ai_profile->flags[AI::Profile_Flags::Better_collision_avoidance]) && sip->is_small_ship()) {
|
||||
// velocity / turn rate gives us a vector which represents the minimum 'bug out' distance
|
||||
// however this will be a significant underestimate, it doesn't take into account acceleration
|
||||
// with regards to its turn speed, nor already existing rotvel, nor the angular distance
|
||||
// to the particular avoidance vector it comes up with
|
||||
// These would significantly complicate the calculation, so for now, it is all bundled into this magic number
|
||||
const float collision_avoidance_aggression = 3.5f;
|
||||
|
||||
vec3d collide_vec = Pl_objp->phys_info.vel * (collision_avoidance_aggression / (PI2 / sip->srotation_time));
|
||||
float radius_contribution = (Pl_objp->phys_info.speed + Pl_objp->radius) / Pl_objp->phys_info.speed;
|
||||
collide_vec *= radius_contribution;
|
||||
|
||||
@@ -9738,7 +9719,7 @@ void set_goal_dock_orient(matrix *dom, matrix *docker_dock_orient, matrix *docke
|
||||
vm_vec_rotate(&uvec, &dockee_dock_orient->vec.uvec, dockee_orient);
|
||||
|
||||
// create a rotation matrix
|
||||
vm_vector_2_matrix(&m1, &fvec, &uvec, nullptr); // we need to normalize the input vectors here to prevent floating point errors from compounding
|
||||
vm_vector_2_matrix(&m1, &fvec, &uvec, NULL);
|
||||
|
||||
// get the global orientation
|
||||
vm_matrix_x_matrix(&m3, dockee_orient, &m1);
|
||||
@@ -9752,7 +9733,7 @@ void set_goal_dock_orient(matrix *dom, matrix *docker_dock_orient, matrix *docke
|
||||
vm_vec_rotate(&uvec, &docker_dock_orient->vec.uvec, docker_orient);
|
||||
|
||||
// create a rotation matrix
|
||||
vm_vector_2_matrix(&m2, &fvec, &uvec, nullptr); // we need to normalize the input vectors here to prevent floating point errors from compounding
|
||||
vm_vector_2_matrix(&m2, &fvec, &uvec, NULL);
|
||||
|
||||
// Pre-multiply the orientation of the source object (docker_orient) by the transpose
|
||||
// of the docking bay's orientation, ie unrotate the source object's matrix.
|
||||
@@ -9835,7 +9816,7 @@ void find_adjusted_dockpoint_info(vec3d *global_dock_point, matrix *global_dock_
|
||||
// find the normal of the first dockpoint
|
||||
model_instance_local_to_global_dir(&fvec, &pm->docking_bays[dock_index].norm[0], pm, pmi, submodel, &objp->orient);
|
||||
|
||||
vm_vector_2_matrix_norm(global_dock_orient, &fvec, &uvec);
|
||||
vm_vector_2_matrix(global_dock_orient, &fvec, &uvec);
|
||||
}
|
||||
// use the static dockpoints
|
||||
else
|
||||
@@ -9850,7 +9831,7 @@ void find_adjusted_dockpoint_info(vec3d *global_dock_point, matrix *global_dock_
|
||||
vm_vec_unrotate(&fvec, &local_fvec, &objp->orient);
|
||||
|
||||
vm_vec_add2(global_dock_point, &objp->pos);
|
||||
vm_vector_2_matrix_norm(global_dock_orient, &fvec, &uvec);
|
||||
vm_vector_2_matrix(global_dock_orient, &fvec, &uvec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10764,7 +10745,7 @@ void ai_big_guard()
|
||||
|
||||
// got the point, now let's go there
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, The_mission.ai_profile->guard_big_orbit_max_speed_percent);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
|
||||
bool free_ab_use = aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use];
|
||||
@@ -10849,20 +10830,8 @@ void ai_guard()
|
||||
return;
|
||||
}
|
||||
|
||||
ship_info* sip = &Ship_info[shipp->ship_info_index];
|
||||
if ((The_mission.ai_profile->flags[AI::Profile_Flags::Better_guard_collision_avoidance]) && sip->is_small_ship()) {
|
||||
|
||||
vec3d collide_vec = Pl_objp->phys_info.vel * (The_mission.ai_profile->better_collision_avoid_aggression_guard / (PI2 / sip->srotation_time));
|
||||
float radius_contribution = (Pl_objp->phys_info.speed + Pl_objp->radius) / Pl_objp->phys_info.speed;
|
||||
collide_vec *= radius_contribution;
|
||||
|
||||
collide_vec += Pl_objp->pos;
|
||||
if (maybe_avoid_big_ship(Pl_objp, En_objp, aip, &collide_vec, 0.f, 0.1f))
|
||||
return;
|
||||
}
|
||||
|
||||
// handler for guard object with BIG radius
|
||||
if (guard_objp->radius > The_mission.ai_profile->guard_big_orbit_above_target_radius) {
|
||||
// handler for gurad object with BIG radius
|
||||
if (guard_objp->radius > BIG_GUARD_RADIUS) {
|
||||
ai_big_guard();
|
||||
return;
|
||||
}
|
||||
@@ -12098,8 +12067,6 @@ void ai_process_subobjects(int objnum)
|
||||
ai_info *aip = &Ai_info[shipp->ai_index];
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
|
||||
bool in_lab = gameseq_get_state() == GS_STATE_LAB;
|
||||
|
||||
// non-player ships that are playing dead do not process subsystems or turrets
|
||||
if ((!(objp->flags[Object::Object_Flags::Player_ship]) || Player_use_ai) && aip->mode == AIM_PLAY_DEAD)
|
||||
return;
|
||||
@@ -12174,9 +12141,7 @@ void ai_process_subobjects(int objnum)
|
||||
|
||||
if ( psub->turret_num_firing_points > 0 )
|
||||
{
|
||||
if (!in_lab) {
|
||||
ai_turret_execute_behavior(shipp, pss);
|
||||
}
|
||||
ai_turret_execute_behavior(shipp, pss);
|
||||
} else {
|
||||
Warning( LOCATION, "Turret %s on ship %s has no firing points assigned to it.\nThis needs to be fixed in the model.\n", psub->name, shipp->ship_name );
|
||||
}
|
||||
@@ -12221,11 +12186,6 @@ void ai_process_subobjects(int objnum)
|
||||
// NOTE: Subsystem submodels are no longer rotated here. See ship_move_subsystems().
|
||||
}
|
||||
|
||||
// Lab doesn't need to do anything else here
|
||||
if (in_lab) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clients must not make actual AI changes! So bail here.
|
||||
if (MULTIPLAYER_CLIENT) {
|
||||
return;
|
||||
@@ -12705,7 +12665,7 @@ int ai_formation()
|
||||
// skip if wing leader has no waypoint order or a different waypoint list
|
||||
// ...or if it's a different start index or direction
|
||||
if ( (laip->mode != AIM_WAYPOINTS)
|
||||
|| (laip->wp_list_index != aip->wp_list_index)
|
||||
|| (laip->wp_list != aip->wp_list)
|
||||
|| (laip->submode_parm0 != aip->submode_parm0)
|
||||
|| ((laip->wp_flags & WPF_BACKTRACK) != (aip->wp_flags & WPF_BACKTRACK))
|
||||
) {
|
||||
@@ -12713,17 +12673,16 @@ int ai_formation()
|
||||
}
|
||||
}
|
||||
|
||||
aip->wp_list_index = laip->wp_list_index;
|
||||
aip->wp_list = laip->wp_list;
|
||||
aip->wp_index = laip->wp_index;
|
||||
aip->wp_flags = laip->wp_flags;
|
||||
|
||||
auto wp_list = find_waypoint_list_at_index(aip->wp_list_index);
|
||||
if (wp_list != nullptr) {
|
||||
if (aip->wp_list != nullptr) {
|
||||
if (aip->wp_flags & WPF_BACKTRACK) {
|
||||
if (aip->wp_index == -1)
|
||||
++aip->wp_index;
|
||||
} else {
|
||||
if (aip->wp_index == static_cast<int>(wp_list->get_waypoints().size()))
|
||||
if (aip->wp_index == (int)aip->wp_list->get_waypoints().size())
|
||||
--aip->wp_index;
|
||||
}
|
||||
}
|
||||
@@ -13132,11 +13091,10 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
|
||||
// For ships on player's team, check if modder wants default constant chance to fire or value from specific AI class profile.
|
||||
// For enemies, use value from specific AI class profile (usually increasing chance with higher skill level).
|
||||
// Or use unifying behavior if specified. --wookieejedi
|
||||
if ( (aip->ai_profile_flags[AI::Profile_Flags::Unify_usage_countermeasure_firechance]) || (shipp->team != Player_ship->team) ) {
|
||||
fire_chance = aip->ai_cmeasure_fire_chance;
|
||||
} else {
|
||||
if ( (shipp->team == Player_ship->team) && !(aip->ai_profile_flags[AI::Profile_Flags::Friendlies_use_countermeasure_firechance]) ) {
|
||||
fire_chance = The_mission.ai_profile->cmeasure_fire_chance[NUM_SKILL_LEVELS/2];
|
||||
} else {
|
||||
fire_chance = aip->ai_cmeasure_fire_chance;
|
||||
}
|
||||
|
||||
// Decrease chance to fire at lower ai class (SUSHI: Only if autoscale is on)
|
||||
@@ -13284,8 +13242,7 @@ void ai_manage_shield(object *objp, ai_info *aip)
|
||||
|
||||
// Scale time until next manage shield based on Skill_level.
|
||||
// Ships on player's team are treated as if Skill_level is average.
|
||||
// Or use unifying behavior if specified. --wookieejedi
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Unify_usage_ai_shield_manage_delay] || (iff_x_attacks_y(Player_ship->team, Ships[objp->instance].team)))
|
||||
if (iff_x_attacks_y(Player_ship->team, Ships[objp->instance].team))
|
||||
{
|
||||
delay = aip->ai_shield_manage_delay;
|
||||
}
|
||||
@@ -13322,8 +13279,8 @@ void ai_manage_shield(object *objp, ai_info *aip)
|
||||
aip->shield_manage_timestamp = timestamp((int) (delay * 1000.0f));
|
||||
|
||||
if (sip->is_small_ship() || (aip->ai_profile_flags[AI::Profile_Flags::All_ships_manage_shields])) {
|
||||
if ((Missiontime - aip->last_hit_time < F1_0 * 10) && !((aip->ai_profile_flags[AI::Profile_Flags::AI_balances_shields_when_attacked])))
|
||||
ai_transfer_shield(objp, aip->danger_shield_quadrant);
|
||||
if (Missiontime - aip->last_hit_time < F1_0*10)
|
||||
ai_transfer_shield(objp, aip->last_hit_quadrant);
|
||||
else
|
||||
ai_balance_shield(objp);
|
||||
}
|
||||
@@ -13767,7 +13724,7 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
|
||||
rvec = parent_objp->orient.vec.rvec;
|
||||
}
|
||||
|
||||
vm_vector_2_matrix_norm(&pl_objp->orient, &fvec, IS_VEC_NULL(&uvec) ? nullptr : &uvec, IS_VEC_NULL(&rvec) ? nullptr : &rvec);
|
||||
vm_vector_2_matrix(&pl_objp->orient, &fvec, IS_VEC_NULL(&uvec) ? nullptr : &uvec, IS_VEC_NULL(&rvec) ? nullptr : &rvec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -14442,8 +14399,6 @@ void ai_warp_out(object *objp)
|
||||
// Goober5000 - make sure the flag is clear (if it was previously set)
|
||||
aip->ai_flags.remove(AI::AI_Flags::Trying_unsuccessfully_to_warp);
|
||||
|
||||
WarpParams* warp_params = &Warp_params[shipp->warpout_params_index];
|
||||
|
||||
switch (aip->submode) {
|
||||
case AIS_WARP_1:
|
||||
aip->force_warp_time = timestamp(10*1000); // Try to avoid a collision for up to ten seconds.
|
||||
@@ -14452,9 +14407,9 @@ void ai_warp_out(object *objp)
|
||||
break;
|
||||
case AIS_WARP_2: // Make sure won't collide with any object.
|
||||
if (timestamp_elapsed(aip->force_warp_time)
|
||||
|| (warp_params->warp_type == WT_SWEEPER)
|
||||
|| (warp_params->warp_type == WT_IN_PLACE_ANIM)
|
||||
|| (!collide_predict_large_ship(objp, objp->radius * 2.0f + 100.0f))) {
|
||||
|| (!collide_predict_large_ship(objp, objp->radius*2.0f + 100.0f)
|
||||
|| (Warp_params[shipp->warpout_params_index].warp_type == WT_HYPERSPACE
|
||||
&& !collide_predict_large_ship(objp, 100000.0f)))) {
|
||||
aip->submode = AIS_WARP_3;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
@@ -14496,7 +14451,7 @@ void ai_warp_out(object *objp)
|
||||
break;
|
||||
case AIS_WARP_4: {
|
||||
// Only lets the ship warp after waiting for the warpout engage time
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + warp_params->warpout_engage_time) ) {
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + Warp_params[shipp->warpout_params_index].warpout_engage_time) ) {
|
||||
shipfx_warpout_start(objp);
|
||||
aip->submode = AIS_WARP_5;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -14601,11 +14556,7 @@ static int ai_find_shockwave_ship(object *objp)
|
||||
shipp = &Ships[A->instance];
|
||||
// Only look at objects in the process of dying.
|
||||
if (shipp->flags[Ship::Ship_Flags::Dying]) {
|
||||
float damage;
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_avoid_shockwave_bugs])
|
||||
damage = ship_get_exp_damage(A); // A is the object that is actually exploding!
|
||||
else
|
||||
damage = ship_get_exp_damage(objp);
|
||||
float damage = ship_get_exp_damage(objp);
|
||||
|
||||
if (damage >= EVADE_SHOCKWAVE_DAMAGE_THRESHOLD) { // Only evade quite large blasts
|
||||
float dist;
|
||||
@@ -14625,8 +14576,6 @@ static int ai_find_shockwave_ship(object *objp)
|
||||
|
||||
int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
{
|
||||
bool fix_bugs = The_mission.ai_profile->flags[AI::Profile_Flags::Fix_avoid_shockwave_bugs];
|
||||
|
||||
// MAKE SURE safe_pos DOES NOT TAKE US TOWARD THE A SHIP WE'RE ATTACKING.
|
||||
if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_weapon]) {
|
||||
// If we don't currently know of a weapon to avoid, try to find one.
|
||||
@@ -14661,7 +14610,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
}
|
||||
|
||||
float danger_dist;
|
||||
vec3d expected_pos = vmd_zero_vector; // Position at which we expect the weapon to detonate.
|
||||
vec3d expected_pos; // Position at which we expect the weapon to detonate.
|
||||
int pos_set = 0;
|
||||
|
||||
danger_dist = wip->shockwave.outer_rad;
|
||||
@@ -14687,50 +14636,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
}
|
||||
}
|
||||
|
||||
if (pos_set) {
|
||||
// if the object is not a small ship, a surface impact is likely to be some distance away from the ship center, so refine the position
|
||||
if (fix_bugs && target_ship_obj && !Ship_info[Ships[target_ship_obj->instance].ship_info_index].is_small_ship()) {
|
||||
// set up cache if needed
|
||||
if (weaponp->homing_cache_ptr == nullptr) {
|
||||
weaponp->homing_cache_ptr.reset(new homing_cache_info{ TIMESTAMP::immediate(), expected_pos, false, false });
|
||||
}
|
||||
|
||||
// only refine the position every so often though
|
||||
if (!weaponp->homing_cache_ptr->skip_future_refinements && timestamp_elapsed(weaponp->homing_cache_ptr->next_update)) {
|
||||
mc_info mc;
|
||||
mc.model_instance_num = Ships[target_ship_obj->instance].model_instance_num;
|
||||
mc.model_num = Ship_info[Ships[target_ship_obj->instance].ship_info_index].model_num;
|
||||
mc.orient = &target_ship_obj->orient;
|
||||
mc.pos = &target_ship_obj->pos;
|
||||
mc.p0 = &weapon_objp->pos; // Point 1 of ray to check
|
||||
mc.p1 = &expected_pos; // Point 2 of ray to check
|
||||
mc.flags = MC_CHECK_MODEL;
|
||||
|
||||
model_collide(&mc);
|
||||
if (mc.num_hits > 0) {
|
||||
// if the refined point was sufficiently close to the homing point, skip future refinements
|
||||
// (refining the point only matters if the surface impact really is far away from the homing position,
|
||||
// e.g. if a missile is homing on the center of a large ship or large subsystem)
|
||||
float refinement_threshold = std::min(10.0f, wip->shockwave.inner_rad * 0.1f);
|
||||
if (vm_vec_dist_squared(&expected_pos, &mc.hit_point_world) < refinement_threshold * refinement_threshold) {
|
||||
weaponp->homing_cache_ptr->skip_future_refinements = true;
|
||||
weaponp->homing_cache_ptr->valid = false;
|
||||
} else {
|
||||
weaponp->homing_cache_ptr->expected_pos = mc.hit_point_world;
|
||||
weaponp->homing_cache_ptr->valid = true;
|
||||
}
|
||||
} else {
|
||||
weaponp->homing_cache_ptr->valid = false;
|
||||
}
|
||||
|
||||
weaponp->homing_cache_ptr->next_update = _timestamp(500);
|
||||
}
|
||||
|
||||
if (weaponp->homing_cache_ptr->valid) {
|
||||
expected_pos = weaponp->homing_cache_ptr->expected_pos;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!pos_set) {
|
||||
float time_scale;
|
||||
|
||||
if (wip->lifetime - weaponp->lifeleft > 5.0f) {
|
||||
@@ -14744,12 +14650,6 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
|
||||
// See if too far away to care about shockwave.
|
||||
if (vm_vec_dist_quick(&objp->pos, &expected_pos) > danger_dist*2.0f) {
|
||||
// Volition commented this out, but based on testing it looks like removing the flag makes more sense.
|
||||
// Also, the corresponding flag is removed in the distance check for ship shockwaves.
|
||||
if (fix_bugs) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
aip->shockwave_object = -1;
|
||||
}
|
||||
//aip->ai_flags &= ~AIF_AVOID_SHOCKWAVE_WEAPON;
|
||||
return 0;
|
||||
} else {
|
||||
@@ -14782,13 +14682,12 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
Assert(aip->shockwave_object > -1);
|
||||
object *ship_objp = &Objects[aip->shockwave_object];
|
||||
if (ship_objp == objp) {
|
||||
aip->shockwave_object = -1; // this one was already present in retail
|
||||
aip->shockwave_object = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ship_objp->type != OBJ_SHIP) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
if (fix_bugs) aip->shockwave_object = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14802,7 +14701,6 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
|
||||
if (vm_vec_dist_quick(&objp->pos, &ship_objp->pos) > outer_rad*1.5f) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
if (fix_bugs) aip->shockwave_object = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14822,7 +14720,6 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
int ai_avoid_shockwave(object *objp, ai_info *aip)
|
||||
{
|
||||
vec3d safe_pos;
|
||||
bool fix_bugs = The_mission.ai_profile->flags[AI::Profile_Flags::Fix_avoid_shockwave_bugs];
|
||||
|
||||
// BIG|HUGE do not respond to shockwaves
|
||||
// Goober5000 - let's treat shockwave response the same way whether from weapon or ship
|
||||
@@ -14830,33 +14727,9 @@ int ai_avoid_shockwave(object *objp, ai_info *aip)
|
||||
// don't come here again
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
if (fix_bugs) aip->shockwave_object = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Don't try to evade a homing weapon until it starts homing
|
||||
if (fix_bugs && aip->ai_flags[AI::AI_Flags::Avoid_shockwave_weapon] && !(aip->ai_flags[AI::AI_Flags::Avoid_shockwave_started])) {
|
||||
// since the "don't all react right away" timer should only start when the weapon begins homing, we need the actual weapon now...
|
||||
// so choose the weapon ahead of time using the same technique aas_1() would normally use later
|
||||
if (aip->shockwave_object == -1) {
|
||||
aip->shockwave_object = ai_find_shockwave_weapon(objp);
|
||||
if (aip->shockwave_object == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is a homing weapon that isn't homing, don't react yet
|
||||
// (this might be a should-be-dead weapon, in which case it will be pruned with an object type check inside aas_1(),
|
||||
// so to minimize changes to the existing logic, don't prune it here)
|
||||
if (!Objects[aip->shockwave_object].flags[Object::Object_Flags::Should_be_dead]) {
|
||||
auto wp = &Weapons[Objects[aip->shockwave_object].instance];
|
||||
if (Weapon_info[wp->weapon_info_index].is_homing() && IS_VEC_NULL(&wp->homing_pos)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't all react right away.
|
||||
if (!(aip->ai_flags[AI::AI_Flags::Avoid_shockwave_started])) {
|
||||
float evadeChance = (aip->ai_shockwave_evade_chance == FLT_MIN)
|
||||
@@ -15009,7 +14882,7 @@ int ai_need_new_target(object *pl_objp, int target_objnum)
|
||||
|
||||
// Goober5000 - targeting the same team is allowed if pl_objp is going bonkers
|
||||
ai_info *pl_aip = &Ai_info[Ships[pl_objp->instance].ai_index];
|
||||
if (pl_aip->active_goal != AI_ACTIVE_GOAL_NONE && pl_aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) {
|
||||
if (pl_aip->active_goal != AI_GOAL_NONE && pl_aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) {
|
||||
if (pl_aip->goals[pl_aip->active_goal].flags[AI::Goal_Flags::Target_own_team]) {
|
||||
return 0;
|
||||
}
|
||||
@@ -15031,8 +14904,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
float dot, dist;
|
||||
vec3d v2g;
|
||||
|
||||
bool better_collision_avoid_and_fighting = (The_mission.ai_profile->flags[AI::Profile_Flags::Better_combat_collision_avoidance] && aip->mode == AIM_CHASE)
|
||||
|| (The_mission.ai_profile->flags[AI::Profile_Flags::Better_guard_collision_avoidance] && aip->mode == AIM_GUARD);
|
||||
bool better_collision_avoid_and_fighting = The_mission.ai_profile->flags[AI::Profile_Flags::Better_collision_avoidance] && aip->mode == AIM_CHASE;
|
||||
|
||||
// if this guy's in battle he doesn't have the time to spend up to 35 seconds recovering!
|
||||
int phase1_time = better_collision_avoid_and_fighting ? 2 : 5;
|
||||
@@ -15212,7 +15084,7 @@ void ai_frame(int objnum)
|
||||
if ( ai_need_new_target(Pl_objp, target_objnum) ) {
|
||||
if ((aip->mode != AIM_EVADE_WEAPON) && (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC)) {
|
||||
aip->resume_goal_time = -1;
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
} else if (aip->resume_goal_time == -1) {
|
||||
// AL 12-9-97: Don't allow cargo and navbuoys to set their aip->target_objnum
|
||||
if ( Ship_info[shipp->ship_info_index].class_type > -1 && (Ship_types[Ship_info[shipp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_auto_attacks]) ) {
|
||||
@@ -15277,7 +15149,7 @@ void ai_frame(int objnum)
|
||||
|
||||
// If there is a goal to resume and enough time has elapsed, resume the goal.
|
||||
if ((aip->resume_goal_time > 0) && (aip->resume_goal_time < Missiontime)) {
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
aip->resume_goal_time = -1;
|
||||
target_objnum = find_enemy(objnum, 2000.0f, The_mission.ai_profile->max_attackers[Game_skill_level]);
|
||||
if (target_objnum != -1) {
|
||||
@@ -15563,7 +15435,7 @@ void init_ai_object(int objnum)
|
||||
aip->time_enemy_near = 0.0f;
|
||||
aip->last_attack_time = 0;
|
||||
aip->last_hit_time = 0;
|
||||
aip->danger_shield_quadrant = 0;
|
||||
aip->last_hit_quadrant = 0;
|
||||
aip->hitter_objnum = -1;
|
||||
aip->hitter_signature = -1;
|
||||
aip->resume_goal_time = -1;
|
||||
@@ -15583,7 +15455,7 @@ void init_ai_object(int objnum)
|
||||
//Init stuff from AI class and AI profiles
|
||||
init_aip_from_class_and_profile(aip, &Ai_classes[Ship_info[ship_type].ai_class], The_mission.ai_profile);
|
||||
|
||||
aip->wp_list_index = -1;
|
||||
aip->wp_list = NULL;
|
||||
aip->wp_index = INVALID_WAYPOINT_POSITION;
|
||||
|
||||
aip->attacker_objnum = -1;
|
||||
@@ -15769,7 +15641,7 @@ void ai_do_default_behavior(object *obj)
|
||||
// default behavior in most cases (especially if we're docked) is to just stay put
|
||||
aip->mode = AIM_NONE;
|
||||
aip->submode_start_time = Missiontime;
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
|
||||
// if we're not docked, we may modify the behavior a bit
|
||||
if (!object_is_docked(obj))
|
||||
@@ -15942,7 +15814,7 @@ void maybe_process_friendly_hit(object *objp_hitter, object *objp_hit, object *o
|
||||
pp->damage_this_burst += accredited_damage;
|
||||
|
||||
// Done with adjustments to damage. Evaluate based on current friendly_damage
|
||||
nprintf(("AI", "Friendly damage: %.1f, threshold: %.1f, inc damage: %.1f, max burst: %.1f\n", pp->friendly_damage, FRIENDLY_DAMAGE_THRESHOLD * (1.0f + (float) (NUM_SKILL_LEVELS + 1 - Game_skill_level)/3.0f), pp->damage_this_burst, MAX_BURST_DAMAGE ));
|
||||
nprintf(("AI", "Friendly damage: %.1f, threshold: %.1f, inc damage: %.1f, max burst: %d\n", pp->friendly_damage, FRIENDLY_DAMAGE_THRESHOLD * (1.0f + (float) (NUM_SKILL_LEVELS + 1 - Game_skill_level)/3.0f), pp->damage_this_burst, MAX_BURST_DAMAGE ));
|
||||
|
||||
if (is_instructor(objp_hit)) {
|
||||
// it's not nice to hit your instructor
|
||||
@@ -16046,7 +15918,7 @@ int firing_aspect_seeking_bomb(object *objp)
|
||||
// *objp collided with big ship *big_objp at some global point.
|
||||
// Make it fly away from the collision point.
|
||||
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
|
||||
void big_ship_collide_recover_start(const object *objp, const object *big_objp, const vec3d *collision_normal)
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -16083,7 +15955,7 @@ void big_ship_collide_recover_start(const object *objp, const object *big_objp,
|
||||
|
||||
float max_lethality = 0.0f;
|
||||
|
||||
void ai_update_lethality(const object *pship_obj, const object *other_obj, float damage)
|
||||
void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
|
||||
{
|
||||
// Goober5000 - stop any trickle-down errors from ship_do_damage
|
||||
Assert(other_obj);
|
||||
@@ -16136,7 +16008,7 @@ void ai_update_lethality(const object *pship_obj, const object *other_obj, float
|
||||
/**
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
|
||||
*/
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, const vec3d *hit_normal)
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
{
|
||||
int hitter_objnum = -2;
|
||||
object *objp_hitter = nullptr;
|
||||
@@ -16182,7 +16054,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, const vec3d *hit_normal)
|
||||
// And the current object is a small ship
|
||||
if (Ship_info[Ships[objp_ship->instance].ship_info_index].is_small_ship()) {
|
||||
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal); // NOLINT(readability-suspicious-call-argument)
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16479,7 +16351,7 @@ void ai_ship_destroy(int shipnum)
|
||||
set_target_objnum(other_aip, -1);
|
||||
// If this ship had a dynamic goal of chasing the dead ship, clear the dynamic goal.
|
||||
if (other_aip->resume_goal_time != -1)
|
||||
other_aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
other_aip->active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
if (other_aip->goal_objnum == dead_shipp->objnum) {
|
||||
@@ -16646,7 +16518,7 @@ void ai_add_rearm_goal( object *requester_objp, object *support_objp )
|
||||
// ensures that the player get a higher priority!
|
||||
requester_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair); // Tell that I'm awaiting repair.
|
||||
if ( requester_objp->flags[Object::Object_Flags::Player_ship] )
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_REARM_REPAIR, -1, requester_shipp->ship_name, support_aip );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_REARM_REPAIR, -1, requester_shipp->ship_name, support_aip );
|
||||
else
|
||||
ai_add_goal_ship_internal( support_aip, AI_GOAL_REARM_REPAIR, requester_shipp->ship_name, -1, -1 );
|
||||
|
||||
@@ -16831,8 +16703,7 @@ void maybe_cheat_fire_synaptic(object *objp)
|
||||
}
|
||||
}
|
||||
|
||||
bool test_line_of_sight(const vec3d* from, const vec3d* to, SCP_unordered_set<int>&& excluded_object_ids, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj)
|
||||
{
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj) {
|
||||
bool collides = false;
|
||||
|
||||
for (object* objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
|
||||
@@ -16840,7 +16711,7 @@ bool test_line_of_sight(const vec3d* from, const vec3d* to, SCP_unordered_set<in
|
||||
continue;
|
||||
|
||||
//Don't collision check against excluded objects
|
||||
if (excluded_object_ids.contains(OBJ_INDEX(objp)))
|
||||
if (excluded_object_ids.count(OBJ_INDEX(objp)) > 0)
|
||||
continue;
|
||||
|
||||
int model_num = 0;
|
||||
|
||||
+105
-162
@@ -53,14 +53,8 @@ struct ship_registry_entry;
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
inline bool purge_goals_one_ship(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_IGNORE_NEW;
|
||||
}
|
||||
#define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
|
||||
#define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
|
||||
|
||||
// goals given from the player to other ships in the game are also handled in this
|
||||
// code
|
||||
@@ -92,7 +86,7 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
|
||||
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
|
||||
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
|
||||
{ "Keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
|
||||
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
|
||||
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
|
||||
@@ -108,7 +102,7 @@ int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
|
||||
// HUD what a ship's current orders are. If the AI goal doesn't correspond to something that
|
||||
// ought to be printable, then NULL is used.
|
||||
// JAS: Converted to a function in order to externalize the strings
|
||||
const char *Ai_goal_text(ai_goal_mode goal, int submode)
|
||||
const char *Ai_goal_text(int goal, int submode)
|
||||
{
|
||||
switch(goal) {
|
||||
case AI_GOAL_CHASE:
|
||||
@@ -141,22 +135,22 @@ const char *Ai_goal_text(ai_goal_mode goal, int submode)
|
||||
return XSTR( "rearm ", 484);
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
return XSTR( "rendezvous with ", 1597);
|
||||
case AI_GOAL_LUA: {
|
||||
case AI_GOAL_LUA:
|
||||
auto mode = ai_lua_find_mode(submode);
|
||||
if (mode == nullptr)
|
||||
return nullptr;
|
||||
return mode->hudText;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Avoid compiler warning
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all fields to their uninitialized defaults. But if this is being called before adding a new goal, the function will set the correct signature and time.
|
||||
* Similarly the added mode, submode, and type can be assigned.
|
||||
*/
|
||||
void ai_goal_reset(ai_goal *aigp, bool adding_goal, ai_goal_mode ai_mode, int ai_submode, ai_goal_type type)
|
||||
void ai_goal_reset(ai_goal *aigp, bool adding_goal, int ai_mode, int ai_submode, int type)
|
||||
{
|
||||
if (ai_mode != AI_GOAL_NONE)
|
||||
Assertion(adding_goal, "If a goal mode is being assigned, the adding_goal parameter must be true so that the signature and mission time can be set");
|
||||
@@ -172,7 +166,7 @@ void ai_goal_reset(ai_goal *aigp, bool adding_goal, ai_goal_mode ai_mode, int ai
|
||||
aigp->target_name = nullptr;
|
||||
aigp->target_name_index = -1;
|
||||
|
||||
aigp->wp_list_index = -1;
|
||||
aigp->wp_list = nullptr;
|
||||
|
||||
aigp->target_instance = -1;
|
||||
aigp->target_signature = -1;
|
||||
@@ -221,13 +215,13 @@ void ai_maybe_add_form_goal(wing* wingp)
|
||||
if (Netgame.type_flags & NG_TYPE_TEAM) {
|
||||
const ship_registry_entry* ship_regp = ship_registry_get(Ships[wingp->ship_index[j]].ship_name);
|
||||
wingnum = TVT_wings[ship_regp->p_objp()->team];
|
||||
ai_add_ship_goal_player(ai_goal_type::PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Ships[Wings[wingnum].ship_index[Wings[wingnum].special_ship]].ship_name, aip);
|
||||
ai_add_ship_goal_player(AIG_TYPE_PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Ships[Wings[wingnum].ship_index[Wings[wingnum].special_ship]].ship_name, aip);
|
||||
} else {
|
||||
wingnum = Starting_wings[0];
|
||||
ai_add_ship_goal_player(ai_goal_type::PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Ships[Wings[wingnum].ship_index[Wings[wingnum].special_ship]].ship_name, aip);
|
||||
ai_add_ship_goal_player(AIG_TYPE_PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Ships[Wings[wingnum].ship_index[Wings[wingnum].special_ship]].ship_name, aip);
|
||||
}
|
||||
} else if (!(Game_mode & GM_MULTIPLAYER)) {
|
||||
ai_add_ship_goal_player(ai_goal_type::PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Player_ship->ship_name, aip);
|
||||
ai_add_ship_goal_player(AIG_TYPE_PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Player_ship->ship_name, aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,13 +280,13 @@ void ai_post_process_mission()
|
||||
* Determines if a goal is valid for a particular type of ship
|
||||
*
|
||||
* @param ship Ship type to test
|
||||
* @param ai_mode Goal type to test
|
||||
* @param ai_goal_type Goal type to test
|
||||
*/
|
||||
int ai_query_goal_valid( int ship, ai_goal_mode ai_mode )
|
||||
int ai_query_goal_valid( int ship, int ai_goal_type )
|
||||
{
|
||||
int accepted;
|
||||
|
||||
if (ai_mode == AI_GOAL_NONE || ai_mode == AI_GOAL_LUA)
|
||||
if (ai_goal_type == AI_GOAL_NONE || ai_goal_type == AI_GOAL_LUA)
|
||||
return 1; // anything can have no orders or Lua'd orders.
|
||||
|
||||
accepted = 0;
|
||||
@@ -302,8 +296,7 @@ int ai_query_goal_valid( int ship, ai_goal_mode ai_mode )
|
||||
int ship_type = Ship_info[Ships[ship].ship_info_index].class_type;
|
||||
if(ship_type > -1)
|
||||
{
|
||||
const auto &set = Ship_types[ship_type].ai_valid_goals;
|
||||
if (set.find(ai_mode) != set.end()) {
|
||||
if(ai_goal_type & Ship_types[ship_type].ai_valid_goals) {
|
||||
accepted = 1;
|
||||
}
|
||||
}
|
||||
@@ -348,7 +341,7 @@ void ai_remove_ship_goal( ai_info *aip, int index )
|
||||
}
|
||||
}
|
||||
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
ai_goal_reset(&aip->goals[index]);
|
||||
@@ -365,7 +358,7 @@ void ai_clear_ship_goals( ai_info *aip )
|
||||
for (i = 0; i < MAX_AI_GOALS; i++)
|
||||
ai_remove_ship_goal( aip, i ); // resets active_goal and default behavior
|
||||
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE; // for good measure
|
||||
aip->active_goal = AI_GOAL_NONE; // for good measure
|
||||
|
||||
// next line moved here on 8/5/97 by MWA
|
||||
// Don't reset player ai (and hence target)
|
||||
@@ -465,8 +458,9 @@ void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
|
||||
|
||||
void ai_mission_goal_complete( ai_info *aip )
|
||||
{
|
||||
// if the active goal is dynamic or none, just return.
|
||||
if ( (aip->active_goal == AI_ACTIVE_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
// if the active goal is dynamic or none, just return. (AI_GOAL_NONE is probably an error, but
|
||||
// I don't think that this is a problem)
|
||||
if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
return;
|
||||
|
||||
ai_remove_ship_goal( aip, aip->active_goal );
|
||||
@@ -503,7 +497,9 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
|
||||
purge_goal = goal_list;
|
||||
for ( i = 0; i < MAX_AI_GOALS; purge_goal++, i++ ) {
|
||||
auto purge_ai_mode = purge_goal->ai_mode;
|
||||
int purge_ai_mode, purge_wing;
|
||||
|
||||
purge_ai_mode = purge_goal->ai_mode;
|
||||
|
||||
// don't need to process AI_GOAL_NONE
|
||||
if ( purge_ai_mode == AI_GOAL_NONE )
|
||||
@@ -523,7 +519,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// 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.
|
||||
int purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
|
||||
purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
|
||||
|
||||
// if the target of the purge goal is a ship (purge_wing will be -1), then if the names
|
||||
// don't match, we can continue; if the wing is valid, don't process if the wing numbers
|
||||
@@ -540,7 +536,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// ignore goals should get rid of any kind of attack goal
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
if (ai_goal_is_disable_or_disarm(purge_ai_mode) || ai_goal_is_specific_chase(purge_ai_mode) || (purge_ai_mode == AI_GOAL_DESTROY_SUBSYSTEM))
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
break;
|
||||
|
||||
@@ -548,7 +544,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// (but not tactical disarm/disable)
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
if (ai_goal_is_specific_chase(purge_ai_mode)) {
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
|
||||
int ai_ship_type;
|
||||
|
||||
// for wings we grab the ship type of the wing leader
|
||||
@@ -589,7 +585,7 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
|
||||
ship_obj *sop;
|
||||
|
||||
// only purge goals if a new goal is one of the types in next statement
|
||||
if (!purge_goals_all_ships(aigp->ai_mode))
|
||||
if (!(aigp->ai_mode & PURGE_GOALS_ALL_SHIPS))
|
||||
return;
|
||||
|
||||
for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
|
||||
@@ -732,9 +728,9 @@ 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, const ai_lua_parameters& lua_target )
|
||||
void ai_add_goal_sub_player(int type, int 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) );
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
ai_goal_reset(aigp, true, mode, submode, type);
|
||||
|
||||
@@ -742,8 +738,8 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
|
||||
|
||||
if ( mode == AI_GOAL_WARP ) {
|
||||
if (submode >= 0) {
|
||||
aigp->wp_list_index = submode;
|
||||
Assert(find_waypoint_list_at_index(aigp->wp_list_index) != nullptr);
|
||||
aigp->wp_list = find_waypoint_list_at_index(submode);
|
||||
Assert(aigp->wp_list != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,7 +766,7 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
|
||||
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)
|
||||
else if ( aigp->type == AIG_TYPE_PLAYER_WING )
|
||||
aigp->priority = PLAYER_PRIORITY_WING; // player wing goals not as high as ship goals
|
||||
else
|
||||
aigp->priority = PLAYER_PRIORITY_SHIP;
|
||||
@@ -822,9 +818,9 @@ int ai_goal_num(ai_goal *goals)
|
||||
}
|
||||
|
||||
|
||||
void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode, int priority, const char *target_name, ai_goal *aigp, int int_data, float float_data)
|
||||
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, const char *target_name, ai_goal *aigp )
|
||||
{
|
||||
Assert ( (type == ai_goal_type::PLAYER_WING) || (type == ai_goal_type::PLAYER_SHIP) );
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
ai_goal_reset(aigp, true, mode, submode, type);
|
||||
|
||||
@@ -837,18 +833,16 @@ void ai_add_goal_sub_scripting(ai_goal_type type, ai_goal_mode mode, int submode
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
|
||||
aigp->priority = priority;
|
||||
aigp->int_data = int_data;
|
||||
aigp->float_data = float_data;
|
||||
}
|
||||
|
||||
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)
|
||||
void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip)
|
||||
{
|
||||
int empty_index;
|
||||
ai_goal *aigp;
|
||||
|
||||
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);
|
||||
ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
|
||||
|
||||
//WMC - hack to get docking setup correctly
|
||||
if ( mode == AI_GOAL_DOCK ) {
|
||||
@@ -865,7 +859,7 @@ 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, const ai_lua_parameters& lua_target)
|
||||
void ai_add_ship_goal_player( int type, int mode, int submode, const char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int empty_index;
|
||||
ai_goal *aigp;
|
||||
@@ -886,7 +880,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, const ai_lua_parameters& lua_target)
|
||||
void ai_add_wing_goal_player( int type, int mode, int submode, const char *shipname, int wingnum, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int i, empty_index;
|
||||
wing *wingp = &Wings[wingnum];
|
||||
@@ -910,10 +904,9 @@ void ai_add_wing_goal_player(ai_goal_type type, ai_goal_mode mode, int submode,
|
||||
|
||||
|
||||
// common routine to add a sexpression mission goal to the appropriate goal structure.
|
||||
void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *aigp, const char *actor_name )
|
||||
void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name )
|
||||
{
|
||||
int node, dummy, op;
|
||||
bool priority_is_nan = false, priority_is_nan_forever = false;
|
||||
|
||||
Assert ( Sexp_nodes[sexp].first != -1 );
|
||||
node = Sexp_nodes[sexp].first;
|
||||
@@ -939,7 +932,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
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->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS;
|
||||
if ( op == OP_AI_WAYPOINTS_ONCE )
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS_ONCE;
|
||||
@@ -957,9 +950,9 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
// store the name of the subsystem in the docker.name field for now -- this field must get
|
||||
// fixed up when the goal is valid since we need to locate the subsystem on the ship's model
|
||||
aigp->docker.name = ai_get_goal_target_name(CTEXT(CDDR(node)), &dummy);
|
||||
aigp->docker.name = ai_get_goal_target_name(CTEXT(CDR(CDR(node))), &dummy);
|
||||
aigp->flags.set(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
aigp->priority = eval_num(CDDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(node)))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
@@ -967,7 +960,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_ENGINE;
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DISARM_SHIP:
|
||||
@@ -975,27 +968,27 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_TURRET;
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_WARP_OUT:
|
||||
aigp->ai_mode = AI_GOAL_WARP;
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
break;
|
||||
|
||||
// the following goal is obsolete, but here for compatibility
|
||||
case OP_AI_WARP:
|
||||
aigp->ai_mode = AI_GOAL_WARP;
|
||||
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->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_UNDOCK:
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
|
||||
// Goober5000 - optional undock with something
|
||||
if (CDDR(node) != -1)
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDDR(node)), &aigp->target_name_index );
|
||||
if (CDR(CDR(node)) != -1)
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(CDR(node))), &aigp->target_name_index );
|
||||
|
||||
aigp->ai_mode = AI_GOAL_UNDOCK;
|
||||
aigp->ai_submode = AIS_UNDOCK_0;
|
||||
@@ -1005,7 +998,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
{
|
||||
aigp->ai_mode = AI_GOAL_REARM_REPAIR;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
// this goal needs some extra setup
|
||||
// if this doesn't work, the goal will be immediately removed
|
||||
@@ -1023,36 +1016,36 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
case OP_AI_STAY_STILL:
|
||||
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);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DOCK:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->docker.name = ai_add_dock_name(CTEXT(CDDR(node)));
|
||||
aigp->dockee.name = ai_add_dock_name(CTEXT(CDDDR(node)));
|
||||
aigp->priority = eval_num(CDDDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
|
||||
aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
|
||||
|
||||
aigp->ai_mode = AI_GOAL_DOCK;
|
||||
aigp->ai_submode = AIS_DOCK_0; // be sure to set the submode
|
||||
break;
|
||||
|
||||
case OP_AI_CHASE_ANY:
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_CHASE_ANY;
|
||||
break;
|
||||
|
||||
case OP_AI_PLAY_DEAD:
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
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->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
break;
|
||||
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
aigp->priority = eval_num(CDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
|
||||
@@ -1062,7 +1055,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDDR(node)) );
|
||||
|
||||
// distance from ship
|
||||
if ( CDDDR(node) < 0 )
|
||||
@@ -1098,7 +1091,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
case OP_AI_IGNORE:
|
||||
case OP_AI_IGNORE_NEW:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = eval_num(CDDR(node), priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
if ( op == OP_AI_CHASE ) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE;
|
||||
@@ -1148,7 +1141,7 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
localnode = CDR(localnode);
|
||||
}
|
||||
|
||||
aigp->priority = eval_num(localnode, priority_is_nan, priority_is_nan_forever);
|
||||
aigp->priority = atoi( CTEXT(localnode) );
|
||||
|
||||
aigp->lua_ai_target = { std::move(target), luaAIMode->sexp.getSEXPArgumentList(CDR(localnode)) };
|
||||
}
|
||||
@@ -1157,12 +1150,8 @@ void ai_add_goal_sub_sexp( int sexp, ai_goal_type type, ai_info *aip, ai_goal *a
|
||||
}
|
||||
}
|
||||
|
||||
if ( priority_is_nan || priority_is_nan_forever ) {
|
||||
Warning(LOCATION, "add-goal tried to add %s with a NaN priority; aborting...", Sexp_nodes[CAR(sexp)].text);
|
||||
ai_goal_reset(aigp);
|
||||
return;
|
||||
} 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));
|
||||
if ( aigp->priority > MAX_GOAL_PRIORITY ) {
|
||||
nprintf (("AI", "bashing sexpression priority of goal %s from %d to %d.\n", CTEXT(node), aigp->priority, MAX_GOAL_PRIORITY));
|
||||
aigp->priority = MAX_GOAL_PRIORITY;
|
||||
}
|
||||
|
||||
@@ -1238,10 +1227,9 @@ int ai_find_goal_index( ai_goal* aigp, int mode, int submode, int priority )
|
||||
|
||||
/* Remove a goal from the given goals structure
|
||||
* Returns the index of the goal that it clears out.
|
||||
* This is important so that if active_goal == index you can set AI_ACTIVE_GOAL_NONE.
|
||||
* NOTE: Callers should check the value of remove_more. If it is true, the function should be called again.
|
||||
* This is important so that if active_goal == index you can set AI_GOAL_NONE
|
||||
*/
|
||||
int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
{
|
||||
/* Sanity check */
|
||||
Assert( Sexp_nodes[ sexp ].first != -1 );
|
||||
@@ -1257,150 +1245,115 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
/* The operator to use */
|
||||
int op = get_operator_const( node );
|
||||
|
||||
// since this logic is common to all goals removed by the remove-goal sexp
|
||||
auto eval_priority_et_seq = [sexp, &remove_more](int n, int priority_if_no_n = -1)->int
|
||||
{
|
||||
bool _priority_is_nan = false, _priority_is_nan_forever = false;
|
||||
|
||||
int _priority = (n >= 0) ? eval_num(n, _priority_is_nan, _priority_is_nan_forever) : priority_if_no_n;
|
||||
n = CDR(sexp); // we want the first node after the goal sub-tree
|
||||
|
||||
if (_priority_is_nan || _priority_is_nan_forever)
|
||||
{
|
||||
Warning(LOCATION, "remove-goal tried to remove %s with a NaN priority; the priority will not be used for goal comparison", Sexp_nodes[CAR(sexp)].text);
|
||||
_priority = -1;
|
||||
}
|
||||
else if (_priority > MAX_GOAL_PRIORITY)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
remove_more = is_sexp_true(n);
|
||||
n = CDR(n);
|
||||
}
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
if (is_sexp_true(n))
|
||||
_priority = -1;
|
||||
n = CDR(n);
|
||||
}
|
||||
|
||||
return _priority;
|
||||
};
|
||||
|
||||
/* We now need to determine what the mode and submode values are*/
|
||||
switch( op )
|
||||
{
|
||||
case OP_AI_WAYPOINTS_ONCE:
|
||||
goalmode = AI_GOAL_WAYPOINTS_ONCE;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WAYPOINTS:
|
||||
goalmode = AI_GOAL_WAYPOINTS;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DESTROY_SUBSYS:
|
||||
goalmode = AI_GOAL_DESTROY_SUBSYSTEM;
|
||||
priority = eval_priority_et_seq(CDDDR(node));
|
||||
priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISARM_SHIP:
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WARP_OUT:
|
||||
goalmode = AI_GOAL_WARP;
|
||||
priority = eval_priority_et_seq(CDR(node));
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WARP:
|
||||
goalmode = AI_GOAL_WARP;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_UNDOCK:
|
||||
goalmode = AI_GOAL_UNDOCK;
|
||||
goalsubmode = AIS_UNDOCK_0;
|
||||
priority = eval_priority_et_seq(CDR(node));
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_STAY_STILL:
|
||||
goalmode = AI_GOAL_STAY_STILL;
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DOCK:
|
||||
goalmode = AI_GOAL_DOCK;
|
||||
goalsubmode = AIS_DOCK_0;
|
||||
priority = eval_priority_et_seq(CDDDDR(node));
|
||||
priority = ( CDR( CDR( CDR( CDR(node) ) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( CDR( node ) ) ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_CHASE_ANY:
|
||||
goalmode = AI_GOAL_CHASE_ANY;
|
||||
priority = eval_priority_et_seq(CDR(node));
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD:
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = eval_priority_et_seq(CDR(node));
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
priority = eval_priority_et_seq(CDR(node));
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
goalmode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
case OP_AI_CHASE:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
if ( wing_name_lookup( CTEXT( CDR( node ) ), 1 ) != -1 )
|
||||
goalmode = AI_GOAL_CHASE_WING;
|
||||
else
|
||||
goalmode = AI_GOAL_CHASE;
|
||||
break;
|
||||
case OP_AI_GUARD:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
if ( wing_name_lookup( CTEXT( CDR( node ) ), 1 ) != -1 )
|
||||
goalmode = AI_GOAL_GUARD_WING;
|
||||
else
|
||||
goalmode = AI_GOAL_GUARD;
|
||||
break;
|
||||
case OP_AI_GUARD_WING:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_GUARD_WING;
|
||||
break;
|
||||
case OP_AI_CHASE_WING:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_CHASE_WING;
|
||||
break;
|
||||
case OP_AI_CHASE_SHIP_CLASS:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
break;
|
||||
case OP_AI_EVADE_SHIP:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_EVADE_SHIP;
|
||||
break;
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
case OP_AI_IGNORE:
|
||||
case OP_AI_IGNORE_NEW:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
|
||||
break;
|
||||
case OP_AI_FORM_ON_WING:
|
||||
priority = eval_priority_et_seq(-1, 99);
|
||||
priority = 99;
|
||||
goalmode = AI_GOAL_FORM_ON_WING;
|
||||
break;
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_FLY_TO_SHIP;
|
||||
break;
|
||||
case OP_AI_REARM_REPAIR:
|
||||
priority = eval_priority_et_seq(CDDR(node));
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_REARM_REPAIR;
|
||||
break;
|
||||
default:
|
||||
@@ -1416,7 +1369,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
localnode = CDR(localnode);
|
||||
}
|
||||
|
||||
priority = eval_priority_et_seq(localnode);
|
||||
priority = localnode >= 0 ? atoi( CTEXT(localnode) ) : -1;
|
||||
}
|
||||
else {
|
||||
UNREACHABLE("Invalid SEXP-OP %s (number %d) for an AI goal!", Sexp_nodes[node].text, op);
|
||||
@@ -1428,10 +1381,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more )
|
||||
int goalindex = ai_find_goal_index( aigp, goalmode, goalsubmode, priority );
|
||||
|
||||
if ( goalindex == -1 )
|
||||
{
|
||||
remove_more = false;
|
||||
return -1; /* no more to do; */
|
||||
}
|
||||
|
||||
/* Clear out the contents of the goal. We can't use ai_remove_ship_goal since it needs ai_info and
|
||||
* we've only got ai_goals */
|
||||
@@ -1445,7 +1395,6 @@ void ai_remove_wing_goal_sexp(int sexp, wing *wingp)
|
||||
{
|
||||
int i;
|
||||
int goalindex = -1;
|
||||
bool remove_more = false;
|
||||
|
||||
// remove the ai goal for any ship that is currently arrived in the game (only if fred isn't running)
|
||||
if ( !Fred_running ) {
|
||||
@@ -1453,13 +1402,9 @@ void ai_remove_wing_goal_sexp(int sexp, wing *wingp)
|
||||
int num = wingp->ship_index[i];
|
||||
if ( num == -1 ) // ship must have been destroyed or departed
|
||||
continue;
|
||||
auto aip = &Ai_info[Ships[num].ai_index];
|
||||
|
||||
do {
|
||||
goalindex = ai_remove_goal_sexp_sub(sexp, aip->goals, remove_more);
|
||||
if (aip->active_goal == goalindex)
|
||||
aip->active_goal = AI_ACTIVE_GOAL_NONE;
|
||||
} while (remove_more);
|
||||
goalindex = ai_remove_goal_sexp_sub( sexp, Ai_info[Ships[num].ai_index].goals );
|
||||
if ( Ai_info[Ships[num].ai_index].active_goal == goalindex )
|
||||
Ai_info[Ships[num].ai_index].active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1467,15 +1412,13 @@ void ai_remove_wing_goal_sexp(int sexp, wing *wingp)
|
||||
// there are more waves to come
|
||||
if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running)
|
||||
{
|
||||
do {
|
||||
ai_remove_goal_sexp_sub(sexp, wingp->ai_goals, remove_more);
|
||||
} while (remove_more);
|
||||
ai_remove_goal_sexp_sub( sexp, wingp->ai_goals );
|
||||
}
|
||||
}
|
||||
|
||||
// adds an ai goal for an individual ship
|
||||
// type determines who has issues this ship a goal (i.e. the player/mission event/etc)
|
||||
void ai_add_ship_goal_sexp( int sexp, ai_goal_type type, ai_info *aip )
|
||||
void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip )
|
||||
{
|
||||
int gindex;
|
||||
|
||||
@@ -1484,7 +1427,7 @@ void ai_add_ship_goal_sexp( int sexp, ai_goal_type type, ai_info *aip )
|
||||
}
|
||||
|
||||
// code to add ai goals to wings.
|
||||
void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp)
|
||||
void ai_add_wing_goal_sexp(int sexp, int type, wing *wingp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1530,7 +1473,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
|
||||
aigp = &(aip->goals[gindex]);
|
||||
ai_goal_reset(aigp, true);
|
||||
|
||||
aigp->type = ai_goal_type::DYNAMIC;
|
||||
aigp->type = AIG_TYPE_DYNAMIC;
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
|
||||
switch ( goal_type ) {
|
||||
@@ -1662,10 +1605,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// check to see if we have a valid list. If not, then try to set one up. If that
|
||||
// fails, then we must pitch this order
|
||||
if ( (aigp->ai_mode == AI_GOAL_WAYPOINTS_ONCE) || (aigp->ai_mode == AI_GOAL_WAYPOINTS) ) {
|
||||
if ( aigp->wp_list_index < 0 ) {
|
||||
aigp->wp_list_index = find_matching_waypoint_list_index(aigp->target_name);
|
||||
if ( aigp->wp_list == NULL ) {
|
||||
aigp->wp_list = find_matching_waypoint_list(aigp->target_name);
|
||||
|
||||
if ( aigp->wp_list_index < 0 ) {
|
||||
if ( aigp->wp_list == NULL ) {
|
||||
Warning(LOCATION, "Unknown waypoint list %s - not found in mission file. Killing ai goal", aigp->target_name );
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
@@ -1917,11 +1860,11 @@ 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 (purge_goals_all_ships(aigp->ai_mode)) {
|
||||
if (aigp->ai_mode & PURGE_GOALS_ALL_SHIPS) {
|
||||
ai_goal_purge_all_invalid_goals(aigp);
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
else if (purge_goals_one_ship(aigp->ai_mode)) {
|
||||
else if (aigp->ai_mode & PURGE_GOALS_ONE_SHIP) {
|
||||
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
@@ -2401,7 +2344,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
flags |= WPF_REPEAT;
|
||||
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
|
||||
flags |= WPF_BACKTRACK;
|
||||
ai_start_waypoints(objp, current_goal->wp_list_index, flags, current_goal->int_data);
|
||||
ai_start_waypoints(objp, current_goal->wp_list, flags, current_goal->int_data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+74
-82
@@ -24,87 +24,81 @@ struct ai_info;
|
||||
|
||||
// macros for goals which get set via sexpressions in the mission code
|
||||
|
||||
// types of ai goals -- these will help us to determine which goals should
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
enum class ai_goal_type
|
||||
{
|
||||
INVALID = 0,
|
||||
EVENT_SHIP, // from mission event direct to ship
|
||||
EVENT_WING, // from mission event direct to wing
|
||||
PLAYER_SHIP, // from player direct to ship
|
||||
PLAYER_WING, // from player direct to wing
|
||||
DYNAMIC // created on the fly
|
||||
};
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x enum, be sure to update the functions
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x define, be sure to update the functions
|
||||
// ai_update_goal_references() and query_referenced_in_ai_goals() or else risk breaking
|
||||
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
|
||||
// to worry about doing this. Also add it to list in Fred\Management.cpp, and let Hoffoss know!
|
||||
// WMC - Oh and add them to Ai_goal_names plz. TY! :)
|
||||
// Goober5000 - As well as Ai_goal_text and Ai_goal_list, if appropriate
|
||||
enum ai_goal_mode : uint8_t
|
||||
{
|
||||
AI_GOAL_NONE = 0,
|
||||
AI_GOAL_PLACEHOLDER_1,
|
||||
#define AI_GOAL_CHASE (1<<1) // 0x00000002
|
||||
#define AI_GOAL_DOCK (1<<2) // 0x00000004 // used for undocking as well
|
||||
#define AI_GOAL_WAYPOINTS (1<<3) // 0x00000008
|
||||
#define AI_GOAL_WAYPOINTS_ONCE (1<<4) // 0x00000010
|
||||
#define AI_GOAL_WARP (1<<5) // 0x00000020
|
||||
#define AI_GOAL_DESTROY_SUBSYSTEM (1<<6) // 0x00000040
|
||||
#define AI_GOAL_FORM_ON_WING (1<<7) // 0x00000080
|
||||
#define AI_GOAL_UNDOCK (1<<8) // 0x00000100
|
||||
#define AI_GOAL_CHASE_WING (1<<9) // 0x00000200
|
||||
#define AI_GOAL_GUARD (1<<10) // 0x00000400
|
||||
#define AI_GOAL_DISABLE_SHIP (1<<11) // 0x00000800
|
||||
#define AI_GOAL_DISARM_SHIP (1<<12) // 0x00001000
|
||||
#define AI_GOAL_CHASE_ANY (1<<13) // 0x00002000
|
||||
#define AI_GOAL_IGNORE (1<<14) // 0x00004000
|
||||
#define AI_GOAL_GUARD_WING (1<<15) // 0x00008000
|
||||
#define AI_GOAL_EVADE_SHIP (1<<16) // 0x00010000
|
||||
|
||||
AI_GOAL_CHASE, // 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,
|
||||
AI_GOAL_WARP,
|
||||
AI_GOAL_DESTROY_SUBSYSTEM,
|
||||
AI_GOAL_FORM_ON_WING,
|
||||
AI_GOAL_UNDOCK,
|
||||
AI_GOAL_CHASE_WING,
|
||||
AI_GOAL_GUARD,
|
||||
AI_GOAL_DISABLE_SHIP,
|
||||
AI_GOAL_DISARM_SHIP,
|
||||
AI_GOAL_CHASE_ANY,
|
||||
AI_GOAL_IGNORE,
|
||||
AI_GOAL_GUARD_WING,
|
||||
AI_GOAL_EVADE_SHIP,
|
||||
// the next goals are for support ships only
|
||||
#define AI_GOAL_STAY_NEAR_SHIP (1<<17) // 0x00020000
|
||||
#define AI_GOAL_KEEP_SAFE_DISTANCE (1<<18) // 0x00040000
|
||||
#define AI_GOAL_REARM_REPAIR (1<<19) // 0x00080000
|
||||
|
||||
// the next goals are for support ships only
|
||||
AI_GOAL_STAY_NEAR_SHIP,
|
||||
AI_GOAL_KEEP_SAFE_DISTANCE,
|
||||
AI_GOAL_REARM_REPAIR,
|
||||
// resume regular goals
|
||||
#define AI_GOAL_STAY_STILL (1<<20) // 0x00100000
|
||||
#define AI_GOAL_PLAY_DEAD (1<<21) // 0x00200000
|
||||
|
||||
// resume regular goals
|
||||
AI_GOAL_STAY_STILL,
|
||||
AI_GOAL_PLAY_DEAD,
|
||||
// added by SCP
|
||||
#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
|
||||
// added by SCP
|
||||
AI_GOAL_CHASE_WEAPON,
|
||||
AI_GOAL_FLY_TO_SHIP,
|
||||
AI_GOAL_IGNORE_NEW,
|
||||
AI_GOAL_CHASE_SHIP_CLASS,
|
||||
AI_GOAL_PLAY_DEAD_PERSISTENT,
|
||||
AI_GOAL_LUA,
|
||||
AI_GOAL_DISARM_SHIP_TACTICAL,
|
||||
AI_GOAL_DISABLE_SHIP_TACTICAL,
|
||||
// now the masks for ship types
|
||||
|
||||
AI_GOAL_NUM_VALUES
|
||||
};
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_FREIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CRUISER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FREIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CORVETTE ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_GAS_MINER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_AWACS ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CAPITAL ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER & ~(AI_GOAL_DOCK | AI_GOAL_UNDOCK) | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPERCAP ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CAPITAL | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT )
|
||||
#define AI_GOAL_ACCEPT_ESCAPEPOD ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT| AI_GOAL_STAY_NEAR_SHIP )
|
||||
*/
|
||||
|
||||
inline ai_goal_mode int_to_ai_goal_mode(int int_mode)
|
||||
{
|
||||
if (int_mode >= 0 && int_mode < AI_GOAL_NUM_VALUES)
|
||||
return static_cast<ai_goal_mode>(int_mode);
|
||||
|
||||
Warning(LOCATION, "ai_goal_mode %d out of range! Setting to AI_GOAL_NONE.", int_mode);
|
||||
return AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
inline bool ai_goal_is_disable_or_disarm(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_DISABLE_SHIP || ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL || ai_mode == AI_GOAL_DISARM_SHIP || ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
}
|
||||
inline bool ai_goal_is_specific_chase(ai_goal_mode ai_mode)
|
||||
{
|
||||
return ai_mode == AI_GOAL_CHASE || ai_mode == AI_GOAL_CHASE_WING || ai_mode == AI_GOAL_CHASE_SHIP_CLASS;
|
||||
}
|
||||
#define MAX_AI_DOCK_NAMES 25
|
||||
|
||||
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
|
||||
|
||||
@@ -116,16 +110,16 @@ struct ai_lua_parameters {
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
ai_goal_mode ai_mode; // one of the AI_GOAL_* modes for this goal
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
ai_goal_type type; // one of the ai_goal_type (originally AIG_TYPE_*) values above
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
int wp_list_index; // waypoints that this ship might fly.
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
@@ -150,20 +144,18 @@ typedef struct ai_goal {
|
||||
|
||||
} ai_goal;
|
||||
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, ai_goal_mode ai_mode = AI_GOAL_NONE, int ai_submode = -1, ai_goal_type type = ai_goal_type::INVALID);
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, int ai_mode = AI_GOAL_NONE, int ai_submode = -1, int type = -1);
|
||||
|
||||
|
||||
typedef flag_def_list_templated<ai_goal_mode> ai_goal_list;
|
||||
typedef flag_def_list ai_goal_list;
|
||||
|
||||
extern ai_goal_list Ai_goal_names[];
|
||||
extern int Num_ai_goals;
|
||||
|
||||
#define MAX_AI_DOCK_NAMES 25
|
||||
|
||||
extern int Num_ai_dock_names;
|
||||
extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
extern const char *Ai_goal_text(ai_goal_mode goal, int submode);
|
||||
extern const char *Ai_goal_text(int goal, int submode);
|
||||
|
||||
// every goal in a mission gets a unique signature
|
||||
extern int Ai_goal_signature;
|
||||
@@ -176,17 +168,17 @@ extern void ai_process_mission_orders( int objnum, ai_info *aip );
|
||||
extern int ai_goal_num(ai_goal *goals);
|
||||
|
||||
// adds goals to ships/wing through sexpressions
|
||||
extern void ai_add_ship_goal_scripting(ai_goal_mode mode, int submode, int priority, const char *shipname, ai_info *aip, int int_data, float float_data);
|
||||
extern void ai_add_ship_goal_sexp(int sexp, ai_goal_type type, ai_info *aip);
|
||||
extern void ai_add_wing_goal_sexp(int sexp, ai_goal_type type, wing *wingp);
|
||||
extern void ai_add_goal_sub_sexp(int sexp, ai_goal_type type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, wing *wingp );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp, bool &remove_more );
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
|
||||
|
||||
// adds goals to ships/sings through player orders
|
||||
extern void ai_add_ship_goal_player(ai_goal_type type, ai_goal_mode mode, int submode, const char* shipname, ai_info* aip, 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_add_ship_goal_player(int type, int mode, int submode, const char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(int type, int mode, int submode, const char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
|
||||
extern void ai_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
@@ -201,7 +193,7 @@ extern void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const
|
||||
extern bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name);
|
||||
extern char *ai_add_dock_name(const char *str);
|
||||
|
||||
extern int ai_query_goal_valid( int ship, ai_goal_mode ai_mode );
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
extern void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate = 1 );
|
||||
|
||||
|
||||
+130
-231
@@ -6,7 +6,6 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "freespace.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "iff_defs/iff_defs.h"
|
||||
@@ -26,7 +25,6 @@
|
||||
#include "weapon/muzzleflash.h"
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
#include "utils/modular_curves.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
@@ -1225,7 +1223,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
|
||||
|
||||
if (use_angles) {
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
|
||||
vm_vec_normalize(gvec);
|
||||
} else {
|
||||
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
|
||||
vm_vec_normalized_dir(gvec, targetp, gpos);
|
||||
@@ -1334,17 +1331,16 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
|
||||
if (!in_lab && ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem* tp = ss->system_info;
|
||||
|
||||
// Get the normalized dir between the turret and the predicted enemy position.
|
||||
// If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
//Get the normalized dir between the turret and the predicted enemy position.
|
||||
//If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
|
||||
|
||||
bool in_fov;
|
||||
|
||||
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
|
||||
|
||||
if (in_fov) {
|
||||
@@ -1352,15 +1348,8 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
} else if (!in_lab && (ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
} else if (in_lab) {
|
||||
// in the lab, if predicted_enemy_pos is zero vec, then go to initial, else try to aim at the target
|
||||
if (predicted_enemy_pos != nullptr && *predicted_enemy_pos == vmd_zero_vector) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
} else {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
|
||||
@@ -1550,27 +1539,22 @@ bool turret_should_pick_new_target(ship_subsys *turret)
|
||||
/**
|
||||
* Set the next fire timestamp for a turret, based on weapon type and ai class
|
||||
*/
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip, const WeaponLaunchCurveData& launch_curve_data)
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
float wait = 1000.0f;
|
||||
// we have to add 1 to wip->burst_shots so that the multiplier behaves as expected, then remove 1 from burst_shots to match the zero-indexed burst_counter
|
||||
int base_burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points : wip->burst_shots + 1);
|
||||
float burst_shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_SHOTS_MULT, launch_curve_data);
|
||||
int burst_shots = MAX(fl2i(i2fl(base_burst_shots) * burst_shots_mult) - 1, 0);
|
||||
// should subtract 1 from firepoints to match behavior of wip->burst_shots
|
||||
int burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points - 1 : wip->burst_shots);
|
||||
|
||||
if (burst_shots > turret->weapons.burst_counter[weapon_num]) {
|
||||
wait *= wip->burst_delay;
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_DELAY_MULT, launch_curve_data);
|
||||
turret->weapons.burst_counter[weapon_num]++;
|
||||
} else {
|
||||
// Random fire delay (DahBlount) used in ship_fire_primary(), added here by wookieejedi to correct oversight
|
||||
if (wip->max_delay != 0.0f && wip->min_delay != 0.0f) {
|
||||
wait *= frand_range(wip->min_delay, wip->max_delay);
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::FIRE_WAIT_MULT, launch_curve_data);
|
||||
} else {
|
||||
wait *= wip->fire_wait;
|
||||
wait *= wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::FIRE_WAIT_MULT, launch_curve_data);
|
||||
}
|
||||
if ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
turret->weapons.burst_counter[weapon_num] = Random::next(burst_shots);
|
||||
@@ -1616,7 +1600,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
} else {
|
||||
// flak guns need to fire more rapidly
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
|
||||
} else {
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile * 0.5f;
|
||||
@@ -1641,7 +1625,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
|
||||
}
|
||||
} else {
|
||||
// give team friendly an advantage
|
||||
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly;
|
||||
} else {
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile;
|
||||
@@ -1696,15 +1680,7 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
|
||||
/**
|
||||
* Fire a weapon from a turret
|
||||
*/
|
||||
bool turret_fire_weapon(int weapon_num,
|
||||
ship_subsys *turret,
|
||||
int parent_objnum,
|
||||
const WeaponLaunchCurveData& launch_curve_data,
|
||||
const vec3d *orig_firing_pos,
|
||||
const vec3d *orig_firing_vec,
|
||||
const vec3d *predicted_pos = nullptr,
|
||||
float flak_range_override = 100.0f,
|
||||
bool play_sound = true)
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
{
|
||||
matrix firing_orient;
|
||||
int weapon_objnum;
|
||||
@@ -1719,12 +1695,6 @@ bool turret_fire_weapon(int weapon_num,
|
||||
if (!wip)
|
||||
return false;
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
|
||||
if (in_lab) {
|
||||
predicted_pos = nullptr;
|
||||
}
|
||||
|
||||
bool last_shot_in_salvo = true;
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
{
|
||||
@@ -1788,7 +1758,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
firing_vec = &firing_vec_buf;
|
||||
}
|
||||
|
||||
vm_vector_2_matrix_norm(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
|
||||
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
|
||||
int old_burst_seed = swp->burst_seed[weapon_num];
|
||||
@@ -1804,12 +1774,12 @@ bool turret_fire_weapon(int weapon_num,
|
||||
|
||||
// set next fire timestamp for the turret
|
||||
if (last_shot_in_salvo)
|
||||
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip, launch_curve_data);
|
||||
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
|
||||
|
||||
// if this weapon is a beam weapon, handle it specially
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
|
||||
// if this beam isn't free to fire
|
||||
if (!in_lab && !(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1833,14 +1803,6 @@ bool turret_fire_weapon(int weapon_num,
|
||||
fire_info.per_burst_rotation = swp->per_burst_rot;
|
||||
fire_info.burst_index = (old_burst_counter * wip->shots) + i;
|
||||
|
||||
// If we're in the lab then force fire
|
||||
if (in_lab) {
|
||||
fire_info.fire_method = BFM_TURRET_FORCE_FIRED;
|
||||
fire_info.bfi_flags |= BFIF_TARGETING_COORDS;
|
||||
fire_info.target_pos1 = turret->last_aim_enemy_pos;
|
||||
}
|
||||
|
||||
|
||||
// fire a beam weapon
|
||||
weapon_objnum = beam_fire(&fire_info);
|
||||
|
||||
@@ -1870,7 +1832,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
swp->current_secondary_bank = 0;
|
||||
}
|
||||
int bank_to_fire = swp->current_secondary_bank;
|
||||
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
|
||||
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
|
||||
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
|
||||
swp->current_secondary_bank++;
|
||||
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
|
||||
@@ -1881,7 +1843,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos, in_lab);
|
||||
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos);
|
||||
|
||||
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
|
||||
return true;
|
||||
@@ -1889,10 +1851,8 @@ bool turret_fire_weapon(int weapon_num,
|
||||
}
|
||||
// now do anything else
|
||||
else {
|
||||
float shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::SHOTS_MULT, launch_curve_data);
|
||||
int shots = fl2i(i2fl(wip->shots) * shots_mult);
|
||||
for (int i = 0; i < shots; i++) {
|
||||
if (!in_lab && turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
|
||||
for (int i = 0; i < wip->shots; i++) {
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
|
||||
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
|
||||
if (wip->subtype == WP_LASER) {
|
||||
int points;
|
||||
@@ -1987,7 +1947,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
// so we need to get the position info separately for each shot
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
|
||||
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, 0.0f, turret, launch_curve_data);
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
|
||||
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
|
||||
|
||||
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
|
||||
@@ -2016,7 +1976,7 @@ bool turret_fire_weapon(int weapon_num,
|
||||
// if the gun is a flak gun
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
|
||||
if(predicted_pos != nullptr)
|
||||
if(predicted_pos != NULL)
|
||||
{
|
||||
// pick a firing range so that it detonates properly
|
||||
flak_pick_range(objp, firing_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
@@ -2032,16 +1992,11 @@ bool turret_fire_weapon(int weapon_num,
|
||||
|
||||
// do mflash if the weapon has it
|
||||
if (wip->muzzle_effect.isValid()) {
|
||||
float radius_mult = 1.f;
|
||||
if (wip->render_type == WRT_LASER) {
|
||||
radius_mult = wip->weapon_curves.get_output(weapon_info::WeaponCurveOutputs::LASER_RADIUS_MULT, *wp, &wp->modular_curves_instance);
|
||||
}
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
|
||||
particleSource->setHost(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();
|
||||
particleSource.moveToTurret(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos);
|
||||
particleSource.setVelocity(&Objects[parent_ship->objnum].phys_info.vel);
|
||||
particleSource.finish();
|
||||
}
|
||||
else if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
@@ -2054,9 +2009,9 @@ bool turret_fire_weapon(int weapon_num,
|
||||
subsys_index = ship_get_subsys_index(turret);
|
||||
Assert( subsys_index != -1 );
|
||||
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
|
||||
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
|
||||
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
|
||||
} else {
|
||||
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
|
||||
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2124,16 +2079,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix_norm(&firing_orient, &turret_fvec, nullptr, nullptr);
|
||||
|
||||
auto launch_curve_data = WeaponLaunchCurveData {
|
||||
tsi->turret->system_info->turret_num_firing_points,
|
||||
0.f,
|
||||
0.f,
|
||||
};
|
||||
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
|
||||
|
||||
// create weapon and homing info
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, 0.0f, tsi->turret, launch_curve_data);
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
|
||||
|
||||
// do other cool stuff if weapon is created.
|
||||
@@ -2162,9 +2111,9 @@ 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(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();
|
||||
particleSource.moveToTurret(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1);
|
||||
particleSource.setVelocity(&Objects[tsi->parent_objnum].phys_info.vel);
|
||||
particleSource.finish();
|
||||
}
|
||||
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);
|
||||
@@ -2184,7 +2133,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
|
||||
subsys_index = ship_get_subsys_index(tsi->turret);
|
||||
Assert( subsys_index != -1 );
|
||||
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum, 0.f, 0.f);
|
||||
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2210,20 +2159,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
vec3d predicted_enemy_pos = vmd_zero_vector;
|
||||
object *objp;
|
||||
|
||||
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
|
||||
|
||||
if (in_lab) {
|
||||
// Adjust behavior for Lab
|
||||
ss->turret_enemy_objnum = -1;
|
||||
lep = nullptr;
|
||||
}
|
||||
|
||||
// Reset the points to target value
|
||||
ss->points_to_target = -1.0f;
|
||||
ss->base_rotation_rate_pct = 0.0f;
|
||||
ss->gun_rotation_rate_pct = 0.0f;
|
||||
|
||||
if (!in_lab && !Ai_firing_enabled) {
|
||||
if (!Ai_firing_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2236,7 +2177,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
}
|
||||
|
||||
// Check turret free
|
||||
if (!in_lab && ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
|
||||
if (ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2301,13 +2242,8 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
|
||||
}
|
||||
|
||||
if (!in_lab) {
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
} else {
|
||||
// Lab hijacks this value to use as the target position
|
||||
predicted_enemy_pos = ss->last_aim_enemy_pos;
|
||||
}
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
|
||||
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
|
||||
bool use_angles = aifft_rotate_turret(objp, shipp, ss, &global_gun_pos, &global_gun_vec, &predicted_enemy_pos);
|
||||
@@ -2331,20 +2267,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range
|
||||
// WMC moved the range check to within the loop, but we can still calculate the enemy distance here
|
||||
float base_dist_to_enemy = 0.0f;
|
||||
float dist_to_enemy = 0.0f;
|
||||
if (lep) {
|
||||
base_dist_to_enemy = vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = base_dist_to_enemy;
|
||||
if (!The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius]) {
|
||||
dist_to_enemy -= lep->radius;
|
||||
}
|
||||
base_dist_to_enemy = MAX(0.0f, base_dist_to_enemy);
|
||||
dist_to_enemy = MAX(0.0f, dist_to_enemy);
|
||||
} else if (in_lab) {
|
||||
base_dist_to_enemy = 500.0f;
|
||||
dist_to_enemy = base_dist_to_enemy;
|
||||
vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos));
|
||||
else
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
|
||||
}
|
||||
|
||||
// count the number of enemies, in case we have a spawning weapon
|
||||
@@ -2356,19 +2284,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
float turret_barrel_length = -1.0f;
|
||||
|
||||
float target_radius = 0.f;
|
||||
|
||||
if (lep != nullptr) {
|
||||
target_radius = lep->radius;
|
||||
}
|
||||
|
||||
// grab the data for the launch curve inputs
|
||||
auto launch_curve_data = WeaponLaunchCurveData {
|
||||
ss->system_info->turret_num_firing_points,
|
||||
base_dist_to_enemy,
|
||||
target_radius,
|
||||
};
|
||||
|
||||
//WMC - go through all valid weapons. Fire spawns if there are any.
|
||||
int valid_weapons[MAX_SHIP_WEAPONS];
|
||||
int num_valid = 0;
|
||||
@@ -2397,10 +2312,10 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
// Turret spawn weapons are a special case. They fire if there are enough enemies in the
|
||||
// immediate area (not necessarily in the turret fov).
|
||||
// However, if this is a 'smart spawn', just use it like a normal weapon
|
||||
if (!in_lab && (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
{
|
||||
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
|
||||
turret_fire_weapon(i, ss, parent_objnum, launch_curve_data, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
turret_fire_weapon(i, ss, parent_objnum, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
} else {
|
||||
// Regardless of firing rate, don't check whether should fire for awhile.
|
||||
if (tp->flags[Model::Subsystem_Flags::Use_multiple_guns])
|
||||
@@ -2415,13 +2330,13 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
we_did_non_spawning_logic = true; // for the post-loop check
|
||||
|
||||
// If beam weapon, check beam free
|
||||
if (!in_lab && wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// the remaining checks in this loop all require a valid lep
|
||||
if (!in_lab && !lep)
|
||||
if (!lep)
|
||||
continue;
|
||||
|
||||
// Get weapon range
|
||||
@@ -2461,88 +2376,84 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
}
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range (or within min range)
|
||||
// In lab we ignore range issues
|
||||
if (!in_lab && (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range)) {
|
||||
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
|
||||
// it's possible another weapon is in range, but if not,
|
||||
// we will end up selecting a new target
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_lab) {
|
||||
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
|
||||
|
||||
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
|
||||
|
||||
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
|
||||
if ( lep->type != OBJ_SHIP ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar check for small weapons
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
|
||||
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
|
||||
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
|
||||
|
||||
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
|
||||
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
|
||||
if (lep->type == OBJ_SHIP) {
|
||||
// Check if we're targeting a protected ship
|
||||
if (lep->flags[Object::Object_Flags::Protected]) {
|
||||
// *none* of the weapons will work on this ship, so just quit the loop
|
||||
tentative_return = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we're targeting a beam protected ship with a beam weapon
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a flak protected ship with a flak weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a laser protected ship with a laser weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a missile protected ship with a missile weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if weapon or turret is set to tagged-only
|
||||
// must check here in case turret has multiple weapons and not all are tagged-only
|
||||
else if (tagged_only && !ship_is_tagged(lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
|
||||
if ( lep->type != OBJ_SHIP ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// check tagged-only for bombs only if the flag is set; see Mantis #3114
|
||||
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar check for small weapons
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
|
||||
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
|
||||
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
|
||||
|
||||
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
|
||||
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
|
||||
if (lep->type == OBJ_SHIP) {
|
||||
// Check if we're targeting a protected ship
|
||||
if (lep->flags[Object::Object_Flags::Protected]) {
|
||||
// *none* of the weapons will work on this ship, so just quit the loop
|
||||
tentative_return = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we're targeting a beam protected ship with a beam weapon
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a flak protected ship with a flak weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a laser protected ship with a laser weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a missile protected ship with a missile weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
// Check if weapon or turret is set to tagged-only
|
||||
// must check here in case turret has multiple weapons and not all are tagged-only
|
||||
else if (tagged_only && !ship_is_tagged(lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check tagged-only for bombs only if the flag is set; see Mantis #3114
|
||||
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
|
||||
tentative_return = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2636,20 +2547,18 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
lep = &Objects[ss->turret_enemy_objnum];
|
||||
} else {
|
||||
if (!in_lab) {
|
||||
if (timestamp_until(ss->turret_next_fire_stamp) < 500) {
|
||||
ss->turret_next_fire_stamp = timestamp(500);
|
||||
}
|
||||
return;
|
||||
if (timestamp_until(ss->turret_next_fire_stamp) < 500) {
|
||||
ss->turret_next_fire_stamp = timestamp(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//This can't happen. See above code -- Except in the Lab as of 4/26/2025
|
||||
//This can't happen. See above code
|
||||
//if ( lep == nullptr ){
|
||||
// return;
|
||||
//}
|
||||
|
||||
//This can't happen. See above code -- Except in the Lab as of 4/26/2025
|
||||
//This can't happen. See above code
|
||||
//Assert(ss->turret_enemy_objnum != -1);
|
||||
|
||||
bool in_fov = turret_fov_test(ss, &global_gun_vec, &v2e);
|
||||
@@ -2657,7 +2566,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
|
||||
// its a ballistic trajectory with no valid path
|
||||
if (in_lab || (in_fov && num_valid && predicted_enemy_pos != vmd_zero_vector)) {
|
||||
if (in_fov && num_valid && predicted_enemy_pos != vmd_zero_vector) {
|
||||
|
||||
// Do salvo thing separately - to prevent messing up things
|
||||
int number_of_firings;
|
||||
@@ -2711,7 +2620,8 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// Fire in the direction the turret is facing, not right at the target regardless of turret dir.
|
||||
// [Yet this retail comment precedes the calculation of vector-to-enemy...]
|
||||
dist_to_enemy = vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = vm_vec_normalize(&v2e);
|
||||
float dot = vm_vec_dot(&v2e, &global_gun_vec);
|
||||
|
||||
// (flak jitter moved to after we obtain shoot_vector below)
|
||||
@@ -2833,27 +2743,16 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
|
||||
// (Despite the retail comment above, retail actually fired toward the enemy; v2e = vector-to-enemy)
|
||||
vec3d shoot_vector = v2e;
|
||||
if (in_lab || tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
if (tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
shoot_vector = global_gun_vec;
|
||||
|
||||
// In the lab the order of operations is a little fuzzy since we're faking targets so always fire along the turret's current vector no matter what if we're a multipart turret
|
||||
if (in_lab && (ss->system_info->turret_gun_sobj >= 0 && ss->system_info->subobj_num != ss->system_info->turret_gun_sobj)) {
|
||||
vec3d new_pos;
|
||||
vec3d new_vec;
|
||||
ship_get_global_turret_gun_info(objp, ss, &new_pos, false, &new_vec, true, nullptr);
|
||||
shoot_vector = new_vec;
|
||||
vm_vec_normalize(&shoot_vector);
|
||||
global_gun_pos = new_pos;
|
||||
predicted_enemy_pos = new_pos + new_vec * 500.0f;
|
||||
}
|
||||
|
||||
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
|
||||
// to make a cool visual effect and make them less lethal
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
flak_jitter_aim(&shoot_vector, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
|
||||
}
|
||||
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, launch_curve_data, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2866,7 +2765,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
// make sure salvo fire mode does not turn into autofire
|
||||
if ((tp->flags[Model::Subsystem_Flags::Turret_salvo]) && ((i + 1) == number_of_firings)) {
|
||||
ai_info *parent_aip = &Ai_info[shipp->ai_index];
|
||||
turret_set_next_fire_timestamp(valid_weapons[valid_index], wip, ss, parent_aip, launch_curve_data);
|
||||
turret_set_next_fire_timestamp(valid_weapons[valid_index], wip, ss, parent_aip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2889,16 +2788,16 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
{
|
||||
//something did fire, get the lowest valid timestamp
|
||||
// don't do this if we already set a turret timestamp previously in the function
|
||||
if (timestamp_since(ss->turret_next_fire_stamp) >= 0)
|
||||
if (timestamp_since(ss->turret_next_fire_stamp) > 0)
|
||||
{
|
||||
int minimum_stamp = -1;
|
||||
|
||||
for (int i = 0; i < MAX_SHIP_WEAPONS; ++i)
|
||||
{
|
||||
{
|
||||
int stamp = (i < MAX_SHIP_PRIMARY_BANKS) ? swp->next_primary_fire_stamp[i] : swp->next_secondary_fire_stamp[i - MAX_SHIP_PRIMARY_BANKS];
|
||||
|
||||
// valid timestamps start at 2; stamp must be in the future
|
||||
if (stamp < 2 || timestamp_since(stamp) >= 0)
|
||||
if (stamp < 2 || timestamp_since(stamp) > 0)
|
||||
continue;
|
||||
|
||||
// find minimum
|
||||
|
||||
+17
-6
@@ -667,10 +667,12 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
*
|
||||
* @param real_filename Filename of animation
|
||||
* @param cf_dir_type
|
||||
*
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
anim *ptr;
|
||||
CFILE *fp;
|
||||
@@ -695,7 +697,7 @@ anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
fp = cfopen(name, "rb", cf_dir_type);
|
||||
fp = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
|
||||
if ( !fp )
|
||||
return NULL;
|
||||
|
||||
@@ -741,9 +743,18 @@ anim *anim_load(const char *real_filename, int cf_dir_type)
|
||||
|
||||
ptr->cfile_ptr = NULL;
|
||||
|
||||
// NOTE: mapped files no longer supported!!
|
||||
ptr->flags |= ANF_STREAMED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", cf_dir_type);
|
||||
if ( file_mapped == PAGE_FROM_MEM) {
|
||||
// Try mapping the file to memory
|
||||
ptr->flags |= ANF_MEM_MAPPED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", CFILE_MEMORY_MAPPED, cf_dir_type);
|
||||
}
|
||||
|
||||
// couldn't memory-map file... must be in a packfile, so stream manually
|
||||
if ( file_mapped == PAGE_FROM_MEM && !ptr->cfile_ptr ) {
|
||||
ptr->flags &= ~ANF_MEM_MAPPED;
|
||||
ptr->flags |= ANF_STREAMED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
|
||||
}
|
||||
|
||||
ptr->cache = NULL;
|
||||
|
||||
|
||||
@@ -38,6 +38,12 @@ typedef struct {
|
||||
int ping_pong;
|
||||
} anim_play_struct;
|
||||
|
||||
enum
|
||||
{
|
||||
PAGE_FROM_DISK = 0,
|
||||
PAGE_FROM_MEM = 1
|
||||
};
|
||||
|
||||
extern int Anim_paused;
|
||||
|
||||
void anim_init();
|
||||
@@ -51,7 +57,7 @@ void anim_ignore_next_frametime();
|
||||
int anim_show_next_frame(anim_instance *instance, float frametime);
|
||||
void anim_release_all_instances(int screen_id = 0);
|
||||
void anim_release_render_instance(anim_instance* instance);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_DISK);
|
||||
int anim_free(anim *ptr);
|
||||
void anim_read_header(anim *ptr, CFILE *fp);
|
||||
void anim_reverse_direction(anim_instance *ai); // called automatically for ping-ponging, and can also be called externally
|
||||
|
||||
+36
-105
@@ -42,7 +42,6 @@
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#define ASTEROID_OBJ_USED (1<<0) // flag used in asteroid_obj struct
|
||||
#define MAX_ASTEROID_OBJS MAX_ASTEROIDS // max number of asteroids tracked in asteroid list
|
||||
@@ -218,38 +217,22 @@ static float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
*/
|
||||
static bool asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
|
||||
if (!asfieldp->has_inner_bound) {
|
||||
if (!asfieldp->has_inner_bound)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Fix_asteroid_bounding_box_check) {
|
||||
return (pos->xyz.x > asfieldp->inner_min_bound.xyz.x + delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x - delta) &&
|
||||
(pos->xyz.y > asfieldp->inner_min_bound.xyz.y + delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y - delta) &&
|
||||
(pos->xyz.z > asfieldp->inner_min_bound.xyz.z + delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z - delta);
|
||||
} else {
|
||||
return (pos->xyz.x > asfieldp->inner_min_bound.xyz.x - delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x + delta) &&
|
||||
(pos->xyz.y > asfieldp->inner_min_bound.xyz.y - delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y + delta) &&
|
||||
(pos->xyz.z > asfieldp->inner_min_bound.xyz.z - delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z + delta);
|
||||
}
|
||||
|
||||
return (pos->xyz.x > asfieldp->inner_min_bound.xyz.x - delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x + delta) &&
|
||||
(pos->xyz.y > asfieldp->inner_min_bound.xyz.y - delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y + delta) &&
|
||||
(pos->xyz.z > asfieldp->inner_min_bound.xyz.z - delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z + delta);
|
||||
}
|
||||
|
||||
static bool asteroid_is_ship_inside_field(asteroid_field* asfieldp, vec3d* pos, float radius) {
|
||||
|
||||
radius *= 2.0f;
|
||||
|
||||
if (Fix_asteroid_bounding_box_check) {
|
||||
return pos->xyz.x - radius > Asteroid_field.min_bound.xyz.x && pos->xyz.x + radius < Asteroid_field.max_bound.xyz.x &&
|
||||
pos->xyz.y - radius > Asteroid_field.min_bound.xyz.y && pos->xyz.y + radius < Asteroid_field.max_bound.xyz.y &&
|
||||
pos->xyz.z - radius > Asteroid_field.min_bound.xyz.z && pos->xyz.z + radius < Asteroid_field.max_bound.xyz.z &&
|
||||
!asteroid_in_inner_bound(asfieldp, pos, radius);
|
||||
} else {
|
||||
return pos->xyz.x + radius > Asteroid_field.min_bound.xyz.x && pos->xyz.x - radius < Asteroid_field.max_bound.xyz.x &&
|
||||
pos->xyz.y + radius > Asteroid_field.min_bound.xyz.y && pos->xyz.y - radius < Asteroid_field.max_bound.xyz.y &&
|
||||
pos->xyz.z + radius > Asteroid_field.min_bound.xyz.z && pos->xyz.z - radius < Asteroid_field.max_bound.xyz.z &&
|
||||
!asteroid_in_inner_bound(asfieldp, pos, radius);
|
||||
}
|
||||
|
||||
return pos->xyz.x + radius > Asteroid_field.min_bound.xyz.x && pos->xyz.x - radius < Asteroid_field.max_bound.xyz.x &&
|
||||
pos->xyz.y + radius > Asteroid_field.min_bound.xyz.y && pos->xyz.y - radius < Asteroid_field.max_bound.xyz.y &&
|
||||
pos->xyz.z + radius > Asteroid_field.min_bound.xyz.z && pos->xyz.z - radius < Asteroid_field.max_bound.xyz.z &&
|
||||
!asteroid_in_inner_bound(asfieldp, pos, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +329,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
}
|
||||
|
||||
// if the model is not loaded then abort
|
||||
if(asip->subtypes[asteroid_subtype].model_number == -1) {
|
||||
if(asip->subtypes[asteroid_subtype].model_pointer == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -471,8 +454,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
objp->phys_info.max_vel.xyz.y = 0.0f;
|
||||
objp->phys_info.max_vel.xyz.z = vm_vec_mag(&objp->phys_info.desired_vel);
|
||||
|
||||
objp->phys_info.mass = model_get(asip->subtypes[asteroid_subtype].model_number)->rad * 700.0f;
|
||||
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*model_get(asip->subtypes[asteroid_subtype].model_number)->rad);
|
||||
objp->phys_info.mass = asip->subtypes[asteroid_subtype].model_pointer->rad * 700.0f;
|
||||
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->subtypes[asteroid_subtype].model_pointer->rad);
|
||||
objp->phys_info.I_body_inv.vec.uvec.xyz.y = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
|
||||
objp->phys_info.I_body_inv.vec.fvec.xyz.z = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
|
||||
objp->hull_strength = asip->initial_asteroid_strength * (0.8f + (float)Game_skill_level/NUM_SKILL_LEVELS)/2.0f;
|
||||
@@ -534,7 +517,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
|
||||
/**
|
||||
* Load in an asteroid model
|
||||
*/
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
{
|
||||
int i;
|
||||
asteroid_info *asip;
|
||||
@@ -563,11 +546,11 @@ void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
if (asip->subtypes[asteroid_subtype].model_number >= 0)
|
||||
return;
|
||||
|
||||
asip->subtypes[asteroid_subtype].model_number = model_load( asip->subtypes[asteroid_subtype].pof_filename );
|
||||
asip->subtypes[asteroid_subtype].model_number = model_load( asip->subtypes[asteroid_subtype].pof_filename, 0, nullptr );
|
||||
|
||||
if (asip->subtypes[asteroid_subtype].model_number >= 0)
|
||||
{
|
||||
polymodel *pm = model_get(asip->subtypes[asteroid_subtype].model_number);
|
||||
polymodel *pm = asip->subtypes[asteroid_subtype].model_pointer = model_get(asip->subtypes[asteroid_subtype].model_number);
|
||||
|
||||
if ( asip->num_detail_levels != pm->n_detail_levels )
|
||||
{
|
||||
@@ -645,7 +628,7 @@ void asteroid_create_all()
|
||||
return;
|
||||
}
|
||||
|
||||
int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_VALUE-Detail.asteroid_density)));
|
||||
int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_LEVEL-Detail.asteroid_density)));
|
||||
|
||||
int num_debris_types = 0;
|
||||
|
||||
@@ -1055,19 +1038,19 @@ static void maybe_throw_asteroid()
|
||||
if (subtype < 0)
|
||||
return;
|
||||
|
||||
object *ast_objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype, Asteroid_field.enhanced_visibility_checks);
|
||||
if (ast_objp != nullptr) {
|
||||
asteroid_aim_at_target(target_objp, ast_objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
|
||||
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype, Asteroid_field.enhanced_visibility_checks);
|
||||
if (objp != nullptr) {
|
||||
asteroid_aim_at_target(target_objp, objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
|
||||
|
||||
// if asteroid is inside inner bound, kill it
|
||||
if (asteroid_in_inner_bound(&Asteroid_field, &ast_objp->pos, 0.0f)) {
|
||||
ast_objp->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
if (asteroid_in_inner_bound(&Asteroid_field, &objp->pos, 0.0f)) {
|
||||
objp->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
} else {
|
||||
Asteroids[ast_objp->instance].target_objnum = target.objnum;
|
||||
Asteroids[objp->instance].target_objnum = target.objnum;
|
||||
target.incoming_asteroids++;
|
||||
|
||||
if ( MULTIPLAYER_MASTER ) {
|
||||
send_asteroid_throw( ast_objp );
|
||||
send_asteroid_throw( objp );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1492,54 +1475,8 @@ void asteroid_render(object * obj, model_draw_list *scene)
|
||||
|
||||
model_render_params render_info;
|
||||
|
||||
uint64_t render_flags = MR_IS_ASTEROID;
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_light])
|
||||
render_flags |= MR_NO_LIGHTING;
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Glowmaps_disabled]) {
|
||||
render_flags |= MR_NO_GLOWMAPS;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Draw_as_wireframe]) {
|
||||
render_flags |= MR_SHOW_OUTLINE_HTL | MR_NO_POLYS | MR_NO_TEXTURING;
|
||||
render_info.set_color(Wireframe_color);
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_full_detail]) {
|
||||
render_flags |= MR_FULL_DETAIL;
|
||||
}
|
||||
|
||||
uint debug_flags = render_info.get_debug_flags();
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_diffuse]) {
|
||||
debug_flags |= MR_DEBUG_NO_DIFFUSE;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_glowmap]) {
|
||||
debug_flags |= MR_DEBUG_NO_GLOW;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_normalmap]) {
|
||||
debug_flags |= MR_DEBUG_NO_NORMAL;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_ambientmap]) {
|
||||
debug_flags |= MR_DEBUG_NO_AMBIENT;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_specmap]) {
|
||||
debug_flags |= MR_DEBUG_NO_SPEC;
|
||||
}
|
||||
|
||||
if (asp->render_flags[Object::Raw_Pof_Flags::Render_without_reflectmap]) {
|
||||
debug_flags |= MR_DEBUG_NO_REFLECT;
|
||||
}
|
||||
|
||||
render_info.set_object_number( OBJ_INDEX(obj) );
|
||||
|
||||
render_info.set_flags(render_flags);
|
||||
render_info.set_debug_flags(debug_flags);
|
||||
render_info.set_flags(MR_IS_ASTEROID);
|
||||
if (asp->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(asp->model_instance_num)->texture_replace);
|
||||
|
||||
@@ -1752,7 +1689,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
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()) {
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, Asteroid_impact_explosion_ani );
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1780,6 +1717,7 @@ void asteroid_level_close()
|
||||
for (size_t i = 0; i < Asteroid_info.size(); i++) {
|
||||
for (size_t j = 0; j < Asteroid_info[i].subtypes.size(); j++) {
|
||||
Asteroid_info[i].subtypes[j].model_number = -1;
|
||||
Asteroid_info[i].subtypes[j].model_pointer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1875,8 +1813,7 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
roids_to_create.push_back(split->asteroid_type);
|
||||
}
|
||||
|
||||
std::random_device rd;
|
||||
std::shuffle(roids_to_create.begin(), roids_to_create.end(), std::mt19937(rd()));
|
||||
random_shuffle(roids_to_create.begin(), roids_to_create.end());
|
||||
|
||||
size_t total_roids = roids_to_create.size();
|
||||
for (size_t i = 0; i < total_roids; i++) {
|
||||
@@ -2238,16 +2175,6 @@ static void asteroid_parse_section()
|
||||
asteroid_p->type = ASTEROID_TYPE_DEBRIS;
|
||||
}
|
||||
|
||||
auto insert_or_replace_subtype_pof = [](SCP_vector<asteroid_subtype_info>& subtypes, const asteroid_subtype_info& new_subtype) {
|
||||
for (auto& subtype : subtypes) {
|
||||
if (lcase_equal(subtype.type_name, new_subtype.type_name)) {
|
||||
strcpy_s(subtype.pof_filename, new_subtype.pof_filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
subtypes.push_back(new_subtype);
|
||||
};
|
||||
|
||||
if (optional_string("$POF file1:")) {
|
||||
asteroid_subtype_info thisType;
|
||||
|
||||
@@ -2256,8 +2183,9 @@ static void asteroid_parse_section()
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
}
|
||||
|
||||
if (optional_string("$POF file2:")) {
|
||||
@@ -2267,8 +2195,9 @@ static void asteroid_parse_section()
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
}
|
||||
|
||||
if (optional_string("$POF file3:")) {
|
||||
@@ -2278,8 +2207,9 @@ static void asteroid_parse_section()
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
}
|
||||
|
||||
// For asteroid types we can have unlimited subtypes
|
||||
@@ -2293,6 +2223,7 @@ static void asteroid_parse_section()
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
bool exists = false;
|
||||
for (const auto& type : asteroid_p->subtypes) {
|
||||
@@ -2855,11 +2786,11 @@ void asteroid_page_in()
|
||||
if (asip->subtypes[k].model_number < 0)
|
||||
continue;
|
||||
|
||||
const auto mp = model_get(asip->subtypes[k].model_number);
|
||||
asip->subtypes[k].model_pointer = model_get(asip->subtypes[k].model_number);
|
||||
|
||||
// Page in textures
|
||||
for (int j = 0; j < mp->n_textures; j++) {
|
||||
mp->maps[j].PageIn();
|
||||
for (int j = 0; j < asip->subtypes[k].model_pointer->n_textures; j++ ) {
|
||||
asip->subtypes[k].model_pointer->maps[j].PageIn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "object/object_flags.h"
|
||||
#include "io/timer.h"
|
||||
|
||||
class object;
|
||||
@@ -57,6 +56,7 @@ typedef struct asteroid_split_info {
|
||||
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
|
||||
typedef struct asteroid_subtype_info {
|
||||
char pof_filename[MAX_FILENAME_LEN];
|
||||
polymodel* model_pointer;
|
||||
int model_number;
|
||||
SCP_string type_name;
|
||||
} asteroid_subtype_info;
|
||||
@@ -103,7 +103,6 @@ public:
|
||||
|
||||
typedef struct asteroid {
|
||||
int flags;
|
||||
flagset<Object::Raw_Pof_Flags> render_flags; // Render flags
|
||||
int objnum;
|
||||
int model_instance_num;
|
||||
int asteroid_type; // 0..MAX_DEBRIS_TYPES
|
||||
@@ -181,9 +180,6 @@ void asteroid_add_target(object* objp);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
|
||||
|
||||
// extern for the lab
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype);
|
||||
|
||||
// need to extern for keycontrol debug commands
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <map>
|
||||
|
||||
// Extern functions/variables
|
||||
extern bool Player_use_ai;
|
||||
extern int Player_use_ai;
|
||||
extern int get_wing_index(object *objp, int wingnum);
|
||||
extern object * get_wing_leader(int wingnum);
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
@@ -66,7 +66,7 @@ int start_dist;
|
||||
void autopilot_ai_waypoint_goal_fixup(ai_goal* aigp)
|
||||
{
|
||||
// this function sets wp_index properly;
|
||||
aigp->wp_list_index = find_matching_waypoint_list_index(aigp->target_name);
|
||||
aigp->wp_list = find_matching_waypoint_list(aigp->target_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,15 +111,13 @@ const vec3d *NavPoint::GetPosition()
|
||||
{
|
||||
if (flags & NP_WAYPOINT)
|
||||
{
|
||||
auto wpt = find_waypoint_at_indexes(target_index, waypoint_num-1);
|
||||
Assert(wpt != nullptr);
|
||||
if (wpt == nullptr)
|
||||
return &vmd_zero_vector;
|
||||
waypoint *wpt = find_waypoint_at_index((waypoint_list*) target_obj, waypoint_num-1);
|
||||
Assert(wpt != NULL);
|
||||
return wpt->get_pos();
|
||||
}
|
||||
else
|
||||
{
|
||||
return &Objects[target_index].pos;
|
||||
return &Objects[((ship*) target_obj)->objnum].pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +239,7 @@ bool StartAutopilot()
|
||||
// is support ship trying to rearm-repair
|
||||
if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
|
||||
// no, so tell it to depart
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_WARP, -1, nullptr, support_ship_aip );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
|
||||
} else {
|
||||
// yes
|
||||
send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING);
|
||||
@@ -270,7 +268,7 @@ bool StartAutopilot()
|
||||
LockAPConv = _timestamp(); // lock convergence instantly
|
||||
else
|
||||
LockAPConv = _timestamp(3 * MILLISECONDS_PER_SECOND); // 3 seconds before we lock convergence
|
||||
Player_use_ai = true;
|
||||
Player_use_ai = 1;
|
||||
set_time_compression(1);
|
||||
lock_time_compression(true);
|
||||
|
||||
@@ -300,16 +298,15 @@ bool StartAutopilot()
|
||||
autopilot_wings.clear();
|
||||
|
||||
// vars for usage w/ cinematic
|
||||
vec3d pos, perp, tpos, rpos = Player_obj->pos, zero;
|
||||
vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero;
|
||||
memset(&zero, 0, sizeof(vec3d));
|
||||
|
||||
|
||||
// instantly turn player toward tpos
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
{
|
||||
vec3d norm1;
|
||||
vm_vec_normalized_dir(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix_norm(&Player_obj->orient, &norm1, nullptr, nullptr);
|
||||
vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_SHIPS; i++)
|
||||
@@ -396,12 +393,10 @@ bool StartAutopilot()
|
||||
radius = Objects[Ships[i].objnum].radius;
|
||||
}
|
||||
|
||||
// instantly turn the ship to match the direction player is looking
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
{
|
||||
vec3d norm1;
|
||||
vm_vec_normalized_dir(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix_norm(&Objects[Ships[i].objnum].orient, &norm1, nullptr, nullptr);
|
||||
{// instantly turn the ship to match the direction player is looking
|
||||
//vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
|
||||
vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
|
||||
}
|
||||
|
||||
// snap wings into formation
|
||||
@@ -467,12 +462,12 @@ bool StartAutopilot()
|
||||
{
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), &Ai_info[Ships[i].ai_index] );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
|
||||
//fixup has to wait until after wing goals
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_add_ship_goal_player( ai_goal_type::PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, &Ai_info[Ships[i].ai_index] );
|
||||
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -488,15 +483,15 @@ bool StartAutopilot()
|
||||
{
|
||||
//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
|
||||
|
||||
//ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
|
||||
//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
|
||||
//ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) );
|
||||
|
||||
ai_clear_wing_goals( &Wings[i] );
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
|
||||
ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), i );
|
||||
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i );
|
||||
|
||||
// "fix up" the goal
|
||||
for (j = 0; j < MAX_AI_GOALS; j++)
|
||||
@@ -510,7 +505,7 @@ bool StartAutopilot()
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_add_wing_goal_player( ai_goal_type::PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, i );
|
||||
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -858,7 +853,7 @@ void EndAutoPilot()
|
||||
|
||||
set_time_compression(1);
|
||||
lock_time_compression(false);
|
||||
Player_use_ai = false;
|
||||
Player_use_ai = 0;
|
||||
//Clear AI Goals
|
||||
|
||||
if (CinematicStarted) // clear cinematic if we need to
|
||||
@@ -879,12 +874,12 @@ void EndAutoPilot()
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
goal = AI_GOAL_WAYPOINTS_ONCE;
|
||||
goal_name = Waypoint_lists[Navs[CurrentNav].target_index].get_name();
|
||||
goal_name = ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
goal = AI_GOAL_FLY_TO_SHIP;
|
||||
goal_name = Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name;
|
||||
goal_name = ((ship*)Navs[CurrentNav].target_obj)->ship_name;
|
||||
}
|
||||
|
||||
// assign ship goals
|
||||
@@ -1099,9 +1094,9 @@ void NavSystem_Do()
|
||||
|
||||
for (i = 0; i < MAX_NAVPOINTS; i++)
|
||||
{
|
||||
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_index >= 0))
|
||||
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_obj != NULL))
|
||||
{
|
||||
if (Objects[Navs[i].target_index].flags[Object::Object_Flags::Should_be_dead])
|
||||
if (((ship*)Navs[i].target_obj)->objnum == -1)
|
||||
{
|
||||
if (CurrentNav == i)
|
||||
CurrentNav = -1;
|
||||
@@ -1113,7 +1108,7 @@ void NavSystem_Do()
|
||||
// check if we're reached a Node
|
||||
for (i = 0; i < MAX_NAVPOINTS; i++)
|
||||
{
|
||||
if (Navs[i].target_index >= 0)
|
||||
if (Navs[i].target_obj != NULL)
|
||||
{
|
||||
if (Navs[i].flags & NP_VALIDTYPE && DistanceTo(i) < 1000)
|
||||
Navs[i].flags |= NP_VISITED;
|
||||
@@ -1397,7 +1392,7 @@ bool AddNav_Ship(const char *Nav, const char *TargetName, int flags)
|
||||
{
|
||||
if (Ships[i].objnum != -1 && !stricmp(TargetName, Ships[i].ship_name))
|
||||
{
|
||||
tnav.target_index = Ships[i].objnum;
|
||||
tnav.target_obj = (void *)&Ships[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1438,7 +1433,7 @@ bool AddNav_Waypoint(const char *Nav, const char *WP_Path, int node, int flags)
|
||||
|
||||
Assert(!(tnav.flags & NP_SHIP));
|
||||
|
||||
tnav.target_index = find_matching_waypoint_list_index(WP_Path);
|
||||
tnav.target_obj = find_matching_waypoint_list(WP_Path);
|
||||
tnav.waypoint_num = node;
|
||||
|
||||
// copy it into it's location
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
|
||||
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };
|
||||
|
||||
int target_index = -1; //waypoint list index if NP_WAYPOINT, otherwise object index
|
||||
const void *target_obj = nullptr;
|
||||
int waypoint_num = -1; //only used when flags & NP_WAYPOINT
|
||||
|
||||
const vec3d *GetPosition();
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
visited_color[1] = 0xFF;
|
||||
visited_color[2] = 0x00;
|
||||
|
||||
target_index = -1;
|
||||
target_obj = nullptr;
|
||||
waypoint_num = -1;
|
||||
}
|
||||
};
|
||||
|
||||
+52
-47
@@ -48,14 +48,14 @@ struct apply_##name##_to_fov { \
|
||||
} \
|
||||
}; \
|
||||
fov_t operator op (const fov_t& zoom, const float& scale) { \
|
||||
return std::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
}
|
||||
APPLY_TO_FOV_T(*, mul)
|
||||
APPLY_TO_FOV_T(+, add)
|
||||
APPLY_TO_FOV_T(-, sub)
|
||||
|
||||
// Used to set the default value for in-game options
|
||||
static float fov_default = DEFAULT_FOV;
|
||||
static constexpr float fov_default = DEFAULT_FOV;
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
@@ -64,15 +64,6 @@ static SCP_string fov_display(float val)
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void parse_fov_func()
|
||||
{
|
||||
float value;
|
||||
stuff_float(&value);
|
||||
CLAMP(value, 0.436332f, 1.5708f);
|
||||
fov_default = value;
|
||||
}
|
||||
|
||||
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})
|
||||
@@ -83,10 +74,9 @@ auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_func([]() { return fov_default; })
|
||||
.default_val(fov_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.parser(parse_fov_func)
|
||||
.finish();
|
||||
|
||||
bool Use_cockpit_fov = false;
|
||||
@@ -210,35 +200,25 @@ void camera::set_object_host(object *objp, int n_object_host_submodel)
|
||||
object_host_submodel = n_object_host_submodel;
|
||||
set_custom_position_function(NULL);
|
||||
set_custom_orientation_function(NULL);
|
||||
|
||||
if (n_object_host_submodel >= 0 && objp != nullptr && objp->type == OBJ_SHIP)
|
||||
if(n_object_host_submodel > 0)
|
||||
{
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while (ssp != END_OF_LIST(&Ships[objp->instance].subsys_list))
|
||||
if(objp != nullptr && objp->type == OBJ_SHIP)
|
||||
{
|
||||
if (ssp->system_info->subobj_num == n_object_host_submodel)
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
|
||||
{
|
||||
if (ssp->system_info->type == SUBSYSTEM_TURRET)
|
||||
if(ssp->system_info->subobj_num == n_object_host_submodel)
|
||||
{
|
||||
set_custom_position_function(get_turret_cam_pos);
|
||||
set_custom_orientation_function(get_turret_cam_orient);
|
||||
if(ssp->system_info->type == SUBSYSTEM_TURRET)
|
||||
{
|
||||
set_custom_position_function(get_turret_cam_pos);
|
||||
set_custom_orientation_function(get_turret_cam_orient);
|
||||
}
|
||||
}
|
||||
ssp = GET_NEXT( ssp );
|
||||
}
|
||||
ssp = GET_NEXT(ssp);
|
||||
}
|
||||
}
|
||||
else if (Use_model_eyepoint_for_set_camera_host && object_host.isValid())
|
||||
{
|
||||
const object* host = object_host.objp();
|
||||
|
||||
vec3d eye_pos;
|
||||
matrix eye_orient;
|
||||
|
||||
object_get_eye(&eye_pos, &eye_orient, host, false, true, true);
|
||||
|
||||
set_position(&eye_pos);
|
||||
set_rotation(&eye_orient);
|
||||
}
|
||||
}
|
||||
|
||||
void camera::set_object_target(object *objp, int n_object_target_submodel)
|
||||
@@ -357,7 +337,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
if (Use_host_orientation_for_set_camera_facing)
|
||||
{
|
||||
// point along the target vector, but using the host orient's roll
|
||||
vm_vector_2_matrix_norm(&temp_matrix, &targetvec, &orient->vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(&temp_matrix, &targetvec, &orient->vec.uvec, nullptr);
|
||||
|
||||
// if we have a host, we need the difference between the camera's current orient and the orient we want
|
||||
// if not, we will later set the absolute orientation, rather than the orientation relative to the host
|
||||
@@ -370,7 +350,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
else
|
||||
{
|
||||
// point directly along the target vector
|
||||
vm_vector_2_matrix_norm(&temp_matrix, &targetvec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&temp_matrix, &targetvec, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,8 +419,16 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
if(object_host.isValid())
|
||||
{
|
||||
object *objp = object_host.objp();
|
||||
polymodel *pm = object_get_model(objp);
|
||||
polymodel_instance *pmi = object_get_model_instance(objp);
|
||||
int model_num = object_get_model(objp);
|
||||
polymodel *pm = nullptr;
|
||||
polymodel_instance *pmi = nullptr;
|
||||
|
||||
if(model_num >= 0)
|
||||
{
|
||||
pm = model_get(model_num);
|
||||
if (objp->type == OBJ_SHIP)
|
||||
pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
}
|
||||
|
||||
if(object_host_submodel < 0 || pm == NULL)
|
||||
{
|
||||
@@ -495,9 +483,18 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
if(object_target.isValid())
|
||||
{
|
||||
object *target_objp = object_target.objp();
|
||||
polymodel *target_pm = object_get_model(target_objp);
|
||||
polymodel_instance *target_pmi = object_get_model_instance(target_objp);
|
||||
int model_num = object_get_model(target_objp);
|
||||
polymodel *target_pm = nullptr;
|
||||
polymodel_instance *target_pmi = nullptr;
|
||||
vec3d target_pos = vmd_zero_vector;
|
||||
|
||||
//See if we can get the model
|
||||
if(model_num >= 0)
|
||||
{
|
||||
target_pm = model_get(model_num);
|
||||
if (target_objp->type == OBJ_SHIP)
|
||||
target_pmi = model_get_instance(Ships[target_objp->instance].model_instance_num);
|
||||
}
|
||||
|
||||
//If we don't have a submodel or don't have the model use object pos
|
||||
//Otherwise, find the submodel pos as it is rotated
|
||||
@@ -515,14 +512,14 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
|
||||
vec3d targetvec;
|
||||
vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos);
|
||||
vm_vector_2_matrix_norm(&c_ori, &targetvec, nullptr, nullptr);
|
||||
vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if(object_host.isValid())
|
||||
{
|
||||
if(eyep)
|
||||
{
|
||||
vm_vector_2_matrix_norm(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp()->orient.vec.uvec) ? nullptr : &object_host.objp()->orient.vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp()->orient.vec.uvec)?NULL:&object_host.objp()->orient.vec.uvec, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if (use_host_orient)
|
||||
@@ -578,7 +575,7 @@ warp_camera::warp_camera(object *objp)
|
||||
|
||||
vec3d object_pos = objp->pos;
|
||||
matrix tmp;
|
||||
object_get_eye(&object_pos, &tmp, objp);
|
||||
ship_get_eye(&object_pos, &tmp, objp);
|
||||
|
||||
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.rvec, 0.0f );
|
||||
vm_vec_scale_add2( &object_pos, &Player_obj->orient.vec.uvec, 0.952f );
|
||||
@@ -791,7 +788,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
|
||||
//Get text size
|
||||
for(int i = 0; i < num_text_lines; i++)
|
||||
{
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], 1.0f, static_cast<size_t>(text_line_lens[i]));
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], static_cast<size_t>(text_line_lens[i]));
|
||||
|
||||
if(w > tw)
|
||||
tw = w;
|
||||
@@ -1085,6 +1082,13 @@ int cam_get_next_sig()
|
||||
return next_sig++;
|
||||
}
|
||||
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
matrix ori;
|
||||
vm_vector_2_matrix_norm(&ori, n_norm);
|
||||
return cam_create(n_name, n_pos, &ori, n_object, n_object_host_submodel);
|
||||
}
|
||||
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
camera *cam = NULL;
|
||||
@@ -1228,7 +1232,7 @@ void subtitles_do_frame_post_shaded(float frametime)
|
||||
}
|
||||
}
|
||||
|
||||
static vec3d normal_cache;
|
||||
vec3d normal_cache;
|
||||
|
||||
void get_turret_cam_pos(camera *cam, vec3d *pos)
|
||||
{
|
||||
@@ -1256,7 +1260,7 @@ void get_turret_cam_orient(camera *cam, matrix *ori)
|
||||
object_h obj(cam->get_object_host());
|
||||
if(!obj.isValid())
|
||||
return;
|
||||
vm_vector_2_matrix_norm(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec) ? nullptr : &cam->get_object_host()->orient.vec.uvec, nullptr);
|
||||
vm_vector_2_matrix(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec)?NULL:&cam->get_object_host()->orient.vec.uvec, NULL);
|
||||
}
|
||||
|
||||
eye* get_submodel_eye(polymodel *pm, int submodel_num)
|
||||
@@ -1293,7 +1297,8 @@ float cam_get_bbox_dist(const object* viewer_obj, float preferred_distance, cons
|
||||
if (preferred_distance > (viewer_obj->radius * EXTERN_CAM_BBOX_MULTIPLIER_PADDING + EXTERN_CAM_BBOX_CONSTANT_PADDING) * 1.5f)
|
||||
return preferred_distance;
|
||||
|
||||
polymodel* pm = object_get_model(viewer_obj);
|
||||
int modelnum = object_get_model(viewer_obj);
|
||||
polymodel* pm = model_get(modelnum);
|
||||
vec3d adjusted_bbox;
|
||||
const vec3d* cam_vec = &cam_orient->vec.fvec;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <variant>
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
#define CAM_STATIONARY_FOV (1<<0)
|
||||
#define CAM_STATIONARY_ORI (1<<1)
|
||||
@@ -28,7 +28,7 @@ struct asymmetric_fov {
|
||||
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
|
||||
};
|
||||
using fov_t = std::variant<float, asymmetric_fov>;
|
||||
using fov_t = mpark::variant<float, asymmetric_fov>;
|
||||
fov_t operator* (const fov_t&, const float&);
|
||||
fov_t operator+ (const fov_t&, const float&);
|
||||
fov_t operator- (const fov_t&, const float&);
|
||||
@@ -179,6 +179,7 @@ void cam_init();
|
||||
void cam_close();
|
||||
void cam_do_frame(float frametime);
|
||||
camid cam_create(const char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
void cam_delete(camid cid);
|
||||
bool cam_set_camera(camid cid);
|
||||
void cam_reset_camera();
|
||||
|
||||
+140
-6
@@ -20,10 +20,12 @@
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h> /* needed for memory mapping of file functions */
|
||||
#endif
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <glob.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
@@ -106,6 +108,12 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type, size_t offset, size_t size);
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const char* original_filename, const void* data, size_t size, int dir_type);
|
||||
|
||||
#if defined _WIN32
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, HANDLE hFile, int type);
|
||||
#elif defined SCP_UNIX
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type);
|
||||
#endif
|
||||
|
||||
static void cf_chksum_long_init();
|
||||
|
||||
static void dump_opened_files()
|
||||
@@ -624,13 +632,18 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
// parameters: *filepath ==> name of file to open (may be path+name)
|
||||
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
|
||||
// passing NULL to mode triggers an assert and returns NULL
|
||||
// type ==> one of: CFILE_NORMAL
|
||||
// CFILE_MEMORY_MAPPED
|
||||
// dir_type => override extension check, value is one of CF_TYPE* #defines
|
||||
//
|
||||
// NOTE: type parameter is an optional parameter. The default value is CFILE_NORMAL
|
||||
//
|
||||
//
|
||||
// returns: success ==> address of CFILE structure
|
||||
// error ==> NULL
|
||||
//
|
||||
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int dir_type,
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
|
||||
bool /* localize */, uint32_t location_flags)
|
||||
{
|
||||
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
|
||||
@@ -646,6 +659,12 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
// Check that all the parameters make sense
|
||||
Assert(file_path && strlen(file_path));
|
||||
Assert( mode != NULL );
|
||||
|
||||
// Can only open read-only binary files in memory mapped mode.
|
||||
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") != 0 ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
// If in write mode, just try to open the file straight off
|
||||
@@ -670,6 +689,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
|
||||
cf_create_default_path_string(longname, dir_type, file_path, location_flags);
|
||||
}
|
||||
Assert( !(type & CFILE_MEMORY_MAPPED) );
|
||||
|
||||
// JOHN: TODO, you should create the path if it doesn't exist.
|
||||
|
||||
@@ -720,11 +740,35 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
auto find_res = cf_find_file_location(file_path, dir_type, location_flags);
|
||||
|
||||
if ( find_res.found ) {
|
||||
|
||||
// Fount it, now create a cfile out of it
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
|
||||
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, find_res, mode, dir_type);
|
||||
if ( type & CFILE_MEMORY_MAPPED ) {
|
||||
|
||||
// Can't open memory mapped files out of pack or memory files
|
||||
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
|
||||
#if defined _WIN32
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, file_path, hFile, dir_type);
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
|
||||
if (fp) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, file_path, fp, dir_type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} else {
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, find_res, mode, dir_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -849,7 +893,27 @@ int cfclose( CFILE * cfile )
|
||||
Assert(cfile != NULL);
|
||||
|
||||
result = 0;
|
||||
if ( cfile->fp != nullptr ) {
|
||||
if ( cfile->data && cfile->mem_mapped ) {
|
||||
// close memory mapped file
|
||||
#if defined _WIN32
|
||||
result = UnmapViewOfFile((void*)cfile->data);
|
||||
Assert(result);
|
||||
result = CloseHandle(cfile->hInFile);
|
||||
Assert(result); // Ensure file handle is closed properly
|
||||
result = CloseHandle(cfile->hMapFile);
|
||||
Assert(result); // Ensure file handle is closed properly
|
||||
result = 0;
|
||||
#elif defined SCP_UNIX
|
||||
// FIXME: result is wrong after munmap() but it is successful
|
||||
//result = munmap(cfile->data, cfile->data_length);
|
||||
//Assert(result);
|
||||
// This const_cast is safe since the pointer returned by mmap was also non-const
|
||||
munmap(const_cast<void*>(cfile->data), cfile->data_length);
|
||||
if ( cfile->fp != nullptr)
|
||||
result = fclose(cfile->fp);
|
||||
#endif
|
||||
|
||||
} else if ( cfile->fp != nullptr ) {
|
||||
Assert(cfile->fp != nullptr);
|
||||
result = fclose(cfile->fp);
|
||||
} else {
|
||||
@@ -894,6 +958,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
} else {
|
||||
CFILE *cfp = &Cfile_block_list[cfile_block_index];
|
||||
cfp->data = nullptr;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->fp = fp;
|
||||
cfp->dir_type = type;
|
||||
cfp->max_read_len = 0;
|
||||
@@ -932,6 +997,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
|
||||
|
||||
cfp->data = nullptr;
|
||||
cfp->fp = fp;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->dir_type = type;
|
||||
cfp->max_read_len = 0;
|
||||
|
||||
@@ -946,6 +1012,70 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cf_open_mapped_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
|
||||
// for the case of a file being opened by cf_open_mapped();
|
||||
//
|
||||
// returns: ptr CFILE structure.
|
||||
//
|
||||
#if defined _WIN32
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, HANDLE hFile, int type)
|
||||
#elif defined SCP_UNIX
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const char* original_filename, FILE *fp, int type)
|
||||
#endif
|
||||
{
|
||||
int cfile_block_index;
|
||||
|
||||
cfile_block_index = cfget_cfile_block();
|
||||
if ( cfile_block_index == -1 ) {
|
||||
#ifdef SCP_UNIX
|
||||
fclose(fp);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
CFILE *cfp = &Cfile_block_list[cfile_block_index];
|
||||
|
||||
cfp->max_read_len = 0;
|
||||
cfp->fp = nullptr;
|
||||
cfp->mem_mapped = true;
|
||||
#if defined _WIN32
|
||||
cfp->hInFile = hFile;
|
||||
#endif
|
||||
cfp->dir_type = type;
|
||||
|
||||
cfp->original_filename = original_filename;
|
||||
cfp->source_file = source;
|
||||
cfp->line_num = line;
|
||||
|
||||
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
|
||||
|
||||
#if defined _WIN32
|
||||
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (cfp->hMapFile == NULL) {
|
||||
nprintf(("Error", "Could not create file-mapping object.\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfp->data = (ubyte*)MapViewOfFile(cfp->hMapFile, FILE_MAP_READ, 0, 0, 0);
|
||||
Assert( cfp->data != NULL );
|
||||
#elif defined SCP_UNIX
|
||||
cfp->fp = fp;
|
||||
cfp->data_length = filelength(fileno(fp));
|
||||
cfp->data = mmap(nullptr, // start
|
||||
cfp->data_length, // length
|
||||
PROT_READ, // prot
|
||||
MAP_SHARED, // flags
|
||||
fileno(fp), // fd
|
||||
0); // offset
|
||||
Assert(cfp->data != nullptr);
|
||||
#endif
|
||||
|
||||
return cfp;
|
||||
}
|
||||
}
|
||||
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const char* original_filename, const void* data, size_t size, int dir_type)
|
||||
{
|
||||
int cfile_block_index;
|
||||
@@ -959,6 +1089,7 @@ static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const ch
|
||||
|
||||
cfp->max_read_len = 0;
|
||||
cfp->fp = nullptr;
|
||||
cfp->mem_mapped = false;
|
||||
cfp->dir_type = dir_type;
|
||||
|
||||
cfp->original_filename = original_filename;
|
||||
@@ -1202,6 +1333,9 @@ int cfwrite_string_len(const char *buf, CFILE *file)
|
||||
int cfilelength(CFILE* cfile) {
|
||||
Assert(cfile != NULL);
|
||||
|
||||
// TODO: return length of memory mapped file
|
||||
Assert(!cfile->mem_mapped);
|
||||
|
||||
// cfile->size gets set at cfopen
|
||||
|
||||
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
|
||||
@@ -1594,7 +1728,7 @@ int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_t
|
||||
*chksum = 0;
|
||||
|
||||
// attempt to open the file
|
||||
cfile = cfopen(filename,"rt",cf_type);
|
||||
cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
|
||||
if(cfile == NULL){
|
||||
return 0;
|
||||
}
|
||||
@@ -1644,7 +1778,7 @@ int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type
|
||||
*chksum = 0;
|
||||
|
||||
// attempt to open the file
|
||||
cfile = cfopen(filename,"rt",cf_type);
|
||||
cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
|
||||
if(cfile == NULL){
|
||||
return 0;
|
||||
}
|
||||
|
||||
+5
-1
@@ -85,6 +85,10 @@ typedef struct {
|
||||
// TRUE if type is specified and valid
|
||||
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
|
||||
|
||||
// #define's for the type parameter in cfopen.
|
||||
#define CFILE_NORMAL 0 // open file normally
|
||||
#define CFILE_MEMORY_MAPPED (1<<0) // open file as a memory-mapped file
|
||||
|
||||
#define CF_SORT_NONE 0
|
||||
#define CF_SORT_NAME 1
|
||||
#define CF_SORT_TIME 2
|
||||
@@ -177,7 +181,7 @@ int cf_get_dir_type(const CFILE *cfile);
|
||||
|
||||
// Opens the file. If no path is given, use the extension to look into the
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode,
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
|
||||
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
|
||||
@@ -149,6 +149,9 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
if (cfile->compression_info.header != 0)
|
||||
return comp_fseek(cfile, offset, where);
|
||||
|
||||
// TODO: seek to offset in memory mapped file
|
||||
Assert( !cfile->mem_mapped );
|
||||
|
||||
size_t goal_position;
|
||||
|
||||
switch( where ) {
|
||||
|
||||
@@ -38,6 +38,13 @@ struct CFILE {
|
||||
int dir_type; // directory location
|
||||
FILE* fp; // File pointer if opening an individual file
|
||||
const void* data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
|
||||
#ifdef _WIN32
|
||||
HANDLE hInFile; // Handle from CreateFile()
|
||||
HANDLE hMapFile; // Handle from CreateFileMapping()
|
||||
#else
|
||||
size_t data_length; // length of data for mmap
|
||||
#endif
|
||||
size_t lib_offset;
|
||||
size_t raw_position;
|
||||
size_t size; // for packed files
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <windows.h>
|
||||
#include <winbase.h> /* needed for memory mapping of file functions */
|
||||
#include <shlwapi.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
|
||||
+20
-61
@@ -261,7 +261,6 @@ Flag exe_params[] =
|
||||
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
|
||||
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
|
||||
{ "-output_script_json", "Output scripting doc to scripting.json", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_json", },
|
||||
{ "-output_script_lua", "Output scripting doc to scripting.lua", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_luastub", },
|
||||
{ "-controlconfig_tbl", "Save control presets to table", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-controlconfig_tbl", },
|
||||
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
|
||||
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
|
||||
@@ -316,6 +315,7 @@ int Cmdline_cd_check = 1;
|
||||
int Cmdline_closed_game = 0;
|
||||
int Cmdline_freespace_no_music = 0;
|
||||
int Cmdline_freespace_no_sound = 0;
|
||||
int Cmdline_gimme_all_medals = 0;
|
||||
int Cmdline_mouse_coords = 0;
|
||||
int Cmdline_multi_log = 0;
|
||||
int Cmdline_multi_stream_chat_to_file = 0;
|
||||
@@ -382,7 +382,7 @@ cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NO
|
||||
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
|
||||
|
||||
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
|
||||
bool Cmdline_no_vsync = false;
|
||||
int Cmdline_no_vsync = 0;
|
||||
|
||||
// HUD related
|
||||
cmdline_parm ballistic_gauge("-ballistic_gauge", NULL, AT_NONE); // Cmdline_ballistic_gauge
|
||||
@@ -405,7 +405,7 @@ cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
bool Cmdline_stretch_menu = false;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_deadzone = -1;
|
||||
bool Cmdline_enable_vr = false;
|
||||
@@ -418,10 +418,8 @@ int Cmdline_no_enhanced_sound = 0;
|
||||
|
||||
// MOD related
|
||||
cmdline_parm mod_arg("-mod", "List of folders to overwrite/add-to the default data", AT_STRING, true); // Cmdline_mod -- DTP modsupport
|
||||
cmdline_parm campaign_arg("-campaign", "Set current campaign", AT_STRING); // Cmdline_campaign
|
||||
|
||||
char *Cmdline_mod = NULL; //DTP for mod argument
|
||||
char *Cmdline_campaign = nullptr; // for campaign argument
|
||||
|
||||
// Multiplayer/Network related
|
||||
cmdline_parm almission_arg("-almission", "Autoload multiplayer mission", AT_STRING); // Cmdline_almission -- DTP for autoload Multi mission
|
||||
@@ -548,9 +546,9 @@ int Cmdline_bmpman_usage = 0;
|
||||
int Cmdline_show_pos = 0;
|
||||
int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
bool Cmdline_window = false;
|
||||
bool Cmdline_fullscreen_window = false;
|
||||
std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = std::nullopt;
|
||||
int Cmdline_window = 0;
|
||||
int Cmdline_fullscreen_window = 0;
|
||||
tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = tl::nullopt;
|
||||
char *Cmdline_res = 0;
|
||||
char *Cmdline_center_res = 0;
|
||||
int Cmdline_verify_vps = 0;
|
||||
@@ -578,7 +576,6 @@ cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", A
|
||||
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
|
||||
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
|
||||
cmdline_parm output_script_json_arg("-output_script_json", nullptr, AT_NONE); // m!m
|
||||
cmdline_parm output_script_luastub_arg("-output_script_lua", nullptr, AT_NONE); // mjnmixael
|
||||
cmdline_parm generate_controlconfig_arg("-controlconfig_tbl", nullptr, AT_NONE);
|
||||
|
||||
// Deprecated flags - CommanderDJ
|
||||
@@ -643,8 +640,8 @@ void cmdline_debug_print_cmdline()
|
||||
}
|
||||
#endif
|
||||
|
||||
// builds simple cmdline
|
||||
SCP_string cmdline_build_string()
|
||||
// prints simple cmdline to multi.log
|
||||
void cmdline_print_cmdline_multi()
|
||||
{
|
||||
cmdline_parm *parmp;
|
||||
int found = 0;
|
||||
@@ -663,18 +660,10 @@ SCP_string cmdline_build_string()
|
||||
}
|
||||
|
||||
if ( !found ) {
|
||||
return "";
|
||||
cmdline << " <none>";
|
||||
}
|
||||
|
||||
return cmdline.str();
|
||||
}
|
||||
|
||||
// prints simple cmdline to multi.log
|
||||
void cmdline_print_cmdline_multi()
|
||||
{
|
||||
auto str = cmdline_build_string();
|
||||
|
||||
ml_printf("Command line:%s", str.empty() ? " <none>" : str.c_str());
|
||||
ml_printf("Command line:%s", cmdline.str().c_str());
|
||||
}
|
||||
|
||||
// Return true if this character is an extra char (white space and quotes)
|
||||
@@ -683,6 +672,7 @@ int is_extra_space(char ch)
|
||||
return ((ch == ' ') || (ch == '\t') || (ch == 0x0a) || (ch == '\'') || (ch == '\"'));
|
||||
}
|
||||
|
||||
|
||||
// eliminates all leading and trailing extra chars from a string. Returns pointer passed in.
|
||||
char *drop_extra_chars(char *str)
|
||||
{
|
||||
@@ -1590,12 +1580,6 @@ bool SetCmdlineParams()
|
||||
{
|
||||
//getcwd(FreeSpace_Directory, 256); // set the directory to our fs2 root
|
||||
|
||||
// DO THIS BEFORE get_flags, as portable_mode can change the value of pref_path printed in the json
|
||||
if (portable_mode.found())
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
}
|
||||
|
||||
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
|
||||
if ( get_flags_arg.found() ) {
|
||||
write_flags();
|
||||
@@ -1776,14 +1760,14 @@ bool SetCmdlineParams()
|
||||
if(window_arg.found()) {
|
||||
// We need to set both values since we don't know if we are going to use the new config system
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
|
||||
Cmdline_window = true;
|
||||
Cmdline_window = 1;
|
||||
}
|
||||
|
||||
if ( fullscreen_window_arg.found( ) )
|
||||
{
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
|
||||
Cmdline_fullscreen_window = true;
|
||||
Cmdline_window = false; /* Make sure no-one sets both */
|
||||
Cmdline_fullscreen_window = 1;
|
||||
Cmdline_window = 0; /* Make sure no-one sets both */
|
||||
}
|
||||
|
||||
if(render_res_arg.found() || deprecated_res_arg.found()){
|
||||
@@ -1878,14 +1862,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_mod = modlist;
|
||||
}
|
||||
|
||||
if(campaign_arg.found()) {
|
||||
Cmdline_campaign = campaign_arg.str();
|
||||
|
||||
// strip off blank space if it's there
|
||||
if ( Cmdline_campaign[strlen(Cmdline_campaign)-1] == ' ' ) {
|
||||
Cmdline_campaign[strlen(Cmdline_campaign)-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (fps_arg.found())
|
||||
{
|
||||
@@ -1934,25 +1910,6 @@ bool SetCmdlineParams()
|
||||
if (fov_arg.found() || fov_cockpit_arg.found()) {
|
||||
Warning(LOCATION, "FoV Command line settings found. VR-Mode will override these with the HMD's native FoV...");
|
||||
}
|
||||
|
||||
// enable other settings to allow VR to work more seamlessly
|
||||
mprintf(("VR-Mode enabled, so forcing on the following settings: capture_mouse, window_res 1000x1000, window, no_vsync \n"));
|
||||
|
||||
// ensure ingame resolution is set to sensible values in VR mode,
|
||||
// which will exceed the resolution otherwise shown and is not dependent on the monitor resolution
|
||||
Cmdline_capture_mouse = true;
|
||||
Cmdline_window_res.emplace(static_cast<uint16_t>(1000), static_cast<uint16_t>(1000));
|
||||
|
||||
Cmdline_fullscreen_window = false;
|
||||
Cmdline_window = true; /* Make sure no-one sets both */
|
||||
removeWindowModeOption();
|
||||
|
||||
// Turn off VSync, since we definitely don't want to be capped by the main monitor
|
||||
// the OpenXR runtime should have a buffered wait which will behave, effectively,
|
||||
// as a VSync to VR goggle driver
|
||||
Gr_enable_vsync = false;
|
||||
removeVSyncOption();
|
||||
|
||||
openxr_prepare();
|
||||
}
|
||||
|
||||
@@ -1970,7 +1927,7 @@ bool SetCmdlineParams()
|
||||
}
|
||||
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = true;
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
|
||||
if ( capture_mouse.found() ) {
|
||||
@@ -2077,9 +2034,6 @@ bool SetCmdlineParams()
|
||||
if (output_script_json_arg.found() )
|
||||
Output_scripting_json = true;
|
||||
|
||||
if (output_script_luastub_arg.found())
|
||||
Output_scripting_luastub = true;
|
||||
|
||||
if (output_sexp_arg.found() ) {
|
||||
Cmdline_output_sexp_info = true;
|
||||
}
|
||||
@@ -2127,6 +2081,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_noshadercache = true;
|
||||
}
|
||||
|
||||
if (portable_mode.found())
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
}
|
||||
|
||||
if (lang_arg.found())
|
||||
{
|
||||
Cmdline_lang = lang_arg.str();
|
||||
|
||||
+7
-11
@@ -12,7 +12,7 @@
|
||||
#ifndef FS_CMDLINE_HEADER_FILE
|
||||
#define FS_CMDLINE_HEADER_FILE
|
||||
|
||||
#include <optional>
|
||||
#include <tl/optional.hpp>
|
||||
|
||||
int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
@@ -34,6 +34,7 @@ extern int Cmdline_cd_check;
|
||||
extern int Cmdline_closed_game;
|
||||
extern int Cmdline_freespace_no_music;
|
||||
extern int Cmdline_freespace_no_sound;
|
||||
extern int Cmdline_gimme_all_medals;
|
||||
extern int Cmdline_mouse_coords;
|
||||
extern int Cmdline_multi_log;
|
||||
extern int Cmdline_multi_stream_chat_to_file;
|
||||
@@ -43,10 +44,10 @@ extern int Cmdline_spew_pof_info;
|
||||
extern int Cmdline_start_netgame;
|
||||
extern int Cmdline_timeout;
|
||||
extern int Cmdline_use_last_pilot;
|
||||
extern bool Cmdline_window;
|
||||
extern bool Cmdline_fullscreen_window;
|
||||
extern int Cmdline_window;
|
||||
extern int Cmdline_fullscreen_window;
|
||||
extern char *Cmdline_res;
|
||||
extern std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
|
||||
extern tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
|
||||
extern char *Cmdline_center_res;
|
||||
|
||||
|
||||
@@ -71,7 +72,7 @@ extern int Cmdline_msaa_enabled;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_NoFPSCap;
|
||||
extern bool Cmdline_no_vsync;
|
||||
extern int Cmdline_no_vsync;
|
||||
|
||||
// HUD related
|
||||
extern int Cmdline_ballistic_gauge;
|
||||
@@ -81,7 +82,7 @@ extern int Cmdline_rearm_timer;
|
||||
|
||||
// Gameplay related
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern bool Cmdline_stretch_menu;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_deadzone;
|
||||
extern bool Cmdline_enable_vr;
|
||||
@@ -92,7 +93,6 @@ extern int Cmdline_no_enhanced_sound;
|
||||
|
||||
// MOD related
|
||||
extern char *Cmdline_mod; // DTP for mod support
|
||||
extern char *Cmdline_campaign; // for campaign support
|
||||
// Multiplayer/Network related
|
||||
extern char *Cmdline_almission; // DTP for autoload mission (for multi only)
|
||||
extern int Cmdline_ingamejoin;
|
||||
@@ -163,9 +163,5 @@ extern bool Cmdline_vulkan;
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
extern WeaponSpewType Cmdline_spew_weapon_stats;
|
||||
|
||||
extern void removeVSyncOption();
|
||||
extern void removeWindowModeOption();
|
||||
extern void removeResolutionOption();
|
||||
extern void removeResolutionVROption();
|
||||
|
||||
#endif
|
||||
@@ -1296,7 +1296,8 @@ bool control_config_accept(bool API_Access)
|
||||
retry:;
|
||||
SCP_string default_string = (Current_preset_name.empty()) ? Player->callsign : Current_preset_name;
|
||||
cstr = popup_input(flags,
|
||||
XSTR( "Confirm new custom preset name.\n\nThe name must not be empty or a default preset.\n\n Press [Enter] to accept, [Esc] to abort to config menu.", 1867),
|
||||
"Confirm new custom preset name.\n\nThe name must not be empty.\n\n Press [Enter] to accept, [Esc] to "
|
||||
"abort to config menu.",
|
||||
32 - 6,
|
||||
default_string.c_str());
|
||||
if (cstr == nullptr) {
|
||||
@@ -1319,13 +1320,14 @@ bool control_config_accept(bool API_Access)
|
||||
});
|
||||
|
||||
if (it != Control_config_presets.end()) {
|
||||
popup(flags | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
|
||||
popup(flags, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists. If so, prompt the user
|
||||
CFILE* fp = cfopen((str + ".json").c_str(),
|
||||
"r",
|
||||
CFILE_NORMAL,
|
||||
CF_TYPE_PLAYER_BINDS,
|
||||
false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
@@ -1333,11 +1335,11 @@ bool control_config_accept(bool API_Access)
|
||||
cfclose(fp);
|
||||
int n = popup(flags,
|
||||
2,
|
||||
POPUP_CANCEL,
|
||||
POPUP_OK,
|
||||
POPUP_CANCEL,
|
||||
"'%s'\n Already exists!\n Press OK to overwrite existing preset, or CANCEL to input another name",
|
||||
str.c_str());
|
||||
if ((n == 0) || (n == -1)) {
|
||||
if ((n == 1) || (n == -1)) {
|
||||
// If Cancel button was pressed, or popup dismissed:
|
||||
// retry
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
@@ -1347,7 +1349,7 @@ bool control_config_accept(bool API_Access)
|
||||
|
||||
// Pack the current bindings into a preset, then save the file
|
||||
CC_preset preset;
|
||||
preset.name = std::move(str);
|
||||
preset.name = str;
|
||||
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
|
||||
Control_config_presets.push_back(preset);
|
||||
save_preset_file(preset, true);
|
||||
@@ -1364,11 +1366,6 @@ bool control_config_accept(bool API_Access)
|
||||
}
|
||||
}
|
||||
|
||||
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
|
||||
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
|
||||
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', true)));
|
||||
}
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
@@ -1384,8 +1381,8 @@ void control_config_cancel_exit(bool API_Access)
|
||||
// Check if any changes were made
|
||||
if (!API_Access && (control_config_get_current_preset() == Control_config_presets.end())) {
|
||||
// Changes were made, prompt the user first.
|
||||
int flags = PF_TITLE_WHITE | PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON;
|
||||
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, XSTR( "You have unsaved changes.\n\n\n Do you wish to continue without saving?", 1866));
|
||||
int flags = PF_TITLE_WHITE;
|
||||
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, "You have unsaved changes.\n\n\n Do you wish to continue without saving?");
|
||||
|
||||
switch (choice) {
|
||||
case -1: // Aborted
|
||||
@@ -1406,11 +1403,6 @@ void control_config_cancel_exit(bool API_Access)
|
||||
// Restore all bindings with the backup
|
||||
std::move(Control_config_backup.begin(), Control_config_backup.end(), Control_config.begin());
|
||||
|
||||
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
|
||||
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
|
||||
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', false)));
|
||||
}
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
}
|
||||
@@ -1766,7 +1758,7 @@ bool control_config_delete_preset(CC_preset preset) {
|
||||
return delete_preset_file(preset);
|
||||
}
|
||||
|
||||
bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
bool control_config_create_new_preset(SCP_string newName)
|
||||
{
|
||||
|
||||
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
|
||||
@@ -1779,14 +1771,13 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists.
|
||||
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
|
||||
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pack the current bindings into a preset, then save the file
|
||||
CC_preset preset;
|
||||
preset.name = newName;
|
||||
preset.type = Preset_t::pst;
|
||||
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
|
||||
|
||||
// Done with the file
|
||||
@@ -1815,7 +1806,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
|
||||
return false; //should be unreachable, but just in case
|
||||
}
|
||||
|
||||
bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newName, bool overwrite) {
|
||||
bool control_config_clone_preset(CC_preset preset, SCP_string newName) {
|
||||
|
||||
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
|
||||
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
|
||||
@@ -1827,7 +1818,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
|
||||
}
|
||||
|
||||
// Check if a preset file with name already exists.
|
||||
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
|
||||
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2144,12 +2135,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
if (!done && (j < JOY_TOTAL_BUTTONS)) {
|
||||
// Bind the joy button
|
||||
Assert(!Control_config[ctrl].is_axis());
|
||||
control_config_bind(ctrl, CC_bind(static_cast<CID>(joy), j), item, API_Access);
|
||||
|
||||
CC_bind joy_bind(static_cast<CID>(joy), j);
|
||||
|
||||
control_config_bind(ctrl, joy_bind, item, API_Access);
|
||||
|
||||
strcpy_s(bound_string, joy_bind.textify().c_str());
|
||||
strcpy_s(bound_string, Joy_button_text[j]);
|
||||
done = true;
|
||||
}
|
||||
|
||||
@@ -2183,10 +2171,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
|
||||
if (mouse_down(mouse_bind)) {
|
||||
Assert(!Control_config[ctrl].is_axis());
|
||||
|
||||
control_config_bind(ctrl, mouse_bind, item, API_Access);
|
||||
|
||||
strcpy_s(bound_string, mouse_bind.textify().c_str());
|
||||
strcpy_s(bound_string, Joy_button_text[i]);
|
||||
done = true;
|
||||
|
||||
break;
|
||||
|
||||
@@ -36,10 +36,8 @@ enum Joy_axis_index : short {
|
||||
JOY_RX_AXIS,
|
||||
JOY_RY_AXIS,
|
||||
JOY_RZ_AXIS,
|
||||
JOY_U_AXIS,
|
||||
JOY_V_AXIS,
|
||||
|
||||
JOY_NUM_AXES //!< Max number of joy axes that FSO can handle. Must be last enum in Joy_axis_index.
|
||||
JOY_NUM_AXES // Number of axes a joystick may have. Must be last enum in Joy_axis_index.
|
||||
};
|
||||
|
||||
// Aliases for mouse axes. Really should unify this...
|
||||
@@ -299,8 +297,6 @@ enum IoActionId : int {
|
||||
|
||||
TOGGLE_HUD_SHADOWS,
|
||||
|
||||
CYCLE_PRIMARY_WEAPON_PATTERN,
|
||||
|
||||
/*!
|
||||
* This must always be below the last defined item
|
||||
*/
|
||||
@@ -561,7 +557,7 @@ class CC_preset {
|
||||
public:
|
||||
SCP_vector<CCB> bindings;
|
||||
SCP_string name;
|
||||
Preset_t type = Preset_t::hardcode;
|
||||
Preset_t type;
|
||||
|
||||
public:
|
||||
CC_preset() = default;
|
||||
@@ -687,6 +683,7 @@ extern SCP_vector<conflict> Conflicts; //!< Stores conflict data for the keybind
|
||||
|
||||
extern SCP_vector<CCI> Control_config; //!< Stores the keyboard configuration
|
||||
extern SCP_vector<CC_preset> Control_config_presets; // tabled control presets; pointers to config_item arrays
|
||||
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
|
||||
|
||||
extern bool Generate_controlconfig_table;
|
||||
|
||||
@@ -845,7 +842,7 @@ bool control_config_delete_preset(CC_preset preset);
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_clone_preset(const CC_preset& preset, const SCP_string& name, bool overwrite);
|
||||
bool control_config_clone_preset(CC_preset preset, SCP_string name);
|
||||
|
||||
/*!
|
||||
* @brief Saves a preset with the current controls
|
||||
@@ -853,7 +850,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& name
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_create_new_preset(const SCP_string& name, bool overwrite);
|
||||
bool control_config_create_new_preset(SCP_string name);
|
||||
|
||||
/*!
|
||||
* Returns the IoActionId (index within Control_config[]) of a control bound to the given key
|
||||
@@ -911,18 +908,7 @@ const char *textify_scancode(int code);
|
||||
*/
|
||||
const char *textify_scancode_universal(int code);
|
||||
|
||||
/**
|
||||
* @brief Creates a button label based on btn index and locale settings.
|
||||
*
|
||||
* @param[in] btn The btn to textify
|
||||
*
|
||||
* @return The text representation of the btn
|
||||
*
|
||||
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
|
||||
*/
|
||||
const char* textify_button(int btn);
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* @brief Checks how long a control has been active
|
||||
*
|
||||
* @param[in] id The IoActionId of the control to check
|
||||
|
||||
@@ -178,7 +178,6 @@ void control_config_common_init_bindings() {
|
||||
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_PATTERN, KEY_ALTED | KEY_O, -1, WEAPON_TAB, 1859, "Cycle Primary Weapon Firing Pattern", CC_TYPE_TRIGGER)
|
||||
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
|
||||
@@ -210,10 +209,10 @@ void control_config_common_init_bindings() {
|
||||
(VIEW_DIST_INCREASE, KEY_PADPLUS, -1, COMPUTER_TAB, 1, "Increase View Distance", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_DIST_DECREASE, KEY_PADMINUS, -1, COMPUTER_TAB, 1, "Decrease View Distance", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_CENTER, KEY_PAD5, -1, COMPUTER_TAB, 1, "Center View", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_UP, -1, iHAT_UP, COMPUTER_TAB, 1, "View Up", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_DOWN, -1, iHAT_DOWN, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, iHAT_LEFT, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, iHAT_RIGHT, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_UP, -1, 33, COMPUTER_TAB, 1, "View Up", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
|
||||
@@ -432,7 +431,6 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Cycle Nav Points", NAV_CYCLE},
|
||||
{"Toggle Gliding", TOGGLE_GLIDING},
|
||||
{"Cycle Primary Weapon Firing Rate", CYCLE_PRIMARY_WEAPON_SEQUENCE},
|
||||
{"Cycle Primary Weapon Firing Pattern", CYCLE_PRIMARY_WEAPON_PATTERN},
|
||||
{"Custom Control 1", CUSTOM_CONTROL_1},
|
||||
{"Custom Control 2", CUSTOM_CONTROL_2},
|
||||
{"Custom Control 3", CUSTOM_CONTROL_3},
|
||||
@@ -440,38 +438,67 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Custom Control 5", CUSTOM_CONTROL_5},
|
||||
};
|
||||
|
||||
// Localization strings for hat positions. Back[0], Forward[1], Left[2], Right[3]
|
||||
// This ordering is used to follow the same logic as hatBtnToEnum in joy-sdl.cpp
|
||||
const char* Joy_hat_text_german_u[JOY_NUM_HAT_POS] = {
|
||||
"Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
const char* Joy_button_text_german_u[] = {
|
||||
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
|
||||
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
|
||||
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
|
||||
"Knopf 19", "Knopf 20", "Knopf 21", "Knopf 22", "Knopf 23", "Knopf 24",
|
||||
"Knopf 25", "Knopf 26", "Knopf 27", "Knopf 28", "Knopf 29", "Knopf 30",
|
||||
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_french_u[JOY_NUM_HAT_POS] = {
|
||||
("Chapeau Arri\xc3\xa8""re"), "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
const char* Joy_button_text_french_u[] = {
|
||||
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
|
||||
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
"Bouton 19", "Bouton 20", "Bouton 21", "Bouton 22", "Bouton 23", "Bouton 24",
|
||||
"Bouton 25", "Bouton 26", "Bouton 27", "Bouton 28", "Bouton 29", "Bouton 30",
|
||||
"Bouton 31", "Bouton 32", ("Chapeau Arri\xc3\xa8""re"), "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_polish_u[JOY_NUM_HAT_POS] = {
|
||||
"Hat Ty\xc5\x82", ("Hat Prz\xc3\xb3""d"), "Hat Lewo", "Hat Prawo"
|
||||
const char* Joy_button_text_polish_u[] = {
|
||||
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
|
||||
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
"Przyc.19", "Przyc.20", "Przyc.21", "Przyc.22", "Przyc.23", "Przyc.24",
|
||||
"Przyc.25", "Przyc.26", "Przyc.27", "Przyc.28", "Przyc.29", "Przyc.30",
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xc5\x82", ("Hat Prz\xc3\xb3""d"), "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_english_u[JOY_NUM_HAT_POS] = {
|
||||
"Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
const char* Joy_button_text_english_u[] = {
|
||||
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
|
||||
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
|
||||
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
|
||||
"Button 19", "Button 20", "Button 21", "Button 22", "Button 23", "Button 24",
|
||||
"Button 25", "Button 26", "Button 27", "Button 28", "Button 29", "Button 30",
|
||||
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_german[JOY_NUM_HAT_POS] = {
|
||||
"Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
const char* Joy_button_text_german[] = {
|
||||
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
|
||||
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
|
||||
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
|
||||
"Knopf 19", "Knopf 20", "Knopf 21", "Knopf 22", "Knopf 23", "Knopf 24",
|
||||
"Knopf 25", "Knopf 26", "Knopf 27", "Knopf 28", "Knopf 29", "Knopf 30",
|
||||
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_french[JOY_NUM_HAT_POS] = {
|
||||
"Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
const char* Joy_button_text_french[] = {
|
||||
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
|
||||
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
"Bouton 19", "Bouton 20", "Bouton 21", "Bouton 22", "Bouton 23", "Bouton 24",
|
||||
"Bouton 25", "Bouton 26", "Bouton 27", "Bouton 28", "Bouton 29", "Bouton 30",
|
||||
"Bouton 31", "Bouton 32", "Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_polish[JOY_NUM_HAT_POS] = {
|
||||
"Hat Ty\xB3", "Hat Prz\xF3\x64", "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
const char* Joy_hat_text_english[JOY_NUM_HAT_POS] = {
|
||||
"Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
const char* Joy_button_text_polish[] = {
|
||||
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
|
||||
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
"Przyc.19", "Przyc.20", "Przyc.21", "Przyc.22", "Przyc.23", "Przyc.24",
|
||||
"Przyc.25", "Przyc.26", "Przyc.27", "Przyc.28", "Przyc.29", "Przyc.30",
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xB3", "Hat Prz\xF3\x64", "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
//English scancodes are still needed eclusively for the scripting API, as we need to give generic and stable scan code names to the API that are neither translated nor localized to keyboard layout.
|
||||
@@ -517,6 +544,17 @@ const char *Scan_code_text_english[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
const char* Joy_button_text_english[] = {
|
||||
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
|
||||
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
|
||||
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
|
||||
"Button 19", "Button 20", "Button 21", "Button 22", "Button 23", "Button 24",
|
||||
"Button 25", "Button 26", "Button 27", "Button 28", "Button 29", "Button 30",
|
||||
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
};
|
||||
|
||||
const char **Joy_button_text = Joy_button_text_english;
|
||||
|
||||
bool Generate_controlconfig_table = false;
|
||||
|
||||
int sections_read = 0; // Number of sections read within the controlconfigdefaults.tbl
|
||||
@@ -685,69 +723,7 @@ const char *textify_scancode_universal(int code)
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
const char* textify_button(int btn) {
|
||||
static char text[BTN_MSG_LEN];
|
||||
|
||||
if ((btn < 0) || (btn >= JOY_TOTAL_BUTTONS))
|
||||
return "None";
|
||||
|
||||
text[0] = '\0';
|
||||
|
||||
if (btn < JOY_NUM_BUTTONS) {
|
||||
// Is a button.
|
||||
if (Lcl_gr) {
|
||||
sprintf(text, "Knopf %i", btn);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
sprintf(text, "Bouton %i", btn);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
sprintf(text, "Przyc.%i", btn);
|
||||
|
||||
} else {
|
||||
sprintf(text, "Button %i", btn);
|
||||
}
|
||||
|
||||
} else {
|
||||
//is Hat
|
||||
btn -= JOY_NUM_BUTTONS;
|
||||
Assertion(btn <= JOY_NUM_HAT_POS, "Invalid btn value '%i' after hat position translation.", btn);
|
||||
|
||||
if (Unicode_text_mode) {
|
||||
// use unicode character maps
|
||||
if (Lcl_gr) {
|
||||
strcpy_s(text, Joy_hat_text_german_u[btn]);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
strcpy_s(text, Joy_hat_text_french_u[btn]);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
strcpy_s(text, Joy_hat_text_polish_u[btn]);
|
||||
|
||||
} else {
|
||||
strcpy_s(text, Joy_hat_text_english_u[btn]);
|
||||
}
|
||||
} else {
|
||||
// use ascii character maps
|
||||
if (Lcl_gr) {
|
||||
strcpy_s(text, Joy_hat_text_german[btn]);
|
||||
|
||||
} else if (Lcl_fr) {
|
||||
strcpy_s(text, Joy_hat_text_french[btn]);
|
||||
|
||||
} else if (Lcl_pl) {
|
||||
strcpy_s(text, Joy_hat_text_polish[btn]);
|
||||
|
||||
} else {
|
||||
strcpy_s(text, Joy_hat_text_english[btn]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
//XSTR:ON
|
||||
//XSTR:ON
|
||||
|
||||
void control_config_common_load_overrides();
|
||||
|
||||
@@ -780,6 +756,36 @@ void control_config_common_init()
|
||||
// load player presets
|
||||
load_preset_files();
|
||||
|
||||
// Init control label localization
|
||||
if (Unicode_text_mode) {
|
||||
if (Lcl_gr) {
|
||||
Joy_button_text = Joy_button_text_german_u;
|
||||
}
|
||||
else if (Lcl_fr) {
|
||||
Joy_button_text = Joy_button_text_french_u;
|
||||
}
|
||||
else if (Lcl_pl) {
|
||||
Joy_button_text = Joy_button_text_polish_u;
|
||||
}
|
||||
else {
|
||||
Joy_button_text = Joy_button_text_english_u;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Lcl_gr) {
|
||||
Joy_button_text = Joy_button_text_german;
|
||||
}
|
||||
else if (Lcl_fr) {
|
||||
Joy_button_text = Joy_button_text_french;
|
||||
}
|
||||
else if (Lcl_pl) {
|
||||
Joy_button_text = Joy_button_text_polish;
|
||||
}
|
||||
else {
|
||||
Joy_button_text = Joy_button_text_english;
|
||||
}
|
||||
}
|
||||
|
||||
// Old XSTR indices have been put beside their corresponding label in case we use them again
|
||||
Axis_text[0] = vm_strdup(XSTR("X Axis", 1647)); // XSTR 1021 - "Joystick/Mouse X Axis"
|
||||
Axis_text[1] = vm_strdup(XSTR("Y Axis", 1648)); // XSTR 1022 - "Joystick/Mouse Y Axis"
|
||||
@@ -787,8 +793,6 @@ void control_config_common_init()
|
||||
Axis_text[3] = vm_strdup(XSTR("rX Axis", 1650)); // XSTR 1024 - "Joystick rX Axis"
|
||||
Axis_text[4] = vm_strdup(XSTR("rY Axis", 1651)); // XSTR 1025 - "Joystick rY Axis"
|
||||
Axis_text[5] = vm_strdup(XSTR("rZ Axis", 1652)); // XSTR 1026 - "Joystick rZ Axis"
|
||||
Axis_text[6] = vm_strdup(XSTR("U Axis", 1860));
|
||||
Axis_text[7] = vm_strdup(XSTR("V Axis", 1861));
|
||||
|
||||
Mouse_button_text[0] = vm_strdup(XSTR("Left Button", 1027));
|
||||
Mouse_button_text[1] = vm_strdup(XSTR("Right Button", 1028));
|
||||
@@ -1150,7 +1154,6 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(TOGGLE_GLIDING)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(CYCLE_PRIMARY_WEAPON_SEQUENCE)
|
||||
ADD_ENUM_TO_ACTION_MAP(CYCLE_PRIMARY_WEAPON_PATTERN)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(CUSTOM_CONTROL_1)
|
||||
ADD_ENUM_TO_ACTION_MAP(CUSTOM_CONTROL_2)
|
||||
@@ -1203,8 +1206,6 @@ void LoadEnumsIntoAxisMap() {
|
||||
mAxisNameToVal["RX_AXIS"] = JOY_RX_AXIS;
|
||||
mAxisNameToVal["RY_AXIS"] = JOY_RY_AXIS;
|
||||
mAxisNameToVal["RZ_AXIS"] = JOY_RZ_AXIS;
|
||||
mAxisNameToVal["U_AXIS"] = JOY_U_AXIS;
|
||||
mAxisNameToVal["V_AXIS"] = JOY_V_AXIS;
|
||||
}
|
||||
|
||||
void LoadEnumsIntoHatMap() {
|
||||
@@ -1956,7 +1957,7 @@ int control_config_common_write_tbl(bool overwrite = false, bool all = false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CFILE* cfile = cfopen("controlconfigdefaults.tbl", "w", CF_TYPE_TABLES);
|
||||
CFILE* cfile = cfopen("controlconfigdefaults.tbl", "w", CFILE_NORMAL, CF_TYPE_TABLES);
|
||||
if (cfile == nullptr) {
|
||||
// Could not open. Bail.
|
||||
return 1;
|
||||
@@ -2649,21 +2650,22 @@ SCP_string CC_bind::textify() const {
|
||||
SCP_string prefix;
|
||||
SCP_string retval;
|
||||
|
||||
// TODO: XSTR the Mouse/Joy prefix
|
||||
switch (cid) {
|
||||
case CID_MOUSE:
|
||||
prefix = XSTR("Mouse ", 1868);
|
||||
prefix = "Mouse ";
|
||||
break;
|
||||
case CID_JOY0:
|
||||
prefix = XSTR("Joy-0 ", 1869);
|
||||
prefix = "Joy-0 ";
|
||||
break;
|
||||
case CID_JOY1:
|
||||
prefix = XSTR("Joy-1 ", 1870);
|
||||
prefix = "Joy-1 ";
|
||||
break;
|
||||
case CID_JOY2:
|
||||
prefix = XSTR("Joy-2 ", 1871);
|
||||
prefix = "Joy-2 ";
|
||||
break;
|
||||
case CID_JOY3:
|
||||
prefix = XSTR("Joy-3 ", 1872);
|
||||
prefix = "Joy-3 ";
|
||||
break;
|
||||
case CID_NONE:
|
||||
case CID_KEYBOARD:
|
||||
@@ -2675,7 +2677,7 @@ SCP_string CC_bind::textify() const {
|
||||
if (flags & CCF_AXIS) {
|
||||
// Is Axis
|
||||
if (cid == CID_NONE) {
|
||||
retval = XSTR("None", 1873);
|
||||
retval = "None";
|
||||
} else {
|
||||
Assert((btn >= 0) && (btn < NUM_AXIS_TEXT));
|
||||
retval = SCP_string(Axis_text[btn]);
|
||||
@@ -2698,12 +2700,12 @@ SCP_string CC_bind::textify() const {
|
||||
case CID_JOY2:
|
||||
case CID_JOY3:
|
||||
Assert((btn >= 0) && (btn < JOY_TOTAL_BUTTONS));
|
||||
retval = SCP_string(textify_button(btn));
|
||||
retval = SCP_string(Joy_button_text[btn]);
|
||||
break;
|
||||
|
||||
case CID_NONE:
|
||||
default:
|
||||
retval = XSTR("None", 1873);
|
||||
retval = "None";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
#include "controlconfig/presets.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "libs/jansson.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "popup/popup.h"
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
@@ -45,7 +43,7 @@ void load_preset_files(SCP_string clone) {
|
||||
std::unique_ptr<PresetFileHandler> handler = nullptr;
|
||||
|
||||
for (const auto &file : filelist) {
|
||||
CFILE* fp = cfopen((file + ".json").c_str(), "r", CF_TYPE_PLAYER_BINDS, false,
|
||||
CFILE* fp = cfopen((file + ".json").c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if (!fp) {
|
||||
@@ -135,12 +133,8 @@ void load_preset_files(SCP_string clone) {
|
||||
Control_config_presets.push_back(preset);
|
||||
|
||||
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
|
||||
if (gameseq_get_state() == GS_STATE_CONTROL_CONFIG) {
|
||||
popup(PF_TITLE_WHITE | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
} else {
|
||||
// Complain and ignore if the preset names or the type differs
|
||||
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
}
|
||||
// Complain and ignore if the preset names or the type differs
|
||||
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
|
||||
|
||||
} // else, silent ignore
|
||||
}
|
||||
@@ -190,7 +184,7 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
|
||||
std::unique_ptr<PresetFileHandler> handler = nullptr;
|
||||
|
||||
// Check if there's a file already
|
||||
CFILE* fp = cfopen(filename.c_str(), "r", CF_TYPE_PLAYER_BINDS, false,
|
||||
CFILE* fp = cfopen(filename.c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if ((fp != nullptr) && !overwrite) {
|
||||
@@ -199,7 +193,7 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
|
||||
}
|
||||
|
||||
// Try opening file for write
|
||||
fp = cfopen(filename.c_str(), "w", CF_TYPE_PLAYER_BINDS, false,
|
||||
fp = cfopen(filename.c_str(), "w", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
if (!fp) {
|
||||
|
||||
@@ -354,25 +354,32 @@ static const char* Text_lines[MAX_TEXT_LINES];
|
||||
|
||||
void cutscenes_screen_play()
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Cutscene_list, Selected_line), "Selected line %d is out of range!", Selected_line);
|
||||
int which_cutscene = Cutscene_list[Selected_line];
|
||||
char name[MAX_FILENAME_LEN]; // *full_name
|
||||
int which_cutscene;
|
||||
|
||||
Assert((Selected_line >= 0) && (Selected_line < (int) Cutscene_list.size()));
|
||||
which_cutscene = Cutscene_list[Selected_line];
|
||||
|
||||
strcpy_s(name, Cutscenes[which_cutscene].filename);
|
||||
// full_name = cf_add_ext(name, NOX(".mve"));
|
||||
|
||||
main_hall_stop_music(true);
|
||||
main_hall_stop_ambient();
|
||||
auto rval = movie::play(Cutscenes[which_cutscene].filename, true);
|
||||
auto rval = movie::play(name);
|
||||
main_hall_start_music();
|
||||
|
||||
if (!rval)
|
||||
{
|
||||
SCP_string str;
|
||||
char str[256];
|
||||
|
||||
if (Cmdline_nomovies)
|
||||
str = XSTR("Movies are currently disabled.", 1574);
|
||||
strcpy_s(str, XSTR("Movies are currently disabled.", 1574));
|
||||
else
|
||||
sprintf(str, XSTR("Unable to play movie %s.", 204), Cutscenes[which_cutscene].name);
|
||||
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str.c_str());
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cutscenes_screen_scroll_line_up()
|
||||
|
||||
+7
-18
@@ -30,7 +30,6 @@
|
||||
#include "io/key.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
#include "network/multi.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
|
||||
extern int Game_mode;
|
||||
extern int Is_standalone;
|
||||
@@ -273,22 +272,12 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
|
||||
namespace movie {
|
||||
// Play one movie
|
||||
bool play(const char* filename, bool via_tech_room = false)
|
||||
{
|
||||
if (scripting::hooks::OnMovieAboutToPlay->isActive())
|
||||
{
|
||||
auto paramList = scripting::hook_param_list(scripting::hook_param("Filename", 's', filename), scripting::hook_param("ViaTechRoom", 'b', via_tech_room));
|
||||
bool skip = scripting::hooks::OnMovieAboutToPlay->isOverride(paramList);
|
||||
scripting::hooks::OnMovieAboutToPlay->run(paramList);
|
||||
if (skip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool play(const char* name) {
|
||||
// mark the movie as viewable to the player when in a campaign
|
||||
// do this before anything else so that we're sure the movie is available
|
||||
// to the player even if it's not going to play right now
|
||||
if (Game_mode & GM_CAMPAIGN_MODE) {
|
||||
cutscene_mark_viewable(filename);
|
||||
cutscene_mark_viewable(name);
|
||||
}
|
||||
|
||||
if (Cmdline_nomovies || Is_standalone) {
|
||||
@@ -317,7 +306,7 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
// clear third buffer (may not be one, but that's ok)
|
||||
gr_clear();
|
||||
|
||||
auto player = cutscene::Player::newPlayer(filename);
|
||||
auto player = cutscene::Player::newPlayer(name);
|
||||
if (player) {
|
||||
PlaybackState state;
|
||||
initialize_player_state(player.get(), &state);
|
||||
@@ -327,7 +316,7 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
player->stopPlayback();
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", filename));
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
}
|
||||
|
||||
Movie_active = false;
|
||||
@@ -338,9 +327,9 @@ bool play(const char* filename, bool via_tech_room = false)
|
||||
return true;
|
||||
}
|
||||
|
||||
void play_two(const char* filename1, const char* filename2) {
|
||||
if (play(filename1)) {
|
||||
play(filename2);
|
||||
void play_two(const char* name1, const char* name2) {
|
||||
if (play(name1)) {
|
||||
play(name2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
namespace movie {
|
||||
|
||||
bool play(const char* filename, bool via_tech_room = false);
|
||||
bool play(const char* name);
|
||||
|
||||
void play_two(const char* filename1, const char* filename2);
|
||||
void play_two(const char* name1, const char* name2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
strcat_s(real_name, ".dds");
|
||||
|
||||
// open it up and go to the data section
|
||||
cfp = cfopen(real_name, "rb", cf_type);
|
||||
cfp = cfopen(real_name, "rb", CFILE_NORMAL, cf_type);
|
||||
|
||||
// just in case
|
||||
if (cfp == nullptr)
|
||||
@@ -558,7 +558,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
|
||||
strcat_s(real_filename, ".dds");
|
||||
}
|
||||
|
||||
CFILE *image = cfopen( real_filename, "wb", CF_TYPE_CACHE );
|
||||
CFILE *image = cfopen( real_filename, "wb", CFILE_NORMAL, CF_TYPE_CACHE );
|
||||
|
||||
if (image == NULL) {
|
||||
mprintf(("Unable to open DDS image for saving!!\n"));
|
||||
|
||||
+31
-49
@@ -22,8 +22,7 @@
|
||||
#include "object/objcollide.h"
|
||||
#include "object/objectsnd.h"
|
||||
#include "particle/particle.h"
|
||||
#include "particle/ParticleEffect.h"
|
||||
#include "particle/volumes/LegacyAACuboidVolume.h"
|
||||
#include "radar/radar.h"
|
||||
#include "radar/radarsetup.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
@@ -55,8 +54,6 @@ int Debris_model = -1;
|
||||
int Debris_vaporize_model = -1;
|
||||
int Debris_num_submodels = 0;
|
||||
|
||||
particle::ParticleEffectHandle Debris_hit_particle;
|
||||
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
|
||||
|
||||
|
||||
@@ -115,27 +112,6 @@ void debris_init()
|
||||
Debris.reserve(SOFT_LIMIT_DEBRIS_PIECES);
|
||||
|
||||
Num_hull_pieces = 0;
|
||||
|
||||
Debris_hit_particle = particle::ParticleManager::get()->addEffect(particle::ParticleEffect(
|
||||
"", //Name
|
||||
::util::UniformFloatRange(10.f), //Particle num
|
||||
particle::ParticleEffect::ShapeDirection::ALIGNED, //Particle direction
|
||||
::util::UniformFloatRange(1.f), //Velocity Inherit
|
||||
false, //Velocity Inherit absolute?
|
||||
make_unique<particle::LegacyAACuboidVolume>(0.3f, 1.f, true), //Velocity volume
|
||||
::util::UniformFloatRange(0.f, 10.f), //Velocity volume multiplier
|
||||
particle::ParticleEffect::VelocityScaling::NONE, //Velocity directional scaling
|
||||
std::nullopt, //Orientation-based velocity
|
||||
std::nullopt, //Position-based velocity
|
||||
nullptr, //Position volume
|
||||
particle::ParticleEffectHandle::invalid(), //Trail
|
||||
1.f, //Chance
|
||||
true, //Affected by detail
|
||||
1.f, //Culling range multiplier
|
||||
true, //Disregard Animation Length. Must be true for everything using particle::Anim_bitmap_X
|
||||
::util::UniformFloatRange(0.25f, 0.75f), //Lifetime
|
||||
::util::UniformFloatRange(0.2f, 0.4f), //Radius
|
||||
particle::Anim_bitmap_id_fire)); //Bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,14 +121,14 @@ void debris_page_in()
|
||||
{
|
||||
uint i;
|
||||
|
||||
Debris_model = model_load( NOX("debris01.pof") );
|
||||
Debris_model = model_load( NOX("debris01.pof"), 0, NULL );
|
||||
if (Debris_model >= 0) {
|
||||
polymodel * pm;
|
||||
pm = model_get(Debris_model);
|
||||
Debris_num_submodels = pm->n_models;
|
||||
}
|
||||
|
||||
Debris_vaporize_model = model_load( NOX("debris02.pof") );
|
||||
Debris_vaporize_model = model_load( NOX("debris02.pof"), 0, NULL );
|
||||
|
||||
for (i=0; i<Species_info.size(); i++ )
|
||||
{
|
||||
@@ -400,7 +376,7 @@ MONITOR(NumHullDebris)
|
||||
* @param exp_force Explosion force, used to assign velocity to pieces. 1.0f assigns velocity like before. 2.0f assigns twice as much to non-inherited part of velocity
|
||||
* @param source_subsys The subsystem this debris came from, if any
|
||||
*/
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, const vec3d *pos, const vec3d *exp_center, bool hull_flag, float exp_force, const ship_subsys* source_subsys)
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
int parent_objnum;
|
||||
object *obj;
|
||||
@@ -425,7 +401,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, const
|
||||
return obj;
|
||||
}
|
||||
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, const vec3d *pos, const matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx)
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx)
|
||||
{
|
||||
int objnum;
|
||||
object *obj;
|
||||
@@ -473,7 +449,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
// non-hull debris has no relation to its parent orientation
|
||||
vec3d rand;
|
||||
vm_vec_rand_vec(&rand);
|
||||
vm_vector_2_matrix_norm(&orient_buf, &rand);
|
||||
vm_vector_2_matrix(&orient_buf, &rand);
|
||||
orient = &orient_buf;
|
||||
}
|
||||
}
|
||||
@@ -634,11 +610,6 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
|
||||
db->model_instance_num = hull_flag ? model_create_instance(objnum, db->model_num) : -1;
|
||||
|
||||
// ensure that any texture replace on parent ship gets copied to debris --wookieejedi
|
||||
int parent_model_instance_num;
|
||||
if ((db->model_instance_num >= 0) && (parent_objnum >= 0) && ((parent_model_instance_num = object_get_model_instance_num(&Objects[parent_objnum])) >= 0))
|
||||
model_get_instance(db->model_instance_num)->texture_replace = model_get_instance(parent_model_instance_num)->texture_replace;
|
||||
|
||||
// assign the network signature. The signature will be 0 for non-hull pieces, but since that
|
||||
// is our invalid signature, it should be okay.
|
||||
obj->net_signature = 0;
|
||||
@@ -695,7 +666,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debris_create_set_velocity(const debris *db, const ship *source_shipp, const vec3d *exp_center, float exp_force, const ship_subsys* source_subsys)
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
auto obj = &Objects[db->objnum];
|
||||
auto source_obj = (source_shipp == nullptr) ? nullptr : &Objects[source_shipp->objnum];
|
||||
@@ -805,18 +776,30 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
|
||||
debris *debris_p = &Debris[debris_obj->instance];
|
||||
|
||||
// Do a little particle spark shower to show we hit
|
||||
if (Debris_hit_particle.isValid()){ // Where the particles emit from
|
||||
{
|
||||
particle::particle_emitter pe;
|
||||
|
||||
pe.pos = *hitpos; // Where the particles emit from
|
||||
pe.vel = debris_obj->phys_info.vel; // Initial velocity of all the particles
|
||||
|
||||
vec3d tmp_norm;
|
||||
vm_vec_sub( &tmp_norm, hitpos, &debris_obj->pos );
|
||||
vm_vec_normalize_safe(&tmp_norm);
|
||||
matrix orient;
|
||||
vm_vector_2_matrix_norm(&orient, &tmp_norm);
|
||||
|
||||
pe.normal = tmp_norm; // What normal the particle emit around
|
||||
pe.normal_variance = 0.3f; // How close they stick to that normal 0=good, 1=360 degree
|
||||
pe.min_rad = 0.20f; // Min radius
|
||||
pe.max_rad = 0.40f; // Max radius
|
||||
|
||||
auto source = particle::ParticleManager::get()->createSource(Debris_hit_particle);
|
||||
auto host = std::make_unique<EffectHostVector>(*hitpos, orient, debris_obj->phys_info.vel);
|
||||
host->setRadius(debris_obj->radius);
|
||||
source->setHost(std::move(host));
|
||||
source->finishCreation();
|
||||
// Sparks for first time at this spot
|
||||
pe.num_low = 10; // Lowest number of particles to create
|
||||
pe.num_high = 10; // Highest number of particles to create
|
||||
pe.normal_variance = 0.3f; // How close they stick to that normal 0=good, 1=360 degree
|
||||
pe.min_vel = 0.0f; // How fast the slowest particle can move
|
||||
pe.max_vel = 10.0f; // How fast the fastest particle can move
|
||||
pe.min_life = 0.25f; // How long the particles live
|
||||
pe.max_life = 0.75f; // How long the particles live
|
||||
particle::emit( &pe, particle::PARTICLE_FIRE, 0 );
|
||||
}
|
||||
|
||||
// multiplayer clients bail here
|
||||
@@ -1122,7 +1105,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
/**
|
||||
* Return the team field for a debris object
|
||||
*/
|
||||
int debris_get_team(const object *objp)
|
||||
int debris_get_team(object *objp)
|
||||
{
|
||||
Assert( objp->type == OBJ_DEBRIS );
|
||||
Assert( objp->instance >= 0 && objp->instance < (int)Debris.size() );
|
||||
@@ -1224,18 +1207,17 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
}
|
||||
}
|
||||
|
||||
bool debris_is_generic(const debris *db)
|
||||
bool debris_is_generic(debris *db)
|
||||
{
|
||||
return db->model_num == Debris_model;
|
||||
}
|
||||
|
||||
bool debris_is_vaporized(const debris *db)
|
||||
bool debris_is_vaporized(debris *db)
|
||||
{
|
||||
return db->model_num == Debris_vaporize_model;
|
||||
}
|
||||
|
||||
void create_generic_debris(object* ship_objp, const vec3d* pos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris)
|
||||
{
|
||||
void create_generic_debris(object* ship_objp, vec3d* pos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris) {
|
||||
Assertion(ship_objp->type == OBJ_SHIP, "create_generic_debris called for a non-ship, only ships can spew debris!");
|
||||
if (ship_objp->type != OBJ_SHIP)
|
||||
return;
|
||||
|
||||
@@ -71,29 +71,29 @@ void debris_delete( object * obj );
|
||||
void debris_process_post( object * obj, float frame_time);
|
||||
|
||||
// Create debris, set velocity, and fire scripting hook
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, const vec3d *pos, const vec3d *exp_center, bool hull_flag, float exp_force, const ship_subsys* source_subsys = nullptr);
|
||||
object *debris_create( object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, ship_subsys* source_subsys = nullptr );
|
||||
|
||||
// Create debris but don't do anything else
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, const vec3d *pos, const matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx);
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx);
|
||||
|
||||
// Set velocity after debris creation
|
||||
void debris_create_set_velocity(const debris *db, const ship *source_shipp, const vec3d *exp_center, float exp_force, const ship_subsys* source_subsys = nullptr);
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys = nullptr);
|
||||
|
||||
// Fire scripting hook after debris creation
|
||||
void debris_create_fire_hook(object *obj, object *source_obj);
|
||||
|
||||
int debris_check_collision( object * obj, object * other_obj, vec3d * hitpos, collision_info_struct *debris_hit_info=NULL, vec3d* hitnormal = NULL );
|
||||
void debris_hit( object * debris_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force );
|
||||
int debris_get_team(object *objp);
|
||||
|
||||
void debris_add_to_hull_list(debris *db);
|
||||
void debris_remove_from_hull_list(debris *db);
|
||||
|
||||
int debris_get_team(const object *objp);
|
||||
bool debris_is_generic(const debris *db);
|
||||
bool debris_is_vaporized(const debris *db);
|
||||
bool debris_is_generic(debris *db);
|
||||
bool debris_is_vaporized(debris *db);
|
||||
|
||||
// creates a burst of generic debris at hitpos from ship_objp, with a random number between min and max
|
||||
// use_ship_debris is for whether the ship's generic debris should be used, or simply debris01.pof
|
||||
void create_generic_debris(object* ship_objp, const vec3d* hitpos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris);
|
||||
void create_generic_debris(object* ship_objp, vec3d* hitpos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris);
|
||||
|
||||
#endif // _DEBRIS_H
|
||||
+24
-2
@@ -26,6 +26,28 @@ DecalDefinition::~DecalDefinition() {
|
||||
}
|
||||
}
|
||||
|
||||
DecalDefinition::DecalDefinition(DecalDefinition&& other) noexcept {
|
||||
*this = std::move(other); // Use operator implementation
|
||||
}
|
||||
|
||||
DecalDefinition& DecalDefinition::operator=(DecalDefinition&& other) noexcept {
|
||||
std::swap(_name, other._name);
|
||||
|
||||
std::swap(_diffuseFilename, other._diffuseFilename);
|
||||
std::swap(_glowFilename, other._glowFilename);
|
||||
std::swap(_normalMapFilename, other._normalMapFilename);
|
||||
|
||||
std::swap(_diffuseBitmap, other._diffuseBitmap);
|
||||
std::swap(_glowBitmap, other._glowBitmap);
|
||||
std::swap(_normalBitmap, other._normalBitmap);
|
||||
|
||||
std::swap(_loopDiffuse, other._loopDiffuse);
|
||||
std::swap(_loopGlow, other._loopGlow);
|
||||
std::swap(_loopNormal, other._loopNormal);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DecalDefinition::parse() {
|
||||
if (optional_string("+Diffuse:")) {
|
||||
stuff_string(_diffuseFilename, F_FILESPEC);
|
||||
@@ -224,7 +246,7 @@ struct Decal {
|
||||
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,
|
||||
Assertion(submodel >= 0 && submodel < model_get(object_get_model(objp))->n_models,
|
||||
"Invalid submodel number detected!");
|
||||
auto smi = &model_instance->submodel[submodel];
|
||||
|
||||
@@ -479,7 +501,7 @@ void renderAll() {
|
||||
draw_list.render();
|
||||
}
|
||||
|
||||
void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
|
||||
void addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ class DecalDefinition {
|
||||
DecalDefinition& operator=(const DecalDefinition&) = delete;
|
||||
|
||||
// Move constructor and operator
|
||||
DecalDefinition(DecalDefinition&& other) noexcept = default;
|
||||
DecalDefinition& operator=(DecalDefinition&& other) noexcept = default;
|
||||
DecalDefinition(DecalDefinition&& other) noexcept;
|
||||
DecalDefinition& operator=(DecalDefinition&& other) noexcept;
|
||||
|
||||
void parse();
|
||||
void loadBitmaps();
|
||||
@@ -134,7 +134,7 @@ void renderAll();
|
||||
* orientation should look along the direction
|
||||
*/
|
||||
void addDecal(creation_info& info,
|
||||
const object* host,
|
||||
object* host,
|
||||
int submodel,
|
||||
const vec3d& local_pos,
|
||||
const matrix& local_orient);
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
-- A version of include for lua. Originally written by Nuke
|
||||
|
||||
local chunck_cache = {}
|
||||
--- function to load and run lua files
|
||||
-- takes string filename and boolean cacheonly
|
||||
-- cfile will try to find filename in all accesible locations and load it only if it hasnt done so already
|
||||
-- if cacheonly flag is set, code will be cached but not executed, good for inits. however it is ignored when calling an already cached chunk.
|
||||
-- returns true on success or nil on failure to find/load file
|
||||
local function execute_lua_file(filename, cacheonly)
|
||||
--dont reload chunks from file if they have already been loaded. because faster == better
|
||||
if (type(chunck_cache[filename]) == "table" and type(chunck_cache[filename][1]) == "function") then
|
||||
if (not chunck_cache[filename][2] and not chunck_cache[filename][3]) then
|
||||
chunck_cache[filename][2] = true
|
||||
local val, err = pcall(chunck_cache[filename][1])
|
||||
if (err) then
|
||||
-- Add an boolean to indicate that this function has caused an error
|
||||
chunck_cache[filename][3] = true
|
||||
|
||||
return false, string.format("Error while executing external lua file %q:\n%s", filename, err)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
if (cf.fileExists(filename, "", true)) then
|
||||
--open the file
|
||||
local file = cf.openFile(filename, "r", "")
|
||||
local fstring = file:read("*a") --load it all into a string
|
||||
file:close()
|
||||
if (fstring and type(fstring) == "string") then
|
||||
--use the string as a code chunk and convert it to function
|
||||
local func, error = loadstring(fstring, filename)
|
||||
if (not func) then -- Compile error
|
||||
return false, string.format("Error while processing file %q. Errormessage:\n%s", filename, error)
|
||||
end
|
||||
chunck_cache[filename] = {}
|
||||
chunck_cache[filename][1] = func
|
||||
chunck_cache[filename][2] = false
|
||||
--maybe execute
|
||||
if (not cacheonly) then
|
||||
chunck_cache[filename][2] = true
|
||||
local val, err = xpcall(chunck_cache[filename][1], function(err)
|
||||
-- Add an boolean to indicate that this function has caused an error
|
||||
chunck_cache[filename][3] = true
|
||||
|
||||
return string.format("Error while executing external lua file %q:\n%s\n\n%s", filename, err, debug.traceback())
|
||||
end)
|
||||
|
||||
if (err) then
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
else
|
||||
return false, string.format("Couldn't find external lua file %q!", filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function include(fileName)
|
||||
if (fileName == nil) then
|
||||
stackErrorf("Invalid argument for 'include'!")
|
||||
else
|
||||
if (not fileName:ends(".lua")) then
|
||||
fileName = fileName .. ".lua"
|
||||
end
|
||||
|
||||
local succ, err = execute_lua_file(fileName)
|
||||
|
||||
if (not succ and err) then
|
||||
error(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,86 +0,0 @@
|
||||
-- Basic forwarders for common Lua methods
|
||||
function error(str)
|
||||
ba.error(str)
|
||||
end
|
||||
|
||||
function warning(str)
|
||||
ba.warning(str)
|
||||
end
|
||||
|
||||
function print(str)
|
||||
ba.print(str)
|
||||
end
|
||||
|
||||
function println(str)
|
||||
if (str) then
|
||||
ba.print(str)
|
||||
end
|
||||
ba.print("\n")
|
||||
end
|
||||
|
||||
function stackError(str, level)
|
||||
if (level == nil) then
|
||||
level = 2
|
||||
else
|
||||
level = level + 1
|
||||
end
|
||||
|
||||
error(debug.traceback(tostring(str) .. "\n", level) .. "\n")
|
||||
end
|
||||
|
||||
function warningf(str, ...)
|
||||
warning(string.format(str, ...))
|
||||
end
|
||||
|
||||
function errorf(str, ...)
|
||||
error(string.format(str, ...))
|
||||
end
|
||||
|
||||
function printf(str, ...)
|
||||
print(string.format(str, ...))
|
||||
end
|
||||
|
||||
function stackErrorf(str, ...)
|
||||
stackError(string.format(str, ...), 2)
|
||||
end
|
||||
|
||||
function string.starts(str, start)
|
||||
return string.sub(str, 1, string.len(start)) == start
|
||||
end
|
||||
|
||||
function string.ends(str, e)
|
||||
return (e == '') or (string.sub(str, -string.len(e)) == e)
|
||||
end
|
||||
|
||||
|
||||
-- Global table that can hold variables that should not be able to be changed
|
||||
Globals = {}
|
||||
Globals.values = {}
|
||||
|
||||
local mt = {}
|
||||
|
||||
function mt.__newindex(t, index, value)
|
||||
if (index == "values") then
|
||||
stackErrorf("Cannot set value to index %q. Index is forbidden!", tostring(index))
|
||||
elseif (rawget(t.values, index) ~= nil) then
|
||||
stackErrorf("Cannot set value to index %q. Index already used!", tostring(index))
|
||||
else
|
||||
rawset(t.values, index, value)
|
||||
end
|
||||
end
|
||||
|
||||
function mt.__index(t, index)
|
||||
if (index == "values") then
|
||||
stackErrorf("Trying to access forbidden value %q!", index)
|
||||
else
|
||||
return rawget(t.values, index)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(Globals, mt)
|
||||
|
||||
|
||||
-- Initial Values
|
||||
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))
|
||||
@@ -8,9 +8,9 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Sentry Gun
|
||||
@@ -28,10 +28,10 @@ $Fog:
|
||||
$AI:
|
||||
+Accept Player Orders: NO
|
||||
+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" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Escape Pod
|
||||
@@ -48,9 +48,9 @@ $Fog:
|
||||
+Compl dist: 600.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "attack wing" "dock" "waypoints" "waypoints once" "depart" "undock" "stay still" "play dead" "play dead (persistent)" "stay near ship" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
@@ -87,11 +87,11 @@ $AI:
|
||||
+Accept Player Orders: YES
|
||||
+Player orders: ( "rearm me" "abort rearm" "depart" )
|
||||
+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" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Active docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Fighter
|
||||
@@ -114,12 +114,12 @@ $AI:
|
||||
+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" "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" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Bomber
|
||||
@@ -142,12 +142,40 @@ $AI:
|
||||
+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" "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" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
$Name: Fighter/bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
$Target as Threat: YES
|
||||
$Show Attack Direction: YES
|
||||
$Warp Pushable: YES
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 4.0
|
||||
$Protected on cripple: YES
|
||||
$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" "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" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Transport
|
||||
@@ -176,7 +204,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -208,7 +236,7 @@ $AI:
|
||||
+Can Form Wing: YES
|
||||
+Active docks: ( "cargo" )
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -238,7 +266,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -268,7 +296,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -298,7 +326,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -328,7 +356,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -358,7 +386,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -386,7 +414,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -412,7 +440,7 @@ $AI:
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -436,7 +464,7 @@ $AI:
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+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" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
|
||||
@@ -291,6 +291,17 @@ static const char *GetExceptionDescription(DWORD ExceptionCode)
|
||||
return "Unknown exception type";
|
||||
}
|
||||
|
||||
static char* GetFilePart(char *source)
|
||||
{
|
||||
char *result = strrchr(source, '\\');
|
||||
if (result) {
|
||||
result++;
|
||||
} else {
|
||||
result = source;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------
|
||||
//
|
||||
// External Functions
|
||||
@@ -327,7 +338,7 @@ int __cdecl RecordExceptionInfo(PEXCEPTION_POINTERS data, const char *Message)
|
||||
ModuleName[0] = 0;
|
||||
}
|
||||
|
||||
char *FilePart = util::get_file_part(ModuleName);
|
||||
char *FilePart = GetFilePart(ModuleName);
|
||||
|
||||
// Extract the file name portion and remove it's file extension. We'll
|
||||
// use that name shortly.
|
||||
@@ -360,7 +371,7 @@ int __cdecl RecordExceptionInfo(PEXCEPTION_POINTERS data, const char *Message)
|
||||
// code address, which is the same as the ModuleHandle. This can be used
|
||||
// to get the filename of the module that the crash happened in.
|
||||
if (VirtualQuery((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) && GetModuleFileName((HINSTANCE)MemInfo.AllocationBase, CrashModulePathName, sizeof(CrashModulePathName)) > 0) {
|
||||
CrashModuleFileName = util::get_file_part(CrashModulePathName);
|
||||
CrashModuleFileName = GetFilePart(CrashModulePathName);
|
||||
}
|
||||
|
||||
// Print out the beginning of the error log in a Win95 error window
|
||||
|
||||
+27
-208
@@ -42,10 +42,17 @@ SCP_vector<fireball_info> Fireball_info;
|
||||
bool fireballs_inited = false;
|
||||
bool fireballs_parsed = false;
|
||||
|
||||
static float exp_to_line(float t, float start_value, float end_slope, float scale)
|
||||
{
|
||||
return -scale * expf(-start_value / scale * t) + end_slope * t + scale;
|
||||
}
|
||||
bool Fireball_use_3d_warp = false;
|
||||
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp",
|
||||
std::pair<const char*, int>{"3D Warp", 1770},
|
||||
std::pair<const char*, int>{"Use a 3D model for warp effects", 1771})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
/**
|
||||
* Play warp in sound for warp effect
|
||||
@@ -199,6 +206,9 @@ static void fireball_set_default_warp_attributes(int idx)
|
||||
strcpy_s(Fireball_info[idx].warp_ball, "warpball01");
|
||||
strcpy_s(Fireball_info[idx].warp_model, "warp.pof");
|
||||
|
||||
if (Fireball_use_3d_warp)
|
||||
Fireball_info[idx].use_3d_warp = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -351,17 +361,9 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
stuff_string(fi->warp_glow, F_NAME, NAME_LENGTH);
|
||||
|
||||
// check for custom warp ball
|
||||
if (optional_string("$Warp ball:")) {
|
||||
if (optional_string("$Warp ball:"))
|
||||
stuff_string(fi->warp_ball, F_NAME, NAME_LENGTH);
|
||||
|
||||
// if we are explicitly specifying a ball, then we'll want to use it,
|
||||
// rather than just having the default ball that might or might not be used
|
||||
fi->warp_flash = true;
|
||||
}
|
||||
|
||||
if (optional_string("$Force warp flash:"))
|
||||
stuff_boolean(&fi->warp_flash);
|
||||
|
||||
// check for custom warp model
|
||||
if (optional_string("$Warp model:"))
|
||||
{
|
||||
@@ -371,114 +373,6 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
// rather than just having the default model that might or might not be used
|
||||
fi->use_3d_warp = true;
|
||||
}
|
||||
|
||||
if (optional_string("$Force 3D Warp:")) {
|
||||
stuff_boolean(&fi->use_3d_warp);
|
||||
}
|
||||
|
||||
if (optional_string("$Warp size ratio:")) {
|
||||
stuff_float(&fi->warp_size_ratio);
|
||||
} else if (first_time) {
|
||||
if (fi->use_3d_warp) {
|
||||
fi->warp_size_ratio = 1 / 25.0f;
|
||||
} else {
|
||||
fi->warp_size_ratio = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$Flare size ratio:")) {
|
||||
stuff_float(&fi->flare_size_ratio);
|
||||
} else if (first_time) {
|
||||
fi->flare_size_ratio = 1.0f;
|
||||
}
|
||||
|
||||
if (optional_string("$Flicker magnitude:")) {
|
||||
stuff_float(&fi->flicker_magnitude);
|
||||
} else if (first_time) {
|
||||
fi->flicker_magnitude = 0.10f;
|
||||
}
|
||||
|
||||
if (optional_string("$Warp flare style:")) {
|
||||
switch (optional_string_one_of(3, "classic", "enhanced", "cinematic")) {
|
||||
case 0:
|
||||
fi->warp_flare_style = warp_style::CLASSIC;
|
||||
break;
|
||||
case 1:
|
||||
fi->warp_flare_style = warp_style::ENHANCED;
|
||||
break;
|
||||
case 2:
|
||||
fi->warp_flare_style = warp_style::CINEMATIC;
|
||||
break;
|
||||
default:
|
||||
error_display(0, "Invalid warp flare style. Must be classic, enhanced, or cinematic.");
|
||||
}
|
||||
|
||||
// Set warp flare option
|
||||
if (optional_string("+Flare size ratio:")) {
|
||||
stuff_float(&fi->flare_size_ratio);
|
||||
} else if (fi->warp_flare_style == warp_style::CLASSIC) {
|
||||
fi->flare_size_ratio = 1.0f;
|
||||
} else if (fi->warp_flare_style == warp_style::CINEMATIC) {
|
||||
fi->flare_size_ratio = 5.3f;
|
||||
}
|
||||
|
||||
} else if (first_time) {
|
||||
fi->warp_flare_style = warp_style::CLASSIC;
|
||||
}
|
||||
|
||||
if (optional_string("$Warp model style:")) {
|
||||
switch (optional_string_one_of(2, "classic", "cinematic")) {
|
||||
case 0:
|
||||
fi->warp_model_style = warp_style::CLASSIC;
|
||||
break;
|
||||
case 1:
|
||||
fi->warp_model_style = warp_style::CINEMATIC;
|
||||
break;
|
||||
default:
|
||||
error_display(0, "Invalid warp model style. Must be classic or cinematic.");
|
||||
}
|
||||
} else if (first_time) {
|
||||
fi->warp_model_style = warp_style::CLASSIC;
|
||||
}
|
||||
|
||||
// Set warp_model_style options if cinematic style is chosen
|
||||
if (fi->warp_model_style == warp_style::CINEMATIC) {
|
||||
if (optional_string("+Warp size ratio:")) {
|
||||
stuff_float(&fi->warp_size_ratio);
|
||||
} else {
|
||||
fi->warp_size_ratio = 1.6f;
|
||||
}
|
||||
|
||||
// The first two values need to be implied multiples of PI
|
||||
// for convenience. These shouldn't need to be faster than a full
|
||||
// rotation per second, which is already ridiculous.
|
||||
if (optional_string("+Rotation anim:")) {
|
||||
stuff_float_list(fi->rot_anim, 3);
|
||||
|
||||
CLAMP(fi->rot_anim[0], 0.0f, 2.0f);
|
||||
CLAMP(fi->rot_anim[1], 0.0f, 2.0f);
|
||||
fi->rot_anim[2] = MAX(0.0f, fi->rot_anim[2]);
|
||||
} else {
|
||||
// PI / 2.75f, PI / 10.0f, 2.0f
|
||||
fi->rot_anim[0] = 0.365f;
|
||||
fi->rot_anim[1] = 0.083f;
|
||||
fi->rot_anim[2] = 2.0f;
|
||||
}
|
||||
|
||||
// Variable frame rate for faster propagation of ripples
|
||||
if (optional_string("+Frame anim:")) {
|
||||
stuff_float_list(fi->frame_anim, 3);
|
||||
|
||||
// A frame rate that is 4 times the normal speed is ridiculous
|
||||
CLAMP(fi->frame_anim[0], 0.0f, 4.0f);
|
||||
CLAMP(fi->frame_anim[1], 1.0f, 4.0f);
|
||||
fi->frame_anim[2] = MAX(0.0f, fi->frame_anim[2]);
|
||||
} else {
|
||||
fi->frame_anim[0] = 1.0f;
|
||||
fi->frame_anim[1] = 1.0f;
|
||||
fi->frame_anim[2] = 3.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required_string("#End");
|
||||
@@ -645,13 +539,7 @@ void fireball_set_framenum(int num)
|
||||
}
|
||||
|
||||
if ( fb->fireball_render_type == FIREBALL_WARP_EFFECT ) {
|
||||
float new_time = fb->time_elapsed;
|
||||
if (fd->warp_model_style == warp_style::CINEMATIC) {
|
||||
float duration_ratio = 2.0f / fb->warp_open_duration;
|
||||
new_time = exp_to_line(fb->time_elapsed, fd->frame_anim[0] * duration_ratio, fd->frame_anim[1], fd->frame_anim[2] * duration_ratio);
|
||||
}
|
||||
|
||||
framenum = bm_get_anim_frame(fl->bitmap_id, new_time, 0.0f, true);
|
||||
framenum = bm_get_anim_frame(fl->bitmap_id, fb->time_elapsed, 0.0f, true);
|
||||
|
||||
if ( fb->orient ) {
|
||||
// warp out effect plays backwards
|
||||
@@ -1076,7 +964,7 @@ void fireballs_page_in()
|
||||
// load the warp model, if we have one
|
||||
if (strlen(fd->warp_model) > 0 && cf_exists_full(fd->warp_model, CF_TYPE_MODELS)) {
|
||||
mprintf(("Loading warp model '%s'\n", fd->warp_model));
|
||||
fd->warp_model_id = model_load(fd->warp_model, nullptr, ErrorType::WARNING);
|
||||
fd->warp_model_id = model_load(fd->warp_model, 0, nullptr, 0);
|
||||
} else {
|
||||
fd->warp_model_id = -1;
|
||||
}
|
||||
@@ -1142,48 +1030,22 @@ int fireball_asteroid_explosion_type(asteroid_info *aip)
|
||||
return index;
|
||||
}
|
||||
|
||||
static float cutscene_wormhole(float t) {
|
||||
float a = 25.0f * powf(t, 4.0f);
|
||||
return a / (a + 1.0f);
|
||||
}
|
||||
|
||||
float fireball_wormhole_intensity(fireball *fb)
|
||||
{
|
||||
float t = fb->time_elapsed;
|
||||
float rad;
|
||||
|
||||
float rad = cutscene_wormhole(t / fb->warp_open_duration);
|
||||
|
||||
fireball_info* fi = &Fireball_info[fb->fireball_info_index];
|
||||
|
||||
if (fi->warp_model_style == warp_style::CINEMATIC) {
|
||||
rad *= cutscene_wormhole((fb->total_time - t) / fb->warp_close_duration);
|
||||
rad /= cutscene_wormhole(fb->total_time / (2.0f * fb->warp_open_duration));
|
||||
rad /= cutscene_wormhole(fb->total_time / (2.0f * fb->warp_close_duration));
|
||||
if ( t < fb->warp_open_duration ) {
|
||||
rad = (float)pow(t / fb->warp_open_duration, 0.4f);
|
||||
} else if ( t < fb->total_time - fb->warp_close_duration ) {
|
||||
rad = 1.0f;
|
||||
} else {
|
||||
if (t < fb->warp_open_duration) {
|
||||
rad = (float)pow(t / fb->warp_open_duration, 0.4f);
|
||||
} else if (t < fb->total_time - fb->warp_close_duration) {
|
||||
rad = 1.0f;
|
||||
} else {
|
||||
rad = (float)pow((fb->total_time - t) / fb->warp_close_duration, 0.4f);
|
||||
}
|
||||
rad = (float)pow((fb->total_time - t) / fb->warp_close_duration, 0.4f);
|
||||
}
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
static float fireball_wormhole_flare_radius(fireball* fb) {
|
||||
float t = fb->time_elapsed;
|
||||
float d1 = fb->warp_open_duration;
|
||||
float d2 = fb->warp_close_duration;
|
||||
|
||||
float rad = 2 * (1.0f - exp(-4.0f * powf(1.7f * t/d1, 3.0f))) - (1.0f - exp(-2.0f * powf(1.7f * t/d1, 3.0f)));
|
||||
rad *= (1.0f - exp(-2.0f * (fb->total_time - t) / d2));
|
||||
|
||||
return rad;
|
||||
}
|
||||
|
||||
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float flare_rad, float flicker_magnitude, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id, bool warp_flash);
|
||||
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id);
|
||||
|
||||
void fireball_render(object* obj, model_draw_list *scene)
|
||||
{
|
||||
@@ -1225,54 +1087,11 @@ void fireball_render(object* obj, model_draw_list *scene)
|
||||
break;
|
||||
|
||||
case FIREBALL_WARP_EFFECT: {
|
||||
fireball_info* fi = &Fireball_info[fb->fireball_info_index];
|
||||
float percent_life = fb->time_elapsed / fb->total_time;
|
||||
float rad = obj->radius * fireball_wormhole_intensity(fb) * fi->warp_size_ratio;
|
||||
float rad = obj->radius * fireball_wormhole_intensity(fb);
|
||||
|
||||
float flare_rad = obj->radius * fi->flare_size_ratio;
|
||||
|
||||
matrix* warp_orientation;
|
||||
matrix dest = ZERO_MATRIX;
|
||||
|
||||
// Flare animation selection
|
||||
if (fi->warp_flare_style == warp_style::ENHANCED) {
|
||||
flare_rad += powf((2.0f * percent_life) - 1.0f, 24.0f) * obj->radius * 1.5f * fi->flare_size_ratio;
|
||||
} else if (fi->warp_flare_style == warp_style::CINEMATIC) {
|
||||
flare_rad *= fireball_wormhole_flare_radius(fb);
|
||||
} else {
|
||||
flare_rad *= fireball_wormhole_intensity(fb);
|
||||
}
|
||||
|
||||
if (fi->warp_model_style == warp_style::CINEMATIC) {
|
||||
matrix m = ZERO_MATRIX;
|
||||
|
||||
float duration_ratio = 2.0f / fb->warp_open_duration;
|
||||
|
||||
float angle = exp_to_line(fb->time_elapsed, PI * fi->rot_anim[0] * duration_ratio,
|
||||
PI * fi->rot_anim[1],
|
||||
fi->rot_anim[2] * duration_ratio);
|
||||
|
||||
matrix* bank_angle = vm_angle_2_matrix(&m, angle, 1);
|
||||
warp_orientation = vm_matrix_x_matrix(&dest, &obj->orient, bank_angle);
|
||||
} else {
|
||||
warp_orientation = &obj->orient;
|
||||
}
|
||||
|
||||
warpin_queue_render(scene,
|
||||
obj,
|
||||
warp_orientation,
|
||||
&obj->pos,
|
||||
fb->current_bitmap,
|
||||
rad,
|
||||
percent_life,
|
||||
flare_rad,
|
||||
fi->flicker_magnitude,
|
||||
obj->radius,
|
||||
fi->use_3d_warp || (fb->flags & FBF_WARP_3D) != 0,
|
||||
fi->warp_glow_bitmap,
|
||||
fi->warp_ball_bitmap,
|
||||
fi->warp_model_id,
|
||||
fi->warp_flash);
|
||||
fireball_info *fi = &Fireball_info[fb->fireball_info_index];
|
||||
warpin_queue_render(scene, obj, &obj->orient, &obj->pos, fb->current_bitmap, rad, percent_life, obj->radius, fi->use_3d_warp || (fb->flags & FBF_WARP_3D) != 0, fi->warp_glow_bitmap, fi->warp_ball_bitmap, fi->warp_model_id);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -39,14 +39,6 @@ class asteroid_info;
|
||||
|
||||
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
|
||||
|
||||
// Gamma39er: Flare animation enum. Add new animation types here.
|
||||
enum class warp_style
|
||||
{
|
||||
CLASSIC,
|
||||
ENHANCED,
|
||||
CINEMATIC
|
||||
};
|
||||
|
||||
// all this moved here by Goober5000 because it makes more sense in the H file
|
||||
typedef struct fireball_lod {
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
@@ -62,21 +54,8 @@ typedef struct fireball_info {
|
||||
float exp_color[3]; // red, green, blue
|
||||
|
||||
bool use_3d_warp;
|
||||
bool warp_flash;
|
||||
bool fireball_used;
|
||||
|
||||
warp_style warp_flare_style;
|
||||
warp_style warp_model_style;
|
||||
|
||||
// Customize how large the warp and it's flare are.
|
||||
float warp_size_ratio;
|
||||
float flare_size_ratio;
|
||||
float flicker_magnitude;
|
||||
|
||||
// Cinematic Warp stuff
|
||||
float rot_anim[3];
|
||||
float frame_anim[3];
|
||||
|
||||
char warp_glow[NAME_LENGTH];
|
||||
int warp_glow_bitmap;
|
||||
char warp_ball[NAME_LENGTH];
|
||||
@@ -164,6 +143,10 @@ float fireball_wormhole_intensity( fireball *fb );
|
||||
// Goober5000
|
||||
extern bool Knossos_warp_ani_used;
|
||||
|
||||
extern bool Fireball_use_3d_warp;
|
||||
|
||||
extern bool Fireball_warp_flash;
|
||||
|
||||
// Cyborg - get a count of how many valid fireballs are in the mission.
|
||||
int fireball_get_count();
|
||||
|
||||
|
||||
@@ -22,6 +22,18 @@
|
||||
#include "render/batching.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash",
|
||||
std::pair<const char*, int>{"Warp Flash", 1768},
|
||||
std::pair<const char*, int>{"Show flash upon warp open or close", 1769})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
{
|
||||
vec3d norm;
|
||||
@@ -42,7 +54,7 @@ void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
batching_add_tri(texture, vertlist); // TODO render as emissive
|
||||
}
|
||||
|
||||
void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float flare_rad, float flicker_magnitude, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id, bool warp_flash)
|
||||
void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id)
|
||||
{
|
||||
vec3d center;
|
||||
vec3d vecs[5];
|
||||
@@ -56,12 +68,17 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
verts[1] = verts[2] = verts[3] = verts[4] = verts[0];
|
||||
|
||||
if (warp_glow_bitmap >= 0) {
|
||||
float r = flare_rad;
|
||||
|
||||
float r = radius;
|
||||
// Add in noise
|
||||
int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES;
|
||||
|
||||
r *= (0.40f + Noise[noise_frame] * flicker_magnitude);
|
||||
r *= (0.40f + Noise[noise_frame] * 0.30f);
|
||||
|
||||
// Bobboau's warp thingie, toggled by cmdline
|
||||
if (Fireball_warp_flash) {
|
||||
r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f;
|
||||
}
|
||||
|
||||
vecs[4] = center;
|
||||
verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f;
|
||||
@@ -78,7 +95,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
if ( (warp_model_id >= 0) && (warp_3d) ) {
|
||||
model_render_params render_info;
|
||||
|
||||
float scale = radius;
|
||||
float scale = radius / 25.0f;
|
||||
|
||||
vec3d warp_scale;
|
||||
|
||||
@@ -142,7 +159,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
warpin_batch_draw_face( texture_bitmap_num, &verts[0], &verts[3], &verts[4] );
|
||||
}
|
||||
|
||||
if (warp_ball_bitmap >= 0 && warp_flash) {
|
||||
if (warp_ball_bitmap >= 0 && Fireball_warp_flash) {
|
||||
flash_ball warp_ball(20, .1f,.25f, &orient->vec.fvec, pos, 4.0f, 0.5f);
|
||||
|
||||
float adg = (2.0f * life_percent) - 1.0f;
|
||||
|
||||
@@ -499,7 +499,7 @@ void help_overlay_blit(int overlay_id, int resolution_index)
|
||||
font::set_font(help_overlaylist[overlay_id].fontlist.at(resolution_index));
|
||||
for (idx = 0; idx < textcount; idx++) {
|
||||
gr_set_color_fast(&Color_black);
|
||||
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, 1.0f, strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
|
||||
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
|
||||
gr_rect(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord-2*HELP_PADDING, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord-3*HELP_PADDING, width+4*HELP_PADDING, height+4*HELP_PADDING, GR_RESIZE_MENU);
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
gr_printf_menu(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord,
|
||||
|
||||
@@ -130,11 +130,6 @@ void gameplay_help_init_control_line(int id, gameplay_help_section &thisHelp)
|
||||
|
||||
auto ci = &Control_config[id];
|
||||
|
||||
// do not draw if a mod has disabled this control --wookieejedi
|
||||
if (ci->disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf[0] = 0;
|
||||
|
||||
strcpy_s(buf, ci->first.textify().c_str());
|
||||
|
||||
@@ -45,24 +45,15 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void parse_music_volume_func()
|
||||
{
|
||||
float volume;
|
||||
stuff_float(&volume);
|
||||
CLAMP(volume, 0.0f, 1.0f);
|
||||
Default_music_volume = volume;
|
||||
}
|
||||
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music",
|
||||
std::pair<const char*, int>{"Music", 1371},
|
||||
std::pair<const char*, int>{"Volume used for playing music", 1760})
|
||||
.category(std::make_pair("Audio", 1826))
|
||||
.default_func([]() { return Default_music_volume;})
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_music_volume_func)
|
||||
.finish();
|
||||
|
||||
typedef struct tagSNDPATTERN {
|
||||
@@ -343,30 +334,16 @@ void event_music_init()
|
||||
// (since event music specifies samples and measures, the audio format is important; so we don't want to assume any format will work)
|
||||
if (!cf_exists_full(filename, CF_TYPE_MUSIC))
|
||||
{
|
||||
static SCP_unordered_map<SCP_string, SCP_string, SCP_string_lcase_hash, SCP_string_lcase_equal_to> filename_substitutions;
|
||||
CFileLocationExt res;
|
||||
|
||||
// see if we ran into this file already (case-insensitive)
|
||||
auto pair = filename_substitutions.find(filename);
|
||||
if (pair != filename_substitutions.end())
|
||||
{
|
||||
// don't warn, since we warned for this file name when we added it to the map
|
||||
strcpy_s(soundtrack.patterns[i].fname, pair->second.c_str());
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
// see if the file exists with a different extension
|
||||
else if (res = cf_find_file_location_ext(filename, NUM_AUDIO_EXT, audio_ext_list, CF_TYPE_MUSIC), res.found)
|
||||
{
|
||||
auto res = cf_find_file_location_ext(filename, NUM_AUDIO_EXT, audio_ext_list, CF_TYPE_MUSIC);
|
||||
if (res.found)
|
||||
Warning(LOCATION, "Soundtrack file %s was not found with its specified extension, but another file %s exists in the modpack. Please update the extension and adjust audio specifications if necessary.", filename, res.name_ext.c_str());
|
||||
filename_substitutions.emplace(filename, res.name_ext);
|
||||
strcpy_s(soundtrack.patterns[i].fname, res.name_ext.c_str());
|
||||
}
|
||||
// file does not exist
|
||||
else
|
||||
{
|
||||
Warning(LOCATION, "Soundtrack file %s was not found. The soundtrack '%s' will not be used.", filename, soundtrack.name);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
Warning(LOCATION, "Soundtrack file %s was not found. The soundtrack '%s' will not be used.", filename, soundtrack.name);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -462,10 +462,9 @@ gamesnd_id parse_game_sound_inline()
|
||||
* @param tag Tag
|
||||
* @param idx_dest Sound index destination
|
||||
* @param flags See the parse_sound_flags enum
|
||||
* @return whether the tag was found and a parse was attempted
|
||||
*
|
||||
*/
|
||||
bool parse_iface_sound(const char* tag, interface_snd_id* idx_dest)
|
||||
{
|
||||
void parse_iface_sound(const char* tag, interface_snd_id* idx_dest) {
|
||||
Assert( Snds_iface.size() == Snds_iface_handle.size() );
|
||||
|
||||
if(optional_string(tag))
|
||||
@@ -479,11 +478,7 @@ bool parse_iface_sound(const char* tag, interface_snd_id* idx_dest)
|
||||
if (!idx_dest->isValid() && buf != "-1") {
|
||||
error_display(0, "Could not find interface sound with name '%s'!", buf.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,9 +491,9 @@ bool parse_iface_sound(const char* tag, interface_snd_id* idx_dest)
|
||||
* @param tag Tag
|
||||
* @param object_name Name of object being parsed
|
||||
* @param flags See the parse_sound_flags enum
|
||||
* @return whether the tag was found and a parse was attempted
|
||||
*
|
||||
*/
|
||||
bool parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& destination, const char* object_name, bool scp_list)
|
||||
void parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& destination, const char* object_name, bool scp_list)
|
||||
{
|
||||
if(optional_string(tag))
|
||||
{
|
||||
@@ -534,11 +529,7 @@ bool parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& desti
|
||||
{
|
||||
mprintf(("%s in '%s' has " SIZE_T_ARG " entries. This does not match entered size of %i.\n", tag, object_name, destination.size(), check));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1367,7 +1358,7 @@ void parse_sound_table(const char* filename)
|
||||
|
||||
// retail sounds with numeric names must match their indexes
|
||||
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
|
||||
error_display(0, "Retail-style game sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
tempIndex = gamesnd_find_nonreserved_last_index(Snds, gamesnd_is_reserved_game_index);
|
||||
@@ -1397,7 +1388,7 @@ void parse_sound_table(const char* filename)
|
||||
|
||||
// retail sounds with numeric names must match their indexes
|
||||
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
|
||||
error_display(0, "Retail-style interface sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
tempIndex = gamesnd_find_nonreserved_last_index(Snds_iface, gamesnd_is_reserved_interface_index);
|
||||
|
||||
@@ -262,7 +262,7 @@ enum class InterfaceSounds {
|
||||
GENERAL_FAIL =10,//!< general failure sound for any event
|
||||
SHIP_ICON_CHANGE =11,//!< ship animation starts (ie text and ship first appear)
|
||||
MAIN_HALL_AMBIENT =12,//!< ambient sound for the Terran main hall (looping)
|
||||
MAIN_HALL_AMBIENT_V =13,//!< ambient sound for the Vasudan main hall (looping); in FS1, SND_BTN_SLIDE which was used for the briefing button slide-in
|
||||
BTN_SLIDE =13,//!< ambient sound for the Vasudan main hall (looping)
|
||||
BRIEF_STAGE_CHG =14,//!< brief stage change
|
||||
BRIEF_STAGE_CHG_FAIL =15,//!< brief stage change fail
|
||||
BRIEF_ICON_SELECT =16,//!< selet brief icon
|
||||
@@ -381,8 +381,8 @@ bool parse_game_sound(const char* tag, gamesnd_id* idx_dest);
|
||||
|
||||
gamesnd_id parse_game_sound_inline();
|
||||
|
||||
bool parse_iface_sound(const char* tag, interface_snd_id* idx_dest);
|
||||
bool parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& destination, const char* object_name, bool scp_list = false);
|
||||
void parse_iface_sound(const char* tag, interface_snd_id* idx_dest);
|
||||
void parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& destination, const char* object_name, bool scp_list = false);
|
||||
|
||||
// this is a callback, so it needs to be a real function
|
||||
void common_play_highlight_sound();
|
||||
|
||||
+17
-28
@@ -220,19 +220,15 @@ struct particle_pnt {
|
||||
vec3d up;
|
||||
};
|
||||
|
||||
// for compiler compatibility, even though C++17 supports omitting the template type...
|
||||
|
||||
//def_list
|
||||
template<typename T>
|
||||
struct flag_def_list_templated {
|
||||
struct flag_def_list {
|
||||
const char *name;
|
||||
T def;
|
||||
int def;
|
||||
ubyte var;
|
||||
};
|
||||
using flag_def_list = flag_def_list_templated<int>;
|
||||
|
||||
//A list of parse names for a flag enum
|
||||
template<typename T>
|
||||
template<class T>
|
||||
struct flag_def_list_new {
|
||||
const char* name; // The parseable representation of this flag
|
||||
T def; // The flag definition for this flag
|
||||
@@ -266,8 +262,6 @@ typedef struct coord2d {
|
||||
extern int Global_warning_count;
|
||||
extern int Global_error_count;
|
||||
|
||||
enum class ErrorType : ubyte { NONE = 0, WARNING, FATAL_ERROR };
|
||||
|
||||
#include "osapi/outwnd.h"
|
||||
|
||||
// To debug printf do this:
|
||||
@@ -330,14 +324,11 @@ constexpr bool LoggingEnabled = false;
|
||||
#define Int3() debug_int3(__FILE__, __LINE__)
|
||||
#endif // NDEBUG
|
||||
|
||||
|
||||
// the older MIN and MAX macros were vulnerable to performance issues since they duplicated their tokens
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) std::min(a,b)
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) std::max(a,b)
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
@@ -389,14 +380,9 @@ const size_t INVALID_SIZE = static_cast<size_t>(-1);
|
||||
#define INTEL_FLOAT(x) (*x)
|
||||
#endif // BYTE_ORDER
|
||||
|
||||
// since a lot of header files will try to #define TRUE and FALSE,
|
||||
// making them constexpr here doesn't gain us much
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
// the trailing underscores are to avoid conflicts with previously #define'd tokens
|
||||
enum class TriStateBool : int { FALSE_ = 0, TRUE_ = 1, UNKNOWN_ = -1 };
|
||||
|
||||
|
||||
// lod checker for (modular) table parsing
|
||||
typedef struct lod_checker {
|
||||
@@ -430,15 +416,18 @@ extern void game_busy(const char *filename = NULL);
|
||||
|
||||
const char *XSTR(const char *str, int index, bool force_lookup = false);
|
||||
|
||||
// The older CLAMP macro was vulnerable to performance issues since it duplicated its tokens. (The older CAP was a function.) Technically
|
||||
// the new macro duplicates the LHS, but that should be ok.
|
||||
|
||||
// Ensure that x is at least min and at most max.
|
||||
#define CLAMP(x, min, max) { x = std::clamp(x, min, max); }
|
||||
|
||||
// Ensure that x is at least min and at most max.
|
||||
#define CAP(v, mn, mx) CLAMP(v, mn, mx)
|
||||
// Caps V between MN and MX.
|
||||
template <class T> void CAP( T& v, T mn, T mx )
|
||||
{
|
||||
if ( v < mn ) {
|
||||
v = mn;
|
||||
} else if ( v > mx ) {
|
||||
v = mx;
|
||||
}
|
||||
}
|
||||
|
||||
// faster version of CAP()
|
||||
#define CLAMP(x, min, max) do { if ( (x) < (min) ) (x) = (min); else if ((x) > (max)) (x) = (max); } while(false)
|
||||
|
||||
//=========================================================
|
||||
// Memory management functions
|
||||
@@ -469,7 +458,7 @@ public:
|
||||
// - is not "none"
|
||||
// - is not "<none>"
|
||||
inline bool VALID_FNAME(const char* x) {
|
||||
return (x != nullptr) && (x[0] != '\0') && stricmp(x, "none") != 0 && stricmp(x, "<none>") != 0;
|
||||
return (x[0] != '\0') && stricmp(x, "none") != 0 && stricmp(x, "<none>") != 0;
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the specified string may be a valid file name
|
||||
|
||||
+172
-233
@@ -155,84 +155,88 @@ void game_busy(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(MAX_DETAIL_VALUE == 4, "MAX_DETAIL_VALUE is assumed to be 4 in SystemVars.cpp");
|
||||
#if MAX_DETAIL_LEVEL != 4
|
||||
#error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
|
||||
#endif
|
||||
|
||||
static_assert(static_cast<int>(DefaultDetailPreset::Num_detail_presets) == 4, "Code in ManagePilot assumes Num_detail_presets = 4");
|
||||
#if NUM_DEFAULT_DETAIL_LEVELS != 4
|
||||
#error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
|
||||
#endif
|
||||
|
||||
// Detail preset stuff
|
||||
detail_levels Detail_defaults[static_cast<int>(DefaultDetailPreset::Num_detail_presets)] = {
|
||||
{
|
||||
DefaultDetailPreset::Low, // setting
|
||||
// ================== Analogs ==================
|
||||
0, // nebula_detail; // 0=lowest detail, MAX_DETAIL_VALUE=highest detail
|
||||
0, // detail_distance; // 0=lowest MAX_DETAIL_VALUE=highest
|
||||
0, // hardware_textures; // 0=max culling, MAX_DETAIL_VALUE=no culling
|
||||
0, // num_small_debris; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
0, // num_particles; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
0, // num_stars; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
0, // shield_effects; // 0=min, MAX_DETAIL_VALUE=max
|
||||
2, // lighting; // 0=min, MAX_DETAIL_VALUE=max
|
||||
// Detail level stuff
|
||||
detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
|
||||
{ // Low
|
||||
0, // setting
|
||||
// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
|
||||
0, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
|
||||
0, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
|
||||
0, // hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
|
||||
0, // num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
0, // num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
0, // num_stars; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
0, // shield_effects; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
2, // lighting; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
|
||||
// ================== Booleans ==================
|
||||
false, // targetview_model; // false=off, true=on
|
||||
false, // planets_suns; // false=off, true=on
|
||||
false, // weapon_extras // false=off, true=on
|
||||
// ==== Booleans ====
|
||||
0, // targetview_model; // 0=off, 1=on
|
||||
0, // planets_suns; // 0=off, 1=on
|
||||
0, // weapon_extras
|
||||
},
|
||||
{
|
||||
DefaultDetailPreset::Medium, // setting
|
||||
// ================== Analogs ==================
|
||||
2, // nebula_detail; // 0=lowest detail, MAX_DETAIL_VALUE=highest detail
|
||||
2, // detail_distance; // 0=lowest MAX_DETAIL_VALUE=highest
|
||||
2, // hardware_textures; // 0=max culling, MAX_DETAIL_VALUE=no culling
|
||||
2, // num_small_debris; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
2, // num_particles; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
2, // num_stars; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
2, // shield_effects; // 0=min, MAX_DETAIL_VALUE=max
|
||||
3, // lighting; // 0=min, MAX_DETAIL_VALUE=max
|
||||
{ // Medium
|
||||
1, // setting
|
||||
// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
|
||||
2, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
|
||||
2, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
|
||||
2, // hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
|
||||
2, // num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
2, // num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
2, // num_stars; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
2, // shield_effects; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
3, // lighting; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
|
||||
// ================== Booleans ==================
|
||||
true, // targetview_model; // false=off, true=on
|
||||
true, // planets_suns; // false=off, true=on
|
||||
true, // weapon_extras // false=off, true=on
|
||||
// ==== Booleans ====
|
||||
1, // targetview_model; // 0=off, 1=on
|
||||
1, // planets_suns; // 0=off, 1=on
|
||||
1, // weapon extras
|
||||
},
|
||||
{
|
||||
DefaultDetailPreset::High, // setting
|
||||
// ================== Analogs ==================
|
||||
2, // nebula_detail; // 0=lowest detail, MAX_DETAIL_VALUE=highest detail
|
||||
2, // detail_distance; // 0=lowest MAX_DETAIL_VALUE=highest
|
||||
3, // hardware_textures; // 0=max culling, MAX_DETAIL_VALUE=no culling
|
||||
3, // num_small_debris; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
3, // num_particles; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
4, // num_stars; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
3, // shield_effects; // 0=min, MAX_DETAIL_VALUE=max
|
||||
4, // lighting; // 0=min, MAX_DETAIL_VALUE=max
|
||||
{ // High level
|
||||
2, // setting
|
||||
// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
|
||||
2, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
|
||||
2, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
|
||||
3, // hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
|
||||
3, // num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
3, // num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
4, // num_stars; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
3, // shield_effects; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
4, // lighting; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
|
||||
// ================== Booleans ==================
|
||||
true, // targetview_model; // false=off, true=on
|
||||
true, // planets_suns; // false=off, true=on
|
||||
true, // weapon_extras // false=off, true=on
|
||||
// ==== Booleans ====
|
||||
1, // targetview_model; // 0=off, 1=on
|
||||
1, // planets_suns; // 0=off, 1=on
|
||||
1, // weapon_extras
|
||||
},
|
||||
{
|
||||
DefaultDetailPreset::VeryHigh, // setting
|
||||
// ================== Analogs ==================
|
||||
4, // nebula_detail; // 0=lowest detail, MAX_DETAIL_VALUE=highest detail
|
||||
4, // detail_distance; // 0=lowest MAX_DETAIL_VALUE=highest
|
||||
4, // hardware_textures; // 0=max culling, MAX_DETAIL_VALUE=no culling
|
||||
4, // num_small_debris; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
4, // num_particles; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
4, // num_stars; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
4, // shield_effects; // 0=min, MAX_DETAIL_VALUE=max
|
||||
4, // lighting; // 0=min, MAX_DETAIL_VALUE=max
|
||||
{ // Highest level
|
||||
3, // setting
|
||||
// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
|
||||
4, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
|
||||
4, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
|
||||
4, // hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
|
||||
4, // num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
4, // num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
4, // num_stars; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
4, // shield_effects; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
4, // lighting; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
|
||||
// ================== Booleans ==================
|
||||
true, // targetview_model; // false=off, true=on
|
||||
true, // planets_suns; // false=off, true=on
|
||||
true, // weapon_extras // false=off, true=on
|
||||
// ==== Booleans ====
|
||||
1, // targetview_model; // 0=off, 1=on
|
||||
1, // planets_suns; // 0=off, 1=on
|
||||
1, // weapon_extras
|
||||
},
|
||||
};
|
||||
|
||||
// Global used to access detail presets in game and libs
|
||||
detail_levels Detail = Detail_defaults[static_cast<int>(DefaultDetailPreset::Num_detail_presets) - 1];
|
||||
// Global used to access detail levels in game and libs
|
||||
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
|
||||
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1160}},
|
||||
@@ -240,267 +244,118 @@ const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues
|
||||
{ 3, {"High", 1162}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
static void parse_model_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::DetailDistance, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
|
||||
std::pair<const char*, int>{"Model Detail", 1739},
|
||||
std::pair<const char*, int>{"Detail level of models", 1740})
|
||||
.importance(8)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.detail_distance;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_model_detail_func)
|
||||
.finish();
|
||||
|
||||
static void parse_texture_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::HardwareTextures, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
|
||||
std::pair<const char*, int>{"3D Hardware Textures", 1362},
|
||||
std::pair<const char*, int>{"Level of detail of textures", 1720})
|
||||
.importance(6)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.hardware_textures;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_texture_detail_func)
|
||||
.finish();
|
||||
|
||||
static void parse_particles_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::NumParticles, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
|
||||
std::pair<const char*, int>{"Particles", 1363},
|
||||
std::pair<const char*, int>{"Level of detail for particles", 1717})
|
||||
.importance(5)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.num_particles;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_particles_detail_func)
|
||||
.finish();
|
||||
|
||||
static void parse_debris_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::NumSmallDebris, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto SmallDebrisOption __UNUSED = options::OptionBuilder<int>("Graphics.SmallDebris",
|
||||
std::pair<const char*, int>{"Impact Effects", 1364},
|
||||
std::pair<const char*, int>{"Level of detail of impact effects", 1743})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.num_small_debris;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.importance(4)
|
||||
.change_listener([](int val,bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_debris_detail_func)
|
||||
.finish();
|
||||
|
||||
static void parse_shield_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::ShieldEffects, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
std::pair<const char*, int>{"Shield Hit Effects", 1718},
|
||||
std::pair<const char*, int>{"Level of detail of shield impacts", 1719})
|
||||
.importance(3)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.shield_effects;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_shield_detail_func)
|
||||
.finish();
|
||||
|
||||
static void parse_stars_detail_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::NumStars, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto StarsOption __UNUSED = options::OptionBuilder<int>("Graphics.Stars",
|
||||
std::pair<const char*, int>{"Stars", 1366},
|
||||
std::pair<const char*, int>{"Number of stars in the mission", 1698})
|
||||
.importance(2)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([](){return Detail.num_stars;})
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_stars_detail_func)
|
||||
.finish();
|
||||
|
||||
// Call this with:
|
||||
// 0 - lowest
|
||||
// Num_detail_presets - highest
|
||||
// NUM_DETAIL_LEVELS - highest
|
||||
// To set the parameters in Detail to some set of defaults
|
||||
void detail_level_set(DefaultDetailPreset preset)
|
||||
void detail_level_set(int level)
|
||||
{
|
||||
if (preset == DefaultDetailPreset::Custom) {
|
||||
Detail.setting = DefaultDetailPreset::Custom;
|
||||
if ( level < 0 ) {
|
||||
Detail.setting = -1;
|
||||
return;
|
||||
}
|
||||
Assert( level >= 0 );
|
||||
Assert( level < NUM_DEFAULT_DETAIL_LEVELS );
|
||||
|
||||
Detail = Detail_defaults[static_cast<int>(preset)];
|
||||
Detail = Detail_defaults[level];
|
||||
}
|
||||
|
||||
// Change detail values 0 - MAX_DETAIL_VALUE
|
||||
void change_default_detail_level(DefaultDetailPreset preset, DetailSetting selection, int value)
|
||||
{
|
||||
|
||||
// Use a switch statement for more readable access to the struct members
|
||||
switch (selection) {
|
||||
case DetailSetting::NebulaDetail:
|
||||
Detail_defaults[static_cast<int>(preset)].nebula_detail = value;
|
||||
break;
|
||||
case DetailSetting::DetailDistance:
|
||||
Detail_defaults[static_cast<int>(preset)].detail_distance = value;
|
||||
break;
|
||||
case DetailSetting::HardwareTextures:
|
||||
Detail_defaults[static_cast<int>(preset)].hardware_textures = value;
|
||||
break;
|
||||
case DetailSetting::NumSmallDebris:
|
||||
Detail_defaults[static_cast<int>(preset)].num_small_debris = value;
|
||||
break;
|
||||
case DetailSetting::NumParticles:
|
||||
Detail_defaults[static_cast<int>(preset)].num_particles = value;
|
||||
break;
|
||||
case DetailSetting::NumStars:
|
||||
Detail_defaults[static_cast<int>(preset)].num_stars = value;
|
||||
break;
|
||||
case DetailSetting::ShieldEffects:
|
||||
Detail_defaults[static_cast<int>(preset)].shield_effects = value;
|
||||
break;
|
||||
case DetailSetting::Lighting:
|
||||
Detail_defaults[static_cast<int>(preset)].lighting = value;
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Invalid detail selection. Get a coder!");
|
||||
}
|
||||
}
|
||||
|
||||
// Change detail values bool overload
|
||||
void change_default_detail_level(DefaultDetailPreset preset, DetailSetting selection, bool value)
|
||||
{
|
||||
|
||||
// Use a switch statement for more readable access to the struct members
|
||||
switch (selection) {
|
||||
case DetailSetting::TargetViewModel:
|
||||
Detail_defaults[static_cast<int>(preset)].targetview_model = value;
|
||||
break;
|
||||
case DetailSetting::PlanetsSuns:
|
||||
Detail_defaults[static_cast<int>(preset)].planets_suns = value;
|
||||
break;
|
||||
case DetailSetting::WeaponExtras:
|
||||
Detail_defaults[static_cast<int>(preset)].weapon_extras = value;
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Invalid detail selection. Get a coder!");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the current detail preset or -1 if custom.
|
||||
DefaultDetailPreset current_detail_preset()
|
||||
// Returns the current detail level or -1 if custom.
|
||||
int current_detail_level()
|
||||
{
|
||||
// return Detail.setting;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ ) {
|
||||
if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 ) {
|
||||
return static_cast<DefaultDetailPreset>(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return DefaultDetailPreset::Custom;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -585,3 +440,87 @@ DCF(detail, "Turns on/off parts of the game for speed testing" )
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stuff that can't be included in vmallocator.h
|
||||
|
||||
std::locale SCP_default_locale("");
|
||||
|
||||
void SCP_tolower(char *str)
|
||||
{
|
||||
for (; *str != '\0'; ++str)
|
||||
*str = SCP_tolower(*str);
|
||||
}
|
||||
|
||||
void SCP_toupper(char *str)
|
||||
{
|
||||
for (; *str != '\0'; ++str)
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
// this is a bit naive but it is good enough for the time being
|
||||
void SCP_totitle(char *str)
|
||||
{
|
||||
bool prev_alpha = false;
|
||||
|
||||
for (; *str != '\0'; ++str)
|
||||
{
|
||||
bool this_alpha = (*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z');
|
||||
|
||||
if (this_alpha)
|
||||
{
|
||||
if (prev_alpha)
|
||||
*str = SCP_tolower(*str);
|
||||
else
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
prev_alpha = this_alpha;
|
||||
}
|
||||
}
|
||||
|
||||
bool lcase_equal(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
if (_Left.size() != _Right.size())
|
||||
return false;
|
||||
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (l_it != _Left.cend())
|
||||
{
|
||||
if (SCP_tolower(*l_it) != SCP_tolower(*r_it))
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lcase_lessthan(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (l_it == _Left.cend())
|
||||
return (r_it != _Right.cend());
|
||||
else if (r_it == _Right.cend())
|
||||
return false;
|
||||
|
||||
auto lch = SCP_tolower(*l_it);
|
||||
auto rch = SCP_tolower(*r_it);
|
||||
|
||||
if (lch < rch)
|
||||
return true;
|
||||
else if (lch > rch)
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -141,73 +141,42 @@ extern bool Trail_render_override;
|
||||
// or bad things will happen, I promise.
|
||||
//====================================================================================
|
||||
|
||||
// This refers to the total number of default levels as defined in Detail_defaults[]. Should only be 4.
|
||||
enum class DefaultDetailPreset {
|
||||
Custom = -1, // Special level used only in certain cases
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
VeryHigh,
|
||||
|
||||
Num_detail_presets
|
||||
};
|
||||
|
||||
#define MAX_DETAIL_VALUE 4 // The highest valid value for the "analog" detail level settings. Lowest is 0.
|
||||
#define MAX_DETAIL_LEVEL 4 // The highest valid value for the "analog" detail level settings
|
||||
|
||||
// If you change this, update player file in ManagePilot.cpp
|
||||
typedef struct detail_levels {
|
||||
|
||||
DefaultDetailPreset setting; // Which default setting this was created from. 0=lowest... DefaultDetailPreset::Num_detail_presets-1, -1=Custom
|
||||
int setting; // Which default setting this was created from. 0=lowest... NUM_DEFAULT_DETAIL_LEVELS-1, -1=Custom
|
||||
|
||||
// "Analogs"
|
||||
int nebula_detail; // 0=lowest detail, MAX_DETAIL_VALUE=highest detail
|
||||
int detail_distance; // 0=lowest MAX_DETAIL_VALUE=highest
|
||||
int hardware_textures; // 0=max culling, MAX_DETAIL_VALUE=no culling
|
||||
int num_small_debris; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
int num_particles; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
int num_stars; // 0=min number, MAX_DETAIL_VALUE=max number
|
||||
int shield_effects; // 0=min, MAX_DETAIL_VALUE=max
|
||||
int lighting; // 0=min, MAX_DETAIL_VALUE=max
|
||||
int nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
|
||||
int detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
|
||||
int hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
|
||||
int num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
int num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
int num_stars; // 0=min number, MAX_DETAIL_LEVEL=max number
|
||||
int shield_effects; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
int lighting; // 0=min, MAX_DETAIL_LEVEL=max
|
||||
|
||||
// Booleans
|
||||
bool targetview_model; // 0=off, 1=on
|
||||
bool planets_suns; // 0=off, 1=on
|
||||
bool weapon_extras; // extra weapon details. trails, glows
|
||||
int targetview_model; // 0=off, 1=on
|
||||
int planets_suns; // 0=off, 1=on
|
||||
int weapon_extras; // extra weapon details. trails, glows
|
||||
} detail_levels;
|
||||
|
||||
// Used for the newer options system to set the above values in more readable and safe way.
|
||||
// This enum class should always match the above struct
|
||||
enum class DetailSetting {
|
||||
NebulaDetail,
|
||||
DetailDistance,
|
||||
HardwareTextures,
|
||||
NumSmallDebris,
|
||||
NumParticles,
|
||||
NumStars,
|
||||
ShieldEffects,
|
||||
Lighting,
|
||||
TargetViewModel,
|
||||
PlanetsSuns,
|
||||
WeaponExtras,
|
||||
|
||||
Num_detail_settings
|
||||
};
|
||||
|
||||
// Global values used to access detail levels in game and libs
|
||||
extern detail_levels Detail;
|
||||
|
||||
#define NUM_DEFAULT_DETAIL_LEVELS 4 // How many "predefined" detail levels there are
|
||||
|
||||
// Call this with:
|
||||
// 0 - lowest
|
||||
// Num_detail_presets - highest
|
||||
// NUM_DEFAULT_DETAIL_LEVELS - highest
|
||||
// To set the parameters in Detail to some set of defaults
|
||||
void detail_level_set(DefaultDetailPreset preset);
|
||||
void detail_level_set(int level);
|
||||
|
||||
// level is 0 - lowest, Num_detail_presets - hights
|
||||
void change_default_detail_level(DefaultDetailPreset preset, DetailSetting selection, int value);
|
||||
void change_default_detail_level(DefaultDetailPreset preset, DetailSetting selection, bool value);
|
||||
|
||||
// Returns the current detail preset or -1 if custom.
|
||||
DefaultDetailPreset current_detail_preset();
|
||||
// Returns the current detail level or -1 if custom.
|
||||
int current_detail_level();
|
||||
|
||||
#define safe_kill(a) if(a)vm_free(a)
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* include toolchain.h which will pull in the file appropriate to
|
||||
* the detected toolchain.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -64,9 +63,6 @@
|
||||
#define SIZE_T_ARG "%zu"
|
||||
#define PTRDIFF_T_ARG "%zd"
|
||||
|
||||
#define UINT64_T_ARG "%" PRIu64
|
||||
#define INT64_T_ARG "%" PRId64
|
||||
|
||||
#define likely(x) __builtin_expect((long) !!(x), 1L)
|
||||
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* or otherwise commercially exploit the source or things you created based on
|
||||
* the source.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(DOXYGEN)
|
||||
/**
|
||||
@@ -47,22 +46,6 @@
|
||||
*/
|
||||
#define PTRDIFF_T_ARG "%zd"
|
||||
|
||||
/**
|
||||
* @brief Format specifier for a @c uint64_t argument
|
||||
*
|
||||
* Due to different runtimes using different format specifier for these types
|
||||
* it's necessary to hide these changes behind a macro.
|
||||
*/
|
||||
#define UINT64_T_ARG "%" PRIu64
|
||||
|
||||
/**
|
||||
* @brief Format specifier for an @c int64_t argument
|
||||
*
|
||||
* Due to different runtimes using different format specifier for these types
|
||||
* it's necessary to hide these changes behind a macro.
|
||||
*/
|
||||
#define INT64_T_ARG "%" PRId64
|
||||
|
||||
/**
|
||||
* @brief Attribute for forcing a static variable to be instantiated
|
||||
*
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
* include toolchain.h which will pull in the file appropriate to
|
||||
* the detected toolchain.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// per toolchain.h, clang takes precedence over gcc if they are both defined
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#if defined(__GNUC__)
|
||||
|
||||
#define SCP_FORMAT_STRING
|
||||
#define SCP_FORMAT_STRING_ARGS(x,y) __attribute__((format(printf, x, y)))
|
||||
@@ -64,9 +62,6 @@
|
||||
#define SIZE_T_ARG "%zu"
|
||||
#define PTRDIFF_T_ARG "%zd"
|
||||
|
||||
#define UINT64_T_ARG "%" PRIu64
|
||||
#define INT64_T_ARG "%" PRId64
|
||||
|
||||
#define likely(x) __builtin_expect((long) !!(x), 1L)
|
||||
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* include toolchain.h which will pull in the file appropriate to
|
||||
* the detected toolchain.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
|
||||
@@ -60,9 +59,6 @@
|
||||
#define SIZE_T_ARG "%zu"
|
||||
#define PTRDIFF_T_ARG "%zd"
|
||||
|
||||
#define UINT64_T_ARG "%" PRIu64
|
||||
#define INT64_T_ARG "%" PRId64
|
||||
|
||||
#define likely(x) __builtin_expect((long) !!(x), 1L)
|
||||
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* include toolchain.h which will pull in the file appropriate to
|
||||
* the detected toolchain.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
@@ -61,9 +60,6 @@
|
||||
#define SIZE_T_ARG "%Iu"
|
||||
#define PTRDIFF_T_ARG "%Id"
|
||||
|
||||
#define UINT64_T_ARG "%I64u"
|
||||
#define INT64_T_ARG "%I64d"
|
||||
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/scp_defines.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
template <typename T> struct is_optional : std::false_type {};
|
||||
template<typename T> struct is_optional<std::optional<T>> : std::true_type {};
|
||||
template<> struct is_optional<std::nullopt_t> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_optional_v = is_optional<T>::value;
|
||||
|
||||
template <typename T> struct is_tuple : std::false_type {};
|
||||
template <typename... U> struct is_tuple<std::tuple <U...>> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_tuple_v = is_tuple<T>::value;
|
||||
|
||||
template<typename T, typename F>
|
||||
constexpr auto has_member_impl(F&& f) -> decltype(f(std::declval<T>()), true) {
|
||||
SCP_UNUSED(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename>
|
||||
constexpr bool has_member_impl(...) { return false; }
|
||||
|
||||
#define has_member(T, member) has_member_impl<T>( [](auto&& obj)->decltype(obj.member){ return obj.member; } )
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct is_dereferenceable_pointer : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_dereferenceable_pointer<T, typename std::enable_if_t<std::is_same_v<typename std::decay_t<T>, std::unique_ptr<typename std::decay_t<T>::element_type>>>> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_dereferenceable_pointer<T, typename std::enable_if_t<std::is_same_v<typename std::decay_t<T>, std::shared_ptr<typename std::decay_t<T>::element_type>>>> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_dereferenceable_pointer<T, typename std::enable_if_t<std::is_same_v<typename std::decay_t<T>, std::weak_ptr<typename std::decay_t<T>::element_type>>>> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_dereferenceable_pointer<T, typename std::enable_if_t<std::is_pointer_v<typename std::decay_t<T>>>> : std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_dereferenceable_pointer_v = is_dereferenceable_pointer<T>::value;
|
||||
|
||||
template<class T, template<class...> class U>
|
||||
inline constexpr bool is_instance_of_v = std::false_type{};
|
||||
|
||||
template<template<class...> class U, class... Vs>
|
||||
inline constexpr bool is_instance_of_v<U<Vs...>,U> = std::true_type{};
|
||||
|
||||
|
||||
+99
-247
@@ -104,23 +104,9 @@ typename T::size_type GeneralizedLevenshteinDistance(const T &source,
|
||||
return lev_dist[min_size];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool stringcost_equal(const T& a, const T& b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template<typename charT>
|
||||
bool stringcost_tolower_equal(const charT& a, const charT& b)
|
||||
{
|
||||
return SCP_tolower(a) == SCP_tolower(b);
|
||||
}
|
||||
|
||||
// Lafiel
|
||||
template<typename T, typename charT = typename T::value_type>
|
||||
typename T::size_type stringcost(const T& op, const T& input, typename T::size_type max_expected_length = NAME_LENGTH,
|
||||
bool (*equal_check)(const charT&a, const charT&b) = stringcost_equal<charT>)
|
||||
{
|
||||
template<typename T>
|
||||
typename T::size_type stringcost(const T& op, const T& input, typename T::size_type max_expected_length = NAME_LENGTH) {
|
||||
using TSizeType = typename T::size_type;
|
||||
|
||||
if(input.empty())
|
||||
@@ -137,7 +123,7 @@ typename T::size_type stringcost(const T& op, const T& input, typename T::size_t
|
||||
for (TSizeType i = 0; i < op.length(); i++) {
|
||||
std::vector<string_search_it> insert;
|
||||
for (auto& it : iterators) {
|
||||
if (it.count < input.length() && equal_check(op[i], input[it.count])) {
|
||||
if (it.count < input.length() && op[i] == input[it.count]) {
|
||||
//We found something. There may be a better match for this later, so only make a copy.
|
||||
insert.emplace_back(string_search_it{it.count + 1, i, i - it.lastpos <= 1 ? it.cost : max_expected_length + i - it.lastpos - 1});
|
||||
}
|
||||
@@ -145,7 +131,7 @@ typename T::size_type stringcost(const T& op, const T& input, typename T::size_t
|
||||
|
||||
iterators.insert(iterators.end(), insert.begin(), insert.end());
|
||||
|
||||
if (equal_check(op[i], input[0]))
|
||||
if (op[i] == input[0])
|
||||
iterators.emplace_back(string_search_it{1, i, i});
|
||||
}
|
||||
|
||||
@@ -161,212 +147,79 @@ typename T::size_type stringcost(const T& op, const T& input, typename T::size_t
|
||||
return cost;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_string(const VECTOR_T& item_vector, FIELD_T* ITEM_T::* field, const char* str)
|
||||
template <typename T>
|
||||
int count_items_with_name(const char* name, const T* item_array, int num_items)
|
||||
{
|
||||
int count = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (str == nullptr && item.*field == nullptr)
|
||||
++count;
|
||||
else if (str == nullptr || item.*field == nullptr)
|
||||
;
|
||||
else if (!stricmp(item.*field, str))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_ptr_string(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
int count = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (str == nullptr && (item.*field).get() == nullptr)
|
||||
++count;
|
||||
else if (str == nullptr || (item.*field).get() == nullptr)
|
||||
;
|
||||
else if (!stricmp((item.*field).get(), str))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_string(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
int count = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.*field, str))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T>
|
||||
int count_items_with_string(const VECTOR_T& item_vector, SCP_string ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return 0;
|
||||
|
||||
return count_items_with_string(item_vector, field, SCP_string(str));
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const FIELD_T& search)
|
||||
{
|
||||
int count = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (item.*field == search)
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_string(const ITEM_T* item_array, int num_items, FIELD_T* ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
if (!name || !item_array)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
{
|
||||
if (str == nullptr && item_array[i].*field == nullptr)
|
||||
++count;
|
||||
else if (str == nullptr || item_array[i].*field == nullptr)
|
||||
;
|
||||
else if (!stricmp(item_array[i].*field, str))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_ptr_string(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
{
|
||||
if (str == nullptr && (item_array[i].*field).get() == nullptr)
|
||||
++count;
|
||||
else if (str == nullptr || (item_array[i].*field).get() == nullptr)
|
||||
;
|
||||
else if (!stricmp((item_array[i].*field).get(), str))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_string(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (lcase_equal(item_array[i].*field, str))
|
||||
if (!stricmp(name, item_array[i].name))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename ITEM_T>
|
||||
int count_items_with_string(const ITEM_T* item_array, int num_items, SCP_string ITEM_T::* field, const char* str)
|
||||
template <typename T>
|
||||
int count_items_with_name(const char* name, const T& item_vector)
|
||||
{
|
||||
if (item_array == nullptr || str == nullptr)
|
||||
return 0;
|
||||
|
||||
return count_items_with_string(item_array, num_items, field, SCP_string(str));
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int count_items_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const FIELD_T& search)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (item_array[i].*field == search)
|
||||
for (const auto& item : item_vector)
|
||||
if (!stricmp(name, item.name))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int count_items_with_scp_string_name(const char* name, const T& item_vector)
|
||||
{
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (const auto& item : item_vector)
|
||||
if (!stricmp(name, item.name.c_str()))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_string(const VECTOR_T& item_vector, FIELD_T* ITEM_T::* field, const char* str)
|
||||
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (str == nullptr && item.*field == nullptr)
|
||||
return index;
|
||||
else if (str == nullptr || item.*field == nullptr)
|
||||
++index;
|
||||
else if (!stricmp(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_ptr_string(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (str == nullptr && (item.*field).get() == nullptr)
|
||||
return index;
|
||||
else if (str == nullptr || (item.*field).get() == nullptr)
|
||||
++index;
|
||||
else if (!stricmp((item.*field).get(), str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_string(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T>
|
||||
int find_item_with_string(const VECTOR_T& item_vector, SCP_string ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
return find_item_with_string(item_vector, field, SCP_string(str));
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (!stricmp(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
@@ -385,49 +238,21 @@ int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, c
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_string(const ITEM_T* item_array, int num_items, FIELD_T* ITEM_T::* field, const char* str)
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
{
|
||||
if (str == nullptr && item_array[i].*field == nullptr)
|
||||
if (!stricmp(item_array[i].*field, str))
|
||||
return i;
|
||||
else if (str == nullptr || item_array[i].*field == nullptr)
|
||||
;
|
||||
else if (!stricmp(item_array[i].*field, str))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_ptr_string(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const char* str)
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
{
|
||||
if (str == nullptr && (item_array[i].*field).get() == nullptr)
|
||||
return i;
|
||||
else if (str == nullptr || (item_array[i].*field).get() == nullptr)
|
||||
;
|
||||
else if (!stricmp((item_array[i].*field).get(), str))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_string(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (lcase_equal(item_array[i].*field, str))
|
||||
return i;
|
||||
@@ -435,21 +260,9 @@ int find_item_with_string(const ITEM_T* item_array, int num_items, FIELD_T ITEM_
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T>
|
||||
int find_item_with_string(const ITEM_T* item_array, int num_items, SCP_string ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (item_array == nullptr || str == nullptr)
|
||||
return -1;
|
||||
|
||||
return find_item_with_string(item_array, num_items, field, str);
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const FIELD_T& search)
|
||||
{
|
||||
if (item_array == nullptr)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (item_array[i].*field == search)
|
||||
return i;
|
||||
@@ -457,8 +270,47 @@ int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* coalesce(const T* possibly_null, const T* value_if_null)
|
||||
template <typename VECTOR_T>
|
||||
int find_item_with_name(const VECTOR_T& item_vector, const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
int index = 0;
|
||||
for (const auto& item : item_vector)
|
||||
{
|
||||
if (!stricmp(item.name, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T>
|
||||
int find_item_with_name(const ITEM_T* item_array, int num_items, const char* str)
|
||||
{
|
||||
return find_item_with_field(item_array, num_items, &ITEM_T::name, str);
|
||||
}
|
||||
|
||||
template <typename VECTOR_T>
|
||||
int find_item_with_name(const VECTOR_T& item_vector, const SCP_string& str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const auto& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.name, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename NULLISH_T>
|
||||
NULLISH_T coalesce(NULLISH_T possibly_null, NULLISH_T value_if_null)
|
||||
{
|
||||
Assertion(value_if_null != nullptr, "value_if_null can never be null itself!");
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
// Stuff that can't be included in vmallocator.h
|
||||
|
||||
#include "globalincs/vmallocator.h"
|
||||
|
||||
std::locale SCP_default_locale("");
|
||||
|
||||
void SCP_tolower(SCP_string &str)
|
||||
{
|
||||
std::for_each(str.begin(), str.end(), [](char &ch) { ch = SCP_tolower(ch); });
|
||||
}
|
||||
|
||||
void SCP_toupper(SCP_string &str)
|
||||
{
|
||||
std::for_each(str.begin(), str.end(), [](char &ch) { ch = SCP_toupper(ch); });
|
||||
}
|
||||
|
||||
void SCP_tolower(char *str)
|
||||
{
|
||||
for (; *str != '\0'; ++str)
|
||||
*str = SCP_tolower(*str);
|
||||
}
|
||||
|
||||
void SCP_toupper(char *str)
|
||||
{
|
||||
for (; *str != '\0'; ++str)
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
// in-place modification of string to title case; this is a bit naive but it is good enough for the time being
|
||||
void SCP_totitle(char *str)
|
||||
{
|
||||
bool prev_alpha = false;
|
||||
|
||||
for (; *str != '\0'; ++str)
|
||||
{
|
||||
bool this_alpha = (*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z');
|
||||
|
||||
if (this_alpha)
|
||||
{
|
||||
if (prev_alpha)
|
||||
*str = SCP_tolower(*str);
|
||||
else
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
prev_alpha = this_alpha;
|
||||
}
|
||||
}
|
||||
|
||||
// in-place modification of string to title case; same naive algorithm as above
|
||||
void SCP_totitle(SCP_string &str)
|
||||
{
|
||||
SCP_string title_str;
|
||||
bool prev_alpha = false;
|
||||
|
||||
std::for_each(str.begin(), str.end(), [&prev_alpha](char &ch)
|
||||
{
|
||||
bool this_alpha = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
|
||||
|
||||
if (this_alpha)
|
||||
{
|
||||
if (prev_alpha)
|
||||
ch = SCP_tolower(ch);
|
||||
else
|
||||
ch = SCP_toupper(ch);
|
||||
}
|
||||
|
||||
prev_alpha = this_alpha;
|
||||
});
|
||||
}
|
||||
|
||||
bool SCP_truncate(SCP_string &str, size_t len)
|
||||
{
|
||||
if (str.length() > len)
|
||||
{
|
||||
str.resize(len);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lcase_equal(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
if (_Left.size() != _Right.size())
|
||||
return false;
|
||||
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (l_it != _Left.cend())
|
||||
{
|
||||
if (SCP_tolower(*l_it) != SCP_tolower(*r_it))
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lcase_lessthan(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (l_it == _Left.cend())
|
||||
return (r_it != _Right.cend());
|
||||
else if (r_it == _Right.cend())
|
||||
return false;
|
||||
|
||||
auto lch = SCP_tolower(*l_it);
|
||||
auto rch = SCP_tolower(*r_it);
|
||||
|
||||
if (lch < rch)
|
||||
return true;
|
||||
else if (lch > rch)
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -18,30 +18,7 @@
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
class SCP_vector : public std::vector<T, std::allocator<T>>
|
||||
{
|
||||
public:
|
||||
using std::vector<T, std::allocator<T>>::vector; // inherit all constructors
|
||||
|
||||
// this is needed as a workaround to a GCC compiler bug when using a templated accessor...
|
||||
// error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
|
||||
inline auto size() const noexcept { return std::vector<T, std::allocator<T>>::size(); }
|
||||
|
||||
bool contains(const T& item) const
|
||||
{
|
||||
return std::find(this->begin(), this->end(), item) != this->end();
|
||||
}
|
||||
|
||||
bool in_bounds(int idx) const
|
||||
{
|
||||
return (idx >= 0) && (static_cast<size_t>(idx) < this->size());
|
||||
}
|
||||
|
||||
bool in_bounds(size_t idx) const
|
||||
{
|
||||
return idx < this->size();
|
||||
}
|
||||
};
|
||||
using SCP_vector = std::vector<T, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
bool SCP_vector_contains(const SCP_vector<T>& vector, const T& item) {
|
||||
@@ -50,7 +27,7 @@ bool SCP_vector_contains(const SCP_vector<T>& vector, const T& item) {
|
||||
|
||||
template <typename T>
|
||||
inline bool SCP_vector_inbounds(const SCP_vector<T>& vector, int idx) {
|
||||
return ((idx >= 0) && (static_cast<size_t>(idx) < vector.size()));
|
||||
return ((idx >= 0) && (idx < static_cast<int>(vector.size())));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -59,39 +36,42 @@ inline bool SCP_vector_inbounds(const SCP_vector<T>& vector, size_t idx) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class SCP_list : public std::list<T, std::allocator<T>>
|
||||
{
|
||||
public:
|
||||
using std::list<T, std::allocator<T>>::list; // inherit all constructors
|
||||
|
||||
bool contains(const T& item) const
|
||||
{
|
||||
return std::find(this->begin(), this->end(), item) != this->end();
|
||||
}
|
||||
};
|
||||
using SCP_list = std::list<T, std::allocator<T>>;
|
||||
|
||||
|
||||
extern std::locale SCP_default_locale;
|
||||
|
||||
template <class charT>
|
||||
[[nodiscard]] charT SCP_toupper(charT ch) { return std::toupper(ch, SCP_default_locale); }
|
||||
charT SCP_toupper(charT ch) { return std::toupper(ch, SCP_default_locale); }
|
||||
|
||||
template <class charT>
|
||||
[[nodiscard]] charT SCP_tolower(charT ch) { return std::tolower(ch, SCP_default_locale); }
|
||||
charT SCP_tolower(charT ch) { return std::tolower(ch, SCP_default_locale); }
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, std::allocator<char>> SCP_string;
|
||||
typedef std::basic_stringstream<char, std::char_traits<char>, std::allocator<char>> SCP_stringstream;
|
||||
typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > SCP_string;
|
||||
|
||||
typedef std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> > SCP_stringstream;
|
||||
|
||||
inline void SCP_tolower(SCP_string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](char c) { return SCP_tolower(c); });
|
||||
}
|
||||
|
||||
inline void SCP_toupper(SCP_string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](char c) { return SCP_toupper(c); });
|
||||
}
|
||||
|
||||
inline bool SCP_truncate(SCP_string &str, size_t c_str_size) {
|
||||
if (str.length() >= c_str_size) {
|
||||
str.resize(c_str_size - 1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern void SCP_tolower(char *str);
|
||||
extern void SCP_toupper(char *str);
|
||||
extern void SCP_totitle(char *str);
|
||||
|
||||
extern void SCP_tolower(SCP_string &str);
|
||||
extern void SCP_toupper(SCP_string &str);
|
||||
extern void SCP_totitle(SCP_string &str);
|
||||
|
||||
extern bool SCP_truncate(SCP_string &str, size_t len);
|
||||
|
||||
extern bool lcase_equal(const SCP_string& _Left, const SCP_string& _Right);
|
||||
extern bool lcase_lessthan(const SCP_string& _Left, const SCP_string& _Right);
|
||||
|
||||
@@ -109,32 +89,44 @@ template <typename T>
|
||||
using SCP_deque = std::deque<T, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
class SCP_set : public std::set<T, std::less<T>, std::allocator<T>>
|
||||
{
|
||||
public:
|
||||
using std::set<T, std::less<T>, std::allocator<T>>::set; // inherit all constructors
|
||||
|
||||
bool contains(const T& item) const
|
||||
{
|
||||
return this->find(item) != this->end();
|
||||
}
|
||||
};
|
||||
using SCP_set = std::set<T, std::less<T>, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
class SCP_multiset : public std::multiset<T, std::less<T>, std::allocator<T>>
|
||||
{
|
||||
public:
|
||||
using std::multiset<T, std::less<T>, std::allocator<T>>::multiset; // inherit all constructors
|
||||
using SCP_multiset = std::multiset<T, std::less<T>, std::allocator<T>>;
|
||||
|
||||
bool contains(const T& item) const
|
||||
#if __cplusplus < 201402L
|
||||
template<class T, bool>
|
||||
struct enum_hasher_util {
|
||||
inline size_t operator()(const T& elem) { return std::hash<T>()(elem); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enum_hasher_util<T, true> {
|
||||
inline size_t operator()(const T& elem)
|
||||
{
|
||||
return this->find(item) != this->end();
|
||||
typedef typename std::underlying_type<T>::type enumType;
|
||||
return std::hash<enumType>()(static_cast<enumType>(elem));
|
||||
}
|
||||
};
|
||||
|
||||
// Now that the codebase is on C++17, we can use the standard hash. (Enum classes are not hashable on C++ < 14.)
|
||||
/**
|
||||
* @brief An enum class compatible hashing class
|
||||
*
|
||||
* This is the same as std::hash except that is can handle enum classes properly using their underlying type. This is
|
||||
* only required for C++ < 14 since after that the standard mandates that enum classes should be hashable.
|
||||
*
|
||||
* @tparam T The type that should be hashed
|
||||
*/
|
||||
template <class T>
|
||||
struct SCP_hash {
|
||||
inline size_t operator()(const T& elem) const { return enum_hasher_util<T, std::is_enum<T>::value>()(elem); }
|
||||
};
|
||||
|
||||
#else
|
||||
// No need for the special hash class so just use the standard hash
|
||||
template <typename T>
|
||||
using SCP_hash = std::hash<T>;
|
||||
#endif
|
||||
|
||||
struct SCP_string_lcase_hash {
|
||||
size_t operator()(const SCP_string& elem) const {
|
||||
@@ -163,16 +155,7 @@ template <typename Key, typename T, typename Hash = SCP_hash<Key>, typename KeyE
|
||||
using SCP_unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, std::allocator<std::pair<const Key, T>>>;
|
||||
|
||||
template <typename Key, typename Hash = SCP_hash<Key>, typename KeyEqual = std::equal_to<Key>>
|
||||
class SCP_unordered_set : public std::unordered_set<Key, Hash, KeyEqual, std::allocator<Key>>
|
||||
{
|
||||
public:
|
||||
using std::unordered_set<Key, Hash, KeyEqual, std::allocator<Key>>::unordered_set; // inherit all constructors
|
||||
|
||||
bool contains(const Key& item) const
|
||||
{
|
||||
return this->find(item) != this->end();
|
||||
}
|
||||
};
|
||||
using SCP_unordered_set = std::unordered_set<Key, Hash, KeyEqual, std::allocator<Key>>;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Args&&... args) {
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "debugconsole/console.h"
|
||||
#include "utils/string_utils.h"
|
||||
|
||||
#if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING )
|
||||
# include "globalincs/mspdb_callstack.h"
|
||||
@@ -51,6 +50,17 @@ extern void gr_activate(int active);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const char *clean_filename( const char *name)
|
||||
{
|
||||
const char *p = name+strlen(name)-1;
|
||||
// Move p to point to first letter of EXE filename
|
||||
while( (*p!='\\') && (*p!='/') && (*p!=':') && (p>= name) )
|
||||
p--;
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* MSVC2005+ callstack support
|
||||
*/
|
||||
@@ -77,7 +87,7 @@ public:
|
||||
UNREFERENCED_PARAMETER( address );
|
||||
|
||||
StackEntry entry;
|
||||
entry.module = util::get_file_part( module );
|
||||
entry.module = clean_filename( module );
|
||||
entry.symbol = symbol;
|
||||
m_stackFrames.push_back( entry );
|
||||
}
|
||||
|
||||
+31
-311
@@ -43,7 +43,6 @@
|
||||
#include "scripting/scripting.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "utils/boost/hash_combine.h"
|
||||
#include "utils/string_utils.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
@@ -90,8 +89,6 @@ const char* Resolution_prefixes[GR_NUM_RESOLUTIONS] = {"", "2_"};
|
||||
|
||||
screen gr_screen;
|
||||
|
||||
lua_screen gr_lua_screen;
|
||||
|
||||
color_gun Gr_red, Gr_green, Gr_blue, Gr_alpha;
|
||||
color_gun Gr_t_red, Gr_t_green, Gr_t_blue, Gr_t_alpha;
|
||||
color_gun Gr_ta_red, Gr_ta_green, Gr_ta_blue, Gr_ta_alpha;
|
||||
@@ -140,55 +137,17 @@ static bool gamma_change_listener(float new_val, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void parse_gamma_func()
|
||||
{
|
||||
float value;
|
||||
stuff_float(&value);
|
||||
|
||||
constexpr float EPSILON = 0.0001f;
|
||||
|
||||
if (value < 0.1f - EPSILON || value > 5.0f + EPSILON) {
|
||||
error_display(0, "%f is not a valid gamma value! (Out of range)", value);
|
||||
return;
|
||||
}
|
||||
|
||||
float expected_i = value / 0.05f;
|
||||
int i = fl2i(std::round(expected_i));
|
||||
|
||||
if (std::abs(value - (0.05f * i)) < EPSILON && i >= 2 && i <= 100) {
|
||||
Gr_gamma = value;
|
||||
return;
|
||||
}
|
||||
|
||||
error_display(0, "%f is not a valid gamma value! (Invalid increment)", value);
|
||||
}
|
||||
|
||||
static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma",
|
||||
std::pair<const char*, int>{"Brightness", 1375},
|
||||
std::pair<const char*, int>{"The brightness value used for the game window", 1738})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_func([]() { return Gr_gamma; })
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_gamma_func)
|
||||
.finish();
|
||||
|
||||
static void parse_lighting_func()
|
||||
{
|
||||
int value[static_cast<int>(DefaultDetailPreset::Num_detail_presets)];
|
||||
stuff_int_list(value, static_cast<int>(DefaultDetailPreset::Num_detail_presets), RAW_INTEGER_TYPE);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(DefaultDetailPreset::Num_detail_presets); i++) {
|
||||
|
||||
if (value[i] < 0 || value[i] > MAX_DETAIL_VALUE) {
|
||||
error_display(0, "%i is an invalid detail level value!", value[i]);
|
||||
} else {
|
||||
change_default_detail_level(static_cast<DefaultDetailPreset>(i), DetailSetting::Lighting, value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1160}},
|
||||
@@ -202,7 +161,7 @@ const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Light
|
||||
.importance(1)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_func([]() { return Detail.lighting; })
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
@@ -211,10 +170,9 @@ const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Light
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.parser(parse_lighting_func)
|
||||
.finish();
|
||||
|
||||
os::ViewportState Gr_configured_window_state = os::ViewportState::Fullscreen;
|
||||
os::ViewportState Gr_configured_window_state = os::ViewportState::Windowed;
|
||||
|
||||
static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
{
|
||||
@@ -234,21 +192,6 @@ static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void parse_window_mode_func()
|
||||
{
|
||||
SCP_string value;
|
||||
stuff_string(value, F_NAME);
|
||||
if (lcase_equal(value, "windowed")) {
|
||||
Gr_configured_window_state = os::ViewportState::Windowed;
|
||||
} else if (lcase_equal(value, "borderless")) {
|
||||
Gr_configured_window_state = os::ViewportState::Borderless;
|
||||
} else if (lcase_equal(value, "fullscreen")) {
|
||||
Gr_configured_window_state = os::ViewportState::Fullscreen;
|
||||
} else {
|
||||
error_display(0, "%s is an invalide window mode", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode",
|
||||
std::pair<const char*, int>{"Window Mode", 1772},
|
||||
std::pair<const char*, int>{"Controls how the game window is created", 1773})
|
||||
@@ -258,18 +201,12 @@ static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState
|
||||
{os::ViewportState::Borderless, {"Borderless", 1675}},
|
||||
{os::ViewportState::Windowed, {"Windowed", 1676}}})
|
||||
.importance(98)
|
||||
.default_func([]() { return Gr_configured_window_state; })
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.parser(parse_window_mode_func)
|
||||
.finish();
|
||||
|
||||
void removeWindowModeOption()
|
||||
{
|
||||
options::OptionsManager::instance()->removeOption(WindowModeOption);
|
||||
}
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, std::nullopt, CHA_ONFRAME);
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
|
||||
|
||||
// z-buffer stuff
|
||||
int gr_zbuffering = 0;
|
||||
@@ -346,10 +283,6 @@ static bool videodisplay_change(int display, bool initial)
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Video display cannot support default settings because graphics have not been
|
||||
// initialized so we can't validate the setting. But also, this should probably
|
||||
// only ever be a user setting
|
||||
static auto VideoDisplayOption = options::OptionBuilder<int>("Graphics.Display",
|
||||
std::pair<const char*, int>{"Primary display", 1741},
|
||||
std::pair<const char*, int>{"The display used for rendering", 1742})
|
||||
@@ -405,22 +338,12 @@ static SCP_vector<ResolutionInfo> resolution_enumerator()
|
||||
|
||||
auto res = ResolutionInfo(mode.w, mode.h);
|
||||
if (std::find(out.begin(), out.end(), res) == out.end()) {
|
||||
out.emplace_back(res);
|
||||
out.push_back(res);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
static SCP_vector<ResolutionInfo> resolution_vr_enumerator()
|
||||
{
|
||||
SCP_vector<ResolutionInfo> out;
|
||||
|
||||
for (int i = 1000; i <= 6000; i += 500) {
|
||||
out.emplace_back(ResolutionInfo(i, i));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
static SCP_string resolution_display(const ResolutionInfo& info)
|
||||
{
|
||||
SCP_string str;
|
||||
@@ -435,10 +358,6 @@ static ResolutionInfo resolution_default()
|
||||
}
|
||||
return {(uint32_t)mode.w, (uint32_t)mode.h};
|
||||
}
|
||||
static ResolutionInfo resolution_vr_default()
|
||||
{
|
||||
return {(uint32_t)2500, (uint32_t)2500};
|
||||
}
|
||||
static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
{
|
||||
if (initial) {
|
||||
@@ -474,18 +393,6 @@ static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static bool resolution_vr_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
{
|
||||
if (initial) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolution cannot support default settings because graphics have not been
|
||||
// initialized so we can't validate the setting. But also, this should probably
|
||||
// only ever be a user setting
|
||||
static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.Resolution",
|
||||
std::pair<const char*, int>{"Resolution", 1748},
|
||||
std::pair<const char*, int>{"The rendering resolution", 1749})
|
||||
@@ -500,78 +407,19 @@ static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.
|
||||
.importance(100)
|
||||
.finish();
|
||||
|
||||
void removeResolutionOption()
|
||||
{
|
||||
options::OptionsManager::instance()->removeOption(ResolutionOption);
|
||||
}
|
||||
|
||||
static auto ResolutionVROption = options::OptionBuilder<ResolutionInfo>("Graphics.ResolutionVR",
|
||||
std::pair<const char*, int>{"VR Resolution", 1878},
|
||||
std::pair<const char*, int>{"The rendering resolution when in VR mode", 1879})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_vr_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_vr_default)
|
||||
.change_listener(resolution_vr_change)
|
||||
.importance(101)
|
||||
.finish();
|
||||
|
||||
void removeResolutionVROption()
|
||||
{
|
||||
options::OptionsManager::instance()->removeOption(ResolutionVROption);
|
||||
}
|
||||
|
||||
bool Gr_enable_soft_particles = true;
|
||||
|
||||
static void parse_soft_particle_func() {
|
||||
bool value;
|
||||
stuff_boolean(&value);
|
||||
|
||||
Gr_enable_soft_particles = value;
|
||||
}
|
||||
bool Gr_enable_soft_particles = false;
|
||||
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles",
|
||||
std::pair<const char*, int>{"Soft Particles", 1761},
|
||||
std::pair<const char*, int>{"Enable or disable soft particle rendering", 1762})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_enable_soft_particles; })
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.parser(parse_soft_particle_func)
|
||||
.finish();
|
||||
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects{};
|
||||
|
||||
static void parse_framebuffer_func() {
|
||||
SCP_string value;
|
||||
stuff_string(value, F_NAME);
|
||||
|
||||
// Convert to lowercase once
|
||||
SCP_tolower(value);
|
||||
|
||||
// Use a map to associate strings with their respective actions
|
||||
static const std::unordered_map<std::string, std::function<void()>> effectActions = {
|
||||
{"shockwaves", []() { Gr_framebuffer_effects.set(FramebufferEffects::Shockwaves); }},
|
||||
{"thrusters", []() { Gr_framebuffer_effects.set(FramebufferEffects::Thrusters); }},
|
||||
{"all", []() {
|
||||
Gr_framebuffer_effects.set(FramebufferEffects::Shockwaves);
|
||||
Gr_framebuffer_effects.set(FramebufferEffects::Thrusters);
|
||||
}},
|
||||
{"none", []() { /* No-op */ }}
|
||||
};
|
||||
|
||||
auto it = effectActions.find(value);
|
||||
if (it != effectActions.end()) {
|
||||
Gr_framebuffer_effects = flagset<FramebufferEffects>(); // Clear only if valid
|
||||
it->second(); // Execute the corresponding action
|
||||
} else {
|
||||
error_display(0, "%s is not a valid framebuffer effect setting", value.c_str());
|
||||
}
|
||||
}
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects;
|
||||
|
||||
static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<FramebufferEffects>>("Graphics.FramebufferEffects",
|
||||
std::pair<const char*, int>{"Framebuffer effects", 1732},
|
||||
@@ -582,42 +430,14 @@ static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<F
|
||||
{{FramebufferEffects::Shockwaves}, {"Shockwaves", 1688}},
|
||||
{{FramebufferEffects::Thrusters}, {"Thrusters", 1689}},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, {"All", 1690}}})
|
||||
.default_func([]() { return Gr_framebuffer_effects; } )
|
||||
.default_val({})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.parser(parse_framebuffer_func)
|
||||
.finish();
|
||||
|
||||
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
|
||||
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
|
||||
|
||||
static void parse_anti_aliasing_func() {
|
||||
SCP_string value;
|
||||
stuff_string(value, F_NAME);
|
||||
|
||||
SCP_tolower(value);
|
||||
|
||||
// Map of valid values to AntiAliasMode
|
||||
static const std::unordered_map<std::string, AntiAliasMode> aaModeMap = {
|
||||
{"none", AntiAliasMode::None},
|
||||
{"fxaa low", AntiAliasMode::FXAA_Low},
|
||||
{"fxaa medium", AntiAliasMode::FXAA_Medium},
|
||||
{"fxaa high", AntiAliasMode::FXAA_High},
|
||||
{"smaa low", AntiAliasMode::SMAA_Low},
|
||||
{"smaa medium", AntiAliasMode::SMAA_Medium},
|
||||
{"smaa high", AntiAliasMode::SMAA_High},
|
||||
{"smaa ultra", AntiAliasMode::SMAA_Ultra},
|
||||
};
|
||||
|
||||
// Look up the value in the map
|
||||
auto it = aaModeMap.find(value);
|
||||
if (it != aaModeMap.end()) {
|
||||
Gr_aa_mode = it->second; // Set the mode
|
||||
} else {
|
||||
error_display(0, "%s is not a valid anti aliasing setting", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
|
||||
std::pair<const char*, int>{"Anti Aliasing", 1752},
|
||||
std::pair<const char*, int>{"Controls the anti aliasing mode of the engine.", 1753})
|
||||
@@ -631,40 +451,12 @@ static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.
|
||||
{AntiAliasMode::SMAA_Medium, {"SMAA Medium", 1685}},
|
||||
{AntiAliasMode::SMAA_High, {"SMAA High", 1686}},
|
||||
{AntiAliasMode::SMAA_Ultra, {"SMAA Ultra", 1687}}})
|
||||
.default_func([]() { return Gr_aa_mode; } )
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.parser(parse_anti_aliasing_func)
|
||||
.finish();
|
||||
|
||||
extern int Cmdline_msaa_enabled;
|
||||
|
||||
static void parse_msaa_func()
|
||||
{
|
||||
SCP_string value;
|
||||
stuff_string(value, F_NAME);
|
||||
|
||||
// Convert to lowercase
|
||||
SCP_string lowercase_value = value;
|
||||
SCP_tolower(lowercase_value);
|
||||
|
||||
// Map valid values to MSAA settings
|
||||
static const std::unordered_map<std::string, int> msaaMap = {
|
||||
{"off", 0},
|
||||
{"4 samples", 4},
|
||||
{"8 samples", 8},
|
||||
//{"16 samples", 16},
|
||||
};
|
||||
|
||||
// Look up the value in the map
|
||||
auto it = msaaMap.find(lowercase_value);
|
||||
if (it != msaaMap.end()) {
|
||||
Cmdline_msaa_enabled = it->second; // Set the MSAA level
|
||||
} else {
|
||||
error_display(0, "%s is not a valid MSAA setting", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples",
|
||||
std::pair<const char*, int>{"Multisample Anti Aliasing", 1758},
|
||||
std::pair<const char*, int>{"Controls whether multisample anti asliasing is enabled, and with how many samples", 1759})
|
||||
@@ -672,11 +464,11 @@ static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamp
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, {"Off", 1693}},
|
||||
{4, {"4 Samples", 1694}},
|
||||
{8, {"8 Samples", 1695}}})
|
||||
.default_func([]() { return Cmdline_msaa_enabled; } )
|
||||
{8, {"8 Samples", 1695}},
|
||||
{16, {"16 Samples", 1696}}})
|
||||
.default_val(0)
|
||||
.bind_to_once(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.parser(parse_msaa_func)
|
||||
.finish();
|
||||
|
||||
bool gr_is_fxaa_mode(AntiAliasMode mode)
|
||||
@@ -687,14 +479,6 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
return mode == AntiAliasMode::SMAA_Low || mode == AntiAliasMode::SMAA_Medium || mode == AntiAliasMode::SMAA_High || mode == AntiAliasMode::SMAA_Ultra;
|
||||
}
|
||||
|
||||
static void parse_post_processing_func()
|
||||
{
|
||||
bool value;
|
||||
stuff_boolean(&value);
|
||||
|
||||
Gr_post_processing_enabled = value;
|
||||
}
|
||||
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.PostProcessing",
|
||||
@@ -702,38 +486,23 @@ static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.
|
||||
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_post_processing_enabled; })
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.parser(parse_post_processing_func)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static void parse_vsync_func()
|
||||
{
|
||||
bool value;
|
||||
stuff_boolean(&value);
|
||||
|
||||
Gr_enable_vsync = value;
|
||||
}
|
||||
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync",
|
||||
std::pair<const char*, int>{"Vertical Sync", 1766},
|
||||
std::pair<const char*, int>{"Controls how the engine does vertical synchronization", 1767})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_enable_vsync; })
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.parser(parse_vsync_func)
|
||||
.finish();
|
||||
|
||||
void removeVSyncOption()
|
||||
{
|
||||
options::OptionsManager::instance()->removeOption(VSyncOption);
|
||||
}
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
|
||||
|
||||
// Forward definitions
|
||||
@@ -1741,21 +1510,9 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
if (Cmdline_enable_vr) {
|
||||
// in VR mode, so set resolution using VR values
|
||||
// and hide/disable the default resolution option
|
||||
auto res = ResolutionVROption->getValue();
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
removeResolutionOption();
|
||||
} else {
|
||||
// in non-VR mode, so set resolution using default values
|
||||
// and hide/disable the VR resolution option
|
||||
auto res = ResolutionOption->getValue();
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
removeResolutionVROption();
|
||||
}
|
||||
auto res = ResolutionOption->getValue();
|
||||
width = res.width;
|
||||
height = res.height;
|
||||
} else if ( !Is_standalone ) {
|
||||
// We cannot continue without this, quit, but try to help the user out first
|
||||
ptr = os_config_read_string(nullptr, NOX("VideocardFs2open"), nullptr);
|
||||
@@ -1921,19 +1678,19 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
height = 800;
|
||||
depth = 32;
|
||||
center_aspect_ratio = -1.0f;
|
||||
Cmdline_window = true;
|
||||
Cmdline_window = 1;
|
||||
#elif defined(_FORCE_DEBUG_1024)
|
||||
width = 1024;
|
||||
height = 768;
|
||||
depth = 32;
|
||||
center_aspect_ratio = -1.0f;
|
||||
Cmdline_window = true;
|
||||
Cmdline_window = 1;
|
||||
#elif defined(_FORCE_DEBUG_640)
|
||||
width = 640;
|
||||
height = 480;
|
||||
depth = 32;
|
||||
center_aspect_ratio = -1.0f;
|
||||
Cmdline_window = true;
|
||||
Cmdline_window = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2117,29 +1874,7 @@ void gr_set_color( int r, int g, int b )
|
||||
|
||||
void gr_set_color_fast(const color *dst)
|
||||
{
|
||||
if (gr_lua_context_active()) {
|
||||
gr_lua_screen.current_color = *dst;
|
||||
} else {
|
||||
gr_screen.current_color = *dst;
|
||||
}
|
||||
}
|
||||
|
||||
//Compares the RGBA values of two colors. Returns true if the colors are identical
|
||||
bool gr_compare_color_values(const color& clr1, const color& clr2)
|
||||
{
|
||||
if (clr1.red != clr2.red) {
|
||||
return false;
|
||||
}
|
||||
if (clr1.green != clr2.green) {
|
||||
return false;
|
||||
}
|
||||
if (clr1.blue != clr2.blue) {
|
||||
return false;
|
||||
}
|
||||
if (clr1.alpha != clr2.alpha) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
gr_screen.current_color = *dst;
|
||||
}
|
||||
|
||||
// shader functions
|
||||
@@ -2161,7 +1896,7 @@ void gr_set_shader(shader *shade)
|
||||
}
|
||||
|
||||
// new bitmap functions
|
||||
void gr_bitmap(int _x, int _y, int resize_mode, bool mirror, float scale_factor)
|
||||
void gr_bitmap(int _x, int _y, int resize_mode)
|
||||
{
|
||||
GR_DEBUG_SCOPE("2D Bitmap");
|
||||
|
||||
@@ -2175,11 +1910,6 @@ void gr_bitmap(int _x, int _y, int resize_mode, bool mirror, float scale_factor)
|
||||
|
||||
bm_get_info(gr_screen.current_bitmap, &_w, &_h, NULL, NULL, NULL);
|
||||
|
||||
if (scale_factor != 1.0f) {
|
||||
_w = static_cast<int>(_w * scale_factor);
|
||||
_h = static_cast<int>(_h * scale_factor);
|
||||
}
|
||||
|
||||
x = i2fl(_x);
|
||||
y = i2fl(_y);
|
||||
w = i2fl(_w);
|
||||
@@ -2194,22 +1924,22 @@ void gr_bitmap(int _x, int _y, int resize_mode, bool mirror, float scale_factor)
|
||||
|
||||
verts[0].screen.xyw.x = x;
|
||||
verts[0].screen.xyw.y = y;
|
||||
verts[0].texture_position.u = mirror ? 1.0f : 0.0f;
|
||||
verts[0].texture_position.u = 0.0f;
|
||||
verts[0].texture_position.v = 0.0f;
|
||||
|
||||
verts[1].screen.xyw.x = x + w;
|
||||
verts[1].screen.xyw.y = y;
|
||||
verts[1].texture_position.u = mirror ? 0.0f : 1.0f;
|
||||
verts[1].texture_position.u = 1.0f;
|
||||
verts[1].texture_position.v = 0.0f;
|
||||
|
||||
verts[2].screen.xyw.x = x + w;
|
||||
verts[2].screen.xyw.y = y + h;
|
||||
verts[2].texture_position.u = mirror ? 0.0f : 1.0f;
|
||||
verts[2].texture_position.u = 1.0f;
|
||||
verts[2].texture_position.v = 1.0f;
|
||||
|
||||
verts[3].screen.xyw.x = x;
|
||||
verts[3].screen.xyw.y = y + h;
|
||||
verts[3].texture_position.u = mirror ? 1.0f : 0.0f;
|
||||
verts[3].texture_position.u = 0.0f;
|
||||
verts[3].texture_position.v = 1.0f;
|
||||
|
||||
// turn off zbuffering
|
||||
@@ -3197,7 +2927,7 @@ static void make_gamma_ramp(float gamma, ushort* ramp)
|
||||
|
||||
for (x = 0; x < 256; x++) {
|
||||
val = (pow(x / 255.0, g) * 65535.0 + 0.5);
|
||||
CLAMP(val, 0., 65535.);
|
||||
CLAMP(val, 0, 65535);
|
||||
|
||||
base_ramp[x] = (ushort)val;
|
||||
}
|
||||
@@ -3205,7 +2935,7 @@ static void make_gamma_ramp(float gamma, ushort* ramp)
|
||||
for (y = 0; y < 3; y++) {
|
||||
for (x = 0; x < 256; x++) {
|
||||
val = (base_ramp[x] * 2) - Gr_original_gamma_ramp[x + y * 256];
|
||||
CLAMP(val, 0., 65535.);
|
||||
CLAMP(val, 0, 65535);
|
||||
|
||||
ramp[x + y * 256] = (ushort)val;
|
||||
}
|
||||
@@ -3273,9 +3003,7 @@ bool gr_is_viewport_window()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Cmdline_enable_vr) {
|
||||
return true;
|
||||
} else if (Using_in_game_options) {
|
||||
if (Using_in_game_options) {
|
||||
switch (Gr_configured_window_state)
|
||||
{
|
||||
case os::ViewportState::Windowed:
|
||||
@@ -3293,11 +3021,3 @@ bool gr_is_viewport_window()
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gr_lua_context_active() {
|
||||
if (gr_lua_screen.force_fso_context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return gr_lua_screen.active;
|
||||
}
|
||||
+2
-39
@@ -935,42 +935,6 @@ typedef struct screen {
|
||||
std::function<bool()> gf_openxr_flip;
|
||||
} screen;
|
||||
|
||||
/**
|
||||
* @brief Scripting context render values
|
||||
*/
|
||||
typedef struct lua_screen {
|
||||
bool active = false;
|
||||
bool force_fso_context = false;
|
||||
color current_color = {
|
||||
0, // is_alphacolor
|
||||
0, // alphacolor
|
||||
0, // magic
|
||||
255, // red
|
||||
255, // green
|
||||
255, // blue
|
||||
255, // alpha
|
||||
0, // ac_type
|
||||
0 // raw8
|
||||
};
|
||||
float line_width = 1.0f;
|
||||
int current_font_index = 0;
|
||||
} lua_screen;
|
||||
|
||||
extern lua_screen gr_lua_screen;
|
||||
|
||||
bool gr_lua_context_active();
|
||||
|
||||
// Macros to easily choose been which context to use for color and line width
|
||||
// Note that font is handled slightly differently for the normal game context by using it's own global in the FontManager namespace
|
||||
// So FontManager::getCurrentFontIndex() is effectively its own macro
|
||||
|
||||
// Gets the current color between the game context and the lua context if active
|
||||
#define GR_CURRENT_COLOR (gr_lua_context_active() ? gr_lua_screen.current_color : gr_screen.current_color)
|
||||
|
||||
// Gets the current line width between the game context and the lua contet if active
|
||||
#define GR_CURRENT_LINE_WIDTH (gr_lua_context_active() ? gr_lua_screen.line_width : gr_screen.line_width)
|
||||
|
||||
|
||||
// handy macro
|
||||
#define GR_MAYBE_CLEAR_RES(bmap) do { int bmw = -1; int bmh = -1; if(bmap != -1){ bm_get_info( bmap, &bmw, &bmh, NULL, NULL, NULL); if((bmw != gr_screen.max_w) || (bmh != gr_screen.max_h)){gr_clear();} } else {gr_clear();} } while(false);
|
||||
|
||||
@@ -1044,7 +1008,7 @@ extern void gr_printf_menu_zoomed( int x, int y, const char * format, SCP_FORMAT
|
||||
extern void gr_printf_no_resize( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4);
|
||||
|
||||
// Returns the size of the string in pixels in w and h
|
||||
extern void gr_get_string_size( int *w, int *h, const char * text, float scaleMultiplier = 1.0f, size_t len = std::string::npos);
|
||||
extern void gr_get_string_size( int *w, int *h, const char * text, size_t len = std::string::npos );
|
||||
|
||||
// Returns the height of the current font
|
||||
extern int gr_get_font_height();
|
||||
@@ -1347,14 +1311,13 @@ void gr_init_color(color *c, int r, int g, int b);
|
||||
void gr_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type = AC_TYPE_HUD );
|
||||
void gr_set_color( int r, int g, int b );
|
||||
void gr_set_color_fast(const color *dst);
|
||||
bool gr_compare_color_values(const color& clr1, const color& clr2);
|
||||
|
||||
// shader functions
|
||||
void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c);
|
||||
void gr_set_shader(shader *shade);
|
||||
|
||||
// new bitmap functions
|
||||
void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f);
|
||||
void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL);
|
||||
void gr_bitmap_uv(int _x, int _y, int _w, int _h, float _u0, float _v0, float _u1, float _v1, int resize_mode = GR_RESIZE_FULL);
|
||||
|
||||
// special function for drawing polylines. this function is specifically intended for
|
||||
|
||||
@@ -87,29 +87,6 @@ void hdr_color::set_rgb(const int* const new_rgb)
|
||||
this->set_rgb(new_rgb[0], new_rgb[1], new_rgb[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets RGBAI values from five 0.0-1.0 floats
|
||||
*/
|
||||
void hdr_color::set_rgbai(float new_r, float new_g, float new_b, float new_a, float new_i)
|
||||
{
|
||||
this->red = new_r;
|
||||
this->green = new_g;
|
||||
this->blue = new_b;
|
||||
this->alpha = new_a;
|
||||
this->intensity = new_i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Multiplies RGBAI values with five 0.0-1.0 floats
|
||||
*/
|
||||
void hdr_color::multiply_rgbai(float r_mult, float g_mult, float b_mult, float a_mult, float i_mult)
|
||||
{
|
||||
this->red *= r_mult;
|
||||
this->green *= g_mult;
|
||||
this->blue *= b_mult;
|
||||
this->alpha *= a_mult;
|
||||
this->intensity *= i_mult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retreives unmultiplied 0.0f-1.0f color component.
|
||||
|
||||
@@ -20,8 +20,6 @@ public:
|
||||
void set_rgb(const int new_r,const int new_g,const int new_b);
|
||||
void set_rgb(const color* const new_rgb);
|
||||
void set_rgb(const int* const new_rgb);
|
||||
void set_rgbai(const float new_r,const float new_g,const float new_b,const float new_a = 1.f,const float new_i = 1.f);
|
||||
void multiply_rgbai(const float r_mult,const float g_mult,const float b_mult,const float a_mult = 1.f,const float i_mult = 1.f);
|
||||
|
||||
float r() const;
|
||||
float r(const float in);
|
||||
|
||||
@@ -187,7 +187,7 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
|
||||
if(ga->use_hud_color)
|
||||
bpp = 8;
|
||||
if (ga->ani.animation == nullptr) {
|
||||
ga->ani.animation = anim_load(ga->filename, CF_TYPE_ANY);
|
||||
ga->ani.animation = anim_load(ga->filename, CF_TYPE_ANY, 0);
|
||||
}
|
||||
if (ga->ani.instance == nullptr) {
|
||||
ga->ani.instance = init_anim_instance(ga->ani.animation, bpp);
|
||||
@@ -697,7 +697,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime,
|
||||
* @param [in] y 2D screen y co-ordinate to render at
|
||||
* @param [in] menu select if this is rendered in menu screen, or fullscreen
|
||||
*/
|
||||
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu, const generic_extras *ge, float scale_factor)
|
||||
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu, const generic_extras *ge)
|
||||
{
|
||||
if ((ge != nullptr) && (ga->use_hud_color == true)) {
|
||||
Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)");
|
||||
@@ -719,11 +719,11 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
|
||||
ga->previous_frame = ga->current_frame;
|
||||
|
||||
if(ga->use_hud_color) {
|
||||
gr_aabitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL), false, scale_factor);
|
||||
gr_aabitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else {
|
||||
if (ge == nullptr) {
|
||||
gr_bitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL), false, scale_factor);
|
||||
gr_bitmap(x, y, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else if (ge->draw == true) {
|
||||
// currently only for lua streaminganim objects
|
||||
|
||||
Loaded 100 of 735 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user