Compare commits

..
Author SHA1 Message Date
JohnAFernandez 3043e1ee2d Update release make to point to 24.0.1 2024-05-11 23:04:13 -04:00
mjn-mixael 7a7841c30a Do not unload debrief bitmaps in API mode 2024-05-11 23:02:38 -04:00
JohnAFernandez d5653674f1 Merge branch 'pr_24_0_1' of https://github.com/scp-fs2open/fs2open.github.com into pr_24_0_1 2024-05-11 22:58:24 -04:00
JohnAFernandez d74627ba61 Remove version_override.cmake
This will hopefully allow the point release to succeed.
2024-04-17 16:36:13 -04:00
JohnAFernandez ed20982b32 Update Version Override 2024-03-25 23:59:39 -04:00
JohnAFernandez e21cc10c5e Update Release Mako with Previous Thread 2024-03-25 22:54:52 -04:00
Asteroth b5fe16081d fix an issue with animation directions 2024-03-25 22:54:52 -04:00
mjn-mixael 41bff809e3 Don't init the debrief ui in API mode 2024-03-25 22:54:52 -04:00
mjn-mixael f119f3d370 Default post processing to on because so many things require it 2024-03-25 22:54:52 -04:00
Joshua Glatt a90a0a55bd Handle container data correctly with eval_num() (#6031) 2024-03-25 22:54:52 -04:00
Joshua Glatt d08d8b4b02 fix crash when right-clicking on container modifier (#6030) 2024-03-25 22:54:52 -04:00
Mike Nelson f1292ad15a Push back instead of direct assignment (#6024)
* push back instead of direct assignment

* remove i
2024-03-25 22:54:51 -04:00
wookieejedi eb911c8ca2 Fix CTD with HUD Preset Switching (#6022)
* Fix CTD with HUD Preset Switching

After #5302 it was discoved that pressing the `Next` button in the HUD presets would cause a CTD.

Thanks for Lafiel for figuring this out
`If HC_current_file is HC_preset_filenames.size() - 1, then it'll oob on a vector access.`

Testing this PR fixes that crash.

* use static cast
2024-03-25 22:54:51 -04:00
MageKing17 125de7f131 Fix SSM strikes with a variable count.
In #2464, a somewhat hard-to-understand equation involving taking the modulo of a random number was replaced with a function that would do those calculations instead. The problem is that the function performed the *entire* formula, while the code it replaced was only operating on the *difference* between the two numbers. Fortunately, this is as easy to fix as changing a `+=` into just an `=`.
2024-03-25 22:54:51 -04:00
Birk Magnussen 78d0bddbe1 Add comment on MAX_OBJECTS 2024-03-25 22:54:51 -04:00
Birk Magnussen b009991fae Increase collision pair cache bitshift 2024-03-25 22:54:51 -04:00
Goober5000 f2806dc77a fix "this ship name is already in use" bug
This rather insidious FRED bug was all down to an improper check for the current ship.  It is possible for multiple objects of different types to be selected at the same time.  If, for example, a waypoint and ship are selected, and the waypoint was selected first, the waypoint will be what `cur_object_index` refers to.  Since the ship is the one and only ship selected, it will be what `single_ship` refers to.  Therefore, to avoid flagging its own ship name as a duplicate, the loop should exclude the single ship, not the current object.

The bug can be reliably triggered by selecting a waypoint, then adding a ship to the selection, then switching the focus to another application and back to FRED.  This finally squashes the bug.
2024-03-14 17:03:17 -04:00
SirKnightly 6cbf0fbbf8 Automated build commit 2024-02-26 02:47:29 +00:00
1056 changed files with 78089 additions and 71462 deletions

No files matched your search

+1 -12
View File
@@ -4,28 +4,20 @@ modernize-*,\
-modernize-avoid-c-arrays,\
-modernize-make-unique,\
-modernize-raw-string-literal,\
-modernize-use-default-member-init,\
-modernize-use-nodiscard,\
-modernize-use-trailing-return-type,\
-modernize-use-using,\
performance-*,\
-performance-no-int-to-ptr,\
-performance-type-promotion-in-math-fn,\
misc-*,\
-misc-include-cleaner,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-no-recursion,\
-misc-non-private-member-variables-in-classes,\
-misc-static-assert,\
-misc-unused-parameters,\
-misc-use-anonymous-namespace,\
readability-*,\
-readability-avoid-const-params-in-decls,\
-readability-else-after-return,\
-readability-function-cognitive-complexity,\
-readability-function-size,\
-readability-identifier-length,\
-readability-identifier-naming,\
-readability-implicit-bool-conversion,\
-readability-inconsistent-declaration-parameter-name,\
@@ -37,13 +29,10 @@ readability-*,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
AnalyzeTemporaryDtors: false
CheckOptions:
- key: 'misc-assert-side-effect.AssertMacros'
value: 'assert,Assert,Assertion'
- key: 'misc-const-correctness.AnalyzeValues'
value: 'false'
- key: 'misc-const-correctness.TransformValues'
value: 'false'
- key: 'modernize-use-emplace.ContainersWithPushBack'
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
- key: 'readability-braces-around-statements.ShortStatementLines'
+21 -36
View File
@@ -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
+25 -40
View File
@@ -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 }}
+53
View File
@@ -0,0 +1,53 @@
name: Publish Standalone docker image
on:
push:
tags:
- 'nightly_*'
- 'release_*'
jobs:
build_images:
if: github.repository == 'scp-fs2open/fs2open.github.com'
strategy:
matrix:
configuration: [FastDebug, Release]
include:
- configuration: FastDebug
tag_suffix: -debug
- configuration: Release
tag_suffix: ""
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v1
with:
images: ghcr.io/scp-fs2open/standalone_server
tag-latest: false
- name: Login to GitHub Docker Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./docker/standalone/Dockerfile
push: true
tags: ${{ steps.docker_meta.outputs.tags }}${{ matrix.tag_suffix }}
labels: ${{ steps.docker_meta.outputs.labels }}
build-args: |
build_type=${{ matrix.configuration }}
+17 -17
View File
@@ -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
+1 -1
View File
@@ -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
+8 -14
View File
@@ -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
+3 -8
View File
@@ -18,9 +18,8 @@ env:
jobs:
build:
name: Build FSO With Coverity Wrapper
if: github.repository == 'scp-fs2open/fs2open.github.com'
runs-on: ${{ matrix.config.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-71099c9
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
strategy:
fail-fast: false
matrix:
@@ -48,7 +47,7 @@ jobs:
- name: Configure CMake for FSO
env:
CONFIGURATION: Release
COMPILER: gcc-9
compiler: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
@@ -66,8 +65,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
View File
@@ -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
View File
@@ -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}")
+1 -8
View File
@@ -5,8 +5,6 @@ set -e
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
git config --global --add safe.directory "$GITHUB_WORKSPACE"
COMMIT_RANGE=$1..$2
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
@@ -18,13 +16,8 @@ fi
# branch
BASE_COMMIT=$(git merge-base $1 $2)
# Note: Manually passing in the Vulkan flags that are normally provided by cmake (but are not so, here), to ensure
# that the source files are checked with the actual configuration used.
echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-extra-arg="-DWITH_VULKAN" \
-extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \
-extra-arg="-DVK_NO_PROTOTYPES" \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+4 -1
View File
@@ -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
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+4 -5
View File
@@ -9,7 +9,7 @@ PLACEHOLDER
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods, we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. Any features listed under Deprecations will be removed or changed when the target version of a mod is at least the version released in this post.
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=99015.0]23.2.1 Release Thread[/url][/size]
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=99238.0]24.0.1 Release Thread[/url][/size]
Launchers, if you don't have one already:
[b]All platforms: [/b] For every day use, we recommend [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url], an integrated solution for downloading and launching mods.
@@ -44,10 +44,9 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
Don't want to deal with that? Use [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url] and it will download the best build specifically for your PC!
[/hidden]
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux[/size][/color]
[size=8pt]Compiled with Ubuntu 20.04 LTS, GCC 9[/size]
[b]x86_64:[/b] ${build(groups["Linux"].subFiles["x86_64"])}
[b]arm64:[/b] ${build(groups["Linux"].subFiles["arm64"])}
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
${build(groups["Linux"].mainFile)}
These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
+1 -1
View File
@@ -1,3 +1,3 @@
Mako==1.2.2
requests==2.32.0
requests==2.31.0
semantic-version==2.8.5
+14 -36
View File
@@ -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)
-16
View File
@@ -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
View File
@@ -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}"
)
+4 -27
View File
@@ -8,31 +8,8 @@ else()
set(IS_64BIT FALSE)
endif()
set(IS_ARM64 FALSE)
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
else()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
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()
set(IS_ARM64 FALSE)
endif()
+1 -2
View File
@@ -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)
-1
View File
@@ -10,7 +10,6 @@
#cmakedefine01 IS_64BIT
#cmakedefine01 IS_ARM64
#cmakedefine01 IS_RISCV
#cmakedefine01 SCP_HAVE_STRCASECMP
#cmakedefine01 SCP_HAVE_STRNCASECMP
+1 -1
View File
@@ -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")
+9 -38
View File
@@ -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}")
+5 -46
View File
@@ -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}")
+39 -25
View File
@@ -46,13 +46,9 @@ target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_STATIC_LINKER_FLAGS "")
if(NOT IS_ARM64)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
endif()
# Release
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
@@ -95,31 +91,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
-49
View File
@@ -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
View File
@@ -6,7 +6,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 24)
set_if_not_defined(FSO_VERSION_MAJOR 23)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
@@ -35,13 +35,7 @@ ELSE()
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
ENDIF()
IF(IS_RISCV)
IF(IS_64BIT)
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv64")
ELSE()
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_riscv32")
ENDIF()
ELSEIF(IS_ARM64)
IF(IS_ARM64)
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
ELSEIF(IS_64BIT)
# This is a 64-bit builds
+11 -12
View File
@@ -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)
+1 -1
View File
@@ -47,7 +47,7 @@ ProgramInstance::ProgramInstance(const actions::Program* program) : _program(pro
ProgramState ProgramInstance::step()
{
if (!_locals.host.isValid()) {
if (!_locals.host.IsValid()) {
return ProgramState::Done;
}
+3 -3
View File
@@ -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,
+4 -4
View File
@@ -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
+5 -3
View File
@@ -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!
+8 -8
View File
@@ -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 {
+6 -4
View File
@@ -26,8 +26,10 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
vec3d local_pos;
matrix local_orient;
if (locals.hostSubobject != -1) {
auto pmi = object_get_model_instance(locals.host.objp());
Assertion(pmi != nullptr, "Model instances are required if a host subobject is specified.");
auto instance = object_get_model_instance(locals.host.objp);
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
model_instance_local_to_global_point_orient(&local_pos,
@@ -45,8 +47,8 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
vec3d global_pos;
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp()->orient);
global_pos += locals.host.objp()->pos;
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
global_pos += locals.host.objp->pos;
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
+10 -12
View File
@@ -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);
@@ -602,8 +601,7 @@ float ai_get_weapon_speed(const ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
// function to change rearm status for ai ships (called from sexpression code)
extern void ai_set_good_rearm_time( int team, int time );
extern void ai_set_bad_rearm_time(int team, int time);
extern void ai_set_rearm_status( int team, int new_status );
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, const char *shipname );
extern void ai_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
@@ -636,6 +634,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
bool test_line_of_sight(const vec3d* from, const vec3d* to, SCP_unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
#endif
+3 -23
View File
@@ -32,8 +32,6 @@ namespace AI {
Unload_primaries, // Fire primaries as fast as possible!
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
Waypoints_no_formation, // wont get into formation when running waypoints as part of a wing
NUM_VALUES
};
@@ -43,7 +41,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 +99,6 @@ namespace AI {
Fix_heat_seeker_stealth_bug,
Fix_linked_primary_bug,
Fix_ramming_stationary_targets_bug,
Fix_avoid_shockwave_bugs, // a) waiting until a homing weapon actually homes before evading;
// b) picking the correct expected impact position for capships;
// c) not clearing shockwave_object for ships;
// d) checking the explosion damage of the correct ship
Force_beam_turret_fov,
Free_afterburner_use,
Glide_decay_requires_thrust,
@@ -141,11 +135,10 @@ namespace AI {
All_nonshielded_ships_can_manage_ets,
Fightercraft_nonshielded_ships_can_manage_ets,
Ships_playing_dead_dont_manage_ets,
Better_combat_collision_avoidance,
Better_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,
@@ -164,20 +157,7 @@ namespace AI {
Whackable_debris,
Whackable_asteroids,
Dynamic_goals_afterburn_hard,
Player_orders_afterburn_hard,
Hudsquadmsg_tactical_disarm_disable,
Align_to_target_when_guarding_still,
Debris_respects_big_damage,
Dont_limit_change_in_speed_due_to_physics_whack,
Guards_ignore_protected_attackers,
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
};
+7 -116
View File
@@ -184,14 +184,6 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Max Beam Friendly Fire Damage:"))
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
if (optional_string("$Max Weapon Friendly Fire Damage:")) {
parse_float_list(profile->weapon_friendly_damage_cap, NUM_SKILL_LEVELS);
}
if (optional_string("$Max Weapon Self Damage:")) {
parse_float_list(profile->weapon_self_damage_cap, NUM_SKILL_LEVELS);
}
if (optional_string("$Player Countermeasure Life Scale:"))
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
@@ -377,7 +369,7 @@ void parse_ai_profiles_tbl(const char *filename)
}
if (optional_string("$Detail Distance Multiplier:"))
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_VALUE + 1);
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1);
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships);
@@ -479,20 +471,10 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
if (optional_string("$exact los minimum detection radius:")) {
stuff_float(&profile->los_min_detection_radius);
}
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
set_flag(profile, "$debris damage respects 'big damage' flag:", AI::Profile_Flags::Debris_respects_big_damage);
set_flag(profile, "$don't limit change in speed due to physics whack:", AI::Profile_Flags::Dont_limit_change_in_speed_due_to_physics_whack);
set_flag(profile, "$guards ignore protected attackers:", AI::Profile_Flags::Guards_ignore_protected_attackers);
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -582,25 +564,11 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_combat_collision_avoidance);
if (optional_string("+combat collision avoidance aggression for fightercraft:")) {
stuff_float(&profile->better_collision_avoid_aggression_combat);
}
set_flag(profile, "$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);
@@ -657,70 +625,15 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
set_flag(profile, "$player orders afterburn hard:", AI::Profile_Flags::Player_orders_afterburn_hard);
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
if (optional_string("$rotation factor multiplier for player collisions:")) {
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
}
set_flag(profile, "$fix avoid-shockwave bugs:", AI::Profile_Flags::Fix_avoid_shockwave_bugs);
set_flag(profile, "$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
if (saved_Mp && (saved_Mp == Mp))
{
char tmp[60];
memset(tmp, 0, 60);
strncpy(tmp, Mp, 59);
mprintf(("WARNING: Unrecognized parameter in %s: %s\n", filename, tmp));
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
Mp++;
}
@@ -794,7 +707,6 @@ void ai_profile_t::reset()
flags.reset();
los_min_detection_radius = 10.0f;
ai_path_mode = AI_PATH_MODE_NORMAL;
subsystem_path_radii = 0;
bay_arrive_speed_mult = 1.0f;
@@ -802,17 +714,6 @@ void ai_profile_t::reset()
second_order_lead_predict_factor = 0;
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
turret_target_recheck_time = 2000.0f;
rot_fac_multiplier_ply_collisions = 0.0f;
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;
@@ -835,12 +736,10 @@ void ai_profile_t::reset()
shield_energy_scale[i] = 0;
afterburner_recharge_scale[i] = 0;
player_damage_scale[i] = 0;
player_damage_inflicted_scale[i] = 0;
player_damage_inflicted_scale[i] = 0;
subsys_damage_scale[i] = 0;
beam_friendly_damage_cap[i] = -1.f;
weapon_friendly_damage_cap[i] = -1.f;
weapon_self_damage_cap[i] = -1.f;
beam_friendly_damage_cap[i] = 0;
turn_time_scale[i] = 0;
glide_attack_percent[i] = 0;
circle_strafe_percent[i] = 0;
@@ -871,7 +770,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;
}
@@ -920,12 +819,4 @@ void ai_profile_t::reset()
if (mod_supports_version(23, 4, 0)) {
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
}
if (mod_supports_version(24, 2, 0)) {
flags.set(AI::Profile_Flags::Debris_respects_big_damage);
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
}
if (mod_supports_version(25, 0, 0)) {
flags.set(AI::Profile_Flags::Fix_avoid_shockwave_bugs);
}
}
+1 -27
View File
@@ -57,8 +57,6 @@ public:
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
float weapon_friendly_damage_cap[NUM_SKILL_LEVELS];
float weapon_self_damage_cap[NUM_SKILL_LEVELS];
float turn_time_scale[NUM_SKILL_LEVELS]; // speed at which enemy ships turn
float glide_attack_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "glide attack" move
float circle_strafe_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "circle strafe" move
@@ -99,10 +97,7 @@ public:
// Player-specific autoaim FOV override
float player_autoaim_fov[NUM_SKILL_LEVELS];
float detail_distance_mult[MAX_DETAIL_VALUE + 1]; //MAX_DETAIL_VALUE really needs to be 4
// minimum radius for the line-of-sight (los) detection --wookieejedi
float los_min_detection_radius;
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
int ai_path_mode;
@@ -123,27 +118,6 @@ public:
// how often turrets shoulds check for new targets, milliseconds
float turret_target_recheck_time;
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
float rot_fac_multiplier_ply_collisions;
// Collision avoidance options --developed by asteroth, exposed by wookieejedi
// Velocity / turn rate gives us a vector which represents the minimum 'bug out' distance.
// However this will be a significant underestimate, it doesn't take into account acceleration
// with regards to its turn speed, nor already existing rotvel, nor the angular distance
// to the particular avoidance vector it comes up with.
// These would significantly complicate the calculation, so for now, it is all bundled into these magic numbers.
float better_collision_avoid_aggression_combat;
float better_collision_avoid_aggression_guard;
// AI strafing options --wookieejedi
float standard_strafe_when_below_speed; // Speed at which standard strafing large ships is possibly triggered
float strafe_retreat_box_dist; // Distance beyond the bounding box to retreat to strafing point
float strafe_max_unhit_time; // Maximum amount of time to stay in strafe mode if not hit
// AI guard options --wookieejedi
float guard_big_orbit_above_target_radius; // Radius of guardee that triggers ai_big_guard()
float guard_big_orbit_max_speed_percent; // Max percent of forward speed that is used in ai_big_guard()
void reset();
};
+29 -32
View File
@@ -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]);
}
}
}
@@ -1933,10 +1933,7 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
weapon_objp = &Objects[weapon_objnum];
Assert(weapon_objp->type == OBJ_WEAPON);
if (weapon_objp->parent < 0) {
return 0;
}
Assert(weapon_objp->parent < MAX_OBJECTS);
Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
parent_objp = &Objects[weapon_objp->parent];
if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
return 0;
+133 -319
View File
File diff suppressed because it is too large. Load diff
+105 -165
View File
@@ -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);
}
}
@@ -755,9 +751,6 @@ void ai_add_goal_sub_player(ai_goal_type type, ai_goal_mode mode, int submode, c
if ( target_name != NULL )
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
if (The_mission.ai_profile->flags[AI::Profile_Flags::Player_orders_afterburn_hard])
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
// special case certain orders from player so that ships continue to do the right thing
@@ -770,7 +763,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 +815,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 +830,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 +856,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 +877,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 +901,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 +929,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 +947,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 +957,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 +965,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 +995,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 +1013,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 +1052,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 +1088,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 +1138,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 +1147,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 +1224,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 +1242,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 +1366,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 +1378,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 +1392,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 +1399,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 +1409,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 +1424,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 +1470,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 +1602,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 +1857,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 +2341,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
View File
@@ -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 );
+1 -1
View File
@@ -389,7 +389,7 @@ ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::USERDATA) {
scripting::api::enum_h enumData;
retVals[0].getValue(scripting::api::l_Enum.Get(&enumData));
if (!enumData.isValid()) {
if (!enumData.IsValid()) {
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
return ai_achievability::ACHIEVABLE;
}
+161 -280
View File
@@ -6,7 +6,6 @@
#include "debugconsole/console.h"
#include "freespace.h"
#include "gamesnd/gamesnd.h"
#include "gamesequence/gamesequence.h"
#include "globalincs/linklist.h"
#include "globalincs/systemvars.h"
#include "iff_defs/iff_defs.h"
@@ -26,7 +25,6 @@
#include "weapon/muzzleflash.h"
#include "weapon/swarm.h"
#include "weapon/weapon.h"
#include "utils/modular_curves.h"
#include <climits>
@@ -135,7 +133,7 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
break;
case OBJ_ASTEROID:
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
break;
default:
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
@@ -1217,7 +1215,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
}
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
// we might not need to calculate this
if (!gvec)
@@ -1225,7 +1222,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
if (use_angles) {
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
vm_vec_normalize(gvec);
} else {
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
vm_vec_normalized_dir(gvec, targetp, gpos);
@@ -1334,17 +1330,16 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
auto pmi = model_get_instance(shipp->model_instance_num);
auto pm = model_get(pmi->model_num);
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
if (ss->turret_enemy_objnum != -1) {
model_subsystem *tp = ss->system_info;
if (!in_lab && ss->turret_enemy_objnum != -1) {
model_subsystem* tp = ss->system_info;
// Get the normalized dir between the turret and the predicted enemy position.
// If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
vec3d v2e;
//Get the normalized dir between the turret and the predicted enemy position.
//If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
vec3d v2e;
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
bool in_fov;
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
if (in_fov) {
@@ -1352,15 +1347,8 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
}
} else if (!in_lab && (ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
} else if (in_lab) {
// in the lab, if predicted_enemy_pos is zero vec, then go to initial, else try to aim at the target
if (predicted_enemy_pos != nullptr && *predicted_enemy_pos == vmd_zero_vector) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
} else {
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
}
}
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
@@ -1550,27 +1538,22 @@ bool turret_should_pick_new_target(ship_subsys *turret)
/**
* Set the next fire timestamp for a turret, based on weapon type and ai class
*/
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip, const WeaponLaunchCurveData& launch_curve_data)
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
float wait = 1000.0f;
// we have to add 1 to wip->burst_shots so that the multiplier behaves as expected, then remove 1 from burst_shots to match the zero-indexed burst_counter
int base_burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points : wip->burst_shots + 1);
float burst_shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::BURST_SHOTS_MULT, launch_curve_data);
int burst_shots = MAX(fl2i(i2fl(base_burst_shots) * burst_shots_mult) - 1, 0);
// should subtract 1 from firepoints to match behavior of wip->burst_shots
int burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points - 1 : wip->burst_shots);
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 +1599,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
} else {
// flak guns need to fire more rapidly
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
if (Ships[aip->shipnum].team == Player_ship->team) {
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
} else {
wait *= aip->ai_ship_fire_delay_scale_hostile * 0.5f;
@@ -1641,7 +1624,7 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
}
} else {
// give team friendly an advantage
if (Player_ship != nullptr && Ships[aip->shipnum].team == Player_ship->team) {
if (Ships[aip->shipnum].team == Player_ship->team) {
wait *= aip->ai_ship_fire_delay_scale_friendly;
} else {
wait *= aip->ai_ship_fire_delay_scale_hostile;
@@ -1696,15 +1679,7 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
/**
* Fire a weapon from a turret
*/
bool turret_fire_weapon(int weapon_num,
ship_subsys *turret,
int parent_objnum,
const WeaponLaunchCurveData& launch_curve_data,
const vec3d *orig_firing_pos,
const vec3d *orig_firing_vec,
const vec3d *predicted_pos = nullptr,
float flak_range_override = 100.0f,
bool play_sound = true)
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
{
matrix firing_orient;
int weapon_objnum;
@@ -1719,12 +1694,6 @@ bool turret_fire_weapon(int weapon_num,
if (!wip)
return false;
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
if (in_lab) {
predicted_pos = nullptr;
}
bool last_shot_in_salvo = true;
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo])
{
@@ -1788,7 +1757,7 @@ bool turret_fire_weapon(int weapon_num,
firing_vec = &firing_vec_buf;
}
vm_vector_2_matrix_norm(&firing_orient, firing_vec, nullptr, nullptr);
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
int old_burst_seed = swp->burst_seed[weapon_num];
@@ -1804,63 +1773,53 @@ bool turret_fire_weapon(int weapon_num,
// set next fire timestamp for the turret
if (last_shot_in_salvo)
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip, launch_curve_data);
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
// if this weapon is a beam weapon, handle it specially
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
// if this beam isn't free to fire
if (!in_lab && !(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
return false;
}
beam_fire_info fire_info;
for (int i = 0; i < wip->shots; i++) {
beam_fire_info fire_info;
// stuff beam firing info
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 1.0f;
fire_info.beam_info_index = turret_weapon_class;
fire_info.beam_info_override = nullptr;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = turret_enemy_objp;
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = old_burst_counter;
// stuff beam firing info
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 1.0f;
fire_info.beam_info_index = turret_weapon_class;
fire_info.beam_info_override = nullptr;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = turret_enemy_objp;
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = (old_burst_counter * wip->shots) + i;
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
// If we're in the lab then force fire
if (in_lab) {
fire_info.fire_method = BFM_TURRET_FORCE_FIRED;
fire_info.bfi_flags |= BFIF_TARGETING_COORDS;
fire_info.target_pos1 = turret->last_aim_enemy_pos;
}
if (weapon_objnum != -1) {
objp = &Objects[weapon_objnum];
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
turret->turret_last_fired = _timestamp();
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
if (weapon_objnum != -1) {
objp = &Objects[weapon_objnum];
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
turret->turret_last_fired = _timestamp();
if (scripting::hooks::OnTurretFired->isActive()) {
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
scripting::hook_param_list(
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
scripting::hook_param("Beam", 'o', objp),
scripting::hook_param("Target", 'o', turret_enemy_objp)
));
}
if (scripting::hooks::OnTurretFired->isActive()) {
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
scripting::hook_param_list(
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
scripting::hook_param("Beam", 'o', objp),
scripting::hook_param("Target", 'o', turret_enemy_objp)
));
}
}
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
}
@@ -1870,7 +1829,7 @@ bool turret_fire_weapon(int weapon_num,
swp->current_secondary_bank = 0;
}
int bank_to_fire = swp->current_secondary_bank;
if (!in_lab && (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
@@ -1881,7 +1840,7 @@ bool turret_fire_weapon(int weapon_num,
return false;
}
} else {
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos, in_lab);
turret_swarm_set_up_info(parent_objnum, turret, wip, turret->turret_next_fire_pos);
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
@@ -1889,10 +1848,8 @@ bool turret_fire_weapon(int weapon_num,
}
// now do anything else
else {
float shots_mult = wip->weapon_launch_curves.get_output(weapon_info::WeaponLaunchCurveOutputs::SHOTS_MULT, launch_curve_data);
int shots = fl2i(i2fl(wip->shots) * shots_mult);
for (int i = 0; i < shots; i++) {
if (!in_lab && turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
for (int i = 0; i < wip->shots; i++) {
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
if (wip->subtype == WP_LASER) {
int points;
@@ -1987,7 +1944,7 @@ bool turret_fire_weapon(int weapon_num,
// so we need to get the position info separately for each shot
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, true, false, 0.0f, turret, launch_curve_data);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
@@ -2016,7 +1973,7 @@ bool turret_fire_weapon(int weapon_num,
// if the gun is a flak gun
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if(predicted_pos != nullptr)
if(predicted_pos != NULL)
{
// pick a firing range so that it detonates properly
flak_pick_range(objp, firing_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
@@ -2031,19 +1988,7 @@ 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();
}
else if (wip->muzzle_flash >= 0) {
if (wip->muzzle_flash >= 0) {
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
}
@@ -2054,9 +1999,9 @@ bool turret_fire_weapon(int weapon_num,
subsys_index = ship_get_subsys_index(turret);
Assert( subsys_index != -1 );
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
} else {
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum, launch_curve_data.distance_to_target, launch_curve_data.target_radius );
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum );
}
}
@@ -2124,16 +2069,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
}
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
vm_vector_2_matrix_norm(&firing_orient, &turret_fvec, nullptr, nullptr);
auto launch_curve_data = WeaponLaunchCurveData {
tsi->turret->system_info->turret_num_firing_points,
0.f,
0.f,
};
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
// create weapon and homing info
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, true, false, 0.0f, tsi->turret, launch_curve_data);
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
// do other cool stuff if weapon is created.
@@ -2159,14 +2098,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
}
// muzzle flash?
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
//spawn particle effect
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
particleSource->setHost(make_unique<EffectHostTurret>(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1));
particleSource->setTriggerRadius(Objects[weapon_objnum].radius);
particleSource->finishCreation();
}
else if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
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 +2116,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
subsys_index = ship_get_subsys_index(tsi->turret);
Assert( subsys_index != -1 );
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum, 0.f, 0.f);
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum );
}
}
}
@@ -2210,20 +2142,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
vec3d predicted_enemy_pos = vmd_zero_vector;
object *objp;
bool in_lab = (gameseq_get_state() == GS_STATE_LAB);
if (in_lab) {
// Adjust behavior for Lab
ss->turret_enemy_objnum = -1;
lep = nullptr;
}
// Reset the points to target value
ss->points_to_target = -1.0f;
ss->base_rotation_rate_pct = 0.0f;
ss->gun_rotation_rate_pct = 0.0f;
if (!in_lab && !Ai_firing_enabled) {
if (!Ai_firing_enabled) {
return;
}
@@ -2236,7 +2160,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
}
// Check turret free
if (!in_lab && ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
if (ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
return;
}
@@ -2301,13 +2225,8 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
}
if (!in_lab) {
// Update predicted enemy position. This used to be done in aifft_rotate_turret
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
} else {
// Lab hijacks this value to use as the target position
predicted_enemy_pos = ss->last_aim_enemy_pos;
}
// Update predicted enemy position. This used to be done in aifft_rotate_turret
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
bool use_angles = aifft_rotate_turret(objp, shipp, ss, &global_gun_pos, &global_gun_vec, &predicted_enemy_pos);
@@ -2331,20 +2250,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// Don't try to fire beyond weapon_limit_range
// WMC moved the range check to within the loop, but we can still calculate the enemy distance here
float base_dist_to_enemy = 0.0f;
float dist_to_enemy = 0.0f;
if (lep) {
base_dist_to_enemy = vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
dist_to_enemy = base_dist_to_enemy;
if (!The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius]) {
dist_to_enemy -= lep->radius;
}
base_dist_to_enemy = MAX(0.0f, base_dist_to_enemy);
dist_to_enemy = MAX(0.0f, dist_to_enemy);
} else if (in_lab) {
base_dist_to_enemy = 500.0f;
dist_to_enemy = base_dist_to_enemy;
vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos);
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos));
else
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
}
// count the number of enemies, in case we have a spawning weapon
@@ -2356,19 +2267,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
float turret_barrel_length = -1.0f;
float target_radius = 0.f;
if (lep != nullptr) {
target_radius = lep->radius;
}
// grab the data for the launch curve inputs
auto launch_curve_data = WeaponLaunchCurveData {
ss->system_info->turret_num_firing_points,
base_dist_to_enemy,
target_radius,
};
//WMC - go through all valid weapons. Fire spawns if there are any.
int valid_weapons[MAX_SHIP_WEAPONS];
int num_valid = 0;
@@ -2397,10 +2295,10 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// Turret spawn weapons are a special case. They fire if there are enough enemies in the
// immediate area (not necessarily in the turret fov).
// However, if this is a 'smart spawn', just use it like a normal weapon
if (!in_lab && (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
{
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
turret_fire_weapon(i, ss, parent_objnum, launch_curve_data, &global_gun_pos, &ss->turret_last_fire_direction);
turret_fire_weapon(i, ss, parent_objnum, &global_gun_pos, &ss->turret_last_fire_direction);
} else {
// Regardless of firing rate, don't check whether should fire for awhile.
if (tp->flags[Model::Subsystem_Flags::Use_multiple_guns])
@@ -2415,13 +2313,13 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
we_did_non_spawning_logic = true; // for the post-loop check
// If beam weapon, check beam free
if (!in_lab && wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
if (wip->wi_flags[Weapon::Info_Flags::Beam] && !(ss->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
tentative_return = true;
continue;
}
// the remaining checks in this loop all require a valid lep
if (!in_lab && !lep)
if (!lep)
continue;
// Get weapon range
@@ -2461,88 +2359,84 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
}
// Don't try to fire beyond weapon_limit_range (or within min range)
// In lab we ignore range issues
if (!in_lab && (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range)) {
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
// it's possible another weapon is in range, but if not,
// we will end up selecting a new target
continue;
}
if (!in_lab) {
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
if ( lep->type != OBJ_SHIP ) {
tentative_return = true;
continue;
}
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
}
// Similar check for small weapons
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
}
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
if (lep->type == OBJ_SHIP) {
// Check if we're targeting a protected ship
if (lep->flags[Object::Object_Flags::Protected]) {
// *none* of the weapons will work on this ship, so just quit the loop
tentative_return = true;
break;
}
// Check if we're targeting a beam protected ship with a beam weapon
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a flak protected ship with a flak weapon
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a laser protected ship with a laser weapon
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a missile protected ship with a missile weapon
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
tentative_return = true;
continue;
}
// Check if weapon or turret is set to tagged-only
// must check here in case turret has multiple weapons and not all are tagged-only
else if (tagged_only && !ship_is_tagged(lep)) {
tentative_return = true;
continue;
}
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
tentative_return = true;
continue;
}
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
if ( lep->type != OBJ_SHIP ) {
tentative_return = true;
continue;
}
else {
// check tagged-only for bombs only if the flag is set; see Mantis #3114
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
tentative_return = true;
continue;
}
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
}
// Similar check for small weapons
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
}
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
// If targeting protected or beam protected ship, don't fire. Reset enemy objnum
// (note: due to the loop, we need to check all weapons on this turret. if none of them are valid, that's when the enemy objnum is reset)
if (lep->type == OBJ_SHIP) {
// Check if we're targeting a protected ship
if (lep->flags[Object::Object_Flags::Protected]) {
// *none* of the weapons will work on this ship, so just quit the loop
tentative_return = true;
break;
}
// Check if we're targeting a beam protected ship with a beam weapon
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a flak protected ship with a flak weapon
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a laser protected ship with a laser weapon
else if ( (lep->flags[Object::Object_Flags::Laser_protected]) && (wip->subtype == WP_LASER) ) {
tentative_return = true;
continue;
}
// Check if we're targeting a missile protected ship with a missile weapon
else if ( (lep->flags[Object::Object_Flags::Missile_protected]) && (wip->subtype == WP_MISSILE) ) {
tentative_return = true;
continue;
}
// Check if weapon or turret is set to tagged-only
// must check here in case turret has multiple weapons and not all are tagged-only
else if (tagged_only && !ship_is_tagged(lep)) {
tentative_return = true;
continue;
}
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
tentative_return = true;
continue;
}
}
else {
// check tagged-only for bombs only if the flag is set; see Mantis #3114
if (tagged_only && ((lep->type != OBJ_WEAPON) || The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turret_tagged_only_targeting])) {
tentative_return = true;
continue;
}
}
@@ -2636,20 +2530,17 @@ 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
//if ( lep == nullptr ){
// return;
//}
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 +2548,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 +2602,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 +2725,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 +2747,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 +2770,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
View File
@@ -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;
+7 -1
View File
@@ -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
+194 -311
View File
@@ -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);
}
/**
@@ -279,25 +262,6 @@ static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
}
}
/**
* Randomly select an asteroid subtype
*/
const SCP_string& pick_random_asteroid_type()
{
return Asteroid_field.field_asteroid_type[Random::next(static_cast<int>(Asteroid_field.field_asteroid_type.size()))];
}
int get_asteroid_subtype_index_by_name(const SCP_string &name, int asteroid_idx) {
asteroid_info* this_asteroid = &Asteroid_info[asteroid_idx];
for (int i = 0; i < static_cast<int>(this_asteroid->subtypes.size()); i++) {
if (this_asteroid->subtypes[i].type_name == name) {
return i;
}
}
return -1;
}
/**
* Create a single asteroid
*/
@@ -315,8 +279,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
int rand_base;
// bogus
if(asfieldp == nullptr) {
return nullptr;
if(asfieldp == NULL) {
return NULL;
}
for (n=0; n<MAX_ASTEROIDS; n++) {
@@ -327,11 +291,15 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
if (n >= MAX_ASTEROIDS) {
nprintf(("Warning","Could not create asteroid, no more slots left\n"));
return nullptr;
return NULL;
}
if (!SCP_vector_inbounds(Asteroid_info, asteroid_type)) {
return nullptr;
if((asteroid_type < 0) || (asteroid_type >= (int)Asteroid_info.size())) {
return NULL;
}
if((asteroid_subtype < 0) || (asteroid_subtype >= NUM_ASTEROID_POFS)) {
return NULL;
}
// HACK: multiplayer asteroid subtype always 0 to keep subtype in sync
@@ -341,13 +309,9 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asip = &Asteroid_info[asteroid_type];
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
return nullptr;
}
// if the model is not loaded then abort
if(asip->subtypes[asteroid_subtype].model_number == -1) {
return nullptr;
// bogus
if(asip->modelp[asteroid_subtype] == NULL) {
return NULL;
}
asp = &Asteroids[n];
@@ -362,7 +326,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asp->collide_objsig = -1;
asp->target_objnum = -1;
radius = model_get_radius(asip->subtypes[asteroid_subtype].model_number);
radius = model_get_radius(asip->model_num[asteroid_subtype]);
vm_vec_sub(&delta_bound, &asfieldp->max_bound, &asfieldp->min_bound);
@@ -415,8 +379,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asp->objnum = objnum;
asp->model_instance_num = -1;
if (model_get(asip->subtypes[asteroid_subtype].model_number)->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
asp->model_instance_num = model_create_instance(objnum, asip->subtypes[asteroid_subtype].model_number);
if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
asp->model_instance_num = model_create_instance(objnum, asip->model_num[asteroid_subtype]);
}
// Add to Asteroid_used_list
@@ -471,8 +435,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->modelp[asteroid_subtype]->rad * 700.0f;
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->modelp[asteroid_subtype]->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;
@@ -501,8 +465,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
int subtype = Asteroids[parent_objp->instance].asteroid_subtype;
new_objp = asteroid_create(&Asteroid_field, asteroid_type, subtype);
// New asteroid size doesn't have this subtype, so abort
if (new_objp == nullptr)
if (new_objp == NULL)
return;
if ( MULTIPLAYER_MASTER ){
@@ -534,40 +497,32 @@ 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;
Assertion(asteroid_info_index < static_cast<int>(Asteroid_info.size()),
"Command to load asteroid at index %i, but only %i asteroids exist",
asteroid_info_index,
static_cast<int>(Asteroid_info.size()));
Assertion(asteroid_info_index < (int)Asteroid_info.size(), "Command to load asteroid at index %i, but only %i asteroids exist", asteroid_info_index, (int)Asteroid_info.size());
Assertion(asteroid_subtype < NUM_ASTEROID_POFS, "Command to load asteroid pof %i, but only %i pofs are allowed", asteroid_subtype, NUM_ASTEROID_POFS);
// invalid asteroid index
if (!SCP_vector_inbounds(Asteroid_info, asteroid_info_index)) {
if ( (asteroid_info_index >= (int)Asteroid_info.size()) || (asteroid_subtype >= NUM_ASTEROID_POFS) ) {
return;
}
asip = &Asteroid_info[asteroid_info_index];
// This asteroid does not have this subtype so just return
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
return;
}
if ( !VALID_FNAME(asip->subtypes[asteroid_subtype].pof_filename) )
if ( !VALID_FNAME(asip->pof_files[asteroid_subtype]) )
return;
//Check if the model is already loaded
if (asip->subtypes[asteroid_subtype].model_number >= 0)
if (asip->model_num[asteroid_subtype] >= 0)
return;
asip->subtypes[asteroid_subtype].model_number = model_load( asip->subtypes[asteroid_subtype].pof_filename );
asip->model_num[asteroid_subtype] = model_load( asip->pof_files[asteroid_subtype], 0, NULL );
if (asip->subtypes[asteroid_subtype].model_number >= 0)
if (asip->model_num[asteroid_subtype] >= 0)
{
polymodel *pm = model_get(asip->subtypes[asteroid_subtype].model_number);
polymodel *pm = asip->modelp[asteroid_subtype] = model_get(asip->model_num[asteroid_subtype]);
if ( asip->num_detail_levels != pm->n_detail_levels )
{
@@ -598,11 +553,10 @@ void asteroid_create_all()
// each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
// choose next type from table ship_debris_odds_table by Random::next()%max_weighted_range,
// the threshold *below* which the debris type is selected.
struct ShipDebrisOdds {
struct {
float random_threshold;
int debris_type;
};
std::vector<ShipDebrisOdds> shipDebrisOddsTable(Asteroid_field.field_debris_type.size());
} ship_debris_odds_table[MAX_ACTIVE_DEBRIS_TYPES];
float max_weighted_range = 0.0f;
@@ -613,8 +567,7 @@ void asteroid_create_all()
return;
}
if ((Asteroid_field.debris_genre == DG_DEBRIS && Asteroid_field.field_debris_type.empty()) ||
(Asteroid_field.debris_genre == DG_ASTEROID && Asteroid_field.field_asteroid_type.empty())) {
if (Asteroid_field.num_used_field_debris_types <= 0) {
Warning(LOCATION, "An asteroid field is enabled, but no asteroid types were enabled.");
return;
}
@@ -645,33 +598,49 @@ 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;
// get number of debris types
// get number of ship debris types
if (Asteroid_field.debris_genre == DG_DEBRIS) {
num_debris_types = static_cast<int>(Asteroid_field.field_debris_type.size());
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
if (Asteroid_field.field_debris_type[idx] != -1) {
num_debris_types++;
}
}
// Calculate the odds table
for (idx=0; idx<num_debris_types; idx++) {
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
shipDebrisOddsTable[idx].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[idx].debris_type = Asteroid_field.field_debris_type[idx];
ship_debris_odds_table[idx].random_threshold = max_weighted_range + debris_weight;
ship_debris_odds_table[idx].debris_type = Asteroid_field.field_debris_type[idx];
max_weighted_range += debris_weight;
}
}
// Load Asteroid/debris models
// Load Asteroid/ship models
if (Asteroid_field.debris_genre == DG_DEBRIS) {
for (idx=0; idx<num_debris_types; idx++) {
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
}
} else {
for (const auto& subtype : Asteroid_field.field_asteroid_type) {
asteroid_load(ASTEROID_TYPE_SMALL, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_SMALL));
asteroid_load(ASTEROID_TYPE_MEDIUM, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_MEDIUM));
asteroid_load(ASTEROID_TYPE_LARGE, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_LARGE));
if (Asteroid_field.field_debris_type[0] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 0);
asteroid_load(ASTEROID_TYPE_MEDIUM, 0);
asteroid_load(ASTEROID_TYPE_LARGE, 0);
}
if (Asteroid_field.field_debris_type[1] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 1);
asteroid_load(ASTEROID_TYPE_MEDIUM, 1);
asteroid_load(ASTEROID_TYPE_LARGE, 1);
}
if (Asteroid_field.field_debris_type[2] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 2);
asteroid_load(ASTEROID_TYPE_MEDIUM, 2);
asteroid_load(ASTEROID_TYPE_LARGE, 2);
}
}
@@ -681,7 +650,17 @@ void asteroid_create_all()
// For asteroid, load only large asteroids
// get a valid subtype
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
if (Asteroid_field.field_debris_type[j] >= 0) {
if (counter == 0) {
subtype = j;
break;
} else
counter--;
}
}
if (subtype >= 0)
asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
@@ -690,10 +669,10 @@ void asteroid_create_all()
float rand_choice = frand() * max_weighted_range;
for (idx = 0; idx < static_cast<int>(Asteroid_field.field_debris_type.size()); idx++) {
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
// for ship debris, choose type according to odds table
if (rand_choice < shipDebrisOddsTable[idx].random_threshold) {
asteroid_create(&Asteroid_field, shipDebrisOddsTable[idx].debris_type, 0);
if (rand_choice < ship_debris_odds_table[idx].random_threshold) {
asteroid_create(&Asteroid_field, ship_debris_odds_table[idx].debris_type, 0);
break;
}
}
@@ -719,7 +698,7 @@ void remove_all_asteroids()
}
// will replace any existing asteroid or debris field with an asteroid field
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types)
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets)
{
remove_all_asteroids();
@@ -753,11 +732,25 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
Asteroid_field.speed = (float)asteroid_speed;
Asteroid_field.debris_genre = DG_ASTEROID;
Asteroid_field.field_debris_type.clear();
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.field_asteroid_type.clear();
int count = 0;
if (brown) {
Asteroid_field.field_debris_type[0] = 1;
count++;
}
if (blue) {
Asteroid_field.field_debris_type[1] = 1;
count++;
}
if (orange) {
Asteroid_field.field_debris_type[2] = 1;
count++;
}
Asteroid_field.field_asteroid_type = std::move(asteroid_types);
Asteroid_field.num_used_field_debris_types = count;
Asteroid_field.min_bound = o_min;
Asteroid_field.max_bound = o_max;
@@ -775,14 +768,16 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
Asteroid_field.inner_max_bound = i_max;
}
Asteroid_field.target_names = targets;
// Only create asteroids if we have some to create
if ((!Asteroid_field.field_asteroid_type.empty()) && (num_asteroids > 0)) {
if ((count > 0) && (num_asteroids > 0)) {
asteroid_create_all();
}
}
// will replace any existing asteroid or debris field with a debris field
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced)
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced)
{
remove_all_asteroids();
@@ -797,11 +792,33 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
Asteroid_field.speed = (float)asteroid_speed;
Asteroid_field.debris_genre = DG_DEBRIS;
Asteroid_field.field_debris_type.clear();
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.field_asteroid_type.clear();
int count = 0;
for (int i = 0; i < MAX_ACTIVE_DEBRIS_TYPES; i++) {
if (debris1 >= 0) {
Asteroid_field.field_debris_type[i] = debris1;
debris1 = -1;
count++;
continue;
}
if (debris2 >= 0) {
Asteroid_field.field_debris_type[i] = debris2;
debris2 = -1;
count++;
continue;
}
if (debris3 >= 0) {
Asteroid_field.field_debris_type[i] = debris3;
debris3 = -1;
count++;
continue;
}
}
Asteroid_field.field_debris_type = std::move(debris_types);
Asteroid_field.num_used_field_debris_types = count;
Asteroid_field.min_bound = o_min;
Asteroid_field.max_bound = o_max;
@@ -814,7 +831,7 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
Asteroid_field.bound_rad = MAX(3000.0f, b_rad);
// Only create debris if we have some to create
if ((!Asteroid_field.field_debris_type.empty()) && (num_asteroids > 0)) {
if ((count > 0) && (num_asteroids > 0)) {
asteroid_create_all();
}
}
@@ -833,8 +850,10 @@ void asteroid_level_init()
Asteroid_field.has_inner_bound = false;
Asteroid_field.field_type = FT_ACTIVE;
Asteroid_field.debris_genre = DG_ASTEROID;
Asteroid_field.field_debris_type.clear();
Asteroid_field.field_asteroid_type.clear();
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.num_used_field_debris_types = 0;
Asteroid_field.target_names.clear();
if (!Fred_running)
@@ -1030,7 +1049,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
*/
static void maybe_throw_asteroid()
{
Assertion(!Asteroid_field.field_asteroid_type.empty(), "maybe_throw_asteroid() called while field_asteroid_type.size was 0; this should never happen, get a coder!");
Assertion(Asteroid_field.num_used_field_debris_types > 0, "maybe_throw_asteroid() called while num_used_field_debris_types was 0; this should never happen, get a coder!");
for (asteroid_target& target : Asteroid_targets) {
if (!timestamp_elapsed(target.throw_stamp))
@@ -1048,26 +1067,36 @@ static void maybe_throw_asteroid()
target.throw_stamp = _timestamp(1000 + 1200 * target.incoming_asteroids / (Game_skill_level+1));
// get a valid subtype
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int i = 0; i < NUM_ASTEROID_POFS; i++) {
if (Asteroid_field.field_debris_type[i] >= 0) {
if (counter == 0) {
subtype = i;
break;
}
else
counter--;
}
}
// this really shouldn't happen but just in case...
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 );
}
}
}
@@ -1226,7 +1255,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// asteroid weapon collision
Assert( other_obj->type == OBJ_WEAPON );
mc.model_instance_num = Asteroids[num].model_instance_num;
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
mc.orient = &pasteroid->orient; // The object's orient
mc.pos = &pasteroid->pos; // The object's position
mc.p0 = &other_obj->last_pos; // Point 1 of ray to check
@@ -1407,7 +1436,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
} else {
// Asteroid is heavier obj
mc.model_instance_num = Asteroids[num].model_instance_num;
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
mc.orient = &pasteroid->orient; // The object's orient
mc.radius = model_get_core_radius(Ship_info[Ships[pship_obj->instance].ship_info_index].model_num);
@@ -1488,62 +1517,14 @@ void asteroid_render(object * obj, model_draw_list *scene)
Assert( asp->flags & AF_USED );
model_clear_instance( Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number);
model_clear_instance( Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype]);
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(MR_IS_ASTEROID);
render_info.set_flags(render_flags);
render_info.set_debug_flags(debug_flags);
if (asp->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(asp->model_instance_num)->texture_replace);
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number, &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype], &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
}
}
@@ -1612,8 +1593,9 @@ static float asteroid_create_explosion(object *objp)
fireball_type = FIREBALL_ASTEROID;
}
if (fireball_type >= static_cast<int>(Fireball_info.size())) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid; only " SIZE_T_ARG " fireball types are defined.", fireball_type, Fireball_info.size());
if (fireball_type >= Num_fireball_types) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid, only %i fireball types are defined.", fireball_type, Num_fireball_types);
return 0;
}
@@ -1752,7 +1734,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 );
}
}
}
@@ -1777,9 +1759,9 @@ void asteroid_level_close()
//when a level is closed, all models are cleared, so let's make sure that
//is tracked for asteroids as well -Mjn
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;
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
Asteroid_info[i].model_num[j] = -1;
}
}
@@ -1875,8 +1857,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,78 +2219,16 @@ 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;
thisType.type_name = "Brown";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
stuff_string(asteroid_p->pof_files[0], F_NAME, MAX_FILENAME_LEN);
}
if (optional_string("$POF file2:")) {
asteroid_subtype_info thisType;
thisType.type_name = "Blue";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
stuff_string(asteroid_p->pof_files[1], F_NAME, MAX_FILENAME_LEN);
}
if (optional_string("$POF file3:")) {
asteroid_subtype_info thisType;
thisType.type_name = "Orange";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
insert_or_replace_subtype_pof(asteroid_p->subtypes, thisType);
}
// For asteroid types we can have unlimited subtypes
if (asteroid_p->type != ASTEROID_TYPE_DEBRIS) {
while (optional_string("$Subtype:")) {
asteroid_subtype_info thisType;
stuff_string(thisType.type_name, F_NAME);
required_string("+POF file:");
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
bool exists = false;
for (const auto& type : asteroid_p->subtypes) {
if (type.type_name == thisType.type_name) {
exists = true;
}
}
if (exists) {
error_display(0,
"Asteroid subtype %s already exists for asteroid %s",
thisType.type_name.c_str(),
asteroid_p->name);
} else {
asteroid_p->subtypes.push_back(thisType);
}
}
stuff_string(asteroid_p->pof_files[2], F_NAME, MAX_FILENAME_LEN);
}
if (optional_string("$Detail distance:")) {
@@ -2332,7 +2251,10 @@ static void asteroid_parse_section()
}
if(optional_string("$Explosion Animations:")){
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
int temp[MAX_FIREBALL_TYPES];
auto parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
asteroid_p->explosion_bitmap_anims.clear();
asteroid_p->explosion_bitmap_anims.insert(asteroid_p->explosion_bitmap_anims.begin(), temp, temp + parsed_ints);
}
if (optional_string("$Explosion Radius Mult:")) {
@@ -2498,7 +2420,7 @@ static void asteroid_parse_tbl(const char* filename)
// Gets the index of an asteroid by name from Asteroid_info
int get_asteroid_index(const char* asteroid_name)
{
for (int i = 0; i < static_cast<int>(Asteroid_info.size()); i++) {
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
if (!stricmp(asteroid_name, Asteroid_info[i].name)) {
return i;
}
@@ -2507,31 +2429,6 @@ int get_asteroid_index(const char* asteroid_name)
return -1;
}
// For FRED. Gets a list of unique asteroid subtype names
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes()
{
SCP_vector<SCP_string> list;
for (const auto& this_asteroid : Asteroid_info) {
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
for (const auto& subtype : this_asteroid.subtypes) {
bool exists = false;
for (const auto& entry : list) {
if (subtype.type_name == entry) {
exists = true;
}
}
if (!exists) {
list.push_back(subtype.type_name);
}
}
}
}
return list;
}
static void verify_asteroid_splits()
{
@@ -2590,14 +2487,7 @@ static void verify_asteroid_list()
}
// Rest should be debris type
for (int i = 0; i < (int)asteroid_list.size(); i++) {
// Remove all subtypes except the first one
asteroid_list[i].subtypes.resize(1);
// Make sure the first subtype is set as debris
asteroid_list[i].subtypes[0].type_name = "Debris";
if (asteroid_list[i].type < 0) {
Asteroid_info.push_back(asteroid_list[i]);
} else {
@@ -2611,8 +2501,14 @@ static void verify_asteroid_list()
//Check that we have the appropriate POF files-Mjn
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
if (Asteroid_info[i].subtypes.size() == 0) {
Error(LOCATION, "Asteroid %s needs at least one subtype!", Asteroid_info[i].name);
if (Asteroid_info[i].pof_files[0][0] == '\0')
Error(LOCATION, "Missing [POF File 1] for %s", Asteroid_info[i].name);
if (Asteroid_info[i].type != ASTEROID_TYPE_DEBRIS) {
if (Asteroid_info[i].pof_files[1][0] == '\0')
Error(LOCATION, "Missing [POF File 2] for %s", Asteroid_info[i].name);
if (Asteroid_info[i].pof_files[2][0] == '\0')
Error(LOCATION, "Missing [POF File 3] for %s", Asteroid_info[i].name);
}
}
}
@@ -2649,7 +2545,7 @@ void asteroid_init()
}
if (Asteroid_icon_closeup_model[0] == '\0')
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].subtypes[0].pof_filename); // magic file from retail
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
}
@@ -2690,7 +2586,7 @@ void asteroid_frame()
}
// If no asteroid types are defined for the field, abort.
if (Asteroid_field.field_asteroid_type.empty()) {
if (Asteroid_field.num_used_field_debris_types <= 0) {
return;
}
@@ -2802,26 +2698,21 @@ void asteroid_page_in()
return;
if (Asteroid_field.num_initial_asteroids > 0 ) {
int i, j, k;
nprintf(( "Paging", "Paging in asteroids\n" ));
size_t num_debris_types = NUM_ASTEROID_SIZES;
if (Asteroid_field.debris_genre == DG_DEBRIS) {
num_debris_types = Asteroid_field.field_debris_type.size();
}
// for asteroids this will loop over all three possible sizes
// for debris this will loop over all selected types
for (size_t i = 0; i < num_debris_types; i++) {
// max of MAX_ACTIVE_DEBRIS_TYPES possible debris field models
for (i=0; i<MAX_ACTIVE_DEBRIS_TYPES; i++) {
asteroid_info *asip;
if (Asteroid_field.debris_genre == DG_ASTEROID) {
// asteroid
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load non-existent asteroid size!");
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load a debris type instead of asteroid type!");
asip = &Asteroid_info[i];
} else {
// debris - always full until empty
// ship debris - always full until empty
if (Asteroid_field.field_debris_type[i] != -1) {
asip = &Asteroid_info[Asteroid_field.field_debris_type[i]];
} else {
@@ -2830,36 +2721,28 @@ void asteroid_page_in()
}
for (size_t k = 0; k < asip->subtypes.size(); k++) {
for (k=0; k<NUM_ASTEROID_POFS; k++) {
// DEBRIS FIELDS - always use subtype 0
// SHIP DEBRIS - use subtype 0
if (Asteroid_field.debris_genre == DG_DEBRIS) {
if (k > 0) {
break;
}
} else {
// ASTEROID FIELDS - use subtype k, if active
bool active = false;
for (const auto& active_type : Asteroid_field.field_asteroid_type) {
if (active_type == asip->subtypes[k].type_name) {
active = true;
}
}
if (!active) {
// ASTEROID DEBRIS - use subtype (Asteroid_field.field_debris_type[] != -1)
if (Asteroid_field.field_debris_type[k] == -1) {
continue;
}
}
// model is already paged in
if (asip->subtypes[k].model_number < 0)
if (asip->model_num[k] < 0)
continue;
const auto mp = model_get(asip->subtypes[k].model_number);
asip->modelp[k] = model_get(asip->model_num[k]);
// Page in textures
for (int j = 0; j < mp->n_textures; j++) {
mp->maps[j].PageIn();
for (j=0; j<asip->modelp[k]->n_textures; j++ ) {
asip->modelp[k]->maps[j].PageIn();
}
}
+20 -23
View File
@@ -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;
@@ -25,14 +24,15 @@ class model_draw_list;
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
#define NUM_ASTEROID_SIZES 3
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
#define ASTEROID_TYPE_DEBRIS -1
#define ASTEROID_TYPE_SMALL 0
#define ASTEROID_TYPE_MEDIUM 1
#define ASTEROID_TYPE_LARGE 2
// Only used for parsing & saving retail compatible mission files
#define MAX_RETAIL_DEBRIS_TYPES 3
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
#define MAX_ASTEROID_DETAIL_LEVELS 5
@@ -54,19 +54,13 @@ typedef struct asteroid_split_info {
int max; //maximum asteroids to spawn
} asteroid_split_info;
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
typedef struct asteroid_subtype_info {
char pof_filename[MAX_FILENAME_LEN];
int model_number;
SCP_string type_name;
} asteroid_subtype_info;
class asteroid_info
{
public:
char name[NAME_LENGTH]; // name for the asteroid
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
int num_detail_levels; // number of detail levels for this asteroid
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
int num_detail_levels; // number of detail levels for this ship
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
float max_speed; // cap on speed for asteroid
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
@@ -78,12 +72,13 @@ public:
float blast; // maximum blast impulse from area effect explosion
float initial_asteroid_strength; // starting strength of asteroid
SCP_vector< asteroid_split_info > split_info;
polymodel *modelp[NUM_ASTEROID_POFS];
int model_num[NUM_ASTEROID_POFS];
SCP_vector<int> explosion_bitmap_anims;
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
SCP_string display_name; // only used for hud targeting display and for debris
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
float gravity_const; // multiplier for mission gravity
SCP_vector<asteroid_subtype_info> subtypes;
asteroid_info( )
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
@@ -95,6 +90,13 @@ public:
name[ 0 ] = 0;
display_name = "";
memset( detail_distance, 0, sizeof( detail_distance ) );
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
{
modelp[i] = NULL;
model_num[i] = -1;
pof_files[i][0] = '\0';
}
}
};
@@ -103,7 +105,6 @@ public:
typedef struct asteroid {
int flags;
flagset<Object::Raw_Pof_Flags> render_flags; // Render flags
int objnum;
int model_instance_num;
int asteroid_type; // 0..MAX_DEBRIS_TYPES
@@ -142,8 +143,8 @@ typedef struct asteroid_field {
int num_initial_asteroids; // Number of asteroids at creation.
field_type_t field_type; // active throws and wraps, passive does not
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
SCP_vector<int> field_debris_type; // one of the debris type defines above
SCP_vector<SCP_string> field_asteroid_type; // one of the asteroid subtypes
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
int num_used_field_debris_types; // how many of the above are used
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
@@ -164,8 +165,8 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = f
void asteroid_level_init();
void asteroid_level_close();
void asteroid_create_all();
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types);
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced);
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced);
void asteroid_render(object* obj, model_draw_list* scene);
void asteroid_delete( object *asteroid_objp );
void asteroid_process_pre( object *asteroid_objp );
@@ -179,10 +180,6 @@ void asteroid_show_brackets();
void asteroid_target_closest_danger();
void asteroid_add_target(object* objp);
int get_asteroid_index(const char* asteroid_name);
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);
+27 -32
View File
@@ -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
+2 -2
View File
@@ -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;
}
};
+4
View File
@@ -1027,6 +1027,10 @@ int bm_is_compressed(int num) {
auto entry = bm_get_entry(num);
BM_TYPE type = BM_TYPE_NONE;
//duh
if (!Use_compressed_textures)
return 0;
type = entry->comp_type;
switch (type) {
+76 -105
View File
@@ -14,8 +14,8 @@
#include "ship/ship.h" //compute_slew_matrix
//*************************IMPORTANT GLOBALS*************************
fov_t VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
fov_t COCKPIT_ZOOM_DEFAULT = DEFAULT_FOV;
fov_t VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
fov_t COCKPIT_ZOOM_DEFAULT = 0.75f;
float Sexp_fov = 0.0f;
warp_camera Warp_camera;
@@ -48,15 +48,12 @@ 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 SCP_string fov_display(float val)
{
auto degrees = fl_degrees(val);
@@ -64,66 +61,19 @@ 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})
.category(std::make_pair("Graphics", 1825))
.category("Graphics")
.range(0.436332f, 1.5708f)
.change_listener([](const float& val, bool) {
VIEWER_ZOOM_DEFAULT = val;
return true;
})
.display(fov_display)
.default_func([]() { return fov_default; })
.default_val(0.75f)
.level(options::ExpertLevel::Advanced)
.importance(60)
.parser(parse_fov_func)
.finish();
bool Use_cockpit_fov = false;
auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVToggle",
std::pair<const char*, int>{"Cockpit FOV Toggle", 1838},
std::pair<const char*, int>{"Whether or not to use a different FOV for cockpit rendering from normal rendering", 1839})
.category(std::make_pair("Graphics", 1825))
.default_val(false)
.change_listener([](bool val, bool) {
if (!val) {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true; // This option will always persist so we never return false
})
.level(options::ExpertLevel::Advanced)
.bind_to(&Use_cockpit_fov)
.importance(61)
.finish();
auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
std::pair<const char*, int>{"Cockpit Field Of View", 1840},
std::pair<const char*, int>{"The vertical field of view for cockpit rendering. Only works if cockpits are active and cockpit FOV toggle is turned on.", 1841})
.category(std::make_pair("Graphics", 1825))
.range(0.436332f, 1.5708f)
.change_listener([](const float& val, bool) {
if (Use_cockpit_fov){
COCKPIT_ZOOM_DEFAULT = val;
} else {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
return true;
})
.display(fov_display)
.default_val(fov_default)
.level(options::ExpertLevel::Advanced)
.importance(62)
.finish();
//*************************CLASS: camera*************************
@@ -210,35 +160,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,11 +297,11 @@ 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
if (object_host.isValid())
if (object_host.IsValid())
{
vm_transpose(orient);
temp_matrix = temp_matrix * *orient;
@@ -370,7 +310,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);
}
}
@@ -384,7 +324,10 @@ void camera::do_frame(float /*in_frametime*/)
object *camera::get_object_host()
{
return object_host.objp_or_null();
if(object_host.IsValid())
return object_host.objp;
else
return NULL;
}
int camera::get_object_host_submodel()
@@ -394,7 +337,10 @@ int camera::get_object_host_submodel()
object *camera::get_object_target()
{
return object_target.objp_or_null();
if(object_target.IsValid())
return object_target.objp;
else
return NULL;
}
int camera::get_object_target_submodel()
@@ -427,7 +373,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
bool use_host_orient = false;
//POSITION
if(!(flags & CAM_STATIONARY_POS) || object_host.isValid())
if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid())
{
c_pos = vmd_zero_vector;
@@ -436,16 +382,24 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
pos_y.get(&pt.xyz.y, NULL);
pos_z.get(&pt.xyz.z, NULL);
if(object_host.isValid())
if(object_host.IsValid())
{
object *objp = object_host.objp();
polymodel *pm = object_get_model(objp);
polymodel_instance *pmi = object_get_model_instance(objp);
object *objp = object_host.objp;
int model_num = object_get_model(objp);
polymodel *pm = nullptr;
polymodel_instance *pmi = nullptr;
if(model_num >= 0)
{
pm = model_get(model_num);
if (objp->type == OBJ_SHIP)
pmi = model_get_instance(Ships[objp->instance].model_instance_num);
}
if(object_host_submodel < 0 || pm == NULL)
{
vm_vec_unrotate(&c_pos, &pt, &object_host.objp()->orient);
vm_vec_add2(&c_pos, &object_host.objp()->pos);
vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
vm_vec_add2(&c_pos, &object_host.objp->pos);
}
else
{
@@ -490,14 +444,23 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
if(orientation != NULL)
{
bool target_set = false;
if(!(flags & CAM_STATIONARY_ORI) || object_target.isValid() || object_host.isValid())
if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid())
{
if(object_target.isValid())
if(object_target.IsValid())
{
object *target_objp = object_target.objp();
polymodel *target_pm = object_get_model(target_objp);
polymodel_instance *target_pmi = object_get_model_instance(target_objp);
object *target_objp = object_target.objp;
int model_num = object_get_model(target_objp);
polymodel *target_pm = nullptr;
polymodel_instance *target_pmi = nullptr;
vec3d target_pos = vmd_zero_vector;
//See if we can get the model
if(model_num >= 0)
{
target_pm = model_get(model_num);
if (target_objp->type == OBJ_SHIP)
target_pmi = model_get_instance(Ships[target_objp->instance].model_instance_num);
}
//If we don't have a submodel or don't have the model use object pos
//Otherwise, find the submodel pos as it is rotated
@@ -515,14 +478,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())
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)
@@ -531,7 +494,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
}
else
{
c_ori = object_host.objp()->orient;
c_ori = object_host.objp->orient;
}
}
else
@@ -578,7 +541,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 +754,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], text_line_lens[i]);
if(w > tw)
tw = w;
@@ -1048,7 +1011,7 @@ int camid::getSignature()
return sig;
}
bool camid::isValid() const
bool camid::isValid()
{
if(idx >= Cameras.size())
return false;
@@ -1085,6 +1048,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,12 +1198,12 @@ void subtitles_do_frame_post_shaded(float frametime)
}
}
static vec3d normal_cache;
vec3d normal_cache;
void get_turret_cam_pos(camera *cam, vec3d *pos)
{
object_h obj(cam->get_object_host());
if(!obj.isValid())
if(!obj.IsValid())
return;
ship* shipp = &Ships[cam->get_object_host()->instance];
ship_subsys* ssp = GET_FIRST(&shipp->subsys_list);
@@ -1254,9 +1224,9 @@ void get_turret_cam_pos(camera *cam, vec3d *pos)
void get_turret_cam_orient(camera *cam, matrix *ori)
{
object_h obj(cam->get_object_host());
if(!obj.isValid())
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 +1263,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;
+3 -4
View File
@@ -10,7 +10,7 @@
#include <string>
#include <variant>
#include <mpark/variant.hpp>
#define CAM_STATIONARY_FOV (1<<0)
#define CAM_STATIONARY_ORI (1<<1)
@@ -20,15 +20,13 @@
#define EXTERN_CAM_BBOX_CONSTANT_PADDING 5.0f
#define EXTERN_CAM_BBOX_MULTIPLIER_PADDING 1.5f
#define DEFAULT_FOV 0.75f;
struct asymmetric_fov {
float left, right, up, down;
friend asymmetric_fov operator* (const asymmetric_fov&, const float&);
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 +177,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
View File
@@ -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 -2
View File
@@ -85,6 +85,10 @@ typedef struct {
// TRUE if type is specified and valid
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
// #define's for the type parameter in cfopen.
#define CFILE_NORMAL 0 // open file normally
#define CFILE_MEMORY_MAPPED (1<<0) // open file as a memory-mapped file
#define CF_SORT_NONE 0
#define CF_SORT_NAME 1
#define CF_SORT_TIME 2
@@ -177,7 +181,7 @@ int cf_get_dir_type(const CFILE *cfile);
// Opens the file. If no path is given, use the extension to look into the
// default path. If mode is NULL, delete the file.
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode,
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
@@ -373,7 +377,6 @@ struct CFileLocation {
SCP_string full_name;
size_t size = 0;
size_t offset = 0;
time_t m_time = 0;
const void* data_ptr = nullptr;
explicit CFileLocation(bool found_in = false) : found(found_in) {}
+3
View File
@@ -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 ) {
+7
View File
@@ -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
+2 -25
View File
@@ -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
@@ -596,7 +595,7 @@ static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
cf_root* root = cf_create_root();
root->path = std::move(rootPath);
root->path = rootPath;
if (primary) {
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
} else {
@@ -827,8 +826,7 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
}
// this log message occurs in the middle of an existing line, hence the extra new lines
// critical files and files in same root are always logged, files in different root are behind a filter
nprintf(((critical || !root->path.compare(r->path)) ? "General" : "CFileSystem", "\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
critical ? "critical " : "",
newfile.c_str(), curfile.c_str()));
@@ -1238,22 +1236,6 @@ static bool sub_path_match(const SCP_string &search, const SCP_string &index)
return !stricmp(search.c_str(), index.c_str());
}
static time_t get_mtime(int fd)
{
#ifdef _WIN32
struct _stat buf;
#define fstat _fstat
#else
struct stat buf;
#endif
if (fstat(fd, &buf) != 0) {
return 0;
}
return buf.st_mtime;
}
/**
* Searches for a file.
*
@@ -1288,7 +1270,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
if (fp) {
CFileLocation res(true);
res.size = static_cast<size_t>(filelength(fileno(fp)));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1351,7 +1332,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
if (fp) {
CFileLocation res(true);
res.size = static_cast<size_t>(filelength( fileno(fp) ));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1408,7 +1388,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
res.name_ext = f->name_ext;
res.m_time = f->write_time;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
@@ -1544,7 +1523,6 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(filelength( fileno(fp) ));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1633,7 +1611,6 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
res.name_ext = f->name_ext;
res.m_time = f->write_time;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
+71 -85
View File
@@ -165,9 +165,11 @@ Flag exe_params[] =
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nonormal" },
{ "-emissive_light", "Enable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-emissive_light" },
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noheight" },
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
{ "-no_post_process", "Disable post-processing", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_post_process" },
{ "-soft_particles", "Enable soft particles", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-soft_particles" },
{ "-aa", "Enable Post-process anti-aliasing", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-aa" },
{ "-nolightshafts", "Disable lightshafts", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nolightshafts"},
{ "-fb_explosions", "Enable Framebuffer Shockwaves", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_explosions", },
{ "-fb_thrusters", "Enable Framebuffer Thrusters", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
@@ -191,10 +193,13 @@ Flag exe_params[] =
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
{ "-3dwarp", "Enable 3D warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
{ "-warp_flash", "Enable flash upon warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
{ "-no_screenshake", "Disable screen shaking", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
{ "-vr", "Enable Virtual Reality Mode", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vr", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-orig_speedx_range", "Restrict speedup/slowdown (1x to 4x)", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-orig_speedx_range", },
//flag launcher text FSO on_flags off_flags category reference URL
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
@@ -237,8 +242,6 @@ Flag exe_params[] =
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
{ "-no_bsp_align", "Disable pof BSP data alignment", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bsp_align", },
{ "-no_large_shaders", "Split large shader into smaller shaders", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_large_shaders", },
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
#endif
@@ -261,7 +264,6 @@ Flag exe_params[] =
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
{ "-output_script_json", "Output scripting doc to scripting.json", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_json", },
{ "-output_script_lua", "Output scripting doc to scripting.lua", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_luastub", },
{ "-controlconfig_tbl", "Save control presets to table", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-controlconfig_tbl", },
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
@@ -316,6 +318,7 @@ int Cmdline_cd_check = 1;
int Cmdline_closed_game = 0;
int Cmdline_freespace_no_music = 0;
int Cmdline_freespace_no_sound = 0;
int Cmdline_gimme_all_medals = 0;
int Cmdline_mouse_coords = 0;
int Cmdline_multi_log = 0;
int Cmdline_multi_stream_chat_to_file = 0;
@@ -339,12 +342,15 @@ cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all a
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // semi-deprecated but still functional
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE); // Cmdline_noscalevid -- disable video scaling that fits to window
cmdline_parm spec_arg("-nospec", NULL, AT_NONE); // Cmdline_spec --
cmdline_parm normal_arg("-nonormal", NULL, AT_NONE); // Cmdline_normal -- disable normal mapping
cmdline_parm height_arg("-noheight", NULL, AT_NONE); // Cmdline_height -- enable support for parallax mapping
cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
cmdline_parm softparticles_arg("-soft_particles", NULL, AT_NONE);
cmdline_parm no_postprocess_arg("-no_post_process", "Disables post-processing", AT_NONE);
cmdline_parm bloom_intensity_arg("-bloom_intensity", "Set bloom intensity, requires post-processing", AT_INT);
cmdline_parm post_process_aa_arg("-aa", "Enables post-process antialiasing", AT_NONE);
cmdline_parm post_process_aa_preset_arg("-aa_preset", "Sets the AA effect to use. See the wiki for details", AT_INT);
cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
@@ -354,6 +360,7 @@ cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), req
cmdline_parm msaa_enabled_arg("-msaa", nullptr, AT_INT);
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
@@ -371,7 +378,10 @@ int Cmdline_spec = 1;
int Cmdline_emissive = 0;
int Cmdline_normal = 1;
int Cmdline_height = 1;
int Cmdline_enable_3d_shockwave = 0;
int Cmdline_softparticles = 0;
int Cmdline_bloom_intensity = 25;
bool Cmdline_force_lightshaft_off = false;
int Cmdline_no_deferred_lighting = 0;
bool Cmdline_deferred_lighting_cockpit = false;
int Cmdline_aniso_level = 0;
@@ -382,7 +392,7 @@ cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NO
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
bool Cmdline_no_vsync = false;
int Cmdline_no_vsync = 0;
// HUD related
cmdline_parm ballistic_gauge("-ballistic_gauge", NULL, AT_NONE); // Cmdline_ballistic_gauge
@@ -397,16 +407,22 @@ int Cmdline_orb_radar = 0;
int Cmdline_rearm_timer = 0;
// Gameplay related
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
cmdline_parm vr("-vr", nullptr, AT_NONE);
cmdline_parm deadzone("-deadzone",
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
int Cmdline_ship_choice_3d = 0;
int Cmdline_weapon_choice_3d = 0;
int Cmdline_autopilot_interruptable = 1;
bool Cmdline_stretch_menu = false;
int Cmdline_stretch_menu = 0;
bool Cmdline_capture_mouse = false;
int Cmdline_no_screenshake = 0;
int Cmdline_deadzone = -1;
bool Cmdline_enable_vr = false;
@@ -418,10 +434,8 @@ int Cmdline_no_enhanced_sound = 0;
// MOD related
cmdline_parm mod_arg("-mod", "List of folders to overwrite/add-to the default data", AT_STRING, true); // Cmdline_mod -- DTP modsupport
cmdline_parm campaign_arg("-campaign", "Set current campaign", AT_STRING); // Cmdline_campaign
char *Cmdline_mod = NULL; //DTP for mod argument
char *Cmdline_campaign = nullptr; // for campaign argument
// Multiplayer/Network related
cmdline_parm almission_arg("-almission", "Autoload multiplayer mission", AT_STRING); // Cmdline_almission -- DTP for autoload Multi mission
@@ -465,7 +479,6 @@ cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
cmdline_parm no_bsp_align_arg("-no_bsp_align", nullptr, AT_NONE);
cmdline_parm no_large_shaders("-no_large_shaders", NULL, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -489,7 +502,6 @@ bool Cmdline_prefer_ipv4 = false;
bool Cmdline_prefer_ipv6 = false;
bool Cmdline_dump_packet_type = false;
bool Cmdline_no_bsp_align = false;
bool Cmdline_no_large_shaders = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -518,7 +530,6 @@ cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_f
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm retail_time_compression_range_arg("-orig_speedx_range", NULL, AT_NONE); //Cmdline_retail_time_compression_range
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
@@ -548,16 +559,15 @@ int Cmdline_bmpman_usage = 0;
int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
bool Cmdline_window = false;
bool Cmdline_fullscreen_window = false;
std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = std::nullopt;
int Cmdline_window = 0;
int Cmdline_fullscreen_window = 0;
tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = tl::nullopt;
char *Cmdline_res = 0;
char *Cmdline_center_res = 0;
int Cmdline_verify_vps = 0;
int Cmdline_reparse_mainhall = 0;
bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_retail_time_compression_range = false;
bool Cmdline_benchmark_mode = false;
const char *Cmdline_pilot = nullptr;
bool Cmdline_noninteractive = false;
@@ -578,7 +588,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
@@ -601,13 +610,6 @@ cmdline_parm deprecated_spec_tube_arg("-spec_tube", "Deprecated", AT_NONE);
cmdline_parm deprecated_ambient_factor_arg("-ambient_factor", "Deprecated", AT_NONE); //
cmdline_parm deprecated_ship_choice_3d_arg("-ship_choice_3d", "Deprecated", AT_NONE);
cmdline_parm deprecated_weapon_choice_3d_arg("-weapon_choice_3d", "Deprecated", AT_NONE);
cmdline_parm deprecated_no_screenshake("-no_screenshake", "Deprecated", AT_NONE);
cmdline_parm deprecated_bloom_intensity_arg("-bloom_intensity", "Deprecated", AT_INT);
cmdline_parm deprecated_nomotiondebris_arg("-nomotiondebris", "Deprecated", AT_NONE);
cmdline_parm deprecated_flightshaftsoff_arg("-nolightshafts", "Deprecated", AT_NONE);
cmdline_parm deprecated_use_warp_flash("-warp_flash", "Deprecated", AT_NONE);
cmdline_parm deprecated_use_3dwarp("-3dwarp", "Deprecated", AT_NONE);
cmdline_parm deprecated_enable_3d_shockwave_arg("-3dshockwave", "Deprecated", AT_NONE);
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
@@ -643,8 +645,8 @@ void cmdline_debug_print_cmdline()
}
#endif
// builds simple cmdline
SCP_string cmdline_build_string()
// prints simple cmdline to multi.log
void cmdline_print_cmdline_multi()
{
cmdline_parm *parmp;
int found = 0;
@@ -663,18 +665,10 @@ SCP_string cmdline_build_string()
}
if ( !found ) {
return "";
cmdline << " <none>";
}
return cmdline.str();
}
// prints simple cmdline to multi.log
void cmdline_print_cmdline_multi()
{
auto str = cmdline_build_string();
ml_printf("Command line:%s", str.empty() ? " <none>" : str.c_str());
ml_printf("Command line:%s", cmdline.str().c_str());
}
// Return true if this character is an extra char (white space and quotes)
@@ -683,6 +677,7 @@ int is_extra_space(char ch)
return ((ch == ' ') || (ch == '\t') || (ch == 0x0a) || (ch == '\'') || (ch == '\"'));
}
// eliminates all leading and trailing extra chars from a string. Returns pointer passed in.
char *drop_extra_chars(char *str)
{
@@ -1590,12 +1585,6 @@ bool SetCmdlineParams()
{
//getcwd(FreeSpace_Directory, 256); // set the directory to our fs2 root
// DO THIS BEFORE get_flags, as portable_mode can change the value of pref_path printed in the json
if (portable_mode.found())
{
Cmdline_portable_mode = true;
}
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
if ( get_flags_arg.found() ) {
write_flags();
@@ -1776,14 +1765,14 @@ bool SetCmdlineParams()
if(window_arg.found()) {
// We need to set both values since we don't know if we are going to use the new config system
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
Cmdline_window = true;
Cmdline_window = 1;
}
if ( fullscreen_window_arg.found( ) )
{
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
Cmdline_fullscreen_window = true;
Cmdline_window = false; /* Make sure no-one sets both */
Cmdline_fullscreen_window = 1;
Cmdline_window = 0; /* Make sure no-one sets both */
}
if(render_res_arg.found() || deprecated_res_arg.found()){
@@ -1878,14 +1867,6 @@ bool SetCmdlineParams()
Cmdline_mod = modlist;
}
if(campaign_arg.found()) {
Cmdline_campaign = campaign_arg.str();
// strip off blank space if it's there
if ( Cmdline_campaign[strlen(Cmdline_campaign)-1] == ' ' ) {
Cmdline_campaign[strlen(Cmdline_campaign)-1] = '\0';
}
}
if (fps_arg.found())
{
@@ -1902,6 +1883,10 @@ bool SetCmdlineParams()
Cmdline_show_pos = 1;
}
if ( nomotiondebris_arg.found() ) {
Motion_debris_enabled = false;
}
if( mipmap_arg.found() ) {
Cmdline_mipmap = 1;
}
@@ -1915,7 +1900,7 @@ bool SetCmdlineParams()
if (val > 0.1) {
VIEWER_ZOOM_DEFAULT = val;
} else {
VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
VIEWER_ZOOM_DEFAULT = 0.75f;
}
}
@@ -1934,25 +1919,6 @@ bool SetCmdlineParams()
if (fov_arg.found() || fov_cockpit_arg.found()) {
Warning(LOCATION, "FoV Command line settings found. VR-Mode will override these with the HMD's native FoV...");
}
// enable other settings to allow VR to work more seamlessly
mprintf(("VR-Mode enabled, so forcing on the following settings: capture_mouse, window_res 1000x1000, window, no_vsync \n"));
// ensure ingame resolution is set to sensible values in VR mode,
// which will exceed the resolution otherwise shown and is not dependent on the monitor resolution
Cmdline_capture_mouse = true;
Cmdline_window_res.emplace(static_cast<uint16_t>(1000), static_cast<uint16_t>(1000));
Cmdline_fullscreen_window = false;
Cmdline_window = true; /* Make sure no-one sets both */
removeWindowModeOption();
// Turn off VSync, since we definitely don't want to be capped by the main monitor
// the OpenXR runtime should have a buffered wait which will behave, effectively,
// as a VSync to VR goggle driver
Gr_enable_vsync = false;
removeVSyncOption();
openxr_prepare();
}
@@ -1961,16 +1927,28 @@ bool SetCmdlineParams()
Cmdline_orb_radar = 1;
}
if ( use_3dwarp.found() ) {
Fireball_use_3d_warp = true;
}
if ( use_warp_flash.found() ) {
Fireball_warp_flash = true;
}
if ( allow_autpilot_interrupt.found() ) {
Cmdline_autopilot_interruptable = 0;
}
if ( no_screenshake.found() ) {
Cmdline_no_screenshake = 1;
}
if ( deadzone.found() ) {
Cmdline_deadzone = deadzone.get_int();
}
if ( stretch_menu.found() ) {
Cmdline_stretch_menu = true;
Cmdline_stretch_menu = 1;
}
if ( capture_mouse.found() ) {
@@ -2077,9 +2055,6 @@ bool SetCmdlineParams()
if (output_script_json_arg.found() )
Output_scripting_json = true;
if (output_script_luastub_arg.found())
Output_scripting_luastub = true;
if (output_sexp_arg.found() ) {
Cmdline_output_sexp_info = true;
}
@@ -2127,6 +2102,11 @@ bool SetCmdlineParams()
Cmdline_noshadercache = true;
}
if (portable_mode.found())
{
Cmdline_portable_mode = true;
}
if (lang_arg.found())
{
Cmdline_lang = lang_arg.str();
@@ -2135,10 +2115,6 @@ bool SetCmdlineParams()
if (no_bsp_align_arg.found()) {
Cmdline_no_bsp_align = true;
}
if (no_large_shaders.found()) {
Cmdline_no_large_shaders = true;
}
#ifdef WIN32
if (fix_registry.found()) {
@@ -2181,6 +2157,11 @@ bool SetCmdlineParams()
Cmdline_ati_color_swap = 1;
}
if ( enable_3d_shockwave_arg.found() )
{
Cmdline_enable_3d_shockwave = 1;
}
if ( softparticles_arg.found() )
{
Cmdline_softparticles = 1;
@@ -2201,6 +2182,16 @@ bool SetCmdlineParams()
Gr_post_processing_enabled = false;
}
if ( bloom_intensity_arg.found() )
{
Cmdline_bloom_intensity = bloom_intensity_arg.get_int();
}
if ( flightshaftsoff_arg.found() )
{
Cmdline_force_lightshaft_off = true;
}
if( reparse_mainhall_arg.found() )
{
Cmdline_reparse_mainhall = 1;
@@ -2266,11 +2257,6 @@ bool SetCmdlineParams()
{
Cmdline_no_unfocus_pause = true;
}
if (retail_time_compression_range_arg.found())
{
Cmdline_retail_time_compression_range = true;
}
if (benchmark_mode_arg.found())
{
+13 -13
View File
@@ -12,7 +12,7 @@
#ifndef FS_CMDLINE_HEADER_FILE
#define FS_CMDLINE_HEADER_FILE
#include <optional>
#include <tl/optional.hpp>
int parse_cmdline(int argc, char *argv[]);
@@ -34,6 +34,7 @@ extern int Cmdline_cd_check;
extern int Cmdline_closed_game;
extern int Cmdline_freespace_no_music;
extern int Cmdline_freespace_no_sound;
extern int Cmdline_gimme_all_medals;
extern int Cmdline_mouse_coords;
extern int Cmdline_multi_log;
extern int Cmdline_multi_stream_chat_to_file;
@@ -43,10 +44,10 @@ extern int Cmdline_spew_pof_info;
extern int Cmdline_start_netgame;
extern int Cmdline_timeout;
extern int Cmdline_use_last_pilot;
extern bool Cmdline_window;
extern bool Cmdline_fullscreen_window;
extern int Cmdline_window;
extern int Cmdline_fullscreen_window;
extern char *Cmdline_res;
extern std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
extern tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
extern char *Cmdline_center_res;
@@ -62,7 +63,10 @@ extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
extern int Cmdline_spec;
extern int Cmdline_normal;
extern int Cmdline_height;
extern int Cmdline_enable_3d_shockwave;
extern int Cmdline_softparticles;
extern int Cmdline_bloom_intensity;
extern bool Cmdline_force_lightshaft_off;
extern int Cmdline_no_deferred_lighting;
extern bool Cmdline_deferred_lighting_cockpit;
extern int Cmdline_emissive;
@@ -71,7 +75,7 @@ extern int Cmdline_msaa_enabled;
// Game Speed related
extern int Cmdline_NoFPSCap;
extern bool Cmdline_no_vsync;
extern int Cmdline_no_vsync;
// HUD related
extern int Cmdline_ballistic_gauge;
@@ -80,9 +84,12 @@ extern int Cmdline_orb_radar;
extern int Cmdline_rearm_timer;
// Gameplay related
extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_autopilot_interruptable;
extern bool Cmdline_stretch_menu;
extern int Cmdline_stretch_menu;
extern bool Cmdline_capture_mouse;
extern int Cmdline_no_screenshake;
extern int Cmdline_deadzone;
extern bool Cmdline_enable_vr;
@@ -92,7 +99,6 @@ extern int Cmdline_no_enhanced_sound;
// MOD related
extern char *Cmdline_mod; // DTP for mod support
extern char *Cmdline_campaign; // for campaign support
// Multiplayer/Network related
extern char *Cmdline_almission; // DTP for autoload mission (for multi only)
extern int Cmdline_ingamejoin;
@@ -124,7 +130,6 @@ extern bool Cmdline_noshadercache;
extern bool Cmdline_prefer_ipv4;
extern bool Cmdline_prefer_ipv6;
extern bool Cmdline_dump_packet_type;
extern bool Cmdline_no_large_shaders;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -144,7 +149,6 @@ extern int Cmdline_verify_vps;
extern int Cmdline_reparse_mainhall;
extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_retail_time_compression_range;
extern bool Cmdline_benchmark_mode;
extern const char *Cmdline_pilot;
extern bool Cmdline_noninteractive;
@@ -163,9 +167,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
+24 -49
View File
@@ -141,9 +141,6 @@ SCP_vector<cc_line> Cc_lines;
// Backups for use when user closes the config menu without saving
SCP_vector<CCI> Control_config_backup;
// The current preset that the user is working on and will likely want to save to
static SCP_string Current_preset_name;
// Undo system
Undo_system Undo_controls;
@@ -926,8 +923,8 @@ bool control_config_do_reset(bool cycle, bool API_Access)
// first, determine how many bindings need to be changed
for (size_t e = 0; e < Control_config.size(); ++e) {
const auto& item = Control_config[e];
const auto& default_item = default_bindings[e];
auto item = Control_config[e];
auto default_item = default_bindings[e];
if (item.disabled) {
// skip
@@ -1294,11 +1291,11 @@ bool control_config_accept(bool API_Access)
char* cstr; // Must be a char *, because popup_input may return nullptr and std::string don't like it
retry:;
SCP_string default_string = (Current_preset_name.empty()) ? Player->callsign : Current_preset_name;
cstr = popup_input(flags,
XSTR( "Confirm new custom preset name.\n\nThe name must not be empty or a default preset.\n\n Press [Enter] to accept, [Esc] to abort to config menu.", 1867),
"Confirm new custom preset name.\n\nThe name must not be empty.\n\n Press [Enter] to accept, [Esc] to "
"abort to config menu.",
32 - 6,
default_string.c_str());
Player->callsign);
if (cstr == nullptr) {
// Abort
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
@@ -1319,13 +1316,14 @@ bool control_config_accept(bool API_Access)
});
if (it != Control_config_presets.end()) {
popup(flags | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
popup(flags, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
goto retry;
}
// Check if a preset file with name already exists. If so, prompt the user
CFILE* fp = cfopen((str + ".json").c_str(),
"r",
CFILE_NORMAL,
CF_TYPE_PLAYER_BINDS,
false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
@@ -1333,11 +1331,11 @@ bool control_config_accept(bool API_Access)
cfclose(fp);
int n = popup(flags,
2,
POPUP_CANCEL,
POPUP_OK,
POPUP_CANCEL,
"'%s'\n Already exists!\n Press OK to overwrite existing preset, or CANCEL to input another name",
str.c_str());
if ((n == 0) || (n == -1)) {
if ((n == 1) || (n == -1)) {
// If Cancel button was pressed, or popup dismissed:
// retry
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
@@ -1347,7 +1345,7 @@ bool control_config_accept(bool API_Access)
// Pack the current bindings into a preset, then save the file
CC_preset preset;
preset.name = std::move(str);
preset.name = str;
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
Control_config_presets.push_back(preset);
save_preset_file(preset, true);
@@ -1356,19 +1354,11 @@ bool control_config_accept(bool API_Access)
// consistant ordering
Control_config_presets.resize(1);
load_preset_files();
// finally, save the new preset so that changes will get saved to this preset
Current_preset_name = preset.name;
} else {
return false;
}
}
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', true)));
}
if (!API_Access) {
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
@@ -1384,8 +1374,8 @@ void control_config_cancel_exit(bool API_Access)
// Check if any changes were made
if (!API_Access && (control_config_get_current_preset() == Control_config_presets.end())) {
// Changes were made, prompt the user first.
int flags = PF_TITLE_WHITE | PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON;
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, XSTR( "You have unsaved changes.\n\n\n Do you wish to continue without saving?", 1866));
int flags = PF_TITLE_WHITE;
int choice = popup(flags, 2, POPUP_NO, POPUP_YES, "You have unsaved changes.\n\n\n Do you wish to continue without saving?");
switch (choice) {
case -1: // Aborted
@@ -1406,11 +1396,6 @@ void control_config_cancel_exit(bool API_Access)
// Restore all bindings with the backup
std::move(Control_config_backup.begin(), Control_config_backup.end(), Control_config.begin());
// adds scripting hook for 'On Control Config Menu Closed' --wookieejedi
if (scripting::hooks::OnControlConfigMenuClosed->isActive()) {
scripting::hooks::OnControlConfigMenuClosed->run(scripting::hook_param_list(scripting::hook_param("OptionsAccepted", 'b', false)));
}
if (!API_Access) {
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
}
@@ -1552,11 +1537,9 @@ void control_config_init(bool API_Access)
// Init preset cycling system
auto preset_it = control_config_get_current_preset();
if (preset_it == Control_config_presets.end()) {
Current_preset_name.clear();
Defaults_cycle_pos = 0;
} else {
Current_preset_name = preset_it->name;
Defaults_cycle_pos = static_cast<unsigned int>(std::distance(Control_config_presets.begin(), preset_it));
}
@@ -1668,9 +1651,6 @@ void control_config_close(bool API_Access)
Cc_lines.clear();
Conflicts.clear();
Undo_controls.clear();
// Clear this, just to be tidy
Current_preset_name.clear();
}
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic) {
@@ -1766,7 +1746,7 @@ bool control_config_delete_preset(CC_preset preset) {
return delete_preset_file(preset);
}
bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
bool control_config_create_new_preset(SCP_string newName)
{
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
@@ -1779,14 +1759,13 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
}
// Check if a preset file with name already exists.
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
return false;
}
// Pack the current bindings into a preset, then save the file
CC_preset preset;
preset.name = newName;
preset.type = Preset_t::pst;
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
// Done with the file
@@ -1815,7 +1794,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
return false; //should be unreachable, but just in case
}
bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newName, bool overwrite) {
bool control_config_clone_preset(CC_preset preset, SCP_string newName) {
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
@@ -1827,7 +1806,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
}
// Check if a preset file with name already exists.
if (!overwrite && ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0)) {
if ((cf_exists_full((newName + ".json").c_str(), CF_TYPE_PLAYER_BINDS)) != 0) {
return false;
}
@@ -1917,7 +1896,7 @@ int control_config_draw_list(int select_tease_line) {
char buf[256]; // c_str buffer
int font_height = gr_get_font_height();
for (line = Scroll_offset; cc_line_query_visible(line) && (line - Scroll_offset < LIST_BUTTONS_MAX); ++line) {
for (line = Scroll_offset; cc_line_query_visible(line); ++line) {
z = Cc_lines[line].cc_index;
// screen coordinate y = list box origin y + (this item's relative y - topmost item's relative y)
@@ -2112,7 +2091,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
}
if ((ctrl == BANK_WHEN_PRESSED || ctrl == GLIDE_WHEN_PRESSED) && (Last_key >= 0) && (k <= 0) &&
!key_is_pressed(Last_key)) {
!keyd_pressed[Last_key]) {
// If the selected cc_item is BANK_WHEN_PRESSED or GLIDE_WHEN_PRESSED, and
// If the polled key is a modifier, and
// k was consumed, and
@@ -2144,12 +2123,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
if (!done && (j < JOY_TOTAL_BUTTONS)) {
// Bind the joy button
Assert(!Control_config[ctrl].is_axis());
control_config_bind(ctrl, CC_bind(static_cast<CID>(joy), j), item, API_Access);
CC_bind joy_bind(static_cast<CID>(joy), j);
control_config_bind(ctrl, joy_bind, item, API_Access);
strcpy_s(bound_string, joy_bind.textify().c_str());
strcpy_s(bound_string, Joy_button_text[j]);
done = true;
}
@@ -2183,10 +2159,9 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
if (mouse_down(mouse_bind)) {
Assert(!Control_config[ctrl].is_axis());
control_config_bind(ctrl, mouse_bind, item, API_Access);
strcpy_s(bound_string, mouse_bind.textify().c_str());
strcpy_s(bound_string, Joy_button_text[i]);
done = true;
break;
@@ -2845,12 +2820,12 @@ int check_control_used(int id, int key)
// check what current modifiers are pressed
mask = 0;
if (key_is_pressed(KEY_LSHIFT, true) || key_is_pressed(KEY_RSHIFT, true)) {
if (keyd_pressed[KEY_LSHIFT] || key_down_count(KEY_LSHIFT) || keyd_pressed[KEY_RSHIFT] || key_down_count(KEY_RSHIFT)) {
// Any shift key is pressed, add KEY_SHIFTED mask
mask |= KEY_SHIFTED;
}
if (key_is_pressed(KEY_LALT, true) || key_is_pressed(KEY_RALT, true)) {
if (keyd_pressed[KEY_LALT] || key_down_count(KEY_LALT) || keyd_pressed[KEY_RALT] || key_down_count(KEY_RALT)) {
// Any alt key is pressed, add KEY_ALTED to the mask
mask |= KEY_ALTED;
}
@@ -2866,7 +2841,7 @@ int check_control_used(int id, int key)
z &= KEY_MASK;
if (key_is_pressed(z, true)) {
if (keyd_pressed[z] || key_down_count(z)) {
// Key combo is pressed, control activated
control_used(id);
return 1;
+6 -20
View File
@@ -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
+107 -109
View File
@@ -48,13 +48,12 @@ int Joy_dead_zone_size = 10;
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
std::pair<const char*, int>{"Deadzone", 1377},
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
.category(std::make_pair("Input", 1827))
.category("Input")
.range(0, 45)
.level(options::ExpertLevel::Beginner)
.default_val(10)
.bind_to(&Joy_dead_zone_size)
.importance(1)
.flags({options::OptionFlags::RetailBuiltinOption})
.finish();
int Joy_sensitivity = 9;
@@ -62,13 +61,12 @@ int Joy_sensitivity = 9;
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
std::pair<const char*, int>{"Sensitivity", 1745},
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
.category(std::make_pair("Input", 1827))
.category("Input")
.range(0, 9)
.level(options::ExpertLevel::Beginner)
.default_val(9)
.bind_to(&Joy_sensitivity)
.importance(2)
.flags({options::OptionFlags::RetailBuiltinOption})
.finish();
//! arrays which hold the key mappings. The array index represents a key-independent action.
@@ -178,7 +176,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 +207,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 +429,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 +436,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 +542,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 +721,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 +754,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 +791,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 +1152,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 +1204,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 +1955,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 +2648,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 +2675,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 +2698,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;
}
}
@@ -2782,12 +2782,10 @@ bool CCB::operator!=(const CCB& A) const {
}
bool CCB::has_first_conflict(const CCB& A) const {
// coverity[copy_paste_error:FALSE]
return !first.empty() && (first.conflicts_with(A.first) || first.conflicts_with(A.second));
}
bool CCB::has_second_conflict(const CCB& A) const {
// coverity[copy_paste_error:FALSE]
return !second.empty() && (second.conflicts_with(A.first) || second.conflicts_with(A.second));
}
+5 -11
View File
@@ -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) {
+13 -6
View File
@@ -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()
+1 -1
View File
@@ -6,7 +6,7 @@ namespace {
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
const int OUT_SAMPLE_RATE = 48000;
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
const int OUT_NUM_CHANNELS = av_popcount64(OUT_CH_LAYOUT);
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
+1 -5
View File
@@ -69,11 +69,7 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
paras.height = stream->codecpar->height;
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 36, 255)
paras.channel_layout = stream->codecpar->ch_layout.u.mask;
#else
paras.channel_layout = stream->codecpar->channel_layout;
#endif
paras.channel_layout = stream->codecpar->channel_layout;
paras.sample_rate = stream->codecpar->sample_rate;
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
+1 -1
View File
@@ -122,7 +122,7 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
}
SubtitleFramePtr frame(new SubtitleFrame());
frame->text = std::move(processed_text);
frame->text = processed_text;
frame->displayStartTime = start_time;
frame->displayEndTime = end_time;
+8 -33
View File
@@ -30,7 +30,6 @@
#include "io/key.h"
#include "mod_table/mod_table.h"
#include "network/multi.h"
#include "scripting/global_hooks.h"
extern int Game_mode;
extern int Is_standalone;
@@ -46,7 +45,6 @@ struct PlaybackState {
vec2d posBottomRight;
int subtitle_font = -1;
color subtitle_color = Color_bright_white;
};
void processEvents()
@@ -104,7 +102,7 @@ void displayVideo(Player* player, PlaybackState* state) {
auto subtitle = player->getCurrentSubtitle();
if (!subtitle.empty() && state->subtitle_font >= 0) {
gr_set_color_fast(&state->subtitle_color);
gr_set_color_fast(&Color_bright_white);
font::set_font(state->subtitle_font);
int width;
@@ -181,20 +179,7 @@ void initialize_player_state(Player* player, PlaybackState* state) {
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
if ((Movie_subtitle_rgba[0] >= 0 && Movie_subtitle_rgba[0] <= 255) &&
(Movie_subtitle_rgba[1] >= 0 && Movie_subtitle_rgba[1] <= 255) &&
(Movie_subtitle_rgba[2] >= 0 && Movie_subtitle_rgba[2] <= 255) &&
(Movie_subtitle_rgba[3] >= 0 && Movie_subtitle_rgba[3] <= 255))
{
gr_init_alphacolor(&state->subtitle_color,
Movie_subtitle_rgba[0],
Movie_subtitle_rgba[1],
Movie_subtitle_rgba[2],
Movie_subtitle_rgba[3]);
}
}
else if (font::FontManager::numberOfFonts() > 0) {
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
@@ -273,22 +258,12 @@ void movie_display_loop(Player* player, PlaybackState* state) {
namespace movie {
// Play one movie
bool play(const char* filename, bool via_tech_room = false)
{
if (scripting::hooks::OnMovieAboutToPlay->isActive())
{
auto paramList = scripting::hook_param_list(scripting::hook_param("Filename", 's', filename), scripting::hook_param("ViaTechRoom", 'b', via_tech_room));
bool skip = scripting::hooks::OnMovieAboutToPlay->isOverride(paramList);
scripting::hooks::OnMovieAboutToPlay->run(paramList);
if (skip)
return false;
}
bool play(const char* name) {
// mark the movie as viewable to the player when in a campaign
// do this before anything else so that we're sure the movie is available
// to the player even if it's not going to play right now
if (Game_mode & GM_CAMPAIGN_MODE) {
cutscene_mark_viewable(filename);
cutscene_mark_viewable(name);
}
if (Cmdline_nomovies || Is_standalone) {
@@ -317,7 +292,7 @@ bool play(const char* filename, bool via_tech_room = false)
// clear third buffer (may not be one, but that's ok)
gr_clear();
auto player = cutscene::Player::newPlayer(filename);
auto player = cutscene::Player::newPlayer(name);
if (player) {
PlaybackState state;
initialize_player_state(player.get(), &state);
@@ -327,7 +302,7 @@ bool play(const char* filename, bool via_tech_room = false)
player->stopPlayback();
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", filename));
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
}
Movie_active = false;
@@ -338,9 +313,9 @@ bool play(const char* filename, bool via_tech_room = false)
return true;
}
void play_two(const char* filename1, const char* filename2) {
if (play(filename1)) {
play(filename2);
void play_two(const char* name1, const char* name2) {
if (play(name1)) {
play(name2);
}
}
}
+2 -2
View File
@@ -14,9 +14,9 @@
namespace movie {
bool play(const char* filename, bool via_tech_room = false);
bool play(const char* name);
void play_two(const char* filename1, const char* filename2);
void play_two(const char* name1, const char* name2);
}
File diff suppressed because it is too large. Load diff
+178 -333
View File
@@ -3,17 +3,6 @@
#include "cfile/cfile.h"
#include "osapi/osregistry.h"
#ifdef WITH_OPENGL
#include <glad/glad.h>
#else
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
#endif
#define BCDEC_IMPLEMENTATION 1
PUSH_SUPPRESS_WARNINGS
#include "ddsutils/bcdec.h"
POP_SUPPRESS_WARNINGS
/* Currently supported formats:
* DXT1a (compressed)
@@ -23,9 +12,12 @@ POP_SUPPRESS_WARNINGS
* uncompressed 1555 (16-bit, 1-bit being alpha)
* uncompressed 8888 (32-bit)
* uncompressed 888 (24-bit, no alpha)
* uncompressed R8 (8-bit, Red channel as luminance)
* paletted 8-bit (256 colors)
*/
int Texture_compression_available = 0;
int Use_compressed_textures = 0;
// power of two check, to verify that a given DDS will always be usable since
// some may not be power-of-2
@@ -34,219 +26,39 @@ static inline int is_power_of_two(int w, int h)
return ( (w && !(w & (w-1))) && (h && !(h & (h-1))) );
}
static bool valid_dx10_format(const DDS_HEADER_DXT10 &header)
// This function is used to verify that the file format specified in the DX10 Header
// is supported by the OpenGL extensions
bool dds_read_dx10_header(CFILE* dds_file, DDS_HEADER_DXT10* header)
{
switch (header.dxgiFormat) {
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
return true;
header->dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(dds_file));
header->resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(dds_file));
header->miscFlag = cfread_uint(dds_file);
header->arraySize = cfread_uint(dds_file);
header->miscFlags2 = cfread_uint(dds_file);
default:
return false;
}
}
static bool conversion_needed(const DDS_HEADER &dds_header)
{
if ((dds_header.ddspf.dwFlags & DDPF_FOURCC) != DDPF_FOURCC) {
switch (header->dxgiFormat) {
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
return true;
default:
return false;
}
switch (dds_header.ddspf.dwFourCC) {
case FOURCC_DXT1:
case FOURCC_DXT3:
case FOURCC_DXT5:
return !GLAD_GL_EXT_texture_compression_s3tc;
case FOURCC_DX10:
// anything other than BC7 will end up invalid
return !GLAD_GL_ARB_texture_compression_bptc;
default:
break;
}
// anything not specifically listed should end up invalid
return false;
}
// Memory usage for uncompressed textures is quite high. Some MVP assets can
// require well over a GB of VRAM for a single ship after conversion. To help
// alleviate this we need to resize those textures where possible. At 1024x1024
// the memory requirement is reduced to about 36 MB per ship with a full set
// of textures.
//
// NOTE: modifies header!!
//
// returns: number of mipmap levels to skip
static uint conversion_resize(DDS_HEADER &dds_header)
{
const size_t MAX_SIZE = 1024;
uint width, height, depth, offset = 0;
if (dds_header.dwMipMapCount <= 1) {
return 0;
}
width = dds_header.dwWidth;
height = dds_header.dwHeight;
depth = dds_header.dwDepth;
// drop levels until we get to an appropriate size, but make sure we have
// at least 1 mipmap level remaining at the end (in case there's not a full chain)
while (((width > MAX_SIZE) || (height > MAX_SIZE)) && (offset < dds_header.dwMipMapCount-1)) {
width >>= 1;
height >>= 1;
depth >>= 1;
++offset;
}
// no change needed
if ( !offset ) {
return offset;
}
// update header with new values
dds_header.dwWidth = std::max(1U, width);
dds_header.dwHeight = std::max(1U, height);
dds_header.dwDepth = std::max(1U, depth);
return offset;
}
static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_DXT10 *dds_header_dx10 = nullptr)
{
DDS_HEADER_DXT10 dx10_header;
// read the code
int code = cfread_int(ddsfile);
// check it
if (code != DDS_FILECODE) {
return DDS_ERROR_BAD_HEADER;
}
// read header variables
dds_header.dwSize = cfread_uint(ddsfile);
dds_header.dwFlags = cfread_uint(ddsfile);
dds_header.dwHeight = cfread_uint(ddsfile);
dds_header.dwWidth = cfread_uint(ddsfile);
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
dds_header.dwDepth = cfread_uint(ddsfile);
dds_header.dwMipMapCount = cfread_uint(ddsfile);
// skip over the crap we don't care about
cfseek(ddsfile, 11*4, CF_SEEK_CUR);
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
dds_header.dwCaps = cfread_uint(ddsfile);
dds_header.dwCaps2 = cfread_uint(ddsfile);
// Unused but need them checked for later
dds_header.dwCaps3 = cfread_uint(ddsfile);
dds_header.dwCaps4 = cfread_uint(ddsfile);
dds_header.dwReserved2 = cfread_uint(ddsfile);
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
dx10_header.dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(ddsfile));
dx10_header.resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(ddsfile));
dx10_header.miscFlag = cfread_uint(ddsfile);
dx10_header.arraySize = cfread_uint(ddsfile);
dx10_header.miscFlags2 = cfread_uint(ddsfile);
if (dds_header_dx10) {
memcpy(dds_header_dx10, &dx10_header, sizeof(DDS_HEADER_DXT10));
}
}
// sanitize values
dds_header.dwDepth = std::max(1U, dds_header.dwDepth);
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
#ifndef NDEBUG
if (dds_header.dwDepth > 1) {
Assertion(dds_header.dwFlags & DDSD_DEPTH, "ERROR: Volume texture missing proper flags!!");
}
#endif
// set pitch manually (per MS docs)
dds_header.dwFlags &= ~DDSD_LINEARSIZE;
dds_header.dwFlags |= DDSD_PITCH;
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
int block_size = (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16;
dds_header.dwPitchOrLinearSize = std::max(1U, (dds_header.dwWidth+3)/4) * block_size;
} else {
// this isn't technically correct, but it's only wrong for formats we don't support
dds_header.dwPitchOrLinearSize = (dds_header.dwWidth * dds_header.ddspf.dwRGBBitCount + 7) / 8;
}
return DDS_ERROR_NONE;
}
static size_t compute_dds_size(const DDS_HEADER &dds_header)
{
uint d_width, d_height, d_depth;
size_t d_size = 0;
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
d_width = std::max(1U, dds_header.dwWidth >> i);
d_height = std::max(1U, dds_header.dwHeight >> i);
d_depth = std::max(1U, dds_header.dwDepth >> i);
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
// size of data block (4x4)
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
} else {
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
}
}
// assumes valid cubemap (should be checked elsewhere)
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
Assertion(d_size > 0, "ERROR: DDS size computed to 0!!");
return d_size;
}
static int get_bit_count(const DDS_HEADER &dds_header)
{
if (dds_header.ddspf.dwFlags & DDPF_RGB) {
return dds_header.ddspf.dwRGBBitCount;
} else if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
return 24;
} else {
return 32;
}
}
return 0;
}
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size)
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size, ubyte *palette)
{
DDS_HEADER dds_header;
DDS_HEADER_DXT10 dds_header_dx10;
int code = 0;
CFILE *ddsfile;
char real_name[MAX_FILENAME_LEN];
int retval = DDS_ERROR_NONE;
int ct = DDS_UNCOMPRESSED;
int is_cubemap = 0;
int bits = 0;
int i, is_cubemap = 0;
uint32_t d_width = 0, d_height = 0, d_depth = 0;
size_t d_size = 0;
if (img_cfp == NULL) {
@@ -269,36 +81,113 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
ddsfile = img_cfp;
}
retval = _dds_read_header(ddsfile, dds_header, &dds_header_dx10);
// read the code
code = cfread_int(ddsfile);
if (retval != DDS_ERROR_NONE) {
// check it
if (code != DDS_FILECODE) {
retval = DDS_ERROR_BAD_HEADER;
goto Done;
}
// check for valid cubemap (we require all 6 faces)
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
// read header variables
dds_header.dwSize = cfread_uint(ddsfile);
dds_header.dwFlags = cfread_uint(ddsfile);
dds_header.dwHeight = cfread_uint(ddsfile);
dds_header.dwWidth = cfread_uint(ddsfile);
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
dds_header.dwDepth = cfread_uint(ddsfile);
dds_header.dwMipMapCount = cfread_uint(ddsfile);
// skip over the crap we don't care about
for (i = 0; i < 11; i++)
cfread_uint(ddsfile);
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
dds_header.dwCaps = cfread_uint(ddsfile);
dds_header.dwCaps2 = cfread_uint(ddsfile);
// Unused but need them checked for later
dds_header.dwCaps3 = cfread_uint(ddsfile);
dds_header.dwCaps4 = cfread_uint(ddsfile);
dds_header.dwReserved2 = cfread_uint(ddsfile);
// sanity
if (dds_header.dwDepth == 0)
dds_header.dwDepth = 1;
if (dds_header.dwMipMapCount < 1)
dds_header.dwMipMapCount = 1;
d_width = dds_header.dwWidth;
d_height = dds_header.dwHeight;
d_depth = dds_header.dwDepth;
// calculate the type and size of the data
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
// did I mention lately that I hate Microsoft?
// this is here to fix the situation where Microsoft doesn't follow their own docs
if ( !(dds_header.dwFlags & (DDSD_LINEARSIZE | DDSD_PITCH) ) || dds_header.dwPitchOrLinearSize <= 0 ) {
// calculate the block size, mult by 8 for DXT1, 16 for DXT3 & 5
d_size = ((dds_header.dwWidth + 3)/4) * ((dds_header.dwHeight + 3)/4) * ((dds_header.dwDepth + 3)/4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
} else {
d_size = dds_header.dwPitchOrLinearSize;
}
// it's a valid cubemap, probably
is_cubemap = 1;
}
// if we have mipmaps then compute them into the final size too
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
// reduce size by half for the next pass
d_width /= 2;
d_height /= 2;
if (d_width <= 0)
d_width = 1;
if (d_height <= 0)
d_height = 1;
// size of data block (4x4)
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
}
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
}
// it's a valid cubemap, probably
is_cubemap = 1;
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
Assert( d_size > 0 );
*size = d_size;
// determine and verify the type of data for internal use
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
switch (dds_header.ddspf.dwFourCC) {
case FOURCC_DXT1:
bits = 24;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT1 : DDS_DXT1;
break;
case FOURCC_DXT3:
bits = 32;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT3 : DDS_DXT3;
break;
case FOURCC_DXT5:
bits = 32;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT5 : DDS_DXT5;
break;
@@ -311,8 +200,9 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
break;
case FOURCC_DX10:
if (valid_dx10_format(dds_header_dx10)) {
if (dds_read_dx10_header(ddsfile, &dds_header_dx10)) {
// Currently only BC7 is supported
bits = 32;
ct = DDS_BC7;
} else {
retval = DDS_ERROR_UNSUPPORTED;
@@ -328,7 +218,46 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
goto Done;
break;
}
} else if (dds_header.ddspf.dwFlags & DDPF_RGB) {
} else if ( dds_header.ddspf.dwFlags & (DDPF_RGB | DDPF_PALETTEINDEXED8) ) {
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
// calculate full data size for all mipmap levels
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
d_width /= 2;
d_height /= 2;
d_depth /= 2;
if (d_width < 1)
d_width = 1;
if (d_height < 1)
d_height = 1;
if (d_depth < 1)
d_depth = 1;
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
}
Assert( d_size > 0 );
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
}
// it's a valid cubemap, probably
is_cubemap = 1;
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
*size = d_size;
bits = dds_header.ddspf.dwRGBBitCount;
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
} else {
// it's not a readable format
@@ -336,33 +265,21 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
goto Done;
}
// maybe do conversion if format not supported
if (conversion_needed(dds_header)) {
// switch to uncompressed format and reset vars
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
dds_header.ddspf.dwFlags |= DDPF_RGB;
dds_header.ddspf.dwRGBBitCount = 32;
// NOTE: modifies header and returns offset for mipmap count
dds_header.dwMipMapCount -= conversion_resize(dds_header);
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
}
// we don't support compressed, non-power-of-2 images
if ( (ct != DDS_UNCOMPRESSED) && (!is_power_of_two(dds_header.dwWidth, dds_header.dwHeight)) ) {
retval = DDS_ERROR_NON_POWER_OF_2;
goto Done;
}
// stuff important info
if (size)
*size = compute_dds_size(dds_header);
// make sure that the video card can handle compressed textures before using them
if ( !Use_compressed_textures && (ct != DDS_UNCOMPRESSED) && (ct != DDS_DXT_INVALID) ) {
retval = DDS_ERROR_NO_COMPRESSION;
goto Done;
}
// stuff important info
if (bpp)
*bpp = get_bit_count(dds_header);
*bpp = bits;
if (compression_type)
*compression_type = ct;
@@ -376,6 +293,12 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
if (levels)
*levels = dds_header.dwMipMapCount;
if (palette && (bits == 8)) {
cfseek(ddsfile, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
cfread(palette, 1, 1024, ddsfile);
}
Done:
if (img_cfp == NULL) {
// close file and return
@@ -390,10 +313,11 @@ Done:
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
{
int retval;
int w,h,ct,lvl;
size_t size = 0;
int bits = 0;
CFILE *cfp;
char real_name[MAX_FILENAME_LEN];
DDS_HEADER dds_header;
// this better not happen.. ever
Assert(filename != NULL);
@@ -405,107 +329,28 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
strcat_s(real_name, ".dds");
// open it up and go to the data section
cfp = cfopen(real_name, "rb", cf_type);
cfp = cfopen(real_name, "rb", CFILE_NORMAL, cf_type);
// just in case
if (cfp == nullptr)
if (cfp == NULL)
return DDS_ERROR_INVALID_FILENAME;
// read the header -- if its at this stage, it should be legal.
retval = _dds_read_header(cfp, dds_header);
retval = dds_read_header(real_name, cfp, &w, &h, &bits, &ct, &lvl, &size);
Assert(retval == DDS_ERROR_NONE);
// this really shouldn't be needed but better safe than sorry
if (retval != DDS_ERROR_NONE) {
cfclose(cfp);
return retval;
}
cfseek(cfp, (dds_header.ddspf.dwFourCC == FOURCC_DX10) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
size = compute_dds_size(dds_header);
cfseek(cfp, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
// read in the data
if ( !conversion_needed(dds_header) ) {
cfread(data, 1, (int)size, cfp);
} else {
// Compression format not supported, convert to BGRA
ubyte *comp_data = (ubyte*)vm_malloc(size);
cfread(comp_data, 1, (int)size, cfp);
ubyte *src = comp_data;
ubyte *dst = data;
uint d_width, d_height, d_depth;
size_t data_offset = 0;
// NOTE: this alters the width, height, and depth values in the header,
// so we have to jump through some hoops to get the proper values
const uint mipmap_offset = conversion_resize(dds_header);
const int num_faces = (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) ? 6 : 1;
const bool has_depth = (dds_header.dwFlags & DDSD_DEPTH) == DDSD_DEPTH;
for (int f = 0; f < num_faces; ++f) {
// if we resized then skip over all of that data (altering values to match pre-resize)
for (uint x = 0; x < mipmap_offset; ++x) {
d_width = std::max(1U, dds_header.dwWidth << (mipmap_offset - x));
d_height = std::max(1U, dds_header.dwHeight << (mipmap_offset - x));
d_depth = has_depth ? std::max(1U, dds_header.dwDepth << (mipmap_offset - x)) : 1U;
src += (d_width * d_height * d_depth);
}
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
// width/height/depth at post-resize mipmap sizes, so compensate here
d_width = std::max(1U, dds_header.dwWidth >> (m - mipmap_offset));
d_height = std::max(1U, dds_header.dwHeight >> (m - mipmap_offset));
d_depth = std::max(1U, dds_header.dwDepth >> (m - mipmap_offset));
for (uint d = 0; d < d_depth; ++d) {
for (uint i = 0; i < d_height; i += 4) {
for (uint j = 0; j < d_width; j += 4) {
dst = data + data_offset + ((i * d_width + j) * 4);
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
bcdec_bc7(src, dst, d_width * 4);
src += BCDEC_BC7_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT5) {
bcdec_bc3(src, dst, d_width * 4);
src += BCDEC_BC3_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
bcdec_bc1(src, dst, d_width * 4);
src += BCDEC_BC1_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT3) {
bcdec_bc2(src, dst, d_width * 4);
src += BCDEC_BC2_BLOCK_SIZE;
}
}
}
}
// we need it in bgra, XOR to the rescue
for (size_t x = data_offset; x < (data_offset + (d_width * d_height * d_depth * 4)); x += 4) {
data[x] ^= data[x+2], data[x+2] ^= data[x], data[x] ^= data[x+2];
}
// bump data offset to next layer
data_offset += (d_width * d_height * d_depth * 4);
}
}
vm_free(comp_data);
comp_data = nullptr;
// switch to uncompressed format and reset vars (needed below to get correct bit count)
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
dds_header.ddspf.dwFlags |= DDPF_RGB;
dds_header.ddspf.dwRGBBitCount = 32;
}
cfread(data, 1, (int)size, cfp);
if (bpp)
*bpp = (ubyte)get_bit_count(dds_header);
*bpp = (ubyte)bits;
// we look done here
cfclose(cfp);
@@ -558,7 +403,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
strcat_s(real_filename, ".dds");
}
CFILE *image = cfopen( real_filename, "wb", CF_TYPE_CACHE );
CFILE *image = cfopen( real_filename, "wb", CFILE_NORMAL, CF_TYPE_CACHE );
if (image == NULL) {
mprintf(("Unable to open DDS image for saving!!\n"));
+4 -2
View File
@@ -59,7 +59,6 @@
#define DDSD_HEIGHT 0x00000002
#define DDSD_CAPS 0x00000001
#define DDSD_MIPMAPCOUNT 0x00020000
#define DDSD_DEPTH 0x00800000
#define DDSCAPS_COMPLEX 0x00000008
#define DDSCAPS_PRIMARYSURFACE 0x00000200
@@ -279,7 +278,7 @@ typedef struct {
//reads a dds header
//returns one of the error values
//'compression_type' comes back as one of the DDS_DXTC* defines
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0);
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0, ubyte *palette = NULL);
//reads bitmap
//size of the data it stored in size
@@ -291,4 +290,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
//returns a string from a DDS error code
const char *dds_error_string(int code);
extern int Texture_compression_available;
extern int Use_compressed_textures;
#endif //__DDS_H
+31 -52
View File
@@ -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() );
@@ -1214,9 +1197,6 @@ void debris_render(object * obj, model_draw_list *scene)
// render_info.set_flags(MR_NO_LIGHTING);
}
if (db->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(db->model_instance_num)->texture_replace);
submodel_render_queue( &render_info, scene, pm, pmi, db->submodel_num, &obj->orient, &obj->pos );
if (tbase != NULL && (swapped!=-1) && pm) {
@@ -1224,18 +1204,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;
+7 -7
View File
@@ -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
+38 -16
View File
@@ -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);
@@ -152,7 +174,7 @@ void parse_decals_table(const char* filename) {
SCP_string name;
stuff_string(name, F_NAME);
DecalDefinition def(std::move(name));
DecalDefinition def(name);
def.parse();
DecalDefinitions.push_back(std::move(def));
@@ -164,17 +186,17 @@ void parse_decals_table(const char* filename) {
return;
}
if (!gr_is_capable(gr_capability::CAPABILITY_DEFERRED_LIGHTING)) {
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
// We need deferred lighting
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
}
if (!gr_is_capable(gr_capability::CAPABILITY_NORMAL_MAP)) {
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
// We need normal mapping for the full feature range
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
}
if (!gr_is_capable(gr_capability::CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
// We need separate blending functions for different color buffers
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
@@ -198,17 +220,17 @@ struct Decal {
vm_vec_make(&scale, 1.f, 1.f, 1.f);
}
bool isValid() const {
if (!object.isValid()) {
bool isValid() {
if (!object.IsValid()) {
return false;
}
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
if (object.objp->flags[Object::Object_Flags::Should_be_dead]) {
return false;
}
if (orig_obj_type != object.objp()->type) {
if (orig_obj_type != object.objp->type) {
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
OBJ_INDEX(object.objp), Object_type_names[orig_obj_type], Object_type_names[object.objp->type]));
return false;
}
@@ -219,12 +241,12 @@ struct Decal {
}
}
auto objp = object.objp();
auto objp = object.objp;
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models,
Assertion(submodel >= 0 && submodel < model_get(object_get_model(objp))->n_models,
"Invalid submodel number detected!");
auto smi = &model_instance->submodel[submodel];
@@ -317,7 +339,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
}
if (required_string_if_new("+Radius:", is_new_entry)) {
dest_info.radius = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
dest_info.radius = util::parseUniformRange(0.0001f);
}
if (required_string_if_new("+Lifetime:", is_new_entry)) {
@@ -325,7 +347,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
dest_info.lifetime = util::UniformFloatRange(-1.0f);
} else {
// Require at least a small lifetime so that the calculations don't have to deal with div-by-zero
dest_info.lifetime = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
dest_info.lifetime = util::parseUniformRange(0.0001f);
}
}
@@ -371,9 +393,9 @@ void initializeMission() {
}
matrix4 getDecalTransform(Decal& decal) {
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
auto objp = decal.object.objp();
auto objp = decal.object.objp;
auto ship = &Ships[objp->instance];
auto pmi = model_get_instance(ship->model_instance_num);
auto pm = model_get(pmi->model_num);
@@ -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;
}
+5 -5
View File
@@ -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();
@@ -65,10 +65,10 @@ typedef int DecalReference;
*/
struct creation_info {
DecalReference definition_handle = -1;
util::ParsedRandomFloatRange radius = ::util::UniformFloatRange(-1.0f);
util::UniformFloatRange radius = ::util::UniformFloatRange(-1.0f);
float width = -1.0f;
float height = -1.0f;
util::ParsedRandomFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
bool random_rotation = false;
};
@@ -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);
+73 -102
View File
@@ -2,9 +2,8 @@
#include "shadows.sdr" //! #include "shadows.sdr"
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "model_shader_flags.h"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
#define MAX_LIGHTS 8
#define LT_DIRECTIONAL 0
@@ -97,56 +96,30 @@ layout (std140) uniform modelData {
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
vec4 position;
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertIn;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
uniform sampler2DArray sBasemap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
uniform sampler2DArray sGlowmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
uniform sampler2DArray sSpecmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
uniform samplerCube sEnvmap;
uniform samplerCube sIrrmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
uniform sampler2DArray sNormalmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
uniform sampler2DArray sAmbientmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
uniform sampler2D sFramebuffer;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
uniform sampler2DArray sMiscmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
uniform sampler2DArray shadow_map;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
out vec4 fragOut0;
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
#ifndef FLAG_SHADOW_MAP
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
@@ -212,7 +185,7 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
// need depth and depth squared for variance shadow maps
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
@@ -232,13 +205,13 @@ void main()
vec3 unitNormal = normalize(vertIn.normal);
vec3 normal = unitNormal;
#prereplace IF_FLAG MODEL_SDR_FLAG_AMBIENT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_AMBIENT)) {
// red channel is ambient occlusion factor which only affects ambient lighting.
// green is cavity occlusion factor which only affects diffuse and specular lighting.
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_AMBIENT
}
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
// Normal map - convert from DXT5nm
vec2 normalSample;
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
@@ -250,7 +223,7 @@ void main()
normal /= norm;
else
normal = unitNormal;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
}
vec2 distort = vec2(0.0, 0.0);
@@ -258,26 +231,26 @@ void main()
distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
}
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
vec2 diffuseTexCoord = texCoord;
if (effect_num == 2) {
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
}
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = srgb_to_linear(baseColor.rgb);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
}
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
baseColor.a *= alphaMult;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
}
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
// if blend_alpha is 2, assume blend func is additive and don't modify color
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
}
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
@@ -290,22 +263,21 @@ void main()
// Now that we have a base color and min gloss value, compute the spec color
vec4 specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
specColor *= alphaMult;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
}
if(alphaGloss) glossData = specColor.a;
if(gammaSpec) {
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
fresnelFactor = 1.0;
}
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
specColor.rgb = srgb_to_linear(specColor.rgb);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
}
}
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
@@ -313,8 +285,8 @@ void main()
vec4 teamMask = vec4(0.0);
vec3 team_color_glow = vec3(0.0);
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
@@ -324,52 +296,52 @@ void main()
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
}
baseColor.rgb += team_color;
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
specColor.rgb += team_color;
specColor.rgb = max(specColor.rgb, vec3(0.03));
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
}
}
}
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
// Ambient lighting still needs to be done since that counts as an "emissive" color
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
emissiveColor.rgb += baseColor.rgb * lightAmbient;
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
}
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
}
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
float shadow = 1.0;
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
}
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
}
}
}
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
// to determine the mip bias.
@@ -413,48 +385,48 @@ void main()
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
}
}
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
if (FLAG_ACTIVE(MODEL_SDR_FLAG_GLOW)) {
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
}
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
}
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_GLOW
}
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
//Since this is emissive, we need to premultiply it for intensity, and apply alpha to not replace existing emissive
emissiveColor *= alphaMult;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
}
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vec3 finalFogColor = fogColor.rgb;
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
finalFogColor = srgb_to_linear(finalFogColor);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
if(blend_alpha == 1) finalFogColor *= baseColor.a;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
}
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
// color.
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
specColor.rgb *= vertIn.fogDist;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
}
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
if(desaturate == 1) {
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
}
if (effect_num == 0) {
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
@@ -463,34 +435,33 @@ void main()
} else if (effect_num == 1) {
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
emissiveColor.rgb += vec3(shinefactor);
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT))) {
// ATI Wireframe fix *grumble*
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
}
} else if (effect_num == 2) {
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
baseColor.a = baseColor.a;
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
} else {
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
}
}
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED))) {
// emissive colors won't be added later when we are using forward rendering so we need to do that here
baseColor.rgb += emissiveColor.rgb;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
}
fragOut0 = baseColor;
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
}
#endif
}
+34 -63
View File
@@ -1,18 +1,17 @@
#extension GL_ARB_gpu_shader5: enable
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
#include "model_shader_flags.h"
#ifdef MODEL_SDR_FLAG_THICK_OUTLINES
#ifdef FLAG_THICK_OUTLINE
layout (triangles) in;
// For every triangle line we generate 2 triangles which can be done with 4 vertices so in total we will need 12 vertices
layout (triangle_strip, max_vertices = 12) out;
#elif defined(MODEL_SDR_FLAG_SHADOW_MAP)
#elif defined(FLAG_SHADOW_MAP)
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#endif
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
@@ -103,17 +102,11 @@ layout (std140) uniform modelData {
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
@@ -123,35 +116,22 @@ in VertexOutput {
#endif
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertIn[];
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
vec4 position;
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertOut;
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
void main(void)
{
#ifdef GL_ARB_gpu_shader5
@@ -161,17 +141,16 @@ out VertexOutput {
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
if (vertIn[vert].clipModel > 0.9) {
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
gl_Position = gl_in[vert].gl_Position;
} else {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
}
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_TRANSFORM
} else {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
}
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
@@ -181,26 +160,22 @@ out VertexOutput {
gl_Layer = instanceID;
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
vertOut.envReflect = vertIn[vert].envReflect;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vertOut.fogDist = vertIn[vert].fogDist;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
}
if (use_clip_plane) {
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
}
@@ -208,7 +183,7 @@ out VertexOutput {
}
EndPrimitive();
}
#elif defined(MODEL_SDR_FLAG_THICK_OUTLINES)
#elif defined(FLAG_THICK_OUTLINE)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
@@ -239,26 +214,22 @@ out VertexOutput {
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
vertOut.envReflect = vertIn[vert].envReflect;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
vertOut.envReflect = vertIn[vert].envReflect;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vertOut.fogDist = vertIn[vert].fogDist;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
}
if (use_clip_plane) {
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
}
+17 -36
View File
@@ -2,9 +2,7 @@
#extension GL_ARB_gpu_shader5: enable
#include "shadows.sdr"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
#include "model_shader_flags.h"
in vec4 vertPosition;
in vec4 vertTexCoord;
@@ -97,22 +95,13 @@ layout (std140) uniform modelData {
int flags;
};
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
@@ -124,15 +113,11 @@ out VertexOutput {
#endif
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertOut;
#define TEXELS_PER_MATRIX 4
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
@@ -142,7 +127,6 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
invisible = transform[3].w >= 0.9;
transform[3].w = 1.0;
}
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
void main()
{
@@ -153,21 +137,20 @@ void main()
mat4 scale = mat4(1.0);
bool clipModel = false;
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
}
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
#prereplace IF_FLAG MODEL_SDR_FLAG_THRUSTER
if (FLAG_ACTIVE(MODEL_SDR_FLAG_THRUSTER)) {
if(vertex.z < -1.5) {
vertex.z *= thruster_scale;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_THRUSTER
}
// Transform the normal into eye space and normalize the result.
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
position = modelViewMatrix * orient * vertex;
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
@@ -179,39 +162,37 @@ void main()
#else
gl_Position = projMatrix * position;
#endif
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
}
// Setup stuff for normal maps and envmaps
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
vec3 b = cross(normal, t) * vertTangent.w;
vertOut.tangentMatrix = mat3(t, b, normal);
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
// Environment mapping reflection vector.
vec3 envReflect = reflect(normalize(position.xyz), normal);
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
if (clipModel) {
// Clip this model by moving all vertices outside the clip volume
gl_Position = vec4(vec3(-2.0), 1.0);
}
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
}
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
@@ -219,7 +200,7 @@ void main()
gl_ClipDistance[0] = 1.0;
}
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
@@ -1,9 +0,0 @@
#predefine IF_FLAG if ((flags & %s) != 0) {
#predefine IF_NOT_FLAG if ((flags & %s) == 0) {
#predefine ELSE_FLAG } else { %s
#predefine ENDIF_FLAG } %s
#predefine IF_FLAG_COMPILED //if true %s
#predefine ENDIF_FLAG_COMPILED //endif true %s
#define MODEL_SDR_FLAG_MODE_GLSL 1
#include "model_shader_flags.h"
@@ -1,6 +0,0 @@
#predefine IF_FLAG #ifdef %s
#predefine IF_NOT_FLAG #ifndef %s
#predefine ELSE_FLAG #else //%s
#predefine ENDIF_FLAG #endif //%s
#predefine IF_FLAG_COMPILED #ifdef %s
#predefine ENDIF_FLAG_COMPILED #endif //%s
@@ -1,35 +1,19 @@
#ifdef MODEL_SDR_FLAG_MODE_CPP
#define SDR_FLAG(name, value, geoshader) constexpr int name = value;
#elif defined MODEL_SDR_FLAG_MODE_CPP_ARRAY
#define SDR_FLAG(name, value, geoshader) {SDR_TYPE_MODEL, geoshader, value, #name, {}, #name},
#elif defined MODEL_SDR_FLAG_MODE_GLSL
#define SDR_FLAG(name, value, geoshader) const int name = value;
#else
#error Make sure to properly define the usage mode for this file!
#endif
#define MODEL_SDR_FLAG_LIGHT (1 << 0)
#define MODEL_SDR_FLAG_DEFERRED (1 << 1)
#define MODEL_SDR_FLAG_HDR (1 << 2)
#define MODEL_SDR_FLAG_DIFFUSE (1 << 3)
#define MODEL_SDR_FLAG_GLOW (1 << 4)
#define MODEL_SDR_FLAG_SPEC (1 << 5)
#define MODEL_SDR_FLAG_ENV (1 << 6)
#define MODEL_SDR_FLAG_NORMAL (1 << 7)
#define MODEL_SDR_FLAG_AMBIENT (1 << 8)
#define MODEL_SDR_FLAG_MISC (1 << 9)
#define MODEL_SDR_FLAG_TEAMCOLOR (1 << 10)
#define MODEL_SDR_FLAG_FOG (1 << 11)
#define MODEL_SDR_FLAG_TRANSFORM (1 << 12)
#define MODEL_SDR_FLAG_SHADOWS (1 << 13)
#define MODEL_SDR_FLAG_THRUSTER (1 << 14)
#define MODEL_SDR_FLAG_ALPHA_MULT (1 << 15)
SDR_FLAG(MODEL_SDR_FLAG_LIGHT , (1 << 0) , false)
SDR_FLAG(MODEL_SDR_FLAG_DEFERRED , (1 << 1) , false)
SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false)
SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false)
SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false)
SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false)
SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false)
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false)
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false)
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false)
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false)
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false)
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false)
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false)
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false)
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false)
#ifndef MODEL_SDR_FLAG_MODE_GLSL
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true)
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true)
#endif
#define FLAG_ACTIVE(flag) (flags & flag) != 0
+2 -3
View File
@@ -174,8 +174,7 @@ void main()
for(int i = 0; i < samples; i++) {
vec4 localPos = texelFetch(texPos, texel, i);
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
//However, if the median distance is 0, only deal with current texel if it's local distance is 0 as well
float localWeight = max(step(-0.001, dist) * step(-0.001, localPos.z),
float localWeight = max(step(-0.001, dist),
smoothstep(dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), dist + dist * texelWidthFactor * voxelDepth, localPos.z) *
smoothstep(dist - dist * texelWidthFactor * voxelDepth, dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), localPos.z)
);
@@ -191,7 +190,7 @@ void main()
fragOut0 = color / weight;
fragOut1 = pos / weight;
fragOut2 = vec4(normalize(normal.xyz), normal.a / weight);
fragOut2 = normalize(normal);
fragOut3 = specular / weight;
fragOut4 = emissive / weight;
gl_FragDepth = depth / weight;
+8 -12
View File
@@ -21,11 +21,9 @@ layout (std140) uniform genericData {
vec3 globalLightDiffuse;
float stepsize;
vec3 nebPos;
float opacitydistance;
float globalstepalpha;
vec3 nebSize;
float alphalim;
vec3 nebulaColor;
float udfScale;
float emissiveSpreadFactor;
float emissiveIntensity;
float emissiveFalloff;
@@ -94,14 +92,12 @@ void main()
vec3 sidestep = 1.0 / vec3(textureSize(volume_tex, 0));
for(float stept = maxtMin; stept < mintMax;) {
for(float stept = maxtMin; stept < mintMax; stept += stepsize) {
//Step setup
vec3 position = camera + rayDirection * stept - nebPos;
vec3 sampleposition = position / nebSize + 0.5;
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
float stepsize_current = min(max(stepsize, volume_sample.x * udfScale), mintMax - stept);
#ifdef DO_EDGE_SMOOTHING
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
float stepcolor_alpha = volume_sample.a;
@@ -121,7 +117,7 @@ void main()
float stepcolor_alpha = volume_sample.a;
#endif
float stepalpha = -(pow(alphalim, 1.0 / (opacitydistance / stepsize_current)) - 1.0f) * stepcolor_alpha;
float stepalpha = globalstepalpha * stepcolor_alpha;
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
if(stepcolor_alpha > 0.01)
{
@@ -131,10 +127,10 @@ void main()
//Diffuse
#ifdef NOISE
//Mix the actual nebula color with the noise color depending on the product of the noise channels multiplied with intensity, smooth-clamped from 0 to 1
vec3 stepcolor_neb = mix(nebulaColor, noiseColor,
vec3 stepcolor_neb = mix(volume_sample.rgb, noiseColor,
smoothstep(0, 1, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
#else
vec3 stepcolor_neb = nebulaColor;
vec3 stepcolor_neb = volume_sample.rgb;
#endif
vec3 stepcolor_diffuse = stepcolor_neb * henyey_greenstein(dot(rayDirection, globalLightDirection));
float directionalLightStep = 4.0 / float(directionalLightSampleSteps);
@@ -149,17 +145,17 @@ void main()
stepcolor_diffuse *= beer_powder_norm * (1 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
//Emissive
cumnebdist += stepcolor_alpha * stepsize_current;
cumnebdist += stepcolor_alpha * stepsize;
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
vec3 stepcolor_emissive = emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity;
vec3 stepcolor_emissive = emissive_lod.rgb * pow(1 - globalstepalpha, (depth - stept) * emissiveFalloff) * emissiveIntensity;
//Step finish
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
float stepalpha = globalstepalpha * stepcolor_alpha;
cumcolor += stepalpha * cumOMAlpha * stepcolor;
}
cumOMAlpha *= 1.0 - stepalpha;
stept += stepsize_current;
if(cumOMAlpha < alphalim)
break;
@@ -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))
+80 -26
View File
@@ -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" "stealth" "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" "stealth" "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" "stealth" "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" "stealth" "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" "stealth" "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" "stealth" "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,37 @@ $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" "stealth" "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" "stealth" "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 - Stealth ships always have another type, so this isn't used
$Name: Stealth
$Counts for Alone: YES
$Praise Destruction: YES
$On Hotkey List: YES
$Target as Threat: YES
$Show Attack Direction: 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" "disarm ship" "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" )
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "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
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "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
@@ -110,16 +136,16 @@ $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")
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "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" )
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "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" "stealth" "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" "stealth" "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
@@ -138,16 +164,44 @@ $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" )
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "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" )
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "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" "stealth" "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" "stealth" "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" "disarm ship" "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" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "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" "stealth" "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 +230,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" "stealth" "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 +262,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" "stealth" "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 +292,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" "stealth" "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 +322,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" "stealth" "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 +352,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" "stealth" "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 +382,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" "stealth" "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 +412,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" "stealth" "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 +440,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" "stealth" "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 +466,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" "stealth" "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 +490,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" "stealth" "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
+13 -2
View File
@@ -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
+61 -246
View File
@@ -37,15 +37,26 @@ constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256;
SCP_vector<fireball> Fireballs;
SCP_vector<int> Unused_fireball_indices;
SCP_vector<fireball_info> Fireball_info;
fireball_info Fireball_info[MAX_FIREBALL_TYPES];
int fireball_used[MAX_FIREBALL_TYPES];
int Num_fireball_types = 0;
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("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Fireball_use_3d_warp)
.importance(65)
.finish();
/**
* Play warp in sound for warp effect
@@ -109,7 +120,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
{
Assertion(SCP_vector_inbounds(Fireball_info, fireball_index), "fireball_index is out of bounds!");
Assert((fireball_index >= 0) && (fireball_index < MAX_FIREBALL_TYPES));
switch (fireball_index)
{
@@ -153,7 +164,7 @@ static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fir
*/
static void fireball_set_default_color(int idx)
{
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
switch (idx)
{
@@ -189,7 +200,7 @@ static void fireball_set_default_color(int idx)
static void fireball_set_default_warp_attributes(int idx)
{
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
switch (idx)
{
@@ -199,6 +210,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;
}
}
@@ -218,9 +232,9 @@ void fireball_info_clear(fireball_info *fb)
int fireball_info_lookup(const char *unique_id)
{
for (size_t i = 0; i < Fireball_info.size(); ++i)
for (int i = 0; i < Num_fireball_types; ++i)
if (!stricmp(Fireball_info[i].unique_id, unique_id))
return static_cast<int>(i);
return i;
return -1;
}
@@ -294,19 +308,25 @@ static void parse_fireball_tbl(const char *table_filename)
// we are creating a new entry, so set some defaults
else
{
int new_fireball_index = static_cast<int>(Fireball_info.size());
Fireball_info.emplace_back();
fi = &Fireball_info.back();
// make sure we don't exceed the max
if (Num_fireball_types >= MAX_FIREBALL_TYPES)
{
error_display(0, "Too many fireball entries! Max is %d", MAX_FIREBALL_TYPES);
return;
}
fi = &Fireball_info[Num_fireball_types];
fireball_info_clear(fi);
// If the table didn't specify a unique ID, generate one. This will be assigned a few lines later.
if (strlen(unique_id) == 0)
fireball_generate_unique_id(unique_id, NAME_LENGTH, new_fireball_index);
fireball_generate_unique_id(unique_id, NAME_LENGTH, Num_fireball_types);
// Set remaining fireball defaults
fireball_set_default_color(new_fireball_index);
fireball_set_default_warp_attributes(new_fireball_index);
fireball_set_default_color(Num_fireball_types);
fireball_set_default_warp_attributes(Num_fireball_types);
Num_fireball_types++;
first_time = true;
}
@@ -351,17 +371,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 +383,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");
@@ -495,9 +399,9 @@ void fireball_parse_tbl()
if (fireballs_parsed)
return;
// every newly parsed fireball_info will get cleared before being added;
// must clear the vector outside of parse_fireball_tbl because it's called more than once
Fireball_info.clear();
// every newly parsed fireball_info will get cleared before being added
// must do this outside of parse_fireball_tbl because it's called twice
Num_fireball_types = 0;
parse_fireball_tbl("fireball.tbl");
@@ -532,11 +436,10 @@ void fireball_parse_tbl()
void fireball_load_data()
{
int i, n, idx;
int i, idx;
fireball_info *fd;
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
for ( i = 0; i < Num_fireball_types; i++ ) {
fd = &Fireball_info[i];
for(idx=0; idx<fd->lod_count; idx++){
@@ -645,13 +548,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
@@ -901,7 +798,8 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
object *obj;
fireball_info *fd;
fireball_lod *fl;
Assertion(SCP_vector_inbounds(Fireball_info, fireball_type), "fireball_type is out of bounds!");
Assert( fireball_type > -1 );
Assert( fireball_type < Num_fireball_types );
fd = &Fireball_info[fireball_type];
@@ -1048,14 +946,13 @@ void fireball_close()
void fireballs_page_in()
{
int i, n, idx;
int i, idx;
fireball_info *fd;
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
for ( i = 0; i < Num_fireball_types; i++ ) {
fd = &Fireball_info[i];
if ((i < NUM_DEFAULT_FIREBALLS) || fd->fireball_used) {
if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]) {
// if this is a Knossos ani, only load if Knossos_warp_ani_used is true
if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
continue;
@@ -1076,7 +973,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;
}
@@ -1087,8 +984,8 @@ void fireball_get_color(int idx, float *red, float *green, float *blue)
{
Assert( red && blue && green );
if (!SCP_vector_inbounds(Fireball_info, idx)) {
UNREACHABLE("idx is out of bounds!");
if ( (idx < 0) || (idx >= Num_fireball_types) ) {
Int3();
*red = 1.0f;
*green = 1.0f;
@@ -1142,48 +1039,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 +1096,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;
@@ -1292,16 +1120,3 @@ int fireball_get_count()
return count;
}
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name)
{
stuff_int_list(list, RAW_INTEGER_TYPE);
list.erase(std::remove_if(list.begin(), list.end(), [&](int index) {
if (!SCP_vector_inbounds(Fireball_info, index)) {
Warning(LOCATION, "Fireball index %d for %s was out of bounds. Removing this index.", index, name);
return true;
}
return false;
}), list.end());
}
+8 -25
View File
@@ -33,19 +33,14 @@ class asteroid_info;
#define FIREBALL_EXPLOSION_LARGE1 4 // Used for the big explosion when a ship breaks into pieces
#define FIREBALL_EXPLOSION_LARGE2 5 // Used for the big explosion when a ship breaks into pieces
#define MAX_FIREBALL_TYPES 32 // The maximum number of fireballs that can be defined
#define NUM_DEFAULT_FIREBALLS 6
#define MAX_FIREBALL_LOD 4
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
// Gamma39er: Flare animation enum. Add new animation types here.
enum class warp_style
{
CLASSIC,
ENHANCED,
CINEMATIC
};
extern int fireball_used[MAX_FIREBALL_TYPES];
// all this moved here by Goober5000 because it makes more sense in the H file
typedef struct fireball_lod {
@@ -62,20 +57,6 @@ 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;
@@ -85,7 +66,8 @@ typedef struct fireball_info {
int warp_model_id;
} fireball_info;
extern SCP_vector<fireball_info> Fireball_info;
extern fireball_info Fireball_info[MAX_FIREBALL_TYPES];
extern int Num_fireball_types;
// flag values for fireball struct flags member
#define FBF_WARP_CLOSE_SOUND_PLAYED (1<<0)
@@ -164,10 +146,11 @@ 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();
// Goober5000 - stuffs fireballs and checks that indexes are in bounds
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name);
#endif /* _FIREBALLS_H */
+22 -5
View File
@@ -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("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to_once(&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;
+1 -1
View File
@@ -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, (int)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,
-5
View File
@@ -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());
+2 -4
View File
@@ -114,8 +114,7 @@ const char *GS_event_text[] =
"GS_EVENT_PXO_HELP",
"GS_EVENT_FICTION_VIEWER", // 65
"GS_EVENT_SCRIPTING",
"GS_EVENT_SCRIPTING_MISSION",
"GS_EVENT_INGAME_OPTIONS"
"GS_EVENT_SCRIPTING_MISSION"
};
//XSTR:ON
@@ -179,8 +178,7 @@ const char *GS_state_text[] =
"GS_STATE_START_GAME",
"GS_STATE_FICTION_VIEWER",
"GS_STATE_SCRIPTING",
"GS_STATE_SCRIPTING_MISSION",
"GS_STATE_INGAME_OPTIONS"
"GS_STATE_SCRIPTING_MISSION"
};
//XSTR:ON
-2
View File
@@ -90,7 +90,6 @@ enum GS_EVENT {
GS_EVENT_FICTION_VIEWER,
GS_EVENT_SCRIPTING,
GS_EVENT_SCRIPTING_MISSION,
GS_EVENT_INGAME_OPTIONS,
GS_NUM_EVENTS // Last one++
};
@@ -162,7 +161,6 @@ enum GS_STATE {
GS_STATE_FICTION_VIEWER,
GS_STATE_SCRIPTING,
GS_STATE_SCRIPTING_MISSION,
GS_STATE_INGAME_OPTIONS,
GS_NUM_STATES // Last one++
};
+10 -34
View File
@@ -45,24 +45,14 @@ 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;})
.category("Audio")
.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 +333,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;
}
}
Loaded 100 of 1056 files, more files were not shown because too many files have changed in this diff. Show more