Compare commits

..
Author SHA1 Message Date
SirKnightly fc04d2086e Automated build commit 2023-02-11 12:13:50 +00:00
1211 changed files with 103506 additions and 133030 deletions

No files matched your search

+8
View File
@@ -1,6 +1,14 @@
cmake/ @asarium
ci/ @asarium @z64555
code/executor/ @asarium
code/scpui/ @asarium
code/scripting/ @asarium
code/controlconfig/ @z64555
code/model/modelanimation*.* @bmagnu
+41 -71
View File
@@ -6,7 +6,7 @@ on:
- 'nightly_*'
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
build_linux:
@@ -15,8 +15,23 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
# - name: Cache Qt
# id: cache-qt-lin
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
@@ -24,8 +39,7 @@ jobs:
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -45,7 +59,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@v3
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -61,12 +75,12 @@ jobs:
submodules: true
fetch-depth: '0'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v1
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
@@ -119,12 +133,7 @@ jobs:
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -135,19 +144,11 @@ jobs:
mkdir build
cd build
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" -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" ..
fi
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" ..
- name: Compile
working-directory: ./build
env:
@@ -164,7 +165,7 @@ jobs:
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
@@ -184,12 +185,12 @@ jobs:
submodules: true
fetch-depth: '0'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v1
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -215,7 +216,7 @@ jobs:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
arch: [x86_64]
name: Mac
runs-on: macos-latest
steps:
@@ -234,17 +235,12 @@ jobs:
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Set up test version
shell: bash
run: |
@@ -257,7 +253,6 @@ jobs:
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -266,39 +261,21 @@ jobs:
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCH: ${{ matrix.arch }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Sign builds
working-directory: ./build/bin
run: |
# make sure OpenAL framework is signed
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
# make sure dylibs are signed
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
# sign binaries
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
# sign apps
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
- name: Package build result
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
working-directory: ./build
run: cd bin && tar -cvzf macos-build.tar *.app
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
mac_zip:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v2
name: Checkout
@@ -307,24 +284,17 @@ jobs:
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-Release-${{ matrix.arch }}
name: mac-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-FastDebug-${{ matrix.arch }}
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
- name: Create Distribution package
working-directory: ./builds
env:
ARCH: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
working-directory: ./builds
+73 -80
View File
@@ -6,7 +6,7 @@ on:
- 'release_*'
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
create_release:
@@ -44,19 +44,59 @@ jobs:
name: Linux
needs: create_release # Don't run this job until create_release is done and successful
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
# - name: Cache Qt
# id: cache-qt-lin
# uses: actions/cache@v1
# cache the Qt directory so we don't have to reinstall it every time
# cache.inputs:
# path - A list of files, directories, and wildcard patterns to cache and restore. See @actions/glob for supported patterns.
# key - An explicit key for restoring and saving the cache
# restore-keys - An ordered list of keys to use for restoring the cache if no cache hit occurred for key
# cache.outputs:
# cache-hit true when an exact match was found for the key, false otherwise.
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# installs Qt in the action workflow
# install-qt-action.inputs:
# version desired qt version to install
# host Host platform of Qt, default to platform used by runs-on
# target target platform of Qt, default to desktop
# arch target architecture of Qt, only used for windows or android builds
# dir root dir Qt will be installed to
# install-deps if true, auto-install dependencies on linux. Default true
# modules whitespace delimited list string of additional addon modules to install
# archives whitespace delimited list string of Qt archives to install
# cached if true, Don't download Qt but set ENVARs; use with cache.outputs.cache-hit
# setup-python Set to false to skip using setup-python to find/download a valid python version
# set-env if true, set ENVARs; default = false
# aqtversion version of aqtinstall to use; default = 2.0.0
# py7zrversion version of py7zr to use; default = 0.16.1
# extra additional arguments to pass to aqinstall
# ENVARS set:
# Qt5_DIR / Qt6_DIR
# Qt bin dir appended to PATH
# QT_PLUGIN_PATH, QML2_IMPORT_PATH, PKG_CONFIG_PATH, LD_LIBRARY_PATH
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
name: Checkout
with:
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
ref: '${{ github.ref }}'
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -76,7 +116,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@v3
uses: actions/upload-artifact@v2
# 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.
@@ -100,16 +140,15 @@ jobs:
with:
submodules: true
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
ref: '${{ github.ref }}'
- name: Download Release builds
# Grab the release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
# Grab the debug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
@@ -120,7 +159,7 @@ jobs:
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
# Stash the result to artifact filespace
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
@@ -147,7 +186,6 @@ jobs:
name: Checkout
with:
submodules: true
ref: '${{ github.ref }}'
# - name: Cache Qt
# # Cache Qt
# id: cache-qt-win
@@ -175,12 +213,7 @@ jobs:
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -191,19 +224,11 @@ jobs:
mkdir build
cd build
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" -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" ..
fi
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" ..
- name: Compile
working-directory: ./build
env:
@@ -220,7 +245,7 @@ jobs:
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
@@ -242,15 +267,15 @@ jobs:
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -265,13 +290,13 @@ jobs:
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
- name: Upload debug package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.debug_name }}
path: ${{ steps.generate_package.outputs.debug_path }}
@@ -290,7 +315,7 @@ jobs:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
arch: [x86_64]
name: Mac
needs: create_release
runs-on: macos-latest
@@ -309,25 +334,18 @@ jobs:
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
ref: '${{ github.ref }}'
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -336,39 +354,21 @@ jobs:
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCH: ${{ matrix.arch }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Sign builds
working-directory: ./build/bin
run: |
# make sure OpenAL framework is signed
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
# make sure dylibs are signed
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
# sign binaries
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
# sign apps
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
- name: Package build result
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
working-directory: ./build
run: cd bin && tar -cvzf macos-build.tar *.app
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
mac_zip:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v2
name: Checkout
@@ -377,28 +377,21 @@ jobs:
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-Release-${{ matrix.arch }}
name: mac-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-FastDebug-${{ matrix.arch }}
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
- name: Create Distribution package
id: generate_package
working-directory: ./builds
env:
ARCH: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
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 }}
+41 -71
View File
@@ -6,7 +6,7 @@ on:
- 'test/*'
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
build_linux:
@@ -15,8 +15,23 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
# - name: Cache Qt
# id: cache-qt-lin
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
@@ -30,8 +45,7 @@ jobs:
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: gcc-9
ENABLE_QTFRED: OFF
COMPILER: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -51,7 +65,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@v3
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -68,12 +82,12 @@ jobs:
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v1
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
@@ -132,12 +146,7 @@ jobs:
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -148,19 +157,11 @@ jobs:
mkdir build
cd build
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" -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" ..
fi
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
-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" ..
- name: Compile
working-directory: ./build
env:
@@ -177,7 +178,7 @@ jobs:
shell: bash
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
@@ -198,12 +199,12 @@ jobs:
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v1
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
@@ -229,7 +230,7 @@ jobs:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
arch: [x86_64]
name: Mac
runs-on: macos-latest
steps:
@@ -248,17 +249,12 @@ jobs:
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Set up test version
shell: bash
run: |
@@ -270,7 +266,6 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -279,39 +274,21 @@ jobs:
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCH: ${{ matrix.arch }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Sign builds
working-directory: ./build/bin
run: |
# make sure OpenAL framework is signed
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
# make sure dylibs are signed
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
# sign binaries
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
# sign apps
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
- name: Package build result
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz *.app
working-directory: ./build
run: cd bin && tar -cvzf macos-build.tar *.app
- name: Upload build result
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
mac_zip:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
matrix:
arch: [x86_64, arm64]
steps:
- uses: actions/checkout@v2
name: Checkout
@@ -320,24 +297,17 @@ jobs:
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-Release-${{ matrix.arch }}
name: mac-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
uses: actions/download-artifact@v2
with:
name: mac-FastDebug-${{ matrix.arch }}
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
- name: Create Distribution package
working-directory: ./builds
env:
ARCH: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
working-directory: ./builds
+20 -14
View File
@@ -6,27 +6,42 @@ on:
- master
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-9, gcc-13, clang-16]
compiler: [gcc-5, gcc-10]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-13
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-13
compiler: gcc-10
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-1ff82e8
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
# - name: Cache Qt
# id: cache-qt-lin
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
@@ -35,22 +50,13 @@ jobs:
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure ccache
run: |
ccache --set-config=sloppiness=pch_defines,time_macros
ccache -p
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
ENABLE_QTFRED: ON
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
- name: Show CCache statistics
run: ccache --show-stats
+32 -48
View File
@@ -3,27 +3,42 @@ name: Check a pull request
on: [pull_request]
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-9, gcc-13, clang-16]
compiler: [gcc-5, gcc-10, clang-9]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-13
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-13
compiler: gcc-10
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-1ff82e8
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
# - name: Cache Qt
# id: cache-qt-lin
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt
# uses: jurplel/install-qt-action@v2
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
@@ -33,18 +48,12 @@ jobs:
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
save: false # Caches are created by a separate job and only restored for PRs
verbose: 1
- name: Configure ccache
run: ccache --set-config=sloppiness=pch_defines,time_macros
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
CCACHE_PATH: /usr/local/bin/ccache
ENABLE_QTFRED: ON
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -55,8 +64,6 @@ jobs:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Show CCache statistics
run: ccache --show-stats
- name: Run Clang Tidy
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
if: startsWith(matrix.compiler, 'clang-')
@@ -106,12 +113,7 @@ jobs:
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -123,23 +125,12 @@ jobs:
cd build
if [ "$COMPILER" = "MinGW" ]; then
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -DFSO_BUILD_WITH_VULKAN="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
else
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
fi
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
else
if [ "$ARCHITECTURE" = "Win32" ]; then
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-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" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
fi
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
fi
- name: Compile
working-directory: ./build
@@ -171,7 +162,7 @@ jobs:
matrix:
configuration: [Debug, Release]
compiler: [clang]
arch: [x86_64, arm64]
arch: [x86_64]
cmake_options: [""]
name: Mac
runs-on: macos-latest
@@ -191,6 +182,7 @@ jobs:
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
@@ -199,21 +191,14 @@ jobs:
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
save: false # Caches are created by a separate job and only restored for PRs
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
@@ -222,7 +207,6 @@ jobs:
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
ARCH: ${{ matrix.arch }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Run Clang Tidy
@@ -233,4 +217,4 @@ jobs:
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
fixesFile: clang-fixes.yaml
fixesFile: clang-fixes.yaml
@@ -1,69 +0,0 @@
name: Weekly Coverity Scan for Freespace Open
# adapted from code by "albert-github" on the doxygen repository
# many thanks for figuring this out first so it could be less painful for us!
# keep this from running on everyone's fork
# if: github.ref == 'refs/heads/master'
#This mode is for testing
#on: [push, pull_request]
# In production, push on a specific schedule
on:
schedule:
- cron: "57 18 * * *" # Run once per a week on Friday morning (4 AM EST), to avoid Coverity's submission limits
env:
QT_VERSION: 5.12.12
coverity_email: [email protected]
coverity_token: ${{ secrets.COVERITY_TOKEN }}
jobs:
build:
name: Build FSO With Coverity Wrapper
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v1
with:
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
# pipe results of wget to a log file because it's very verbose and rarely fails
- name: Install Coverity
run: |
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
mkdir cov-scan
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
- name: Setup Environment
run: |
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
- name: Configure CMake for FSO
env:
CONFIGURATION: FastDebug
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Build FSO with Coverity Wrapper
working-directory: ./build
env:
CONFIGURATION: Release
run: cov-build --dir cov-int ninja -k 20 all
- name: Compress Results
working-directory: ./build
run: tar zcf cov-scan.tgz cov-int
#Comment this out when testing to keep from running into upload limits
- name: Upload to Coverity
run: |
cd build
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
-1
View File
@@ -250,7 +250,6 @@ documentation/doxygen/*
projects/*
/.vs
CMakeSettings.json
CMakePresets.json
# Weird files created by Linux
.fuse_hidden*
+175
View File
@@ -0,0 +1,175 @@
language: bash
sudo: required
dist: xenial
cache:
directories:
- $HOME/cmake-3.8
- $HOME/.ccache
- $HOME/curl_cache
addons:
apt:
packages: &global_deps
- ninja-build
- libopenal-dev
- libreadline6-dev
- libpng12-dev
- libjpeg62-dev
- liblua5.1-0-dev
- libjansson-dev
- libsdl2-dev
- libfreetype6-dev
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
notification_email: [email protected]
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
# These declarations set DATACORDER_USER and DATACORDER_PASSWORD
- secure: "dpBH/dDN3bmU/NFlh+2v9isNx9wX0ocoRy+W+kBXRH32sosUGp26REhMqgVRpBNP5oxPBU8ic5bEogxAYWCB+0xUygBbkxAwyMPgoA34s0OXdTCY/ofw14ni8qqV2Ffy7fQJbP/jkMURyiMHx3kBTxNv3YjxKJqLnOuOMlQLpT8="
- secure: "tLMRBD1Ufp5iKNwlqPDVbbuczgusaXNoBJyAnPATpJq2YwlkW4j3PqP9rW5vd85+52xam2EOP20w9PoBR5J6FLdiXRu4Lf7yCEhSHFAgowVqQj8QcJpPlyXr90bM4emFGrGqpdxVwxyQ5AFhKwLuEZKsI14GYLN+UMEwpNCMing="
deploy:
- provider: releases
api_key:
secure: "q619+eQTe7lv8UVphK4OIzU8Jw84KBbVkuprN2sWIubRcV3IbZr2+WahJoUMt+nyhiy3YjDYtstO2ZgkxupwnZgwGUBVIiD1c4SPuyy+HTjNMOtiVsEUHT2hf+xPAemWpTlK5HcwhMmHAOh6rt6dEj57QOg0gcmGiwD/tCbEriA="
skip_cleanup: true
file_glob: true
file: "/tmp/builds/*"
on:
condition: '"$RELEASE_BUILD" == true'
tags: true
- provider: script
script: bash ci/travis/ftp_deploy.sh
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
- provider: script
skip_cleanup: true
script: bash ci/travis/ftp_deploy.sh
on:
condition: $TEST_BUILD = true
all_branches: true
matrix:
include:
# note that gcc Debug MUST be 1st for Coverity
- os: linux
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-9 CXX=g++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-9
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Debug"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: linux
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=gcc-9 CXX=g++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-9
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Release"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
# There is a GCC compiler bug with MinGW that causes compilation failures on Windows at the moment
allow_failures:
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
fast_finish: true
before_install:
# ugly hack; if running a coverity scan abort all except the 1st build
# see note re gcc compiler above needing to be 1st
# also note that branch_pattern & the TRAVIS_BRANCH check must match
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
# build process
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
- source "./ci/travis/check_release.sh"
- "./ci/travis/before_install.sh"
install:
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake-3.6/bin:$PATH
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
+15 -6
View File
@@ -47,6 +47,20 @@ endif()
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
# Enable ccache on Mac even for clang
if(CCACHE_PROGRAM AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR APPLE))
if(NOT CMAKE_C_COMPILER_LAUNCHER)
message(STATUS "Using ccache for C compilation: ${CCACHE_PROGRAM}")
SET(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
if(NOT CMAKE_CXX_COMPILER_LAUNCHER)
message(STATUS "Using ccache for C++ compilation: ${CCACHE_PROGRAM}")
SET(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
endif()
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)
@@ -123,11 +137,8 @@ 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_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)
OPTION(FSO_BUILD_WITH_OPENXR_DEBUG "Enables debug option for OpenXR" OFF)
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
@@ -140,9 +151,7 @@ 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_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_DEBUG)
# Include cotire file from https://github.com/sakra/cotire/
include(cotire)
-179
View File
@@ -3,185 +3,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [23.2.0] - 2023-06-16
### Changes
<details><summary> <b>Big Feature: MSAA</b> </summary>
> The return of a long forgotten feature, with optimizations and improvements
> Noticeable reduction to artifacts caused by subpixel geometry and glinting.
</details>
<details><summary> <b>Big Feature: SCPUI</b> </summary>
> A modernized approach to defining menus in FS
> Tired of having your Menus in FSO be at a resolution of potato? Use SCPUI to have them rendered from Fake-HTML to the actual screensize as opposed to a prebuilt graphics!
> Tired of being limited to whatever people in the SCP hardcoded in for buttons? Use SCPUI to define buttons and all other manner of shenanigans as Lua-code just as you like.
> Tired of needing to replace a bajillion interface graphics to reskin FSO? Use SCPUI, and especially Mjn's existing collection of Lua, CSS, Fake-HTML and images, and you only need to replace about 250 graphics.
</details>
<details><summary> <b>Big Feature: Localized Volumetric Nebulae</b> </summary>
> Allows specifying a POF as the "hull" of a nebula, which will be rendered using ray marching
> Further details can be found on the [GitHub Pull Request](https://github.com/scp-fs2open/fs2open.github.com/pull/5231)
> Note: As this is a new feature, many improvements and optimizations remain to be made
> Adapted from Andrew Schneider's 2015 SIGGRAPH talk "The real-time volumetric cloudscapes of Horizon: Zero Dawn"
</details>
<details><summary>Game: </summary>
- Per bank autoaim
</details>
<details><summary>Animation: </summary>
- Fix CTD on bad legacy animation data
- Add proper time wrapping for Animations
- Actually handle a mssing `Fade_anim` properly
</details>
<details><summary>Controls: </summary>
- Organize and map additional keys to librocket
- Catch when SDL fails to open a joystick that is enumerated by the OS
</details>
<details><summary>FRED: </summary>
- Add SpaceMouse support
- Add pre-parse enums support
- Add music player to FRED
- Enhanced SEXP comments
- FRED Dialog for Volumetrics
- QoL improvements to Object Editor
- Add FRED support for the "required weapon" feature
- SEXP Tree search and filter
</details>
<details><summary>QtFRED: </summary>
- Campaign Editor
- Add SpaceMouse support
- Make 'player starts in chase view' a toggle
</details>
<details><summary>Graphics: </summary>
- "The other great shader flag removal effort"
- Enhance handling of motion debris
- Expose texture filtering as a built-in option
- Improved particle culling and performance
- Optimized trail renderer
- Beam Particles
- Multiple lighting profiles
- Use volume particles for poofs
- Optimize for simple trails
- Kink shamed the laser bitmaps
</details>
<details><summary>HUD: </summary>
- Flag to apply HUD shudder to chase view
- Add missing HUD gauges
- Explicitly do not split lines when making the message log
</details>
<details><summary>Localization: </summary>
- Add some XSTR entries
</details>
<details><summary>Modding: </summary>
- Mapify built-in strings
- Allow `gameplay_profiles.tbl` to be an alias of `ai_profiles.tbl`
- Modular rank table
- Toggle auto-assigning personas
- Add some parameters for corkscrew starting angle
- Add clip planes to `game_settings.tbl`
- Add `+Use ship` as a Template
- Modular messages table
- Add arbitrary curves support
- Traitor overrides
- Add support for loose lz4 compressed files
- Add per-species warp effects
</details>
<details><summary>Models: </summary>
- Fix submodel sanity check
- Fix techroom modelnum references
- Adjust movement sanity checks to account for more situations
- Modular POF Features 2
- Add fov values to .pof models
- Add a Translation Moveable
- Remove model octants
- Fix glowpoints on animated submodels
- Update type_flags when dock name changes
- Add additional checks for Animation List handling of nonexistent polymodel instances
- Virtual POFs: Modify Subsystems
- Validate chunk size to avoid alignment crash and add align skip flag
</details>
<details><summary>Multiplayer: </summary>
- Generic Lua Multiplayer RPC
</details>
<details><summary>Performance: </summary>
- Increase sound update rate
- Add `line of sight` as an optional AI override
</details>
<details><summary>SEXPs: </summary>
- `turret-fired-since`, returns `true` if the specified turret has fired in the last `N` milliseconds
- `is-ship-emp-active`, returns `true` if the specified ship or list of ships is currently under an EMP effect
- `turret-has-primary` and `turret-has-secondary`, returns `true` if the specified turret contains the specified weapon
- `has-armor-type`, returns `true` if the specified ship or subsystem has the specified armor type
- `OPF_ANY_HUD_GAUGE` and `OPF_EVENT_NAME`, new Lua SEXP parameters
- Enhance Dynamic SEXPs with parent parameters
- Add "afterburn hard" AI goal flag
</details>
<details><summary>Scripting: </summary>
- Add option to deprecate hooks
- Get audiostream duration in float seconds
- Lua method to check if the game has focus
- `On warp complete` hook
- Allow Lua to set the Discord presence to custom strings
- Add virtvars for goal satisfaction and score
- Allow scripts to read and add LuaEnums
- Funcs and virtvars for SCPUI pause screen
- Expose pausing weapon sounds
- Make collision_group_id accessible to parse objects
- Pass shortcut key character to Lua as a hook variable
- Lua method to free all loaded models
- `On Asteroid Created` hook
- SCPUI methods required for handling closeup briefing icons
- Expose some Nebula settings to Lua
- SCPUI mission log
- SCPUI APIsfor the Game Help UI, medals access, and control config
- Force expand wings instead of toggle for SCPUI
- Add misc. validity checks
- Convert hotkey types to enum
- Finalize SCPUI API
- Blocking `On Frame` executor
- SCPUI Hud Config API
- Configurable restriction for ships that accept Lua player orders
- Add `ship::isPlayer()`
- Lua access to default countermeasures class
- Flag to check if a ship or weapon class is player allowed
- Add hooks for comm menu opening/closing
</details>
<details><summary>Technical: </summary>
- Improve CFLAGS handling
</details>
## [22.2.0] - 2022-08-06
```
+2
View File
@@ -1,5 +1,7 @@
FreeSpace2 *S*ource *C*ode *P*roject
==
[![Travis-CI Build Status](https://travis-ci.org/scp-fs2open/fs2open.github.com.svg?branch=master)](https://travis-ci.org/scp-fs2open/fs2open.github.com)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/scp-fs2open/fs2open.github.com?branch=master&svg=true)](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
[![Coverity](https://img.shields.io/coverity/scan/870.svg)](https://scan.coverity.com/projects/870)
Building
+62
View File
@@ -0,0 +1,62 @@
version: 1.0.0.{build}
image: Visual Studio 2015
configuration:
- Debug
- Release
clone_depth: 10
environment:
matrix:
- BuildID: 0
CMAKE_GENERATOR: Visual Studio 14 2015
PlatformToolset: v140
QT_DIR: C:\Qt\5.9\msvc2015
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140
QT_DIR: C:\Qt\5.9\msvc2015_64
before_build:
- git submodule update --init --recursive
build_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
test_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
deploy:
- provider: GitHub
auth_token:
secure: h55Scpy+3vmo1Yb7WlSIGA4d9DRnsbzUYc2LYsQdByQHZHbqrqjBpicH0D2FFLEO
on:
ReleaseBuild: true # deploy on release push only
- provider: FTP
protocol: sftp
host: scp.indiegames.us
username:
secure: SFivQZfatqWHXK1ijYK3GQ==
password:
secure: q6Zk/412o1ri+NEya1dl1Q==
folder: public_html/builds/nightly/$(VersionName)
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: sftp
host: porphyrion.feralhosting.com
username:
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
password:
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$(VersionName)
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: sftp
host: porphyrion.feralhosting.com
username:
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
password:
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$(VersionName)
on:
TestBuild: true # deploy on test build push only
+164
View File
@@ -0,0 +1,164 @@
class BuildConfig {
[string]$Generator
[string]$PackageType
[string]$Toolset
[string]$SimdType
[string]$QtDir
[Bool]$SourcePackage
}
$NightlyConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# },
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
)
$ReleaseConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$true;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
)
$BuildConfigurations = $null
# Default values
$ReleaseBuild = $false
$NightlyBuild = $false
$TestBuild = $false
# Set to true to test either the release or the nightly part of this script
$ReleaseTest = $false
$NightlyTest = $false
$TestBuildTest = $false
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
# Tag matches
$ReleaseBuild = $true
$PackageName = "fs2_open_$($matches[1])"
$BuildConfigurations = $ReleaseConfigurations
}
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
# Tag matches
$NightlyBuild = $true
$PackageName = "nightly_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
}
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
# Tag matches
$TestBuild = $true
$PackageName = "test_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
# Override the revision string so that the builds are named correctly
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
}
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
$buildID = [convert]::ToInt32($env:BuildID) * 2
if ($Env:Configuration -eq "Release") {
$buildID = $buildID + 1
}
$DeployBuild = $false
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
$DeployBuild = $true
}
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
New-Item build -type directory
Set-Location -Path build
if ($DeployBuild) {
# Release build
if ($buildID -ge $BuildConfigurations.Length) {
# Not needed
exit 0
}
$buildConfig = $BuildConfigurations[$buildID]
if ($buildConfig.SourcePackage -eq $True) {
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
}
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=OFF `
-DFSO_INSTALL_DEBUG_FILES="ON" `
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
$Configs = @("Release", "FastDebug")
foreach ($config in $Configs) {
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
if (! ($?)) {
Add-AppveyorMessage "A release build failed!"
exit 1
}
}
7z a -xr'!*.pdb' "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
7z a "$($PackageName)-debug-$($buildConfig.PackageType).7z" "$env:APPVEYOR_BUILD_FOLDER/../install/*.pdb"
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
} else {
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
-DFSO_BUILD_QTFRED=OFF -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
if (! ($?)) {
exit 1
}
}
+13
View File
@@ -0,0 +1,13 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
# Skip tests for deployment
exit 0
} else {
write "Running unit tests..."
# Run unit tests
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
if (! ($?)) {
exit 1
}
}
+14 -25
View File
@@ -1,27 +1,27 @@
#!/usr/bin/env bash
if [ "$COMPILER" = "gcc-9" ]; then
export CC=gcc-9
export CXX=g++-9
if [ "$COMPILER" = "gcc-5" ]; then
export CC=gcc-5
export CXX=g++-5
fi
if [ "$COMPILER" = "gcc-13" ]; then
export CC=gcc-13
export CXX=g++-13
if [ "$COMPILER" = "gcc-10" ]; then
export CC=gcc-10
export CXX=g++-10
fi
if [ "$COMPILER" = "clang-16" ]; then
export CC=clang-16
export CXX=clang++-16
if [ "$COMPILER" = "clang-9" ]; then
# Work around bug in clang that uses the wrong installation directory: https://bugs.llvm.org/show_bug.cgi?id=47460
export CC=$(readlink -f $(which clang-9))
export CXX=$(readlink -f $(which clang++-9))
fi
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
if [ "$RUNNER_OS" = "macOS" ]; then
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
# TODO: Vulkan support is disabled on MacOS due to issues with the test suite not linking correctly
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
PLATFORM_CMAKE_OPTIONS=""
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
fi
@@ -29,13 +29,6 @@ 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
echo "Using ccache at $CCACHE_PATH"
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
fi
mkdir build
@@ -48,11 +41,7 @@ export LD_LIBRARY_PATH
if [ "$RUNNER_OS" = "macOS" ]; then
brew install ninja
fi
# CMAKE_JOB_POOLS and CMAKE_JOB_POOL_LINK ensure that when using ninja, link operations are done sequentially
# we have some build rules that do not play nice with parallel invocation and that fixes these issues
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS $PLATFORM_CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=${ENABLE_QTFRED:-OFF} \
-DSHADERS_ENABLE_COMPILATION=ON -DCMAKE_JOB_POOLS=link=1 -DCMAKE_JOB_POOL_LINK=link ..
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF \
-DSHADERS_ENABLE_COMPILATION=ON ..
+13 -13
View File
@@ -10,27 +10,27 @@ source $HERE/dist_functions.sh
if [ "$OS" = "Linux" ]; then
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
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
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Linux.tar.gz"
echo "::set-output name=package_name::$(get_package_name)-builds-Linux.tar.gz"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")"
elif [ "$OS" = "Windows" ]; then
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
echo "package_path=$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
echo "package_name=$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")" >> $GITHUB_OUTPUT
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip"
echo "::set-output name=package_name::$(get_package_name)-builds-$ARCH-$SIMD.zip"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")"
7z a "$(get_package_name)-debug-$ARCH-$SIMD.7z" "*.pdb"
echo "debug_path=$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
echo "::set-output name=debug_path::$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_name::$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")"
elif [ "$OS" = "Mac" ]; then
tar -cvzf "$(get_package_name)-builds-Mac-$ARCH.tar.gz" *.app
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
echo "package_name=$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Mac.tar.gz"
echo "::set-output name=package_name::$(get_package_name)-builds-Mac.tar.gz"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac.tar.gz")"
else
echo "Invalid OS: $OS"
fi
-7
View File
@@ -5,13 +5,6 @@ HERE=$(dirname "$SCRIPT")
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
# if on mac and building for architecture that doesn't match host
# then unittests will fail so we just need to skip it (for now)
if [ "$RUNNER_OS" = "macOS" ] && [ "$ARCH" != "$(uname -m)" ]; then
echo "Skipping tests due to architecture mismatch!"
exit 0
fi
if [ "$CONFIGURATION" = "Debug"] && [[ "$RUNNER_OS" != "macOS" ]] ; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
+3 -13
View File
@@ -10,21 +10,11 @@ HERE=$(dirname "$SCRIPT")
source $HERE/dist_functions.sh
if [ "$UPLOAD_TYPE" = "nightly" ]; then
any_success=false
if SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"; then
any_success=true
fi
SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/nightly"; then
any_success=true
fi
if [ "$any_success" = "false" ]; then
echo "All uploads failed"
exit 1
fi
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"
elif [ "$UPLOAD_TYPE" = "test" ]; then
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/test"
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/test"
else
echo "Unknown upload type $UPLOAD_TYPE"
exit 1
+3 -7
View File
@@ -19,7 +19,7 @@
# HLP_API:
# HLP_KEY:
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
import sys
@@ -137,8 +137,8 @@ def main():
"pass": os.environ["INDIEGAMES_SSHPASS"],
"path": "public_html/builds/{type}/{version}/",
"mirrors": (
"https://perses.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
"https://scp.indiegames.us/builds/{type}/{version}/{file}",
"https://porphyrion.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
"http://scp.indiegames.us/builds/{type}/{version}/{file}",
),
},
"nebula": {
@@ -260,10 +260,6 @@ def main():
if "Linux" not in groups.keys():
print("ERROR: No Linux builds were detected!")
sys.exit(1)
if "Mac" not in groups.keys():
print("ERROR: No Mac builds were detected!")
sys.exit(1)
# z64: What dose this do???
# print(installer.render_installer_config(version, groups, config))
+5 -9
View File
@@ -8,8 +8,7 @@ from file_list import ReleaseFile
from util import retry_multi, GLOBAL_TIMEOUT
LINUX_KEY = "Linux"
MACOSX_X64_KEY = "Mac-x86_64"
MACOSX_ARM64_KEY = "Mac-arm64"
MACOSX_KEY = "Mac"
WIN32_SSE2_KEY = "Win32-SSE2"
WIN64_SSE2_KEY = "Win64-SSE2"
WIN32_AVX_KEY = "Win32-AVX"
@@ -35,8 +34,7 @@ metadata = {
platforms = {
LINUX_KEY: 'linux',
MACOSX_X64_KEY: 'macosx',
MACOSX_ARM64_KEY: 'macosx',
MACOSX_KEY: 'macosx',
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows',
WIN32_AVX_KEY: 'windows',
@@ -45,8 +43,7 @@ platforms = {
envs = {
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
MACOSX_X64_KEY: 'macosx && x86_64',
MACOSX_ARM64_KEY: 'macosx && arm64',
MACOSX_KEY: 'macosx',
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows && x86_64',
WIN32_AVX_KEY: 'windows && avx',
@@ -138,7 +135,7 @@ def render_nebula_release(version, stability, files, config):
'label': label,
'properties': props,
})
elif group.startswith('Mac') and fn.startswith(os.path.basename(fn) + '.app/'):
elif group == MACOSX_KEY and fn.startswith(os.path.basename(fn) + '.app/'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
@@ -151,8 +148,7 @@ def render_nebula_release(version, stability, files, config):
label = None
props = {
"arm64": "arm64" in fn,
"x64": "x64" in fn,
"x64": True, # All Mac builds are 64-bit
"sse2": True, # There are no forced options on mac but 64-bit always implies SSE2 so we set that here
"avx": False,
"avx2": False,
+11 -19
View File
@@ -7,22 +7,22 @@ PLACEHOLDER
[b]Deprecations:[/b]
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.
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. The features listed above 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=98360.0]22.2.0 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.
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
[hidden=Alternative Launchers]
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (legacy project for a unified launcher)
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=https://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
@@ -41,10 +41,10 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
[url=https://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
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!
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/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 64-bit[/size][/color]
[img]http://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)}
@@ -52,22 +52,14 @@ These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] wh
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.
[img]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
[size=8pt]macOS 10.9+[/size]
[b]Intel (64-bit):[/b] ${build(groups["Mac"].subFiles["x86_64"])}
[b]Apple Silicon:[/b] ${build(groups["Mac"].subFiles["arm64"])}
These builds are not signed and so by default will fail to launch. To run them simply right-click on the app, click open, then click open again on the security confirmation dialog. You should only have to do this once for each app.
If running the game through Knossos or Knossos.NET this step should not be necessary.
[size=8pt][color=red][b]NOTE:[/b][/color] macOS builds currently have limited support and may exhibit issues not present on other platforms.[/size]
[img]http://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]OS X[/size][/color]
[b][color=red]Not available[/color][/b] We recently lost access to our Mac CI environment which we usually used for compiling these builds so for the time being, there will be no builds for this OS.
[hidden=TrackIR Users]
[size=12pt]Important!![/size]
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
TrackIR is only supported on Windows.
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=https://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
Known issues:
[list]
+1 -1
View File
@@ -1,3 +1,3 @@
Mako==1.2.2
requests==2.31.0
requests==2.26.0
semantic-version==2.8.5
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env sh
set -ex
if [ "$NIGHTLY_BUILD" = true ]; then
echo "Generating bintray config..."
sed -e "s/\$VERSION_NAME/$VERSION_NAME/" ci/bintray.template.json > ci/bintray.json
fi
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env sh
set -ex
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export DEBIAN_FRONTEND=noninteractive
sudo add-apt-repository -y "ppa:msulikowski/valgrind" # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo add-apt-repository -y 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
sudo apt-get -yq update
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
# Nothing to do here
:
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
# Nothing to do here
:
fi
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -ex
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
mkdir -p /tmp/builds
if [ "$RELEASE_BUILD" = true ]; then
# Package the source code in release builds
PARENT_DIR="$(basename "$PWD")"
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
fi
mkdir -p build
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
export CXXFLAGS
export CFLAGS
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
if [ "$BUILD_DEPLOYMENT" = true ]; then
for config in $BUILD_CONFIGS
do
mkdir -p $config
cd $config
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
cd ..
done
else
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF ..
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$BUILD_DEPLOYMENT" = true ]; then
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
else
cmake -G "Xcode" $CMAKE_OPTIONS ..
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
fi
fi
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env sh
RELEASE_BUILD=false
NIGHTLY_BUILD=false
TEST_BUILD=false
BUILD_DEPLOYMENT=false
BUILD_CONFIGS="Release FastDebug"
VERSION_NAME=""
PACKAGE_NAME=""
RELEASE_PATTERN="^release_(.*)$"
NIGHTLY_PATTERN="^nightly_(.*)$"
TEST_BUILD_PATTERN="^test\/(.*)$"
# These are for testing
NIGHTLY_TEST=false
RELEASE_TEST=false
TEST_BUILD_TEST=false
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
echo "This is a release tag!";
RELEASE_BUILD=true;
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
fi
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
echo "This is a nightly tag!";
NIGHTLY_BUILD=true;
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
fi
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
echo "This is a test build branch!";
TEST_BUILD=true;
if [ "$TEST_BUILD_TEST" = true ]; then
VERSION_NAME="test";
PACKAGE_NAME="test_test";
else
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
fi
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
fi
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
BUILD_DEPLOYMENT=true;
fi
if [ "$BUILD_DEPLOYMENT" = true ]; then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
echo "Skipping non-release compiler";
exit 0;
fi
if ([[ "$CONFIGURATION" == "Debug" ]]); then
echo "Skipping non-release configuration";
exit 0;
fi
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
echo "Skipping non-release platform"
exit 0
fi
fi
export RELEASE_BUILD
export NIGHTLY_BUILD
export TEST_BUILD
export BUILD_DEPLOYMENT
export BUILD_CONFIGS
export VERSION_NAME
export PACKAGE_NAME
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
set -e
set -u
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
# Before
echo "Before:"
curl -V
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ -f ~/curl_cache/curl*.deb ]; then
cd ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
else
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
mkdir /tmp/curl
cd /tmp/curl
sudo apt-get update
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
apt-get source curl
sudo apt-get build-dep curl
cd curl-*
export DEB_BUILD_OPTIONS="nocheck"
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
cd ..
dpkg -l | grep curl
ls -al
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp libcurl3*.deb curl*.deb ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install libssh2
if [ -d ~/curl_cache/curl ]; then
cd ~/curl_cache/curl
sudo make install
else
mkdir /tmp/curl
cd /tmp/curl
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
tar -xjf curl-7.64.0.tar.bz2
cd curl-7.64.0
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp -a . ~/curl_cache/curl
sudo make install
fi
export PATH=/usr/local/bin:$PATH
fi
# After
echo "After:"
curl -V
fi
cd /tmp/builds
for file in *; do
if [ "$TEST_BUILD" = true ]; then
# Upload to datacorder
curl -k "sftp://porphyrion.feralhosting.com/www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
else
# Upload to indiegames
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
# Upload to datacorder
curl -k "sftp://porphyrion.feralhosting.com/~/www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
fi
done
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -ex
FILENAME=
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export DEBIAN_FRONTEND=noninteractive
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
# If the cache does not currently contain CMake then download and install it
mkdir -p $HOME/cmake-3.8/
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
fi
export PATH=$HOME/cmake-3.8/bin:$PATH
cd $HOME
if [ "${BUILD_DEPLOYMENT}" = true ]; then
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
chmod a+x ./appimagetool
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
chmod a+x ./linuxdeployqt
fi
sudo apt-get -yq install valgrind
if [[ "$CC" = "clang-9" ]]; then
sudo apt-get -yq install clang-9 clang-tidy-9
fi
if [[ "$CC" = "clang-4.0" ]]; then
# Fix a header bug present in ubuntu...
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
gem install xcpretty
brew update
brew outdated cmake || brew upgrade cmake
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
choco install mingw ninja
fi
cmake --version
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env sh
set -ex
mkdir -p /tmp/builds
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
cd build
for config in $BUILD_CONFIGS
do
cd "$config"
# Compile all targets
ninja all
# Install Freespace2 targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
: <<'END'
# Install qtFRED targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
PREV="$(pwd)"
cd /tmp/release/$config/qtfred
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
# Move our AppRun script to the right location
mv usr/AppRun AppRun
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
cd "$PREV"
END
cd ..
done
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cd build
for config in $BUILD_CONFIGS
do
cmake --build . --config "$config" --target install | tee build.log \
| xcpretty
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
exit $XCODE_RET
fi
done
ls -al /tmp/release
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-MacOSX.tar.gz *)
fi
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env sh
set -e
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
ninja -k 20 all
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://keep.sh"
exit $XCODE_RET
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake --build . --config "$CONFIGURATION"
else
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
fi
fi
-6
View File
@@ -7,9 +7,3 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
else()
set(IS_64BIT FALSE)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
else()
set(IS_ARM64 FALSE)
endif()
-8
View File
@@ -22,14 +22,6 @@ SET(LIBRAY_DESTINATION "../Frameworks")
set(PLATFORM_MAC TRUE CACHE INTERNAL "" FORCE)
# Maybe override arm64 setting if we are compiling for different architecture
# If not specified, or if it's a universal build, then this should do nothing
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
set(IS_ARM64 TRUE)
elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
set(IS_ARM64 FALSE)
endif()
# Generate and don't strip debug symbols
# These settings don't seem to generate debug symbols for code and Freespace2
# so those settings are set manually in code and Freespace2's CMakeLists.txt files
-1
View File
@@ -9,7 +9,6 @@
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
#cmakedefine01 IS_64BIT
#cmakedefine01 IS_ARM64
#cmakedefine01 SCP_HAVE_STRCASECMP
#cmakedefine01 SCP_HAVE_STRNCASECMP
+3 -3
View File
@@ -4,7 +4,7 @@ MESSAGE(STATUS "Doing configuration specific to Apple Clang...")
# TODO: Actually add Mac specific flags here...
# Suppress specific warning
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fsigned-char -Wno-unknown-pragmas")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -funroll-loops -fsigned-char -Wno-unknown-pragmas")
# Omit "conversion from string literal to 'char *' is deprecated" warnings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
@@ -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 "-O2 -Wno-unused-variable -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS_RELEASE "-Wno-unused-variable")
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
set(CMAKE_CXX_FLAGS_DEBUG "-Wextra -Wshadow -Wno-unused-parameter")
+10 -31
View File
@@ -33,7 +33,7 @@ set(COMPILER_FLAGS "")
_enable_extra_compiler_warnings_flags()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
# Omit "argument unused during compilation" when clang is used with ccache.
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
@@ -83,41 +83,20 @@ if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
endif()
# Check if there is a user-set optimisation flag
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})
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
# If no user-set opt flag, set -O2 and -Og
if ("${CXX_OPT_FLAG}" STREQUAL "")
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 "-O2")
set(C_OPT_FLAG_DEBUG "-Og")
else()
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
endif()
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
# Always use the base flags and add our compiler flags at the back
# Always use the base flags and add our compiler flags at the bacl
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS "")
@@ -141,7 +120,7 @@ if (FSO_FATAL_WARNINGS)
target_compile_options(compiler INTERFACE "-Werror")
endif()
# Always define this to make sure that the fixed-width format macros are available
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
+8 -30
View File
@@ -45,7 +45,7 @@ endif()
_enable_extra_compiler_warnings_flags()
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
if (NOT GCC_INCREMENTAL_LINKING)
# Place each function and data in its own section so the linker can
@@ -113,41 +113,19 @@ if(SUPPORTS_STRINGOP_TRUNCATION)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
endif()
# Check if there is a user-set optimisation flag
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})
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
# If no user-set opt flag, set -O2 and -Og
if ("${CXX_OPT_FLAG}" STREQUAL "")
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 "-O2")
set(C_OPT_FLAG_DEBUG "-Og")
else()
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
endif()
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
# Always use the base flags and add our compiler flags at the back
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
@@ -187,7 +165,7 @@ if (FSO_FATAL_WARNINGS)
target_compile_options(compiler INTERFACE "-Werror")
endif()
# Always define this to make sure that the fixed-width format macros are available
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
+17 -30
View File
@@ -67,43 +67,30 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
MACRO(COPY_FILE_TO_TARGET _target _file)
if (IS_DIRECTORY "${_file}")
get_filename_component(_dirName "${_file}" NAME)
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
# Otherwise we end up creating duplicate files in the copied framework.
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
COMMENT "copying '${_file}'..."
VERBATIM
)
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
COMMENT "copying '${_file}'..."
VERBATIM
)
endif()
if(UNIX)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
)
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
VERBATIM
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
)
endif()
endmacro(COPY_FILE_TO_TARGET)
MACRO(COPY_FILES_TO_TARGET _target)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
VERBATIM
)
if(UNIX)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
)
endif()
FOREACH(file IN LISTS TARGET_COPY_FILES)
COPY_FILE_TO_TARGET("${_target}" "${file}")
ENDFOREACH(file)
+3 -5
View File
@@ -6,8 +6,8 @@ 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_MINOR 1)
set_if_not_defined(FSO_VERSION_MAJOR 22)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
@@ -35,9 +35,7 @@ ELSE()
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
ENDIF()
IF(IS_ARM64)
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
ELSEIF(IS_64BIT)
IF(IS_64BIT)
# This is a 64-bit builds
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_x64")
ENDIF()
+5 -32
View File
@@ -20,13 +20,6 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
if (FSO_BUILD_WITH_OPENGL)
target_link_libraries(code PUBLIC OpenGL)
if(FSO_BUILD_WITH_OPENGL_DEBUG)
add_definitions(-DFS_OPENGL_DEBUG)
endif()
endif()
if(FSO_BUILD_WITH_OPENXR_DEBUG)
add_definitions(-DFS_OPENXR_DEBUG)
endif()
TARGET_LINK_LIBRARIES(code PUBLIC openal)
@@ -54,6 +47,10 @@ target_link_libraries(code PUBLIC libRocket)
target_link_libraries(code PUBLIC pcp)
if (FSO_BUILD_WITH_VULKAN)
target_link_libraries(code PUBLIC vulkan-hpp)
endif()
target_link_libraries(code PUBLIC parsers)
target_link_libraries(code PUBLIC mdns)
@@ -73,23 +70,8 @@ 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(NOT APPLE)
target_link_libraries(code PUBLIC OpenXR::openxr_loader)
target_include_directories(code PUBLIC OpenXR::Headers)
ENDIF()
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
# On Linux, we need to access X11 window data.
# On Windows, SDL already provides everything, so no need to do anything
find_package(X11)
target_link_libraries(code PUBLIC ${X11_LIBRARIES})
ENDIF()
# Headers for standalone "gui" on UNIX
IF(UNIX)
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
@@ -112,16 +94,7 @@ if (FSO_BUILD_WITH_OPENGL)
target_compile_definitions(code PUBLIC WITH_OPENGL)
endif()
if (FSO_BUILD_WITH_VULKAN)
find_package(Vulkan REQUIRED)
if (Vulkan_FOUND)
target_compile_definitions(code PUBLIC WITH_VULKAN)
target_link_libraries(code PRIVATE Vulkan::Vulkan)
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
else()
message(WARNING "FSO_BUILD_WITH_VULKAN was set, but the package was unable to be found. Forcing OFF.")
set(FSO_BUILD_WITH_VULKAN OFF CACHE BOOL "Enable compilation of the Vulkan renderer" FORCE)
endif()
target_compile_definitions(code PUBLIC WITH_VULKAN)
endif()
include(shaders.cmake)
+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;
}
+23 -22
View File
@@ -34,13 +34,7 @@ typedef struct ai_flag_name {
char flag_name[TOKEN_LENGTH];
} ai_flag_name;
typedef struct ai_flag_description {
AI::AI_Flags flag;
SCP_string flag_desc;
} ai_flag_description;
extern ai_flag_name Ai_flag_names[];
extern ai_flag_description Ai_flag_descriptions[];
extern const int Num_ai_flag_names;
// dock_orient_and_approach() modes.
@@ -56,6 +50,12 @@ extern const int Num_ai_flag_names;
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
// Submodes for seeking safety.
#define AISS_1 41 // Pick a spot to fly to.
#define AISS_2 42 // Flying to spot.
#define AISS_3 43 // Gotten near spot, fly about there.
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
// Flags to ai_turn_towards_vector().
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
@@ -87,7 +87,7 @@ extern const int Num_ai_flag_names;
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
#define AIM_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
#define AIM_LUA 22 // Generic Lua-based AI mode
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
@@ -180,12 +180,6 @@ typedef struct ai_class {
#define AIS_UNDOCK_3 33
#define AIS_UNDOCK_4 34
// Submodes for seeking safety.
#define AISS_1 41 // Pick a spot to fly to.
#define AISS_2 42 // Flying to spot.
#define AISS_3 43 // Gotten near spot, fly about there.
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
// Submodes for Guard behavior
#define AIS_GUARD_PATROL 101
#define AIS_GUARD_ATTACK 102
@@ -240,6 +234,7 @@ typedef struct ai_info {
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
int shipnum; // Ship using this slot, -1 means none.
int behavior; // AI behavior; vestigial field from early development of FS1
int mode;
int previous_mode;
int mode_time; // timestamp at which current mode elapses.
@@ -277,7 +272,7 @@ typedef struct ai_info {
// Probably become obsolete, to be replaced by path_start, path_cur, etc.
waypoint_list *wp_list; // waypoint list being followed
int wp_index; // waypoint index in list
size_t 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
@@ -307,7 +302,6 @@ typedef struct ai_info {
fix submode_start_time; // time at which we entered the current submode
int submode_parm0; // parameter specific to current submode
int submode_parm1; // SUSHI: Another optional parameter
float submode_float0; // Goober5000: a float parameter
fix next_predict_pos_time; // Next time to predict position.
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
@@ -373,6 +367,11 @@ typedef struct ai_info {
float ai_turret_max_aim_update_delay;
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
union {
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
};
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
ship_subsys* last_subsys_target; // last known subsystem target
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
@@ -533,11 +532,11 @@ 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, waypoint_list *wp_list, int wp_flags, int start_index);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
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);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, vec3d* turnrate_mod = nullptr);
extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
extern void ai_level_init(void); // Call before each level to reset AI
@@ -560,7 +559,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
extern void ai_deathroll_start(object *ship_obj);
extern int set_target_objnum(ai_info *aip, int objnum);
extern void ai_form_on_wing(object *objp, object *goal_objp);
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
@@ -589,16 +588,14 @@ extern int ai_fire_primary_weapon(object *objp); //changed to return weather it
extern int ai_fire_secondary_weapon(object *objp);
extern float ai_get_weapon_dist(ship_weapon *swp);
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override, matrix* target_orient = nullptr, int flags = 0);
extern bool ai_willing_to_afterburn_hard(ai_info* aip);
extern void ai_afterburn_hard(object* objp, ai_info* aip);
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
extern int is_instructor(object *objp);
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
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);
float ai_get_weapon_speed(ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, 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_rearm_status( int team, int new_status );
@@ -620,6 +617,10 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
// moved to header file by Goober5000
void ai_announce_ship_dying(object *dying_objp);
// added by kazan
void ai_start_fly_to_ship(object *objp, int shipnum);
void ai_fly_to_ship();
//Moved declaration here for player ship -WMC
void ai_process_subobjects(int objnum);
+4 -14
View File
@@ -45,9 +45,7 @@ namespace AI {
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 ;)
Target_own_team, // this attack goal is allowed to target friendlies
Afterburn_hard, // afterburn as hard as possible to the goal
Waypoints_in_reverse, // decrement instead of increment
Target_own_team,
NUM_VALUES
};
@@ -123,7 +121,7 @@ namespace AI {
Smart_shield_management,
Smart_subsystem_targeting_for_turrets,
Strict_turret_tagged_only_targeting,
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
Turrets_ignore_target_radius,
Use_actual_primary_range,
Use_subsystem_path_point_radii,
@@ -132,9 +130,8 @@ namespace AI {
Use_only_single_fov_for_turrets,
No_turning_directional_bias,
Use_axial_turnrate_differences,
All_nonshielded_ships_can_manage_ets,
Fightercraft_nonshielded_ships_can_manage_ets,
Ships_playing_dead_dont_manage_ets,
all_nonshielded_ships_can_manage_ets,
fightercraft_nonshielded_ships_can_manage_ets,
Better_collision_avoidance,
Require_exact_los,
Improved_missile_avoidance,
@@ -153,13 +150,6 @@ namespace AI {
Fixed_removing_play_dead_order,
Disable_bay_emerge_timeout,
Adjusted_AI_class_autoscale,
Carry_shield_difficulty_scaling_bug,
Whackable_debris,
Whackable_asteroids,
Dynamic_goals_afterburn_hard,
Player_orders_afterburn_hard,
Hudsquadmsg_tactical_disarm_disable,
Align_to_target_when_guarding_still,
NUM_VALUES
};
+11 -51
View File
@@ -223,9 +223,6 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:"))
parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Player Damage Inflicted Factor:"))
parse_float_list(profile->player_damage_inflicted_scale, NUM_SKILL_LEVELS);
// represented in fractions of F1_0
if (optional_string("$Predict Position Delay:"))
{
@@ -258,7 +255,7 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Glide Attack Percent:")) {
parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) {
@@ -271,7 +268,7 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Circle Strafe Percent:")) {
parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) {
@@ -284,7 +281,7 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Glide Strafe Percent:")) {
parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) {
@@ -297,7 +294,7 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Random Sidethrust Percent:")) {
parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) {
@@ -549,20 +546,16 @@ void parse_ai_profiles_tbl(const char *filename)
mprintf(("Warning: \"$ships with no shields can manage ETS\" flag is deprecated in favor of \"$any ship with no shields can manage ETS\"\n"));
bool temp;
stuff_boolean(&temp);
profile->flags.set(AI::Profile_Flags::All_nonshielded_ships_can_manage_ets, temp);
profile->flags.set(AI::Profile_Flags::all_nonshielded_ships_can_manage_ets, temp);
}
// ----------
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::All_nonshielded_ships_can_manage_ets);
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::all_nonshielded_ships_can_manage_ets);
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::Fightercraft_nonshielded_ships_can_manage_ets);
set_flag(profile, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
@@ -617,19 +610,6 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$use adjusted AI class autoscale:", AI::Profile_Flags::Adjusted_AI_class_autoscale);
set_flag(profile, "$carry shield difficulty scaling bug:", AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
set_flag(profile, "$debris affected by physics whacks:", AI::Profile_Flags::Whackable_debris);
set_flag(profile, "$asteroids affected by physics whacks:", AI::Profile_Flags::Whackable_asteroids);
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 we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
@@ -672,21 +652,12 @@ void ai_profiles_init()
// init retail entry first
parse_ai_profiles_tbl(NULL);
// Allow mission_profiles.tbl to be a alias of ai_profiles.tbl, but only load one or the other.
// mission_profiles.tbl would be newer so assume intended, but print to the log to be sure - Mjn
char filename[MAX_FILENAME_LEN] = "ai_profiles.tbl";
if (cf_exists_full("mission_profiles.tbl", CF_TYPE_TABLES)) {
mprintf(("mission_profiles.tbl was found! Using that instead of ai_profiles.tbl...\n"));
strcpy_s(filename, "mission_profiles.tbl");
}
// now parse the supplied table (if any)
if (cf_exists_full(filename, CF_TYPE_TABLES))
parse_ai_profiles_tbl(filename);
if (cf_exists_full("ai_profiles.tbl", CF_TYPE_TABLES))
parse_ai_profiles_tbl("ai_profiles.tbl");
// parse any modular tables
parse_modular_table("*-aip.tbm", parse_ai_profiles_tbl);
parse_modular_table("*-msp.tbm", parse_ai_profiles_tbl);
// set default if specified
temp = ai_profile_lookup(Default_profile_name);
@@ -740,7 +711,6 @@ 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;
subsys_damage_scale[i] = 0;
beam_friendly_damage_cap[i] = 0;
@@ -790,7 +760,7 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::Fix_ai_path_order_bug);
flags.set(AI::Profile_Flags::Aspect_invulnerability_fix);
flags.set(AI::Profile_Flags::Use_actual_primary_range);
flags.set(AI::Profile_Flags::Fightercraft_nonshielded_ships_can_manage_ets);
flags.set(AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
}
// this flag has been enabled ever since 3.7.2
if (mod_supports_version(3, 7, 2)) {
@@ -800,10 +770,6 @@ void ai_profile_t::reset()
if (mod_supports_version(3, 6, 10)) {
flags.set(AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
}
// backwards compatible flag for a bug accidentally introduced during this time
if (mod_supports_version(3, 6, 14) && !mod_supports_version(23, 1, 0)) {
flags.set(AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
}
if (mod_supports_version(21, 4, 0)) {
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
}
@@ -817,10 +783,4 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::No_continuous_turn_on_attack);
flags.set(AI::Profile_Flags::Fixed_removing_play_dead_order);
}
if (mod_supports_version(23, 2, 0)) {
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
}
if (mod_supports_version(23, 4, 0)) {
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
}
}
-1
View File
@@ -53,7 +53,6 @@ public:
float shield_energy_scale[NUM_SKILL_LEVELS]; // shield energy available
float afterburner_recharge_scale[NUM_SKILL_LEVELS]; // speed of afterburner recharge
float player_damage_scale[NUM_SKILL_LEVELS]; // damage applied to the player
float player_damage_inflicted_scale[NUM_SKILL_LEVELS]; // damage applied by the player
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
+68 -58
View File
@@ -67,6 +67,7 @@ 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 int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
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);
@@ -76,15 +77,16 @@ extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d
// If truly_random flag set (haha), then generate a pretty random number. Otherwise, generate a static rand which
// tends to not change from frame to frame.
// Try four times and choose nearest point to increase chance of getting a good point.
void ai_bpap(const object *objp, const vec3d *attacker_objp_pos, const vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, const ship_subsys *ss)
void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, ship_subsys *ss)
{
float nearest_dist;
vec3d result_point, best_point;
vec3d rel_point;
int num_tries;
int i;
model_octant *octp;
polymodel *pm;
int i, q, octs[4];
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
polymodel* pm = model_get(sip->model_num);
model_subsystem *tp = NULL;
if (ss != NULL)
tp = ss->system_info;
@@ -92,53 +94,63 @@ void ai_bpap(const object *objp, const vec3d *attacker_objp_pos, const vec3d *at
best_point = objp->pos;
nearest_dist = weapon_travel_dist;
// attempt anywhere from 16 to 4 times, more if we're closer
model_which_octant_distant_many(attacker_objp_pos, sip->model_num, &objp->orient, &objp->pos, &pm, octs);
num_tries = (int) (vm_vec_dist(&objp->pos, attacker_objp_pos)/objp->radius);
if (num_tries >= 4)
num_tries = 1;
else
num_tries = (4 - num_tries) * 4;
num_tries = 4 - num_tries;
vm_vec_zero(local_attack_point);
// Index #0 is best one.
if ( pm->octants[octs[0]].verts ) {
*local_attack_point = *pm->octants[octs[0]].verts[0]; // Set just in case it doesn't get set below.
} else {
vm_vec_zero(local_attack_point);
}
auto collision_tree = model_get_bsp_collision_tree(pm->submodel[pm->detail[0]].collision_tree_index);
for (q=0; q<4; q++) {
octp = &pm->octants[octs[q]];
if (octp->nverts > 0) {
if (!collision_tree->poly_centers.empty()) {
int num_polies = (int)collision_tree->poly_centers.size();
if (num_tries > octp->nverts)
num_tries = octp->nverts;
if (num_tries > num_polies)
num_tries = num_polies;
if (num_tries > octp->nverts)
num_tries = octp->nverts;
for (i=0; i<num_tries; i++) {
int index;
float dist, dot;
vec3d v2p;
for (i=0; i<num_tries; i++) {
int index;
float dist, dot;
vec3d v2p;
index = (int) (frand() * num_polies);
index = (int) (frand() * (octp->nverts));
rel_point = collision_tree->poly_centers[index];
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
vm_vec_add2(&result_point, &objp->pos);
rel_point = *octp->verts[index];
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
vm_vec_add2(&result_point, &objp->pos);
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
bool in_fov = false;
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
bool in_fov = false;
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
if (tp == NULL) {
if (dot > fov)
in_fov = true;
} else {
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
}
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
if (tp == NULL) {
if (dot > fov)
in_fov = true;
} else {
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
}
if (in_fov) {
if (dist < nearest_dist) {
nearest_dist = dist;
best_point = result_point;
*local_attack_point = rel_point;
Assert( !vm_is_vec_nan(local_attack_point) );
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
goto done_1;
if (in_fov) {
if (dist < nearest_dist) {
nearest_dist = dist;
best_point = result_point;
*local_attack_point = rel_point;
Assert( !vm_is_vec_nan(local_attack_point) );
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
goto done_1;
}
}
}
}
@@ -162,6 +174,8 @@ done_1:
}
mc_info mc;
mc_info_init(&mc);
mc.model_instance_num = Ships[objp->instance].model_instance_num;
mc.model_num = sip->model_num;
mc.orient = &objp->orient;
@@ -193,7 +207,7 @@ done_1:
//
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
{
if (!timestamp_elapsed(ssp->turret_pick_big_attack_point_timestamp)) {
vec3d result_point;
@@ -213,7 +227,7 @@ void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
// Note, attacker_objp can be a ship or a weapon.
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov)
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
{
Assert(objp->instance > -1);
Assert(objp->type == OBJ_SHIP);
@@ -411,7 +425,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
}
}
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, true) ) {
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 1) ) {
subsys_in_sight = 1;
}
}
@@ -535,18 +549,18 @@ bool ai_new_maybe_reposition_attack_subsys() {
// get world pos of eye (stored in geye)
ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
model_local_to_global_point(&geye, &ep->pnt, pm->id, 0, &Pl_objp->orient, &Pl_objp->pos);
// get world pos of subsystem
get_subsystem_pos(&gsubpos, target_objp, aip->targeted_subsys);
vm_vec_unrotate(&gsubpos, &aip->targeted_subsys->system_info->pnt, &En_objp->orient);
vm_vec_add2(&gsubpos, &En_objp->pos);
// you're in sight! shoot it!
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, false))
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
return false;
// not in sight, gotta get there
vec3d* good_pos = nullptr;
vec3d world_goal_pos;
// For performance reasons we only recheck once a second, otherwise we reuse the last found target.
if (timestamp_elapsed(aip->next_dynamic_path_check_time)) {
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
@@ -568,6 +582,7 @@ bool ai_new_maybe_reposition_attack_subsys() {
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
// then scale in (or out) towards our subsys
vec3d world_goal_pos;
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
world_goal_pos += target_objp->pos;
@@ -603,7 +618,6 @@ bool ai_new_maybe_reposition_attack_subsys() {
else
good_pos = &world_goal_pos;
aip->next_dynamic_path_check_time = timestamp( AI_DYNAMIC_PATH_RECHECK_DELAY );
aip->last_dynamic_path_goal = *good_pos;
}
else{ //Not enough time has passed till recheck.
@@ -617,17 +631,15 @@ bool ai_new_maybe_reposition_attack_subsys() {
accelerate_ship(aip, subsys_distance > 200.0f ? 1.0f : subsys_distance / 200.0f);
if (!(Ships[Pl_objp->instance].flags[Ship::Ship_Flags::Afterburner_locked])) {
if (ai_willing_to_afterburn_hard(aip) && subsys_distance > 1000.0f)
ai_afterburn_hard(Pl_objp, aip);
else if (subsys_distance > 300.0f) {
if (subsys_distance > 300.0f) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 2 * F1_0;
}
}
} else
afterburners_stop(Pl_objp);
else
afterburners_stop(Pl_objp);
}
return true;
}
@@ -747,7 +759,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if ( ai_big_maybe_follow_subsys_path() ) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && !ai_willing_to_afterburn_hard(aip)) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
afterburners_stop(Pl_objp);
}
return;
@@ -839,9 +851,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
} else {
accelerate_ship(aip, accel);
if (ai_willing_to_afterburn_hard(aip) && accel > 0.99f && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked])) {
ai_afterburn_hard(Pl_objp, aip);
} else if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 3*F1_0;
@@ -913,13 +923,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]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
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]) || ((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(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && 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]) {
@@ -1034,7 +1044,7 @@ void ai_big_chase()
ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
weapon_info* wip = ai_get_weapon(&shipp->weapons);
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip && wip->gravity_const != 0.0f;
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip->gravity_const != 0.0f;
bool valid_ballistic_trajectory = true;
if (!ballistic_aiming) {
@@ -1841,7 +1851,7 @@ void ai_big_strafe()
/*
if ( aip->goal_objnum != aip->target_objnum ) {
UNREACHABLE("The goal objnum does not match the target objnum in ai_big_strafe(), please report to the SCP!"); // what is going on here? - Get Alan
Int3(); // what is going on here? - Get Alan
aip->mode = AIM_NONE;
return;
}
+2 -2
View File
@@ -24,8 +24,8 @@ void ai_big_subsys_path_cleanup(ai_info *aip);
void ai_big_strafe();
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov=1.0f);
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
// default distance for following subsystem path points --wookieejedi
// the value is 5 because that was the original value specified in ai_big_maybe_follow_subsys_path()
+388 -634
View File
File diff suppressed because it is too large. Load diff
+177 -245
View File
@@ -13,7 +13,6 @@
#include "ai/aigoals.h"
#include "ai/ailua.h"
#include "globalincs/linklist.h"
#include "globalincs/utility.h"
#include "mission/missionlog.h"
#include "mission/missionparse.h"
#include "network/multi.h"
@@ -51,8 +50,6 @@ struct ship_registry_entry;
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
#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)
@@ -77,9 +74,7 @@ ai_goal_list Ai_goal_names[] =
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
{ "Guard ship", AI_GOAL_GUARD, 0 },
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
@@ -124,10 +119,8 @@ const char *Ai_goal_text(int goal, int submode)
case AI_GOAL_GUARD_WING:
return XSTR( "guard ", 480);
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
return XSTR( "disable ", 481);
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
return XSTR( "disarm ", 482);
case AI_GOAL_EVADE_SHIP:
return XSTR( "evade ", 483);
@@ -214,7 +207,7 @@ void ai_maybe_add_form_goal(wing* wingp)
int wingnum;
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];
wingnum = TVT_wings[ship_regp->p_objp->team];
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];
@@ -487,12 +480,10 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
// these goals cannot be associated to wings, but can to a ship in a wing. So, we should find out
// if the ship is in a wing so we can purge goals which might operate on that wing
ship_index = ship_name_lookup(name);
Assertion(ship_index > -1, "Found a bad ship_index of %d in ai_goal_purge_invalid_goals, please report to the SCP!", ship_index); // get allender -- this is sort of odd
if ( ship_index < 0 ) {
return;
if ( ship_index == -1 ) {
Int3(); // get allender -- this is sort of odd
return;
}
wingnum = Ships[ship_index].wingnum;
purge_goal = goal_list;
@@ -536,12 +527,11 @@ 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 ( 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) )
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | 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;
// disarm/disable goals should remove attacks from certain ships types
// (but not tactical disarm/disable)
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISABLE_SHIP:
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
@@ -558,17 +548,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
}
// grab the ship type of the ship that is being disarmed/disabled
int crippled_ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
if (ai_ship_type < 0 || crippled_ship_type < 0)
break;
ship_type_info *crippled_ship_type_info = &Ship_types[crippled_ship_type];
// work through all the ship types to see if the class matching our ai ship must ignore the ship
// work through all the ship types which to see if the class matching our ai ship must ignore the ship
// being disarmed/disabled
for ( j=0 ; j < (int)crippled_ship_type_info->ai_cripple_ignores.size(); j++) {
if (crippled_ship_type_info->ai_cripple_ignores[j] == ai_ship_type) {
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
purge_goal->flags.set(AI::Goal_Flags::Purge);
}
}
@@ -728,7 +713,7 @@ 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(int type, int 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, char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
{
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
@@ -751,9 +736,6 @@ void ai_add_goal_sub_player(int type, int mode, int submode, const char *target_
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
@@ -818,7 +800,7 @@ int ai_goal_num(ai_goal *goals)
}
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, const char *target_name, ai_goal *aigp )
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, char *target_name, ai_goal *aigp )
{
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
@@ -835,7 +817,7 @@ void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, co
aigp->priority = priority;
}
void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip)
void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip)
{
int empty_index;
ai_goal *aigp;
@@ -859,7 +841,7 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char
// 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( int type, int 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, char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
{
int empty_index;
ai_goal *aigp;
@@ -880,7 +862,7 @@ void ai_add_ship_goal_player( int type, int mode, int submode, const char *shipn
// 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( int type, int 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, char *shipname, int wingnum, const ai_lua_parameters& lua_target)
{
int i, empty_index;
wing *wingp = &Wings[wingnum];
@@ -904,7 +886,7 @@ void ai_add_wing_goal_player( int type, int mode, int submode, const char *shipn
// common routine to add a sexpression mission goal to the appropriate goal structure.
void ai_add_goal_sub_sexp( int sexp, int 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, char *actor_name )
{
int node, dummy, op;
@@ -918,30 +900,22 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
switch (op) {
case OP_AI_WAYPOINTS_ONCE:
case OP_AI_WAYPOINTS:
{
case OP_AI_WAYPOINTS: {
int ref_type;
bool is_nan, is_nan_forever;
ref_type = Sexp_nodes[CDR(node)].subtype;
Assertion(ref_type == SEXP_ATOM_STRING || ref_type == SEXP_ATOM_CONTAINER_DATA, "Found a bad ref_type in ai_add_goal_sub_sexp of %d. Please report to the SCP!", ref_type);
// referenced by name
// save the waypoint path name -- the list will get resolved when the goal is checked
// for achievability.
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
if (ref_type == SEXP_ATOM_STRING) { // referenced by name
// save the waypoint path name -- the list will get resolved when the goal is checked
// for achievability.
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
} else
Int3();
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;
if (CDDDDR(node) < 0)
aigp->int_data = 0; // handle optional node separately because we don't subtract 1 here
else
aigp->int_data = eval_num(CDDDDR(node), is_nan, is_nan_forever) - 1;
if (is_sexp_true(CDDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Waypoints_in_reverse);
break;
}
@@ -956,16 +930,14 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
break;
case OP_AI_DISABLE_SHIP:
case OP_AI_DISABLE_SHIP_TACTICAL:
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->ai_submode = -SUBSYSTEM_ENGINE;
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
break;
case OP_AI_DISARM_SHIP:
case OP_AI_DISARM_SHIP_TACTICAL:
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
aigp->ai_mode = AI_GOAL_DISARM_SHIP;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->ai_submode = -SUBSYSTEM_TURRET;
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
@@ -1003,9 +975,9 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
// this goal needs some extra setup
// if this doesn't work, the goal will be immediately removed
auto ship_entry = ship_registry_get(aigp->target_name);
if (ship_entry && ship_entry->has_shipp())
if (ship_entry->status == ShipStatus::PRESENT)
{
auto target_aip = &Ai_info[ship_entry->shipp()->ai_index];
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
Assertion(aip != nullptr, "Must provide aip if assigning a rearm goal!");
ai_goal_fixup_dockpoints( aip, aigp );
@@ -1049,32 +1021,15 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
break;
case OP_AI_FLY_TO_SHIP:
case OP_AI_STAY_NEAR_SHIP:
{
bool is_nan, is_nan_forever;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->priority = atoi( CTEXT(CDDR(node)) );
// distance from ship
if ( CDDDR(node) < 0 )
aigp->float_data = 300.0f;
else
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
// (the CDDDDR argument is whether to afterburn, and is handled at the end of the function, so don't handle it here)
// whether to "escort" the ship
if ( CDDDDDR(node) >= 0 )
aigp->int_data = is_sexp_true(CDDDDDR(node)) ? 1 : 0;
if (op == OP_AI_FLY_TO_SHIP)
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
else
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
break;
}
case OP_AI_FORM_ON_WING:
aigp->priority = 99;
@@ -1090,6 +1045,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
case OP_AI_EVADE_SHIP:
case OP_AI_IGNORE:
case OP_AI_IGNORE_NEW:
case OP_AI_FLY_TO_SHIP:
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
@@ -1116,10 +1072,14 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
aigp->ai_mode = AI_GOAL_CHASE_WING;
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
} else if ( op == OP_AI_IGNORE ) {
aigp->ai_mode = AI_GOAL_IGNORE;
} else if ( op == OP_AI_IGNORE_NEW ) {
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
} else if ( op == OP_AI_FLY_TO_SHIP ) {
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
} else
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
@@ -1156,45 +1116,15 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, cons
}
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
if (is_sexp_true(CDDDR(node)))
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
}
if ( op == OP_AI_DESTROY_SUBSYS ) {
if (is_sexp_true(CDDDDR(node)))
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
}
// maybe get the afterburn hard flag
if (op == OP_AI_CHASE_ANY) {
if (is_sexp_true(CDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_GUARD ||
op == OP_AI_GUARD_WING ||
op == OP_AI_WAYPOINTS ||
op == OP_AI_WAYPOINTS_ONCE) {
if (is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_CHASE ||
op == OP_AI_CHASE_WING ||
op == OP_AI_CHASE_SHIP_CLASS ||
op == OP_AI_DISABLE_SHIP ||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
op == OP_AI_DISARM_SHIP ||
op == OP_AI_DISARM_SHIP_TACTICAL ||
op == OP_AI_STAY_NEAR_SHIP ||
op == OP_AI_FLY_TO_SHIP) {
if (is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_DESTROY_SUBSYS || op == OP_AI_DOCK) {
if (is_sexp_true(CDDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
// Goober5000 - since none of the goals act on the actor,
// don't assign the goal if the actor's goal target is itself
if (aigp->target_name != NULL && !strcmp(aigp->target_name, actor_name))
@@ -1261,13 +1191,11 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
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;
goalmode = AI_GOAL_DISABLE_SHIP;
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;
goalmode = AI_GOAL_DISABLE_SHIP;
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
break;
case OP_AI_WARP_OUT:
@@ -1297,8 +1225,11 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_PLAY_DEAD:
goalmode = AI_GOAL_PLAY_DEAD;
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_PLAY_DEAD_PERSISTENT:
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_KEEP_SAFE_DISTANCE:
@@ -1340,9 +1271,12 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
goalmode = AI_GOAL_STAY_NEAR_SHIP;
break;
case OP_AI_IGNORE:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_IGNORE;
break;
case OP_AI_IGNORE_NEW:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
goalmode = AI_GOAL_IGNORE_NEW;
break;
case OP_AI_FORM_ON_WING:
priority = 99;
@@ -1465,8 +1399,15 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
int gindex;
ai_goal *aigp;
#ifndef NDEBUG
// Goober5000 - none of the goals act on the actor, as in ai_add_goal_sub_sexp
Assertion(strcmp(name, Ships[aip->shipnum].ship_name) != 0, "The goals apply to the actor in ai_add_goal_ship_internal for ship %s, please report to the SCP!", name);
if (!strcmp(name, Ships[aip->shipnum].ship_name))
{
// not good
Int3();
return;
}
#endif
// find an empty slot to put this goal in.
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
@@ -1517,7 +1458,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
break;
default:
UNREACHABLE("unsupported internal goal of %d found in ai_add_goal_ship_internal. Please report to the SCP", goal_type); // see Mike K or Mark A.
Int3(); // unsupported internal goal -- see Mike K or Mark A.
return;
}
@@ -1557,11 +1498,13 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
int status;
ai_achievability return_val;
ai_info *aip;
int index = -1, sindex = -1;
int modelnum = -1;
auto objp = &Objects[objnum];
Assert( objp->instance != -1 );
auto shipp = &Ships[objp->instance];
auto aip = &Ai_info[shipp->ai_index];
aip = &Ai_info[Ships[objp->instance].ai_index];
// these orders are always achievable.
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
@@ -1572,11 +1515,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (aigp->ai_mode == AI_GOAL_LUA)
return ai_lua_is_achievable(aigp, objnum);
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
// warp (depart) only achievable if there's somewhere to depart to
if (aigp->ai_mode == AI_GOAL_WARP)
{
ship *shipp = &Ships[objp->instance];
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
if ( ship_can_warp_full_check(shipp) )
return ai_achievability::ACHIEVABLE;
@@ -1595,7 +1538,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// if the wing target is valid then be sure to set the override bit so that it always
// gets executed next
if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
if (!target_ship_entry || !target_ship_entry->has_shipp())
sindex = ship_name_lookup( aigp->target_name );
if (sindex < 0)
return ai_achievability::NOT_ACHIEVABLE;
aigp->flags.set(AI::Goal_Flags::Goal_override);
@@ -1652,10 +1597,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup( aigp->target_name );
// can't determine the status of this goal if ship not valid
// or we haven't found a valid subsystem index yet
if ( !target_ship_entry || !target_ship_entry->has_shipp() || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
status = 0;
break;
}
@@ -1664,46 +1610,46 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
// for this goal to be valid).
Assert ( aigp->ai_submode >= 0 );
ssp = ship_get_indexed_subsys( target_ship_entry->shipp(), aigp->ai_submode );
ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
if (ssp != NULL) {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (ssp->current_hits <= 0.0f) ? 1 : 0;
} else {
// not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, target_ship_entry->shipp()->ship_name));
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
status = 0;
}
break;
}
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
{
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup(aigp->target_name);
// can't determine the status of this goal if ship not valid
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
if (sindex < 0) {
status = 0;
} else {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
status = (Ships[sindex].subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
}
break;
}
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
{
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup(aigp->target_name);
// can't determine the status of this goal if ship not valid
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
if (sindex < 0) {
status = 0;
} else {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
status = (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
}
break;
}
@@ -1722,23 +1668,22 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// MWA -- 4/22/98. Check for the ship actually being in the mission before
// checking departure and destroyed. In multiplayer, since ships can respawn,
// they get log entries for being destroyed even though they have respawned.
// Goober5000 - update this to use ship registry status with similar logic
if (target_ship_entry && target_ship_entry->status == ShipStatus::EXITED) {
status = 1;
return_val = ai_achievability::NOT_ACHIEVABLE;
sindex = ship_name_lookup( aigp->target_name );
if ( sindex < 0 ) {
status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
if ( !status ) {
status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
if ( !status ) {
status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
}
}
if ( status )
return_val = ai_achievability::NOT_ACHIEVABLE;
} else {
status = 0;
}
// fly-to-ship can potentially be determined
if (aigp->ai_mode == AI_GOAL_FLY_TO_SHIP && target_ship_entry && target_ship_entry->has_objp()) {
auto dist = vm_vec_dist(&target_ship_entry->objp()->pos, &objp->pos);
if (dist < aigp->float_data) {
return_val = ai_achievability::SATISFIED;
status = 1;
}
}
break;
}
@@ -1776,7 +1721,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
default:
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode);
Int3();
status = 0;
break;
}
@@ -1791,12 +1736,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// the if statement.
if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
{
int wingnum = wing_name_lookup( aigp->target_name );
sindex = wing_name_lookup( aigp->target_name );
if (wingnum < 0)
if (sindex < 0)
return ai_achievability::NOT_KNOWN;
wing *wingp = &Wings[wingnum];
wing *wingp = &Wings[sindex];
if ( wingp->flags[Ship::Wing_Flags::Gone] )
return ai_achievability::NOT_ACHIEVABLE;
@@ -1813,22 +1758,24 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
else
{
if (!target_ship_entry)
auto ship_entry = ship_registry_get(aigp->target_name);
if (!ship_entry)
{
status = SHIP_STATUS_UNKNOWN;
}
// goal ship is currently in mission
else if (target_ship_entry->status == ShipStatus::PRESENT || target_ship_entry->status == ShipStatus::DEATH_ROLL)
else if (ship_entry->status == ShipStatus::PRESENT)
{
status = SHIP_STATUS_ARRIVED;
}
// goal ship is still on the arrival list
else if (target_ship_entry->status == ShipStatus::NOT_YET_PRESENT)
else if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
{
status = SHIP_STATUS_NOT_ARRIVED;
}
// goal ship has left the area
else if (target_ship_entry->status == ShipStatus::EXITED)
else if (ship_entry->status == ShipStatus::EXITED)
{
status = SHIP_STATUS_GONE;
}
@@ -1839,21 +1786,16 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (status == SHIP_STATUS_UNKNOWN)
{
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", shipp->ship_name, aigp->target_name));
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
}
}
// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
{
if (target_ship_entry && target_ship_entry->has_shipp()) {
// if the ship has no turrets, we can't disarm it!
if (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_TURRET].type_count == 0)
return ai_achievability::NOT_ACHIEVABLE;
} else {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
// if the ship has no turrets, we can't disarm it!
if (Ships[ship_name_lookup(aigp->target_name)].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
return ai_achievability::NOT_ACHIEVABLE;
}
// if the goal is an ignore/disable/disarm goal, then
@@ -1875,36 +1817,37 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// this goal will get removed.
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
int modelnum = Ship_info[shipp->ship_info_index].model_num;
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
Assert( modelnum >= 0 );
aigp->docker.index = model_find_dock_name_index(modelnum, aigp->docker.name);
index = model_find_dock_name_index(modelnum, aigp->docker.name);
aigp->docker.index = index;
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
}
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
if (target_ship_entry && target_ship_entry->has_shipp()) {
int modelnum = Ship_info[target_ship_entry->shipp()->ship_info_index].model_num;
aigp->dockee.index = model_find_dock_name_index(modelnum, aigp->dockee.name);
sindex = ship_name_lookup(aigp->target_name);
if ( sindex != -1 ) {
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
aigp->dockee.index = index;
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
} else
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
}
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
Warning(LOCATION, "Cannot determine docking information for %s!", shipp->ship_name); // for now, allender wants to know about these things!!!!
Int3(); // for now, allender wants to know about these things!!!!
return ai_achievability::NOT_ACHIEVABLE;
}
// if ship is disabled, don't know if it can dock or not
if ( shipp->flags[Ship::Ship_Flags::Disabled] )
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Disabled] )
return ai_achievability::NOT_KNOWN;
// we must also determine if we're prevented from docking for any reason
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto goal_objp = target_ship_entry->objp();
sindex = ship_name_lookup(aigp->target_name);
Assert( sindex >= 0 );
object *goal_objp = &Objects[Ships[sindex].objnum];
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
// [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
@@ -1953,14 +1896,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
{
if ( target_ship_entry && target_ship_entry->has_objp() ) {
// only put it on hold if it's someone other than the guy we're undocking from right now!!
if (aip->goal_objnum != target_ship_entry->objnum)
return ai_achievability::NOT_KNOWN;
} else {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
// only put it on hold if it's someone other than the guy we're undocking from right now!!
if (aip->goal_objnum != Ships[ship_name_lookup(aigp->target_name)].objnum)
return ai_achievability::NOT_KNOWN;
}
} else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
@@ -1968,21 +1906,23 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
// the ship's subsystem list
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
if ( target_ship_entry && target_ship_entry->has_shipp() ) {
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp(), aigp->docker.name );
sindex = ship_name_lookup( aigp->target_name );
if ( sindex != -1 ) {
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
} else {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
Int3();
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
object *ignored;
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
if (!target_ship_entry || !target_ship_entry->has_objp()) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto ignored = target_ship_entry->objp();
sindex = ship_name_lookup( aigp->target_name );
Assert( sindex != -1 ); // should be true because of above status
ignored = &Objects[Ships[sindex].objnum];
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
@@ -1998,9 +1938,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
case AI_GOAL_GUARD:
case AI_GOAL_GUARD_WING:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
@@ -2017,7 +1955,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
else if ( status == SHIP_STATUS_UNKNOWN )
return ai_achievability::NOT_KNOWN;
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, shipp->ship_name); // get allender -- bad logic
Int3(); // get allender -- bad logic
break;
}
@@ -2029,29 +1967,31 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
// we mark the goal as not achievable.
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
Int3(); // get Allender. this shouldn't happen!!!
return ai_achievability::NOT_ACHIEVABLE;
}
if ( status == SHIP_STATUS_GONE )
return ai_achievability::NOT_ACHIEVABLE;
if ( !target_ship_entry || !target_ship_entry->has_shipp() ) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
sindex = ship_name_lookup( aigp->target_name );
if ( sindex < 0 ) {
Int3();
return ai_achievability::NOT_ACHIEVABLE;
}
// if destination currently being repaired, then goal is still active
if ( Ai_info[target_ship_entry->shipp()->ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
// if desitnation currently being repaired, then goal is stil active
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
return ai_achievability::ACHIEVABLE;
// if the destination ship is dying or departing (but not completed yet), the mark goal as
// not achievable.
if ( target_ship_entry->shipp()->is_dying_or_departing())
if ( Ships[sindex].is_dying_or_departing())
return ai_achievability::NOT_ACHIEVABLE;
// if the destination object is no longer awaiting repair, then remove the item
if ( !(Ai_info[target_ship_entry->shipp()->ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
return ai_achievability::NOT_ACHIEVABLE;
// not repairing anything means that he can do this goal!!!
@@ -2066,14 +2006,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// if he is repairing something, he can satisfy his repair goal (his goal_objnum)
// return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
// satisfied.
if ( aip->goal_objnum != target_ship_entry->objnum )
if ( aip->goal_objnum != Ships[sindex].objnum )
return ai_achievability::NOT_KNOWN;
return ai_achievability::ACHIEVABLE;
}
default:
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode); // invalid case in switch:
Int3(); // invalid case in switch:
}
return ai_achievability::NOT_KNOWN;
@@ -2184,11 +2124,11 @@ void validate_mission_goals(int objnum, ai_info *aip)
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold]) )
aip->mode = AIM_NONE;
// if the active goal is a rearm/repair or undock goal,
// then put all other valid goals (which are not rearm/repair or undock goals) on hold
if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR || aip->goals[0].ai_mode == AI_GOAL_UNDOCK) && object_is_docked(&Objects[objnum]) ) {
// if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
// on hold
if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR) && object_is_docked(&Objects[objnum]) ) {
for ( i = 1; i < MAX_AI_GOALS; i++ ) {
if ( aip->goals[i].ai_mode == AI_GOAL_NONE || aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR || aip->goals[i].ai_mode == AI_GOAL_UNDOCK )
if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
continue;
aip->goals[i].flags.set(AI::Goal_Flags::Goal_on_hold);
}
@@ -2340,14 +2280,19 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
case AI_GOAL_WAYPOINTS: // do nothing for waypoints
case AI_GOAL_WAYPOINTS_ONCE: {
int flags = 0;
if (current_goal->ai_mode == AI_GOAL_WAYPOINTS)
if ( current_goal->ai_mode == AI_GOAL_WAYPOINTS)
flags |= WPF_REPEAT;
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
flags |= WPF_BACKTRACK;
ai_start_waypoints(objp, current_goal->wp_list, flags, current_goal->int_data);
ai_start_waypoints(objp, current_goal->wp_list, flags);
break;
}
case AI_GOAL_FLY_TO_SHIP:
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
ai_start_fly_to_ship(objp, shipnum);
break;
case AI_GOAL_DOCK: {
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
@@ -2422,27 +2367,22 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
// when destroying a subsystem, we can destroy a specific instance of a subsystem
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
// instances of a specific type
// when destroying a subsystem, we can destroy a specific instance of a subsystem
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
// instances of a specific type
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL: {
case AI_GOAL_DISARM_SHIP: {
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_attack_object( objp, other_obj);
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
// don't protect-ship for tactical goals
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
if (aip->target_objnum != -1) {
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
}
} else // Just in case this ship had been protected, unprotect it.
@@ -2520,17 +2460,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// labels for support ship commands
case AI_GOAL_STAY_NEAR_SHIP:
case AI_GOAL_FLY_TO_SHIP:
{
case AI_GOAL_STAY_NEAR_SHIP: {
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
ai_do_stay_near(objp, other_obj, dist, additional_data);
ai_do_stay_near(objp, other_obj, dist);
break;
}
}
case AI_GOAL_KEEP_SAFE_DISTANCE:
// todo MK: hook to keep support ship at a safe distance
@@ -2551,7 +2488,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
default:
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal->ai_mode);
Int3();
break;
}
@@ -2559,7 +2496,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
ai_formation_object_recalculate_slotnums(old_form_objnum);
}
void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *old_name, const char *new_name)
void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name)
{
int i, mode, flag, dummy;
@@ -2569,8 +2506,8 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
flag = 0;
switch (type)
{
case sexp_ref_type::SHIP:
case sexp_ref_type::PLAYER:
case REF_TYPE_SHIP:
case REF_TYPE_PLAYER:
switch (mode)
{
case AI_GOAL_CHASE:
@@ -2578,9 +2515,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_GUARD:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
@@ -2589,7 +2524,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
}
break;
case sexp_ref_type::WING:
case REF_TYPE_WING:
switch (mode)
{
case AI_GOAL_CHASE_WING:
@@ -2598,7 +2533,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
}
break;
case sexp_ref_type::WAYPOINT:
case REF_TYPE_WAYPOINT:
switch (mode)
{
case AI_GOAL_WAYPOINTS:
@@ -2607,7 +2542,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
}
break;
case sexp_ref_type::WAYPOINT_PATH:
case REF_TYPE_PATH:
switch (mode)
{
case AI_GOAL_WAYPOINTS:
@@ -2618,7 +2553,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
break;
default:
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", static_cast<int>(type));
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", type);
break;
}
@@ -2635,7 +2570,7 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
}
}
bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name)
int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
{
int i, mode, flag;
@@ -2645,8 +2580,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
flag = 0;
switch (type)
{
case sexp_ref_type::SHIP:
case sexp_ref_type::PLAYER:
case REF_TYPE_SHIP:
switch (mode)
{
case AI_GOAL_CHASE:
@@ -2654,9 +2588,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_GUARD:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
@@ -2665,7 +2597,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
}
break;
case sexp_ref_type::WING:
case REF_TYPE_WING:
switch (mode)
{
case AI_GOAL_CHASE_WING:
@@ -2674,7 +2606,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
}
break;
case sexp_ref_type::WAYPOINT:
case REF_TYPE_WAYPOINT:
switch (mode)
{
case AI_GOAL_WAYPOINTS:
@@ -2683,7 +2615,7 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
}
break;
case sexp_ref_type::WAYPOINT_PATH:
case REF_TYPE_PATH:
switch (mode)
{
case AI_GOAL_WAYPOINTS:
@@ -2696,11 +2628,11 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
if (flag) // is this a valid goal to parse for this conversion?
{
if (!stricmp(goals[i].target_name, name))
return true;
return 1;
}
}
return false;
return 0;
}
char *ai_add_dock_name(const char *str)
+9 -11
View File
@@ -73,17 +73,15 @@ struct ai_info;
#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
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
#define AI_GOAL_LUA (1<<27) // 0x04000000
// now the masks for ship types
// 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_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_DISARM_SHIP | 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 )
@@ -168,17 +166,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(int mode, int submode, int priority, const char *shipname, ai_info *aip);
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, 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 void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char *actor_name);
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(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_add_ship_goal_player(int type, int mode, int submode, 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, 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 );
@@ -189,8 +187,8 @@ extern void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip );
extern void ai_mission_goal_complete( ai_info *aip );
extern void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp );
extern void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *old_name, const char *new_name);
extern bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name);
extern void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name);
extern int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name);
extern char *ai_add_dock_name(const char *str);
extern int ai_query_goal_valid( int ship, int ai_goal_type );
+7 -7
View File
@@ -14,24 +14,24 @@
#include "weapon/weapon.h"
//Returns true if the specified object is a stealth ship, false if not
bool is_object_stealth_ship(const object* objp);
bool is_object_stealth_ship(object* objp);
//Number of live turrets on the object attacking
int num_turrets_attacking(const object *turret_parent, int target_objnum);
int num_turrets_attacking(object *turret_parent, int target_objnum);
//Determine whether an object is targetable within a nebula (checks for stealth)
bool object_is_targetable(const object *target, const ship *viewer);
int object_is_targetable(object *target, ship *viewer);
//Returns the number of enemy fighters within threshold of pos.
int num_nearby_fighters(int enemy_team_mask, const vec3d *pos, float threshold);
int num_nearby_fighters(int enemy_team_mask, vec3d *pos, float threshold);
//Returns true if OK for *aip to fire its current weapon at its current target.
bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int secondary_bank, const vec3d *firing_pos_global);
int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int secondary_bank, ship_subsys* turret);
//Returns true if *aip has a line of sight to its current target.
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, const vec3d *firing_pos_global);
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret);
//Does all the stuff needed to aim and fire a turret.
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss);
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss);
#endif
+6 -187
View File
@@ -18,9 +18,9 @@ void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
}
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
Player_orders.back().localize();
Lua_player_orders.emplace(sexp_op, std::move(order));
return true;
@@ -48,140 +48,6 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
return &aiLuaOrder->second;
}
int ai_lua_get_num_general_orders() {
int count = 0;
for (const auto& order : Lua_player_orders) {
if (order.second.generalOrder) {
count++;
}
}
return count;
}
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
{
SCP_vector<SCP_string> list;
for (const auto& order : Lua_player_orders) {
const SCP_string &cat = order.second.category;
// If it's not a general order then move on
if (!order.second.generalOrder) {
continue;
}
// If the order is not enabled then move on
if (enabled_only && !order.second.cur_enabled) {
continue;
}
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
for (size_t i = 0; i <= list.size(); i++) {
// reached the end of the list, so add it
if (i == list.size()) {
list.push_back(cat);
break;
}
// if it's already in the list then don't add it
if (cat == list[i]) {
break;
}
}
}
return list;
}
// Provides a list of general orders for mission saving. You can only get one kind
// of list at a time. If onlyEnabled and onlyValid are both true, for example, you will get
// a list of onlyEnabled orders. If you need a list of enabled orders that are also valid, you'll
// need to get both lists separately and compare.
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
{
SCP_vector<SCP_string> list;
for (const auto& order : Lua_player_orders) {
if (order.second.generalOrder) {
bool add = false;
// All general orders
if (!onlyEnabled && !onlyValid && category.empty()) {
add = true;
} else {
// Only enabled orders
if (onlyEnabled && order.second.cur_enabled) {
add = true;
// Only valid orders
} else if (onlyValid && order.second.cur_valid) {
add = true;
// Only orders that match the category requested
} else if ((!category.empty()) && (order.second.category == category)) {
add = true;
}
}
if (add) {
list.push_back(order.second.parseText);
}
}
}
return list;
}
int ai_lua_find_general_order_id(const SCP_string& name) {
for (const auto& order : Lua_player_orders) {
if (order.second.parseText == name) {
return order.first;
}
}
return -1;
}
void ai_lua_enable_general_order(int sexp_op, bool enable) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_enabled = enable;
}
void ai_lua_validate_general_order(int sexp_op, bool validity)
{
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_valid = validity;
}
void ai_lua_reset_general_orders() {
for (const auto& order : Lua_player_orders) {
ai_lua_enable_general_order(order.first, false);
ai_lua_validate_general_order(order.first, false);
}
}
bool ai_lua_is_general_order(int sexp_op) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return false;
return aiLuaOrder->second.generalOrder;
}
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
if (!action.isValid()) {
Error(LOCATION,
@@ -190,11 +56,7 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
}
luacpp::LuaValueList luaParameters;
if (aip->shipnum >= 0){
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
} else {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
}
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
}
@@ -205,13 +67,8 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
if (retVals[0].getValue<bool>()) {
// If we don't have a ship then it's a general order and we have nothing else to do
if (aip->shipnum >= 0) {
ai_mission_goal_complete(aip);
}
}
if (retVals[0].getValue<bool>())
ai_mission_goal_complete(aip);
}
}
@@ -246,26 +103,6 @@ void ai_lua_start(ai_goal* aigp, object* objp){
run_ai_lua_action(action, lua_ai, aip);
}
// For sending general orders that don't run on a ship.
// Essentially just runs arbitrary lua script when the command is called
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
{
//Create a dummy aip to pass the target data
ai_info aip;
aip.shipnum = -1;
if (target_objnum >= 0 && Objects[target_objnum].type == OBJ_SHIP) {
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
}
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
const auto& lua_ai_sexp = lua_ai->sexp;
const auto& action = lua_ai_sexp.getActionEnter();
run_ai_lua_action(action, *lua_ai, &aip);
}
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
ship* target = &Ships[Objects[target_objnum].instance];
@@ -349,24 +186,6 @@ bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t o
return ai_lua_is_valid_target_lua(mode, target_objnum, self);
}
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self)
{
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
switch (order.shipRestrictions) {
case player_order_lua::ship_restrictions::ANY:
return true;
case player_order_lua::ship_restrictions::WING:
return isWing;
case player_order_lua::ship_restrictions::IN_PLAYER_WING:
return self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
case player_order_lua::ship_restrictions::PLAYER_WING:
return isWing && self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
}
return false;
}
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
@@ -389,7 +208,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;
}
-15
View File
@@ -19,12 +19,7 @@ struct player_order_lua {
int ai_message = MESSAGE_YESSIR;
SCP_string parseText = "";
SCP_string displayText = "";
bool generalOrder = false;
SCP_string category = "";
bool cur_enabled = false;
bool cur_valid = false;
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
};
@@ -33,17 +28,7 @@ bool ai_lua_add_order(int sexp_op, player_order_lua order);
bool ai_lua_has_mode(int sexp_op);
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
const player_order_lua* ai_lua_find_player_order(int sexp_op);
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
int ai_lua_get_num_general_orders();
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
int ai_lua_find_general_order_id(const SCP_string& name);
void ai_lua_enable_general_order(int sexp_op, bool enable);
void ai_lua_validate_general_order(int sexp_op, bool validity);
void ai_lua_reset_general_orders();
bool ai_lua_is_general_order(int sexp_op);
void ai_lua(ai_info* aip);
void ai_lua_start(ai_goal* aigp, object* objp);
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
+247 -201
View File
@@ -58,43 +58,35 @@ const char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
#define EEOF_BIG_ONLY (1<<0) // turret fires only at big and huge ships
#define EEOF_SMALL_ONLY (1<<1) // turret fires only at small ships
#define EEOF_TAGGED_ONLY (1<<2) // turret fires only at tagged ships
#define EEOF_BEAM (1<<3) // turret is a beam
#define EEOF_FLAK (1<<4) // turret is flak
#define EEOF_LASER (1<<5) // turret is a laser
#define EEOF_MISSILE (1<<6) // turret is a missile
const char* Turret_valid_types[NUM_TURRET_TYPES] = {
"Beam",
"Flak",
"Laser",
"Missile",
};
typedef struct eval_enemy_obj_struct {
int turret_parent_objnum = -1; // parent of turret
float weapon_travel_dist = 0.0f; // max targeting range of turret weapon
int enemy_team_mask = 0;
bool weapon_system_ok = false; // is the weapon subsystem of turret ship ok
int eeo_flags = 0;
int turret_parent_objnum; // parent of turret
float weapon_travel_dist; // max targeting range of turret weapon
int enemy_team_mask;
int weapon_system_ok; // is the weapon subsystem of turret ship ok
int eeo_flags;
const vec3d *tpos = nullptr;
const vec3d *tvec = nullptr;
const ship_subsys *turret_subsys = nullptr;
int current_enemy = -1;
vec3d *tpos;
vec3d *tvec;
ship_subsys *turret_subsys;
int current_enemy;
float nearest_attacker_dist = 99999.0f; // nearest ship
int nearest_attacker_objnum = -1;
float nearest_attacker_dist; // nearest ship
int nearest_attacker_objnum;
float nearest_homing_bomb_dist = 99999.0f; // nearest homing bomb
int nearest_homing_bomb_objnum = -1;
float nearest_homing_bomb_dist; // nearest homing bomb
int nearest_homing_bomb_objnum;
float nearest_bomb_dist = 99999.0f; // nearest non-homing bomb
int nearest_bomb_objnum = -1;
float nearest_bomb_dist; // nearest non-homing bomb
int nearest_bomb_objnum;
float nearest_dist = 99999.0f; // nearest ship attacking this turret
int nearest_objnum = -1;
float nearest_dist; // nearest ship attacking this turret
int nearest_objnum;
} eval_enemy_obj_struct;
// the current world orientation of the turret matrix, corresponding to its fvec and uvec defined in the model
@@ -118,9 +110,9 @@ void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num,
* @param tpos Turret initial position
* @param dist Distance from turret to center point of object
*
* @return true if objp is in fov of the specified turret. Otherwise return false.
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
*/
bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d *tvec, const vec3d *tpos, float dist)
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
{
vec3d v2e;
float size_mod;
@@ -175,9 +167,9 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
* @param bomb_objp Bomb specified
* @param ship_objp Ship specified
*
* @return true if bomb_objp is headed towards ship_objp
* @return 1 if bomb_objp is headed towards ship_objp
*/
bool bomb_headed_towards_ship(const object *bomb_objp, const object *ship_objp)
int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
{
float dot;
vec3d bomb_to_ship_vector;
@@ -185,7 +177,11 @@ bool bomb_headed_towards_ship(const object *bomb_objp, const object *ship_objp)
vm_vec_normalized_dir(&bomb_to_ship_vector, &ship_objp->pos, &bomb_objp->pos);
dot = vm_vec_dot(&bomb_objp->orient.vec.fvec, &bomb_to_ship_vector);
return ( dot > 0 );
if ( dot > 0 ) {
return 1;
}
return 0;
}
// Set active weapon for turret
@@ -197,7 +193,7 @@ bool bomb_headed_towards_ship(const object *bomb_objp, const object *ship_objp)
* @note All non-negative return values are expressed in what I like to call "widx"s.
* @return -1 if unable to find a weapon for the target at all.
*/
int turret_select_best_weapon(const ship_subsys *turret, const object * /*target*/)
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
{
//TODO: Fill this out with extraodinary gun-picking algorithms
if(turret->weapons.num_primary_banks > 0)
@@ -211,7 +207,7 @@ int turret_select_best_weapon(const ship_subsys *turret, const object * /*target
/**
* Returns true if all weapons in swp have the specified flag
*/
bool all_turret_weapons_have_flags(const ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
bool all_turret_weapons_have_flags(ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
{
int i;
for(i = 0; i < swp->num_primary_banks; i++)
@@ -228,7 +224,7 @@ bool all_turret_weapons_have_flags(const ship_weapon *swp, flagset<Weapon::Info_
return true;
}
bool all_turret_weapons_have_flags(const ship_weapon *swp, Weapon::Info_Flags flags)
bool all_turret_weapons_have_flags(ship_weapon *swp, Weapon::Info_Flags flags)
{
int i;
for (i = 0; i < swp->num_primary_banks; i++)
@@ -249,7 +245,7 @@ bool all_turret_weapons_have_flags(const ship_weapon *swp, Weapon::Info_Flags fl
* Returns true if any of the weapons in swp have flags
*
*/
bool turret_weapon_has_flags(const ship_weapon *swp, Weapon::Info_Flags flags)
bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
{
Assert(swp != NULL);
@@ -275,7 +271,7 @@ bool turret_weapon_has_flags(const ship_weapon *swp, Weapon::Info_Flags flags)
/**
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
*/
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(const ship_weapon *swp)
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
{
Assert(swp != NULL);
@@ -303,7 +299,7 @@ flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(const ship_weapon *swp
* @note It might be a little faster to optimize based on WP_LASER should only appear in primaries
* and WP_MISSILE in secondaries. but in the interest of future coding I leave it like this.
*/
bool turret_weapon_has_subtype(const ship_weapon *swp, int subtype)
bool turret_weapon_has_subtype(ship_weapon *swp, int subtype)
{
Assert(swp != NULL);
@@ -331,7 +327,7 @@ bool turret_weapon_has_subtype(const ship_weapon *swp, int subtype)
*
* @return a pointer to the Weapon_info for weapon_num
*/
const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
weapon_info *get_turret_weapon_wip(ship_weapon *swp, int weapon_num)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
Assert(weapon_num >= 0);
@@ -348,7 +344,7 @@ const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
return &Weapon_info[wi_index];
}
int get_turret_weapon_next_fire_stamp(const ship_weapon *swp, int weapon_num)
int get_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
Assert(weapon_num >= 0);
@@ -375,7 +371,7 @@ void set_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num, int del
*
* @todo This function is kinda slow
*/
float longest_turret_weapon_range(const ship_weapon *swp)
float longest_turret_weapon_range(ship_weapon *swp)
{
float longest_range_so_far = 0.0f;
float weapon_range;
@@ -488,7 +484,7 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
{
object *turret_parent_obj = &Objects[eeo->turret_parent_objnum];
ship *shipp;
auto ss = eeo->turret_subsys;
ship_subsys *ss = eeo->turret_subsys;
float dist, dist_comp;
bool turret_has_no_target = false;
@@ -766,10 +762,12 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
* @param laser_flag
* @param missile_flag
*/
int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turret_subsys, int enemy_team_mask, const vec3d *tpos, const vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subsys, int enemy_team_mask, vec3d *tpos, vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
{
//float weapon_travel_dist;
int weapon_system_ok;
eval_enemy_obj_struct eeo;
auto swp = &turret_subsys->weapons;
ship_weapon *swp = &turret_subsys->weapons;
// list of stuff to go thru
ship_obj *so;
@@ -782,7 +780,10 @@ int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turre
// weapon_travel_dist=wip->lssm_lock_range;
// Set flag based on strength of weapons subsystem. If weapons subsystem is destroyed, don't let turrets fire at bombs
bool weapon_system_ok = !ship_subsystems_blown(&Ships[Objects[turret_parent_objnum].instance], SUBSYSTEM_WEAPONS);
weapon_system_ok = 0;
if ( ship_get_subsystem_strength( &Ships[Objects[turret_parent_objnum].instance], SUBSYSTEM_WEAPONS ) > 0 ) {
weapon_system_ok = 1;
}
// Initialize eeo struct.
eeo.turret_parent_objnum = turret_parent_objnum;
@@ -814,6 +815,18 @@ int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turre
eeo.tvec = tvec;
eeo.turret_subsys = turret_subsys;
eeo.nearest_attacker_dist = 99999.0f;
eeo.nearest_attacker_objnum = -1;
eeo.nearest_homing_bomb_dist = 99999.0f;
eeo.nearest_homing_bomb_objnum = -1;
eeo.nearest_bomb_dist = 99999.0f;
eeo.nearest_bomb_objnum = -1;
eeo.nearest_dist = 99999.0f;
eeo.nearest_objnum = -1;
// here goes the new targeting priority setting
int n_tgt_priorities;
int priority_weapon_idx = -1;
@@ -1043,7 +1056,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turre
break;
default:
UNREACHABLE("Invalid target type of %d sent to get_nearest_turret_objnum. Please report to the SCP!", turret_subsys->turret_targeting_order[i]);
Int3(); //Means invalid number passed.
}
}
}
@@ -1063,7 +1076,7 @@ DCF_BOOL(use_parent_target, Use_parent_target)
* @param tvec Forward vector of turret (world coords)
* @param current_enemy Objnum of current turret target
*/
int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d *tpos, const vec3d *tvec, int current_enemy)
int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d *tvec, int current_enemy)
{
int enemy_team_mask, enemy_objnum;
ship_info *sip;
@@ -1083,7 +1096,7 @@ int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
if ((sip->class_type >= 0) && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
int target_objnum = aip->target_objnum;
if (Objects[target_objnum].signature == aip->target_signature) {
@@ -1150,9 +1163,9 @@ int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Flak_protected]) && flak_flag) );
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Laser_protected]) && laser_flag) );
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Missile_protected]) && missile_flag) );
Assertion(!Objects[enemy_objnum].flags[Object::Object_Flags::Protected], "find_turret_enemy selected an object of type %d %s that is protected, please report to the SCP!", Objects[enemy_objnum].type, Objects[enemy_objnum].type == OBJ_SHIP ? Ships[Objects[enemy_objnum].instance].ship_name : "");
if ( Objects[enemy_objnum].flags[Object::Object_Flags::Protected] ) {
Int3();
enemy_objnum = aip->target_objnum;
}
}
@@ -1184,6 +1197,8 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
model_instance_local_to_global_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
}
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
/**
* Given an object and a turret on that object, return the actual firing point of the gun and its normal.
*
@@ -1194,44 +1209,86 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
* @param objp Pointer to object
* @param ssp Pointer to turret subsystem
* @param gpos Absolute position of gun firing point
* @param avg_origin Use virtual gun pos corresponding to the average of the firing points
* @param gvec Vector from *gpos to *targetp
* @param use_angles Use current angles
* @param targetp Absolute position of target object
* @param targetp Pointer to target object
*/
void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp, vec3d *gpos, bool avg_origin, vec3d *gvec, bool use_angles, const vec3d *targetp)
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp)
{
vec3d *gun_pos;
vec3d * gun_pos;
model_subsystem *tp = ssp->system_info;
polymodel_instance *pmi = model_get_instance(Ships[objp->instance].model_instance_num);
polymodel *pm = model_get(pmi->model_num);
vec3d avg_gun_pos;
if (avg_origin) {
vm_vec_avg_n(&avg_gun_pos, tp->turret_num_firing_points, tp->turret_firing_point);
gun_pos = &avg_gun_pos;
} else {
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
}
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
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)
return;
if (use_angles) {
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
model_instance_local_to_global_point(&tmp_pos, &avg, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
if (targetp == nullptr) {
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship name %s is invalid.", ssp->turret_enemy_objnum, ssp->sub_name, shipp->ship_name);
object *lep = &Objects[ssp->turret_enemy_objnum];
int best_weapon_tidx = turret_select_best_weapon(ssp, lep);
//This turret doesn't have any good weapons
if (best_weapon_tidx < 0)
return;
weapon_info *wip = get_turret_weapon_wip(&ssp->weapons, best_weapon_tidx);
float weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
if ((ssp->targeted_subsys != nullptr) && !(ssp->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
vm_vec_unrotate(&enemy_point, &ssp->targeted_subsys->system_info->pnt, &Objects[ssp->turret_enemy_objnum].orient);
vm_vec_add2(&enemy_point, &ssp->last_aim_enemy_pos);
} else {
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
// the turret norm here is from the perspective of the base submodel, not the gun submodel
model_instance_local_to_global_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
}
else {
enemy_point = ssp->last_aim_enemy_pos;
}
}
vec3d target_moving_direction = ssp->last_aim_enemy_vel;
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
}
set_predicted_enemy_pos_turret(&tmp_target, &tmp_pos, objp, &enemy_point, &target_moving_direction, wip->max_speed, ssp->turret_time_enemy_in_range * (weapon_system_strength + 1.0f) / 2.0f);
} else {
tmp_target = *targetp;
}
vm_vec_normalized_dir(gvec, &tmp_target, &tmp_pos);
} else {
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
//vector gun_pos2;
//vm_vec_add(&gun_pos2, gpos, gun_pos);
vm_vec_normalized_dir(gvec, targetp, gpos);
}
// per firingpoint based changes go here for turrets
}
/**
* Update turret aiming data based on max turret aim update delay
*/
void turret_ai_update_aim(const ai_info *aip, const object *En_Objp, ship_subsys *ss)
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss)
{
if (Missiontime >= ss->next_aim_pos_time)
{
@@ -1246,15 +1303,26 @@ void turret_ai_update_aim(const ai_info *aip, const object *En_Objp, ship_subsys
}
}
/**
* Sets predicted enemy position. Previously done at the beginning of aifft_rotate_turret.
* Rotate a turret towards an enemy.
*
* Some obscure model thing only John Slagel knows about.
* Sets predicted enemy position.
* If the turret (*ss) has a subsystem targeted, the subsystem is used as the predicted point.
*
* @return TRUE if caller should use angles in subsequent rotations.
*/
void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const object *lep, vec3d *predicted_enemy_pos)
int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep, vec3d *predicted_enemy_pos, vec3d *gvec)
{
int ret_val __UNUSED = 0; // to be used in future, see comment @ end of function
auto pmi = model_get_instance(shipp->model_instance_num);
auto pm = model_get(pmi->model_num);
if (ss->turret_enemy_objnum != -1) {
model_subsystem *tp = ss->system_info;
vec3d target_vel;
vec3d gun_pos, gun_vec, target_vel;
//float weapon_speed;
float weapon_system_strength;
//HACK HACK HACK -WMC
//This should use the best weapon variable
@@ -1263,13 +1331,15 @@ void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, shi
//This turret doesn't have any good weapons
if (best_weapon_tidx < 0)
return;
return 0;
auto wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
weapon_info *wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
// weapon_system_strength scales time enemy in range in 0..1. So, the lower this is, the worse the aiming will be.
weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
ship_get_global_turret_info(objp, tp, &gun_pos, &gun_vec);
//Update "known" position and velocity of target. Only matters if max_aim_update_delay is set.
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ss->turret_enemy_objnum], ss);
@@ -1283,7 +1353,7 @@ void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, shi
}
} else {
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
ai_big_pick_attack_point_turret(lep, ss, global_gun_pos, global_gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
ai_big_pick_attack_point_turret(lep, ss, &gun_pos, &gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
} else {
enemy_point = ss->last_aim_enemy_pos;
}
@@ -1296,13 +1366,24 @@ void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, shi
vm_vec_scale_sub2(&target_vel, &objp->phys_info.vel, wip->vel_inherit_amount);
}
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
vec3d temp;
ship_get_global_turret_gun_info(objp, ss, &gun_pos, &temp, 1, nullptr);
}
if (IS_VEC_NULL(&The_mission.gravity) || wip->gravity_const == 0.0f)
set_predicted_enemy_pos_turret(predicted_enemy_pos, global_gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
set_predicted_enemy_pos_turret(predicted_enemy_pos, &gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
else {
vec3d shoot_vec;
vec3d gravity_vec = The_mission.gravity * wip->gravity_const;
if (physics_lead_ballistic_trajectory(global_gun_pos, &enemy_point, &target_vel, wip->max_speed, &gravity_vec, &shoot_vec)) {
*predicted_enemy_pos = *global_gun_pos + shoot_vec * 1000.0f;
if (physics_lead_ballistic_trajectory(&gun_pos, &enemy_point, &target_vel, wip->max_speed, &The_mission.gravity, &shoot_vec)) {
*predicted_enemy_pos = gun_pos + shoot_vec * 1000.0f;
} 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, predicted_enemy_pos, true);
}
return ret_val;
}
}
@@ -1314,54 +1395,36 @@ void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, shi
// Add to predicted_enemy_pos value in .45 to 1.5x radius of enemy ship, so will often miss, but not by a huge amount.
vm_vec_scale_add2(predicted_enemy_pos, &rand_vec, (1.0f - weapon_system_strength)*1.5f * lep->radius);
}
}
}
/**
* Rotate a turret towards an enemy.
*
* Some obscure model thing only John Slagel knows about.
*
* @return TRUE if caller should use angles in subsequent rotations.
*/
bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const vec3d *predicted_enemy_pos)
{
bool ret_val __UNUSED = false; // to be used in future, see comment @ end of function
auto pmi = model_get_instance(shipp->model_instance_num);
auto pm = model_get(pmi->model_num);
if (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;
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, &gun_pos);
bool in_fov;
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
in_fov = turret_fov_test(ss, gvec, &v2e);
if (in_fov) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
} 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);
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
}
} 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);
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
}
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
// but we need to keep retail behavior by default, which means always returning false unless a special
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
// but we need to keep retail behavior by default, which means always returning 0 unless a special
// flag is used. the "ret_val" stuff is here is needed/wanted at a later date however.
//return ret_val;
// return false by default (to preserve retail behavior) but allow for a per-subsystem option
// return 0 by default (to preserve retail behavior) but allow for a per-subsystem option
// for using the turret normals for firing
if (ss->system_info->flags[Model::Subsystem_Flags::Fire_on_normal])
return true;
return 1;
return false;
return 0;
}
/**
@@ -1369,7 +1432,7 @@ bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss,
*
* @return Dot product of vector from point abs_gunposp to *enemy_subsysp, if hittable
*/
float aifft_compute_turret_dot(const object *objp, const object *enemy_objp, const vec3d *abs_gunposp, const ship_subsys *turret_subsysp, const ship_subsys *enemy_subsysp)
float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunposp, ship_subsys *turret_subsysp, ship_subsys *enemy_subsysp)
{
float dot_out;
vec3d subobj_pos, vector_out;
@@ -1377,7 +1440,7 @@ float aifft_compute_turret_dot(const object *objp, const object *enemy_objp, con
vm_vec_unrotate(&subobj_pos, &enemy_subsysp->system_info->pnt, &enemy_objp->orient);
vm_vec_add2(&subobj_pos, &enemy_objp->pos);
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, true, &dot_out, &vector_out)) {
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
vec3d turret_norm;
model_instance_local_to_global_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
@@ -1431,7 +1494,7 @@ DCF(mf, "Adjusts the maximum number of tries an AI may do when trying to pick a
*
* @return Dot product from turret to subsystem in *dot_out
*/
ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp, const vec3d *global_gun_pos, const object *enemy_objp, float *dot_out)
ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *enemy_objp, float *dot_out)
{
ship *eshipp, *shipp;
ship_info *esip;
@@ -1448,6 +1511,10 @@ ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp
float best_dot = 0.0f;
*dot_out = best_dot;
// Compute absolute gun position.
vec3d abs_gun_pos;
ship_get_global_turret_info(objp, ssp->system_info, &abs_gun_pos, nullptr);
// Only pick a turret to attack on large ships.
if (!esip->is_big_or_huge())
return best_subsysp;
@@ -1503,7 +1570,7 @@ ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp
if(stride <= 0){
stride = 1;
}
int offset = Random::next((aifft_list_size % stride) + 1); // returns an offset in [0, size % stride] inclusive
int offset = (int)frand_range(0.0f, (float)(aifft_list_size % stride));
int idx;
float dot_fov_modifier = 0.0f;
@@ -1513,7 +1580,7 @@ ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp
}
for(idx=offset; idx<aifft_list_size; idx+=stride){
dot = aifft_compute_turret_dot(objp, enemy_objp, global_gun_pos, ssp, aifft_list[idx]);
dot = aifft_compute_turret_dot(objp, enemy_objp, &abs_gun_pos, ssp, aifft_list[idx]);
if ((dot - dot_fov_modifier)* aifft_rank[idx] > best_dot) {
best_dot = (dot - dot_fov_modifier)*aifft_rank[idx];
@@ -1528,17 +1595,34 @@ ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp
}
/**
* @return true if the specified target should scan for a new target, otherwise return false
* @return !0 if the specified target should scan for a new target, otherwise return 0
*/
bool turret_should_pick_new_target(ship_subsys *turret)
int turret_should_pick_new_target(ship_subsys *turret)
{
return timestamp_elapsed(turret->turret_next_enemy_check_stamp);
// int target_type;
if ( timestamp_elapsed(turret->turret_next_enemy_check_stamp) ) {
return 1;
}
/*
if ( turret->turret_enemy_objnum == -1 ) {
return 1;
}
target_type = Objects[turret->turret_enemy_objnum].type;
if ( (target_type != OBJ_SHIP) && (target_type != OBJ_ASTEROID) ) {
return 1;
}
*/
return 0;
}
/**
* 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)
void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsys *turret, ai_info *aip)
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
float wait = 1000.0f;
@@ -1651,13 +1735,13 @@ void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship
/**
* Decide if a turret should launch an aspect seeking missile
*/
bool turret_should_fire_aspect(const ship_subsys *turret, const weapon_info *wip, bool in_sight)
int turret_should_fire_aspect(ship_subsys *turret, weapon_info *wip, bool in_sight)
{
if ( in_sight && (turret->turret_time_enemy_in_range >= MIN(wip->min_lock_time,AICODE_TURRET_MAX_TIME_IN_RANGE)) ) {
return true;
return 1;
}
return false;
return 0;
}
/**
@@ -1679,9 +1763,9 @@ 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 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, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f)
{
matrix firing_orient;
matrix turret_orient;
int weapon_objnum;
ai_info *parent_aip;
ship *parent_ship;
@@ -1743,21 +1827,16 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
#endif
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, orig_firing_pos)) {
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, turret)) {
auto turret_enemy_objp = (turret->turret_enemy_objnum >= 0) ? &Objects[turret->turret_enemy_objnum] : nullptr;
ship_weapon* swp = &turret->weapons;
turret->turret_last_fire_direction = *orig_firing_vec;
turret->turret_last_fire_direction = *firing_vec;
const vec3d *firing_vec = orig_firing_vec;
vec3d firing_vec_buf;
if (turret->turret_inaccuracy > 0.0f)
vm_vec_random_cone(firing_vec, firing_vec, turret->turret_inaccuracy);
if (turret->turret_inaccuracy > 0.0f) {
vm_vec_random_cone(&firing_vec_buf, firing_vec, turret->turret_inaccuracy);
firing_vec = &firing_vec_buf;
}
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
vm_vector_2_matrix(&turret_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];
@@ -1808,7 +1887,6 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_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 },
@@ -1936,15 +2014,11 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
}
}
vec3d firing_pos_buf;
const vec3d *firing_pos = &firing_pos_buf;
// zookeeper - Firepoints should cycle normally between shots,
// 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);
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, turret_pos, firing_vec, 1, nullptr);
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
weapon_objnum = weapon_create( turret_pos, &turret_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));
@@ -1955,7 +2029,6 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = wp->weapon_info_index;
turret->turret_last_fired = _timestamp();
wp->target_num = turret->turret_enemy_objnum;
// AL 1-6-97: Store pointer to turret subsystem
@@ -1976,7 +2049,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
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));
flak_pick_range(objp, turret_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
// determine what that range was
flak_range = flak_get_range(objp);
@@ -1989,7 +2062,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
// do mflash if the weapon has it
if (wip->muzzle_flash >= 0) {
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
mflash_create(turret_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
}
// in multiplayer (and the master), then send a turret fired packet.
@@ -2005,10 +2078,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
}
if ( play_sound && wip->launch_snd.isValid() ) {
if ( wip->launch_snd.isValid() ) {
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), firing_pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
}
}
}
@@ -2040,7 +2113,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
{
int weapon_objnum;
matrix firing_orient;
matrix turret_orient;
vec3d turret_pos, turret_fvec;
// parent not alive, quick out.
@@ -2053,7 +2126,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
tsi->turret->turret_next_fire_pos = tsi->weapon_num;
// change firing point
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, false, &turret_fvec, true, nullptr);
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, &turret_fvec, 1, NULL);
tsi->turret->turret_next_fire_pos++;
//check if this really is a swarm. If not, how the hell did it get here?
@@ -2068,11 +2141,11 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
turret_fvec = tsi->turret->turret_last_fire_direction;
}
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
// make turret_orient from turret_fvec -- turret->turret_last_fire_direction
vm_vector_2_matrix(&turret_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, 1, 0, 0.0f, tsi->turret);
weapon_objnum = weapon_create(&turret_pos, &turret_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.
@@ -2082,7 +2155,6 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
Ships[Objects[tsi->parent_objnum].instance].last_fired_turret = tsi->turret;
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
tsi->turret->turret_last_fired = _timestamp();
if (scripting::hooks::OnTurretFired->isActive()) {
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{
@@ -2131,7 +2203,7 @@ int Num_turrets_fired = 0;
* all turret movement and resetting when idle
*/
extern int Nebula_sec_range;
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
{
float weapon_firing_range;
float weapon_min_range; // *Weapon minimum firing range -Et1
@@ -2215,21 +2287,12 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
objp = &Objects[shipp->objnum];
Assert(objp->type == OBJ_SHIP);
vec3d global_gun_pos, global_gun_vec;
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, true, nullptr);
} else {
// Use the turret info for all guns, not one gun in particular.
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
}
// 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);
// Use the turret info for all guns, not one gun in particular.
vec3d gvec, gpos;
ship_get_global_turret_info(objp, tp, &gpos, &gvec);
// 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);
int use_angles = aifft_rotate_turret(objp, shipp, ss, lep, &predicted_enemy_pos, &gvec);
// Multiplayer clients are now able to try to track their targets and also reset to their idle positions.
// But everything after this point is turret firing, so we need to bail here.
@@ -2253,20 +2316,18 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
float dist_to_enemy = 0.0f;
if (lep) {
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));
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos));
else
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos) - lep->radius);
}
// count the number of enemies, in case we have a spawning weapon
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &global_gun_pos, 1500.0f);
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &gpos, 1500.0f);
// some flags considering there may be different weapon types on this turret
bool we_did_non_spawning_logic = false;
bool tentative_return = false;
float turret_barrel_length = -1.0f;
//WMC - go through all valid weapons. Fire spawns if there are any.
int valid_weapons[MAX_SHIP_WEAPONS];
int num_valid = 0;
@@ -2298,7 +2359,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
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, &global_gun_pos, &ss->turret_last_fire_direction);
turret_fire_weapon(i, ss, parent_objnum, &gpos, &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])
@@ -2346,16 +2407,10 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// If the barrel of this turret is long, we shouldn't try to fire if the enemy is under the gun.
// Note that this isn't the same thing as min_range, which is unrelated to barrel length.
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
if (turret_barrel_length < 0.0f) {
if (tp->turret_gun_sobj >= 0) {
auto pm = model_get(tp->model_num);
auto submodel = &pm->submodel[tp->turret_gun_sobj];
turret_barrel_length = 2 * submodel->rad;
} else {
turret_barrel_length = 0.0f;
}
}
if (dist_to_enemy < turret_barrel_length) continue;
vec3d fpoint, fvec;
ship_get_global_turret_gun_info(objp, ss, &fpoint, &fvec, use_angles, &predicted_enemy_pos);
auto barrel_length = vm_vec_dist(&fpoint, &gpos);
if (dist_to_enemy < barrel_length) continue;
}
// Don't try to fire beyond weapon_limit_range (or within min range)
@@ -2473,7 +2528,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// Maybe pick a new enemy, unless targeting has been taken over by scripting
if ( turret_should_pick_new_target(ss) && !ss->scripting_target_override && !(ss->flags[Ship::Subsystem_Flags::Forced_target])) {
Num_find_turret_enemy++;
int objnum = find_turret_enemy(ss, parent_objnum, &global_gun_pos, &global_gun_vec, ss->turret_enemy_objnum);
int objnum = find_turret_enemy(ss, parent_objnum, &gpos, &gvec, ss->turret_enemy_objnum);
if (objnum >= 0) {
if (ss->turret_enemy_objnum == -1) {
@@ -2495,7 +2550,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
float dot = 1.0f;
lep = &Objects[ss->turret_enemy_objnum];
if (( lep->type == OBJ_SHIP ) && !(ss->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, &global_gun_pos, lep, &dot);
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, lep, &dot);
}
// recheck in 2-3 seconds
ss->turret_next_enemy_check_stamp = timestamp((int)((MAX(dot, 0.5f) * The_mission.ai_profile->turret_target_recheck_time) + (The_mission.ai_profile->turret_target_recheck_time / 2.0f)));
@@ -2536,15 +2591,14 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
return;
}
//This can't happen. See above code
//if ( lep == nullptr ){
// return;
//}
if ( lep == nullptr ){
return;
}
//This can't happen. See above code
//Assert(ss->turret_enemy_objnum != -1);
bool in_fov = turret_fov_test(ss, &global_gun_vec, &v2e);
bool in_fov = turret_fov_test(ss, &gvec, &v2e);
bool something_was_ok_to_fire = false;
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
@@ -2563,8 +2617,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
number_of_firings = num_valid;
}
auto sound_played = gamesnd_id();
for (int i = 0; i < number_of_firings; ++i)
{
int valid_index;
@@ -2574,13 +2626,6 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
valid_index = i;
auto wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[valid_index]);
bool play_sound = false;
if (sound_played != wip->launch_snd) {
sound_played = wip->launch_snd;
play_sound = true;
}
// Forces the firing turret to retain the firingpoints of their weapons:
// if the turret has multiple banks, the first bank will only fire from the first firepoint,
// the second bank only from the second firepoint, and so on.
@@ -2599,13 +2644,13 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// We're ready to fire... now get down to specifics, like where is the
// actual gun point and normal, not just the one for whole turret.
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, use_angles, &predicted_enemy_pos);
ship_get_global_turret_gun_info(objp, ss, &gpos, &gvec, use_angles, &predicted_enemy_pos);
// 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...]
vm_vec_sub(&v2e, &predicted_enemy_pos, &global_gun_pos);
vm_vec_sub(&v2e, &predicted_enemy_pos, &gpos);
dist_to_enemy = vm_vec_normalize(&v2e);
float dot = vm_vec_dot(&v2e, &global_gun_vec);
float dot = vm_vec_dot(&v2e, &gvec);
// (flak jitter moved to after we obtain shoot_vector below)
@@ -2670,7 +2715,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
// Check if turret should fire and enemy's engines are
// in line of sight
if (turret_should_fire_aspect(ss, wip, in_sight) &&
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &global_gun_pos))
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &gpos))
{
ok_to_fire = true;
}
@@ -2680,14 +2725,15 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
if ( ok_to_fire && (tp->flags[Model::Subsystem_Flags::Turret_hull_check]) ) {
int model_num = Ship_info[shipp->ship_info_index].model_num;
vec3d end;
vm_vec_scale_add(&end, &global_gun_pos, &global_gun_vec, model_get_radius(model_num));
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
mc_info hull_check;
mc_info_init(&hull_check);
hull_check.model_instance_num = shipp->model_instance_num;
hull_check.model_num = model_num;
hull_check.orient = &objp->orient;
hull_check.pos = &objp->pos;
hull_check.p0 = &global_gun_pos;
hull_check.p0 = &gpos;
hull_check.p1 = &end;
hull_check.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
@@ -2727,7 +2773,7 @@ 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 (tp->flags[Model::Subsystem_Flags::Fire_on_normal])
shoot_vector = global_gun_vec;
shoot_vector = gvec;
// 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
@@ -2735,7 +2781,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
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, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &gpos, &shoot_vector, &predicted_enemy_pos);
}
else
{
@@ -2804,7 +2850,7 @@ void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
}
}
bool turret_std_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
bool turret_std_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
model_subsystem *tp = ss->system_info;
float dot = vm_vec_dot(v2e, gvec);
@@ -2814,7 +2860,7 @@ bool turret_std_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *
return false;
}
bool turret_adv_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
model_subsystem *tp = ss->system_info;
float dot = vm_vec_dot(v2e, gvec);
@@ -2840,10 +2886,10 @@ bool turret_adv_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *
return false;
}
bool turret_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
bool in_fov = false;
if (ss->system_info->turret_base_fov > -1.0f)
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_base_restricted_fov])
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
else
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
+1 -1
View File
@@ -670,7 +670,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
* @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.
* @return Pointer to anim that is loaded if sucess, NULL if failure.
*/
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
{
+3 -3
View File
@@ -22,19 +22,19 @@ anim_instance *init_anim_instance(anim *ptr, int bpp)
{
anim_instance *inst;
Assertion(ptr, "Bad pointer in init_anim_instance(), please report to the SCP!");
if (!ptr) {
Int3();
return NULL;
}
if ( ptr->flags & ANF_STREAMED ) {
Assertion(ptr->file_offset > -1, "Bad file offset of %d in init_anim_instance(), please report to the SCP!", ptr->file_offset);
if ( ptr->file_offset < 0 ) {
Int3();
return NULL;
}
} else {
Assertion(ptr->data, "Bad data in init_anim_instance(), please report to the SCP!");
if ( !ptr->data ) {
Int3();
return NULL;
}
}
+104 -185
View File
@@ -265,7 +265,7 @@ static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
/**
* Create a single asteroid
*/
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility)
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype)
{
int n, objnum;
matrix orient;
@@ -356,13 +356,6 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
angs.h = static_randf( rand_base++ ) * PI2;
}
// If the generated asteroid position is within the player view then abort
// I'm unsure how Eyepoint is handled for multiplayer, so this may need to move up into the SP
// only section - Mjn
if (check_visibility && asteroid_is_within_view(&pos, -1.0f, true)) {
return nullptr;
}
vm_angles_2_matrix(&orient, &angs);
flagset<Object::Object_Flags> asteroid_default_flagset;
asteroid_default_flagset += Object::Object_Flags::Renders;
@@ -401,12 +394,12 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
vec3d rotvel;
if ( Game_mode & GM_NORMAL ) {
vm_vec_rand_vec_quick(&rotvel);
vm_vec_scale(&rotvel, asip->rotational_vel_multiplier * (frand()/4.0f + 0.1f));
vm_vec_scale(&rotvel, frand()/4.0f + 0.1f);
objp->phys_info.rotvel = rotvel;
vm_vec_rand_vec_quick(&objp->phys_info.vel);
} else {
static_randvec( rand_base++, &rotvel );
vm_vec_scale(&rotvel, asip->rotational_vel_multiplier * (static_randf(rand_base++)/4.0f + 0.1f));
vm_vec_scale(&rotvel, static_randf(rand_base++)/4.0f + 0.1f);
objp->phys_info.rotvel = rotvel;
static_randvec( rand_base++, &objp->phys_info.vel );
}
@@ -444,12 +437,6 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
// ensure vel is valid
Assert( !vm_is_vec_nan(&objp->phys_info.vel) );
if (scripting::hooks::OnAsteroidCreated->isActive()) {
scripting::hooks::OnAsteroidCreated->run(
scripting::hook_param_list(
scripting::hook_param("Asteroid", 'o', objp)));
}
return objp;
}
@@ -704,29 +691,11 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
Asteroid_field.num_initial_asteroids = num_asteroids;
switch (field_type) {
case 0:
Asteroid_field.field_type = FT_PASSIVE;
Asteroid_field.enhanced_visibility_checks = false;
break;
case 1:
Asteroid_field.field_type = FT_ACTIVE;
Asteroid_field.enhanced_visibility_checks = false;
break;
case 2:
Asteroid_field.field_type = FT_PASSIVE;
Asteroid_field.enhanced_visibility_checks = true;
break;
case 3:
Asteroid_field.field_type = FT_ACTIVE;
Asteroid_field.enhanced_visibility_checks = true;
break;
default: //Any other number will just give default behavior
Asteroid_field.field_type = FT_PASSIVE;
Asteroid_field.enhanced_visibility_checks = false;
break;
if (field_type == 0) {
Asteroid_field.field_type = FT_PASSIVE;
} else {
Asteroid_field.field_type = FT_ACTIVE;
}
vm_vec_rand_vec_quick(&Asteroid_field.vel);
vm_vec_scale(&Asteroid_field.vel, (float)asteroid_speed);
Asteroid_field.speed = (float)asteroid_speed;
@@ -777,7 +746,7 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
}
// will replace any existing asteroid or debris field with a debris field
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_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max)
{
remove_all_asteroids();
@@ -785,8 +754,6 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int deb
Asteroid_field.field_type = FT_PASSIVE;
Asteroid_field.enhanced_visibility_checks = enhanced;
vm_vec_rand_vec_quick(&Asteroid_field.vel);
vm_vec_scale(&Asteroid_field.vel, (float)asteroid_speed);
Asteroid_field.speed = (float)asteroid_speed;
@@ -916,37 +883,37 @@ static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
}
/**
* Generates a potential new position for an asteroid that might wrap
* from one end of the asteroid field to the other
* Wrap an asteroid from one end of the asteroid field to the other
*/
static void asteroid_wrap_pos(vec3d *pos, asteroid_field *asfieldp)
static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
{
if (pos->xyz.x < asfieldp->min_bound.xyz.x) {
pos->xyz.x = asfieldp->max_bound.xyz.x + (pos->xyz.x - asfieldp->min_bound.xyz.x);
if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
}
if (pos->xyz.y < asfieldp->min_bound.xyz.y) {
pos->xyz.y = asfieldp->max_bound.xyz.y + (pos->xyz.y - asfieldp->min_bound.xyz.y);
if (objp->pos.xyz.y < asfieldp->min_bound.xyz.y) {
objp->pos.xyz.y = asfieldp->max_bound.xyz.y + (objp->pos.xyz.y - asfieldp->min_bound.xyz.y);
}
if (objp->pos.xyz.z < asfieldp->min_bound.xyz.z) {
objp->pos.xyz.z = asfieldp->max_bound.xyz.z + (objp->pos.xyz.z - asfieldp->min_bound.xyz.z);
}
if (pos->xyz.z < asfieldp->min_bound.xyz.z) {
pos->xyz.z = asfieldp->max_bound.xyz.z + (pos->xyz.z - asfieldp->min_bound.xyz.z);
if (objp->pos.xyz.x > asfieldp->max_bound.xyz.x) {
objp->pos.xyz.x = asfieldp->min_bound.xyz.x + (objp->pos.xyz.x - asfieldp->max_bound.xyz.x);
}
if (pos->xyz.x > asfieldp->max_bound.xyz.x) {
pos->xyz.x = asfieldp->min_bound.xyz.x + (pos->xyz.x - asfieldp->max_bound.xyz.x);
if (objp->pos.xyz.y > asfieldp->max_bound.xyz.y) {
objp->pos.xyz.y = asfieldp->min_bound.xyz.y + (objp->pos.xyz.y - asfieldp->max_bound.xyz.y);
}
if (pos->xyz.y > asfieldp->max_bound.xyz.y) {
pos->xyz.y = asfieldp->min_bound.xyz.y + (pos->xyz.y - asfieldp->max_bound.xyz.y);
}
if (pos->xyz.z > asfieldp->max_bound.xyz.z) {
pos->xyz.z = asfieldp->min_bound.xyz.z + (pos->xyz.z - asfieldp->max_bound.xyz.z);
if (objp->pos.xyz.z > asfieldp->max_bound.xyz.z) {
objp->pos.xyz.z = asfieldp->min_bound.xyz.z + (objp->pos.xyz.z - asfieldp->max_bound.xyz.z);
}
// wrap on inner bound, check all 3 axes as needed, use of rand ok for multiplayer with send_asteroid_throw()
inner_bound_pos_fixup(asfieldp, pos);
inner_bound_pos_fixup(asfieldp, &objp->pos);
}
@@ -993,8 +960,7 @@ static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float de
vm_vec_add2(&rand_vec, &objp->orient.vec.rvec);
vm_vec_normalize(&rand_vec);
auto asp = &Asteroids[asteroid_objp->instance];
speed = Asteroid_info[asp->asteroid_type].max_speed * (frand()/2.0f + 0.5f);
speed = Asteroid_info[0].max_speed * (frand()/2.0f + 0.5f);
vm_vec_copy_scale(&asteroid_objp->phys_info.vel, &rand_vec, -speed);
asteroid_objp->phys_info.desired_vel = asteroid_objp->phys_info.vel;
@@ -1017,39 +983,12 @@ static void sanitize_asteroid_targets_list() {
}
}
/**
* Checks if an asteroid will be within the player's view
*
**/
bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
{
vec3d vec_to_asteroid;
// Distance and view cone for the position in relation to the player
float dist = vm_vec_normalized_dir(&vec_to_asteroid, pos, &Eye_position);
float dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
// if asteroid is within view or far enough away then wrap
if (dot > cos(g3_get_hfov(Proj_fov))) {
if (range_override) {
return true;
} else {
if (dist < range) {
return true;
}
}
}
return false;
}
/**
* Call once per frame to maybe throw some asteroids at one or more ships.
*
*/
static void maybe_throw_asteroid()
{
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))
@@ -1084,7 +1023,7 @@ static void maybe_throw_asteroid()
if (subtype < 0)
return;
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype, Asteroid_field.enhanced_visibility_checks);
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
if (objp != nullptr) {
asteroid_aim_at_target(target_objp, objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
@@ -1135,7 +1074,7 @@ void asteroid_delete( object * obj )
}
/**
* See if we should reposition the asteroid.
* See if we should reposition the asteroid.
* Only reposition if oustide the bounding volume and the player isn't looking towards the asteroid.
*/
static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
@@ -1145,74 +1084,61 @@ static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
return;
}
if (asteroid_should_wrap(objp, asfieldp)) {
if ( asteroid_should_wrap(objp, asfieldp) ) {
vec3d vec_to_asteroid, old_asteroid_pos, old_vel;
float dot, dist;
// Generate a possible new position if we do end up wrapping, but don't move the asteroid yet
vec3d new_pos = objp->pos;
asteroid_wrap_pos(&new_pos, asfieldp);
old_asteroid_pos = objp->pos;
old_vel = objp->phys_info.vel;
bool wrap = false;
bool reverse = false;
// don't wrap asteroid if it is a target of some ship
if ( !asteroid_is_targeted(objp) ) {
// If asteroid is targeted then we cannot wrap because they player would see it and say "SHENANIGANS!"
// So we bail
if (asteroid_is_targeted(objp)) {
return;
}
// only wrap if player won't see asteroid disappear/reverse direction
dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
if ( (dot < 0.7f) || (dist > asfieldp->bound_rad) ) {
if (Num_asteroids > MAX_ASTEROIDS-10) {
objp->flags.set(Object::Object_Flags::Should_be_dead);
} else {
// check to ensure player won't see asteroid appear either
asteroid_wrap_pos(objp, asfieldp);
asteroid* astp = &Asteroids[objp->instance];
// if asteroid is not within view...
if (!asteroid_is_within_view(&objp->pos, asfieldp->bound_rad, asfieldp->enhanced_visibility_checks)) {
if (asfieldp->field_type == FT_ACTIVE) {
// this doesnt count as a thrown asteroid anymore
for (asteroid_target& target : Asteroid_targets)
if (target.objnum == astp->target_objnum)
target.incoming_asteroids--;
// if asteroid new position is within view then reverse velocity, otherwise wrap
if (asteroid_is_within_view(&new_pos, (asfieldp->bound_rad * 1.3f), asfieldp->enhanced_visibility_checks)) {
astp->target_objnum = -1;
}
// if the mission has gravity, then we can't reverse. So make sure gravity is null
if (IS_VEC_NULL(&The_mission.gravity)) {
reverse = true;
dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
//probably don't reverse direction if there's gravity involved
if (IS_VEC_NULL(&The_mission.gravity)) {
if ((dot > 0.7f) && (dist < (asfieldp->bound_rad * 1.3f))) {
// player would see asteroid pop out other side, so reverse velocity instead of wrapping
objp->pos = old_asteroid_pos;
vm_vec_copy_scale(&objp->phys_info.vel, &old_vel, -1.0f);
objp->phys_info.desired_vel = objp->phys_info.vel;
Asteroids[objp->instance].target_objnum = -1;
}
}
// update last pos (after vel is known)
vm_vec_scale_add(&objp->last_pos, &objp->pos, &objp->phys_info.vel, -flFrametime);
asteroid_update_collide(objp);
if (asfieldp->field_type == FT_ACTIVE) {
if (MULTIPLAYER_MASTER)
send_asteroid_throw(objp);
}
}
} else {
wrap = true;
}
}
// we can wrap, but we have too many asteroids, so destroy this one instead
if (wrap && (Num_asteroids > MAX_ASTEROIDS - 10)) {
objp->flags.set(Object::Object_Flags::Should_be_dead);
return;
}
// Reverse instead of wrap!
if (reverse) {
vm_vec_copy_scale(&objp->phys_info.vel, &objp->phys_info.vel, -1.0f);
objp->phys_info.desired_vel = objp->phys_info.vel;
Asteroids[objp->instance].target_objnum = -1;
return;
}
// We can wrap, so wrap!
if (wrap) {
objp->pos = new_pos;
asteroid *astp = &Asteroids[objp->instance];
if (asfieldp->field_type == FT_ACTIVE) {
// this doesnt count as a thrown asteroid anymore
for (asteroid_target &target : Asteroid_targets)
if (target.objnum == astp->target_objnum)
target.incoming_asteroids--;
astp->target_objnum = -1;
}
// update last pos (after vel is known)
vm_vec_scale_add(&objp->last_pos, &objp->pos, &objp->phys_info.vel, -flFrametime);
asteroid_update_collide(objp);
if (asfieldp->field_type == FT_ACTIVE) {
if (MULTIPLAYER_MASTER)
send_asteroid_throw(objp);
}
}
}
@@ -1240,6 +1166,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
mc_info mc;
mc_info_init(&mc);
int num, asteroid_subtype;
Assert( pasteroid->type == OBJ_ASTEROID );
@@ -1333,9 +1260,10 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE);
// copy important data
int orig_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
vec3d orig_p0 = *mc.p0;
vec3d orig_p1 = *mc.p1;
int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
vec3d copy_p0, copy_p1;
copy_p0 = *mc.p0;
copy_p1 = *mc.p1;
// first test against the sphere - if this fails then don't do any submodel tests
mc.flags = MC_ONLY_SPHERE | MC_CHECK_SPHERELINE;
@@ -1361,7 +1289,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
// Only check single submodel now, since children of moving submodels are handled as moving as well
mc.flags = orig_flags | MC_SUBMODEL;
mc.flags = copy_flags | MC_SUBMODEL;
// check each submodel in turn
for (auto submodel: submodel_vector) {
@@ -1406,9 +1334,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
}
// Now complete base model collision checks that do not take into account rotating submodels.
mc.flags = orig_flags;
mc.p0 = &orig_p0;
mc.p1 = &orig_p1;
mc.flags = copy_flags;
*mc.p0 = copy_p0;
*mc.p1 = copy_p1;
mc.orient = &heavy_obj->orient;
// usual ship_ship collision test
@@ -1673,7 +1601,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
weapon_area_apply_blast(nullptr, ship_objp, &asteroid_objp->pos, blast, false);
weapon_area_apply_blast(NULL, ship_objp, &asteroid_objp->pos, blast, 0);
} // end for
}
@@ -1685,7 +1613,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
* @param hitpos world position asteroid was hit, can be NULL if hit by area effect
* @param damage amount of damage to apply to asteroid
*/
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force )
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage )
{
float explosion_life;
asteroid *asp;
@@ -1697,13 +1625,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
}
if ( MULTIPLAYER_MASTER ){
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage, force );
}
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_asteroids]) {
vec3d rel_hit_pos = *hitpos - pasteroid_obj->pos;
physics_calculate_and_apply_whack(force, &rel_hit_pos, &pasteroid_obj->phys_info, &pasteroid_obj->orient, &pasteroid_obj->phys_info.I_body_inv);
pasteroid_obj->phys_info.desired_vel = pasteroid_obj->phys_info.vel;
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage );
}
pasteroid_obj->hull_strength -= damage;
@@ -1963,6 +1885,7 @@ static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_i
static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
{
mc_info mc;
mc_info_init(&mc);
asteroid_test_collide(pasteroid_obj, escort_objp, &mc);
@@ -2092,6 +2015,7 @@ float asteroid_time_to_impact(object *asteroid_objp)
float time=-1.0f, total_dist, speed;
asteroid *asp;
mc_info mc;
mc_info_init(&mc);
asp = &Asteroids[asteroid_objp->instance];
@@ -2113,6 +2037,17 @@ float asteroid_time_to_impact(object *asteroid_objp)
return time;
}
int get_asteroid_position(const char* name)
{
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
if (!stricmp(name, Asteroid_info[i].name)) {
return i;
}
}
return -1;
}
static SCP_string setup_display_name(SCP_string name)
{
@@ -2183,7 +2118,7 @@ static void asteroid_parse_section()
asteroid_t.name);
}
} else {
// Don't create asteroid if it has +nocreate and is in a modular table.
// Don't create poof if it has +nocreate and is in a modular table.
if (!create_if_not_found && Parsing_modular_table) {
if (!skip_to_start_of_string_either("$Name:", "#end")) {
error_display(1, "Missing [#end] or [$Name] after asteroid %s", asteroid_t.name);
@@ -2239,10 +2174,6 @@ static void asteroid_parse_section()
stuff_float(&asteroid_p->max_speed);
}
if (optional_string("$Rotational Velocity Multiplier:")) {
stuff_float(&asteroid_p->rotational_vel_multiplier);
}
if(optional_string("$Damage Type:")) {
char buf[NAME_LENGTH];
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -2418,7 +2349,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)
static int get_asteroid_index(const char* asteroid_name)
{
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
if (!stricmp(asteroid_name, Asteroid_info[i].name)) {
@@ -2530,10 +2461,6 @@ void asteroid_init()
// parse any modular tables
parse_modular_table("*-ast.tbm", asteroid_parse_tbl);
//No asteroids defined. Bail!
if (asteroid_list.empty())
return;
// now verify the asteroids were found and put them in the correct order
verify_asteroid_list();
@@ -2585,11 +2512,6 @@ void asteroid_frame()
return;
}
// If no asteroid types are defined for the field, abort.
if (Asteroid_field.num_used_field_debris_types <= 0) {
return;
}
// If there are no explicit targets, fall back to default retail targeting behavior
if (Asteroid_field.target_names.empty()) {
int objnum = set_asteroid_throw_objnum();
@@ -2694,9 +2616,6 @@ void asteroid_target_closest_danger()
void asteroid_page_in()
{
if (Asteroid_info.empty())
return;
if (Asteroid_field.num_initial_asteroids > 0 ) {
int i, j, k;
+4 -11
View File
@@ -63,7 +63,6 @@ public:
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
int damage_type_idx; //Damage type of the asteroid
int damage_type_idx_sav; // stored value from table used to reset damage_type_idx
float inner_rad; // radius within which maximum area effect damage is applied
@@ -81,8 +80,7 @@ public:
float gravity_const; // multiplier for mission gravity
asteroid_info( )
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
rotational_vel_multiplier(1), damage_type_idx(0),
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0), damage_type_idx(0),
damage_type_idx_sav( -1 ), inner_rad( 0 ), outer_rad( 0 ),
damage( 0 ), blast( 0 ), initial_asteroid_strength( 0 ),
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
@@ -145,7 +143,6 @@ typedef struct asteroid_field {
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
int num_used_field_debris_types; // how many of the above are used
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
} asteroid_field;
@@ -161,28 +158,24 @@ extern vec3d Asteroid_icon_closeup_position; // closeup position for asteroid f
extern float Asteroid_icon_closeup_zoom; // zoom position for asteroid field briefing icon rendering
void asteroid_init();
bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = false);
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, 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_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max);
void asteroid_render(object* obj, model_draw_list* scene);
void asteroid_delete( object *asteroid_objp );
void asteroid_process_pre( object *asteroid_objp );
void asteroid_process_post( object *asteroid_objp);
int asteroid_check_collision( object *asteroid_objp, object * other_obj, vec3d * hitpos, collision_info_struct *asteroid_hit_info=NULL, vec3d* hitnormal=NULL );
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage, vec3d* force );
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage );
int asteroid_count();
int asteroid_collide_objnum(object *asteroid_objp);
float asteroid_time_to_impact(object *asteroid_objp);
void asteroid_show_brackets();
void asteroid_target_closest_danger();
void asteroid_add_target(object* objp);
int get_asteroid_index(const char* asteroid_name);
// need to extern for keycontrol debug commands
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
int get_asteroid_position(const char* name);
// need to extern for multiplayer
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
+25 -39
View File
@@ -869,7 +869,7 @@ void EndAutoPilot()
Assert( CurrentNav >= 0 );
int goal = 0;
const char *goal_name = NULL;
char *goal_name = NULL;
if (Navs[CurrentNav].flags & NP_WAYPOINT)
{
@@ -1011,7 +1011,7 @@ void nav_warp(bool prewarp=false)
vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap);
// Find all ships that are supposed to autopilot with the player and move them
// to the cinematic location or the final destination
// to the cinimatic location or the final destination
for (int i = 0; i < MAX_SHIPS; i++)
{
if (Ships[i].objnum != -1
@@ -1020,12 +1020,11 @@ void nav_warp(bool prewarp=false)
{
vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
Objects[Ships[i].objnum].phys_info.vel = velocity;
// retime collision pairs
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
}
}
// retime all collision pairs
obj_collide_retime_cached_pairs();
}
// ********************************************************************************************
@@ -1184,10 +1183,6 @@ void send_autopilot_msgID(int msgid)
if (msgid < 0 || msgid >= NP_NUM_MESSAGES)
return;
// bail out if message is not set
if (NavMsgs[msgid].message[0] == '\0')
return;
send_autopilot_msg(NavMsgs[msgid].message, NavMsgs[msgid].filename);
}
// ********************************************************************************************
@@ -1227,15 +1222,6 @@ void NavSystem_Init()
for (int i = 0; i < MAX_NAVPOINTS; i++)
Navs[i].clear();
//Initialize all these as empty strings so we can detect and bail out later -Mjn
for (int i = 0; i < NP_NUM_MESSAGES; i++)
NavMsgs[i].message[0] = '\0';
//Set defaults here before parsing
NavLinkDistance = 1000;
AutopilotMinEnemyDistance = 5000;
AutopilotMinAsteroidDistance = 1000;
LockWeaponsDuringAutopilot = false;
AutoPilotEngaged = false;
CurrentNav = -1;
audio_handle = -1;
@@ -1243,9 +1229,10 @@ void NavSystem_Init()
UseCutsceneBars = true;
// defaults... can be tabled or bound to mission later
parse_autopilot_table("autopilot.tbl");
parse_modular_table("*-aplt.tbm", parse_autopilot_table);
if (cf_exists_full("autopilot.tbl", CF_TYPE_TABLES))
parse_autopilot_table("autopilot.tbl");
else
parse_autopilot_table(NULL);
}
// ********************************************************************************************
@@ -1256,16 +1243,10 @@ void parse_autopilot_table(const char *filename)
try
{
if (!Parsing_modular_table) {
// if table doesn't exist, use the default table
if (cf_exists_full(filename, CF_TYPE_TABLES))
read_file_text(filename, CF_TYPE_TABLES);
else
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
} else {
if (filename == NULL)
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
}
reset_parse();
@@ -1273,17 +1254,23 @@ void parse_autopilot_table(const char *filename)
required_string("#Autopilot");
// autopilot link distance
if (optional_string("$Link Distance:"))
stuff_int(&NavLinkDistance);
required_string("$Link Distance:");
stuff_int(&NavLinkDistance);
if (optional_string("$Interrupt autopilot if enemy within distance:"))
stuff_int(&AutopilotMinEnemyDistance);
else
AutopilotMinEnemyDistance = 5000;
if (optional_string("$Interrupt autopilot if asteroid within distance:"))
stuff_int(&AutopilotMinAsteroidDistance);
else
AutopilotMinAsteroidDistance = 1000;
if (optional_string("$Lock Weapons During Autopilot:"))
stuff_boolean(&LockWeaponsDuringAutopilot);
else
LockWeaponsDuringAutopilot = false;
// optional no cutscene bars
if (optional_string("+No_Cutscene_Bars"))
@@ -1298,14 +1285,13 @@ void parse_autopilot_table(const char *filename)
"$Support Present:", "$Support Working:" };
for (int i = 0; i < NP_NUM_MESSAGES; i++)
{
if (optional_string(msg_tags[i])) {
required_string(msg_tags[i]);
required_string("+Msg:");
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
required_string("+Msg:");
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
required_string("+Snd File:");
stuff_string(NavMsgs[i].filename, F_NAME, 256);
}
required_string("+Snd File:");
stuff_string(NavMsgs[i].filename, F_NAME, 256);
}
+1 -1
View File
@@ -100,7 +100,7 @@ void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort fla
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true );
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
const size_t BM_BLOCK_SIZE = 4096;
+10 -101
View File
@@ -425,7 +425,6 @@ DCF(bm_used, "Shows BmpMan Slot Usage") {
SCP_stringstream text;
text << "BmpMan Used Slots\n";
text << " " << std::dec << std::setw(4) << std::setfill('0') << none << ", NONE\n";
text << " " << std::dec << std::setw(4) << std::setfill('0') << pcx << ", PCX\n";
text << " " << std::dec << std::setw(4) << std::setfill('0') << user << ", User\n";
text << " " << std::dec << std::setw(4) << std::setfill('0') << tga << ", TGA\n";
@@ -586,59 +585,6 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
return n;
}
int bm_create_3d(int bpp, int w, int h, int d, void* data) {
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int n = find_block_of(1);
// Out of bitmap slots
if (n == -1)
return -1;
// make sure that we have valid data
if (data == nullptr) {
UNREACHABLE("No valid data received for 3D Bitmap creation!");
return -1;
}
auto entry = bm_get_entry(n);
memset(entry, 0, sizeof(bitmap_entry));
sprintf_safe(entry->filename, "TMP%dx%dx%d+%d", w, h, d, bpp);
entry->type = BM_TYPE_3D;
entry->comp_type = BM_TYPE_NONE;
entry->bm.w = (short)w;
entry->bm.h = (short)h;
entry->bm.d = (short)d;
entry->bm.rowsize = (short)w;
entry->bm.bpp = (ubyte)bpp;
entry->bm.true_bpp = (ubyte)bpp;
entry->bm.flags = (ubyte)BMP_TEX_XPARENT;
entry->bm.data = 0;
entry->bm.palette = nullptr;
entry->info.user.bpp = (ubyte)bpp;
entry->info.user.data = data;
entry->info.user.flags = (ubyte)BMP_TEX_XPARENT;
entry->signature = Bm_next_signature++;
entry->handle = n;
entry->mem_taken = (w * h * d * (bpp >> 3));
entry->load_count++;
bm_update_memory_used(n, (int)entry->mem_taken);
gr_bm_create(bm_get_slot(n));
return n;
}
void bm_convert_format(bitmap *bmp, ushort flags) {
int idx;
@@ -682,7 +628,7 @@ void bm_free_data(bitmap_slot* bs, bool release)
// Don't free up memory for user defined bitmaps, since
// BmpMan isn't the one in charge of allocating/deallocing them.
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
if (be->type==BM_TYPE_USER) {
#ifdef BMPMAN_NDEBUG
if ( be->data_size != 0 )
bm_texture_ram -= be->data_size;
@@ -738,7 +684,7 @@ void bm_free_data_fast(int handle)
// Don't free up memory for user defined bitmaps, since
// BmpMan isn't the one in charge of allocating/deallocing them.
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
if (be->type == BM_TYPE_USER) {
#ifdef BMPMAN_NDEBUG
if ( be->data_size != 0 )
bm_texture_ram -= be->data_size;
@@ -946,27 +892,6 @@ int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *f
}
}
int bm_get_depth(int handle, int* depth) {
bitmap* bmp;
if (!bm_inited) return -1;
auto entry = bm_get_entry(handle);
Assertion(entry->handle == handle, "Invalid bitmap handle %d passed to bm_get_info().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
if (entry->type != BM_TYPE_3D) {
*depth = 0;
return -1;
}
bmp = &(entry->bm);
*depth = bmp->d;
return handle;
}
int bm_get_num_mipmaps(int num) {
auto entry = bm_get_entry(num);
@@ -1482,10 +1407,6 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
bm_lock_user(handle, bs, bmp, true_bpp, flags);
break;
case BM_TYPE_3D:
bm_lock_user(handle, bs, bmp, true_bpp, flags, false);
break;
default:
Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
return -1;
@@ -1596,13 +1517,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
// MAX_FILENAME_LEN-10 == 5 character frame designator plus '.' plus 3 letter ext plus NULL terminator
// we only check for -5 here since the filename should already have the extension on it, and it must have passed the previous check
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
// Don't check PNGs yet, because a PNG could be a regular non-animated image
if (type != BM_TYPE_PNG) {
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
if (img_cfp != nullptr)
cfclose(img_cfp);
return -1;
}
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
if (img_cfp != nullptr)
cfclose(img_cfp);
return -1;
}
// it's an effect file, any readable image type with eff being txt
@@ -1686,14 +1604,6 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
return -1;
}
}
// Now do the same filename length check that was deferred for PNGs above
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
if (img_cfp != nullptr)
cfclose(img_cfp);
return -1;
}
}
else {
Warning(LOCATION, "Unsupported image type: %i", type);
@@ -2478,7 +2388,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags
bm_convert_format(bmp, flags);
}
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) {
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
auto be = &bs->entry;
// Unload any existing data
@@ -2518,8 +2428,7 @@ void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort
break;
}
if (convert)
bm_convert_format(bmp, flags);
bm_convert_format(bmp, flags);
}
int bm_make_render_target(int width, int height, int flags) {
@@ -2603,7 +2512,7 @@ void *bm_malloc(int n, size_t size) {
void bm_page_in_aabitmap(int handle, int nframes) {
int i;
if (handle < 0)
if (handle == -1)
return;
Assert(bm_get_entry(handle)->handle == handle);
@@ -3222,7 +3131,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
return -1; // Already been released
}
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
if (be->type == BM_TYPE_USER) {
return -1;
}
+1 -27
View File
@@ -79,9 +79,7 @@ enum BM_TYPE
BM_TYPE_CUBEMAP_DDS, //!< generic DDS cubemap (uncompressed cubemap surface)
BM_TYPE_CUBEMAP_DXT1, //!< 24-bit cubemap (compressed cubemap surface)
BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface)
BM_TYPE_3D //!< 3D in-memory
BM_TYPE_CUBEMAP_DXT5 //!< 32-bit cubemap (compressed cubemap surface)
};
/**
@@ -92,7 +90,6 @@ struct bitmap
{
short w; //!< Width, in number of pixels
short h; //!< Height, in number of pixels
short d; //!< Depth, in number of pixels
short rowsize; //!< What you need to add to go to next row
int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
int true_bpp; //!< The image's actual bitdepth
@@ -220,19 +217,6 @@ int bm_load_duplicate(const char *filename);
*/
int bm_create(int bpp, int w, int h, void *data = NULL, int flags = 0);
/**
* Loads a 3D bitmap which exists somewhere in the RAM.
*
* @param bpp The bitdepth of the bitmap
* @param w The width of the bitmap
* @param h The height of the bitmap
* @param d The depth of the bitmap
* @param[in] data The bitmap's data glob
*
* @note The used RAM cannot be freed until bm_release is called on the created bitmap
*/
int bm_create_3d(int bpp, int w, int h, int d, void* data = nullptr);
/**
* @brief Unloads a bitmap's data, but not the bitmap info
*
@@ -389,16 +373,6 @@ int bm_is_valid(int handle);
*/
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
/**
* @brief Gets 3D info on the bitmap indexed by handle.
*
* @param[out] depth If non-null, gets the depth
*
* @returns The handle on success
* @returns -1 on failure
*/
int bm_get_depth(int handle, int* depth);
/**
* @brief Gets the filename of the bitmap indexed by handle
*
+34 -106
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;
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
float COCKPIT_ZOOM_DEFAULT = 0.75f;
float Sexp_fov = 0.0f;
warp_camera Warp_camera;
@@ -27,36 +27,6 @@ SCP_vector<camera*> Cameras;
camid Current_camera;
camid Main_camera;
asymmetric_fov operator* (const asymmetric_fov& left, const float& right) {
return asymmetric_fov{ left.left * right, left.right * right, left.up * right, left.down * right };
}
asymmetric_fov operator+ (const asymmetric_fov& left, const float& right) {
float ar = (left.up - left.down) / (left.right - left.left);
return asymmetric_fov{ left.left - right * 0.5f, left.right + right * 0.5f, left.up + right * 0.5f * ar, left.down - right * 0.5f * ar };
}
asymmetric_fov operator- (const asymmetric_fov& left, const float& right) {
float ar = (left.up - left.down) / (left.right - left.left);
return asymmetric_fov{ left.left + right * 0.5f, left.right - right * 0.5f, left.up - right * 0.5f * ar, left.down + right * 0.5f * ar };
}
#define APPLY_TO_FOV_T(op, name) \
struct apply_##name##_to_fov { \
float r; \
template<typename T> \
fov_t operator()(const T& l) { \
return fov_t(l op r); \
} \
}; \
fov_t operator op (const fov_t& zoom, const float& scale) { \
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 constexpr float fov_default = DEFAULT_FOV;
static SCP_string fov_display(float val)
{
auto degrees = fl_degrees(val);
@@ -64,57 +34,15 @@ static SCP_string fov_display(float val)
sprintf(out, u8"%.1f\u00B0", degrees);
return out;
}
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))
.range(0.436332f, 1.5708f)
.change_listener([](const float& val, bool) {
VIEWER_ZOOM_DEFAULT = val;
return true;
})
.display(fov_display)
.default_val(fov_default)
.level(options::ExpertLevel::Advanced)
.importance(60)
.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();
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
.category("Graphics")
.range(0.436332f, 1.5708f)
.bind_to(&VIEWER_ZOOM_DEFAULT)
.display(fov_display)
.default_val(0.75f)
.level(options::ExpertLevel::Advanced)
.importance(60)
.finish();
//*************************CLASS: camera*************************
//This is where the camera class begins! :D
@@ -157,7 +85,7 @@ void camera::reset()
func_custom_orientation = NULL;
fov.clear();
fov.set(g3_get_hfov(VIEWER_ZOOM_DEFAULT));
fov.set(VIEWER_ZOOM_DEFAULT);
pos_x.clear();
pos_y.clear();
@@ -176,7 +104,7 @@ void camera::set_name(const char *in_name)
strncpy(name, in_name, NAME_LENGTH-1);
}
void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
{
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
{
@@ -186,23 +114,26 @@ void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_
}
flags &= ~CAM_STATIONARY_FOV;
if(g3_get_hfov(in_fov) <= 0.0f)
if(in_fov <= 0.0f)
{
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
}
fov.setAVD(g3_get_hfov(in_fov), in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
}
void camera::set_object_host(object *objp, int n_object_host_submodel)
{
if(objp == NULL)
object_host = object_h();
object_host = object_h(objp);
object_host_submodel = n_object_host_submodel;
set_custom_position_function(NULL);
set_custom_orientation_function(NULL);
if(n_object_host_submodel > 0)
{
if(objp != nullptr && objp->type == OBJ_SHIP)
if(objp->type == OBJ_SHIP)
{
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
@@ -341,7 +272,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
// 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;
@@ -364,7 +295,7 @@ void camera::do_frame(float /*in_frametime*/)
object *camera::get_object_host()
{
if(object_host.isValid())
if(object_host.IsValid())
return object_host.objp;
else
return NULL;
@@ -377,7 +308,7 @@ int camera::get_object_host_submodel()
object *camera::get_object_target()
{
if(object_target.isValid())
if(object_target.IsValid())
return object_target.objp;
else
return NULL;
@@ -388,14 +319,11 @@ int camera::get_object_target_submodel()
return object_target_submodel;
}
fov_t camera::get_fov()
float camera::get_fov()
{
if(!(flags & CAM_STATIONARY_FOV))
{
float fov_now;
fov.get(&fov_now, nullptr);
return fov_now;
//TODO enable moving asymmetric fov
fov.get(&c_fov, NULL);
}
return c_fov;
@@ -413,7 +341,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;
@@ -422,7 +350,7 @@ 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;
int model_num = object_get_model(objp);
@@ -484,9 +412,9 @@ 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;
int model_num = object_get_model(target_objp);
@@ -521,7 +449,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
target_set = true;
}
else if(object_host.isValid())
else if(object_host.IsValid())
{
if(eyep)
{
@@ -794,7 +722,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], 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;
@@ -1051,7 +979,7 @@ int camid::getSignature()
return sig;
}
bool camid::isValid() const
bool camid::isValid()
{
if(idx >= Cameras.size())
return false;
@@ -1243,7 +1171,7 @@ 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);
@@ -1251,7 +1179,7 @@ void get_turret_cam_pos(camera *cam, vec3d *pos)
{
if(ssp->system_info->subobj_num == cam->get_object_host_submodel())
{
ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, true, &normal_cache, true, nullptr);
ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, &normal_cache, 1, NULL);
vec3d offset = vmd_zero_vector;
offset.xyz.x = 0.0001f;
vm_vec_add2(pos, &offset); // prevent beam turrets from crashing with a nullvec
@@ -1264,7 +1192,7 @@ 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(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec)?NULL:&cam->get_object_host()->orient.vec.uvec, NULL);
}
+5 -20
View File
@@ -10,8 +10,6 @@
#include <string>
#include <mpark/variant.hpp>
#define CAM_STATIONARY_FOV (1<<0)
#define CAM_STATIONARY_ORI (1<<1)
#define CAM_STATIONARY_POS (1<<2)
@@ -20,19 +18,6 @@
#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 = 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&);
class camera
{
protected:
@@ -56,7 +41,7 @@ protected:
avd_movement ori[9];
//Cache stuff
fov_t c_fov;
float c_fov;
vec3d c_pos;
matrix c_ori;
public:
@@ -74,7 +59,7 @@ public:
void set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *pos));
void set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *ori));
void set_fov(fov_t in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
@@ -89,7 +74,7 @@ public:
int get_object_host_submodel();
object *get_object_target();
int get_object_target_submodel();
fov_t get_fov();
float get_fov();
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
//Is
@@ -170,8 +155,8 @@ public:
//Some global stuff
extern SCP_vector<subtitle> Subtitles;
extern fov_t VIEWER_ZOOM_DEFAULT;
extern fov_t COCKPIT_ZOOM_DEFAULT;
extern float VIEWER_ZOOM_DEFAULT;
extern float COCKPIT_ZOOM_DEFAULT;
extern float Sexp_fov;
//Helpful functions
+17 -19
View File
@@ -91,10 +91,12 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
};
// clang-format on
#define CFILE_STACK_MAX 8
int cfile_inited = 0;
static int Cfile_stack_pos = 0;
static SCP_vector<SCP_string> Cfile_stack;
static char Cfile_stack[CFILE_STACK_MAX][CFILE_ROOT_DIRECTORY_LEN];
std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
@@ -328,16 +330,17 @@ int cfile_push_chdir(int type)
_getcwd(OriginalDirectory, CFILE_ROOT_DIRECTORY_LEN - 1);
cf_create_default_path_string(dir, type, NULL);
Assert(Cfile_stack_pos < CFILE_STACK_MAX);
int rc = _cfile_chdir(dir.c_str(), OriginalDirectory);
// if success then push the original directory on to the stack
if (rc == 0) {
Cfile_stack.push_back(OriginalDirectory);
if (Cfile_stack_pos >= CFILE_STACK_MAX) {
return -1;
}
return rc;
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
cf_create_default_path_string(dir, type, NULL);
return _cfile_chdir(dir.c_str(), OriginalDirectory);
}
/**
@@ -360,16 +363,13 @@ int cfile_chdir(const char *dir)
int cfile_pop_dir()
{
if (Cfile_stack.empty())
Assert(Cfile_stack_pos);
if ( !Cfile_stack_pos )
return -1;
int rc = cfile_chdir(Cfile_stack.back().c_str());
Assertion(rc == 0, "Failed to chdir() to previous directory (%s)!", Cfile_stack.back().c_str());
Cfile_stack.pop_back();
return rc;
Cfile_stack_pos--;
return cfile_chdir(Cfile_stack[Cfile_stack_pos]);
}
// flush (delete all files in) the passed directory (by type), return the # of files deleted
@@ -438,7 +438,7 @@ int cfile_flush_dir(int dir_type)
// filename = name of filename or filepath to process
// ext = extension to add. Must start with the period
// Returns: new filename or filepath with extension.
const char *cf_add_ext(const char *filename, const char *ext)
char *cf_add_ext(const char *filename, const char *ext)
{
static char path[MAX_PATH_LEN];
@@ -681,8 +681,6 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
} else {
// Path type given?
Assert( dir_type != CF_TYPE_ANY );
if (dir_type == CF_TYPE_ANY)
return NULL;
// Create the directory if necessary
cf_create_directory(dir_type, location_flags);
+1 -1
View File
@@ -171,7 +171,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
void cfile_close();
// add an extension to a filename if it doesn't already have it
const char *cf_add_ext(const char *filename, const char *ext);
char *cf_add_ext(const char *filename, const char *ext);
// return filename of a CFILE you called cfopen() successfully on.
const char *cf_get_filename(const CFILE *cfile);
+8 -43
View File
@@ -775,10 +775,9 @@ int is_ext_in_list( const char *ext_list, const char *ext )
// Run a basic test for indexed files that may be shadowed
#ifndef NDEBUG
#define ENABLE_SHADOW_CHECK 1
SCP_vector<SCP_string> critical_shadowed;
#endif
static void check_file_shadows(const int root_index __UNUSED, const int pathtype __UNUSED, const SCP_string &name __UNUSED, const SCP_string &sub_path __UNUSED, const char *real_name = nullptr)
static void check_file_shadows(const int root_index __UNUSED, const int pathtype __UNUSED, const SCP_string &name __UNUSED, const SCP_string sub_path __UNUSED)
{
#if ENABLE_SHADOW_CHECK
if ( !cf_should_scan_subdirs(pathtype) ) {
@@ -787,12 +786,11 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
SCP_string curfile, newfile;
const bool critical = ((pathtype == CF_TYPE_TABLES) || (pathtype == CF_TYPE_MISSIONS));
const auto root = cf_get_root(root_index);
newfile = root->path + ((root->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
newfile += cf_get_root_pathtype(root, pathtype) + DIR_SEPARATOR_CHAR;
newfile += sub_path + (real_name ? real_name : name);
newfile += sub_path + name;
for (uint i = 0; i < Num_files; ++i) {
const auto f = cf_get_file(i);
@@ -817,23 +815,14 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
continue;
}
if (r->roottype == CF_ROOTTYPE_PATH) {
curfile = f->real_name;
} else {
curfile = r->path + ((r->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
curfile += cf_get_root_pathtype(r, pathtype) + DIR_SEPARATOR_CHAR;
curfile += f->sub_path + f->name_ext;
}
curfile = r->path + ((r->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
curfile += cf_get_root_pathtype(r, pathtype) + DIR_SEPARATOR_CHAR;
curfile += f->sub_path + f->name_ext;
// this log message occurs in the middle of an existing line, hence the extra new lines
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
critical ? "critical " : "",
mprintf(("\nWARNING! A file being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
newfile.c_str(), curfile.c_str()));
if (critical) {
critical_shadowed.push_back(name);
}
break;
}
#endif
@@ -897,18 +886,12 @@ void cf_search_root_path(int root_index)
for (auto &file : files) {
auto ext_idx = file.name.rfind('.');
auto orig_name = file.name;
if ( ext_idx != SCP_string::npos && SCP_string_lcase_equal_to()(file.name.substr(ext_idx), SCP_string(".lz41")) ) {
file.name = file.name.erase(ext_idx, file.name.length());
ext_idx = file.name.rfind('.');
}
if ( ext_idx == SCP_string::npos || !is_ext_in_list(Pathtypes[i].extensions, file.name.substr(ext_idx+1).c_str()) ) {
continue;
}
check_file_shadows(root_index, i, file.name, file.sub_path, orig_name.c_str());
check_file_shadows(root_index, i, file.name, file.sub_path);
cf_file *cfile = cf_create_file();
@@ -918,7 +901,7 @@ void cf_search_root_path(int root_index)
cfile->write_time = file.m_time;
cfile->size = static_cast<int>(file.size);
cfile->pack_offset = 0;
cfile->real_name = search_path + DIR_SEPARATOR_STR + file.sub_path + orig_name;
cfile->real_name = search_path + DIR_SEPARATOR_STR + file.sub_path + file.name;
cfile->sub_path = file.sub_path;
++num_files;
@@ -1160,24 +1143,6 @@ void cf_build_file_list()
}
}
#ifndef NDEBUG
// if some special/critical files might be shadowed then make sure the user knows about it
if ( !critical_shadowed.empty() && !running_unittests ) {
SCP_string shadowed;
const auto count = critical_shadowed.size();
// only report a few of the files so that the warning dialog doesn't get freakishly large
for (size_t j = 0; (j < 5) && (j < count); ++j) {
shadowed += critical_shadowed[j] + '\n';
}
Warning(LOCATION, "Some critical files might be shadowed! Please check the debug log for details.\n\n"
SIZE_T_ARG " file(s) detected, including:\n%s", count, shadowed.c_str());
}
critical_shadowed.clear();
critical_shadowed.shrink_to_fit();
#endif
}
+4 -9
View File
@@ -16,11 +16,7 @@ bool CustomCheat::canUseCheat() {
void CustomCheat::runCheat() {
if (!canUseCheat()) return;
//Only try to send the message if we actually have one to send and are in a mission
if (!cheatMsg.empty() && (Game_mode & GM_IN_MISSION))
HUD_printf("%s", cheatMsg.c_str());
HUD_printf("%s", cheatMsg.c_str());
scripting::hooks::OnCheat->run(scripting::hook_param_list(scripting::hook_param("Cheat", 's', cheatCode)));
CheatUsed = cheatCode;
}
@@ -82,7 +78,7 @@ void SpawnShipCheat::runCheat() {
if (ptr->system_info->type == SUBSYSTEM_TURRET)
{
ptr->weapons.flags.set(Ship::Weapon_Flags::Beam_Free);
ptr->turret_next_fire_stamp = timestamp(Random::next(50, 4000));
ptr->turret_next_fire_stamp = timestamp((int)frand_range(50.0f, 4000.0f));
}
}
@@ -112,9 +108,8 @@ void parse_cheat_table(const char* filename) {
code = code.substr(0, CHEAT_BUFFER_LEN);
}
if (optional_string("+Message:")) {
stuff_string(msg, F_MESSAGE);
}
required_string("+Message:");
stuff_string(msg, F_MESSAGE);
if (optional_string("+RequireCheats:")) {
stuff_boolean(&requireCheats);
+77 -196
View File
@@ -15,7 +15,6 @@
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "globalincs/version.h"
#include "graphics/openxr.h"
#include "graphics/shadows.h"
#include "hud/hudconfig.h"
#include "io/joy.h"
@@ -40,7 +39,6 @@
#ifdef SCP_UNIX
#include "osapi/osapi.h"
#include <dirent.h>
#include <sys/stat.h>
#endif
#include <cstring>
@@ -190,7 +188,6 @@ Flag exe_params[] =
//flag launcher text FSO on_flags off_flags category reference URL
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
{ "-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",},
@@ -198,8 +195,6 @@ Flag exe_params[] =
{ "-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", },
//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", },
@@ -223,7 +218,6 @@ Flag exe_params[] =
//flag launcher text FSO on_flags off_flags category reference URL
{ "-no_set_gamma", "Disable setting of gamma", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_set_gamma", },
{ "-no_ingame_options", "Disable using ingame options", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ingame_options", },
{ "-nomovies", "Disable video playback", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomovies", },
{ "-noparseerrors", "Disable parsing errors", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noparseerrors", },
{ "-loadallweps", "Load all weapons, even those not used", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-loadallweps", },
@@ -241,7 +235,6 @@ Flag exe_params[] =
{ "-prefer_ipv4", "Prefer IPv4 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv4", },
{ "-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", },
#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
@@ -269,6 +262,7 @@ Flag exe_params[] =
{ "-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", },
{ "-reparse_mainhall", "Reparse mainhall.tbl when loading halls", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
@@ -279,7 +273,6 @@ Flag exe_params[] =
{ "-slow_frames_ok", "Don't adjust timestamps for slow frames", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-slow_frames_ok", },
{ "-imgui_debug", "Show imgui debug/demo window in the lab", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-imgui_debug", },
{ "-luadev", "Make lua errors non-fatal", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-luadev", },
{"-vulkan", "Use vulkan render backend", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vulkan", },
};
// clang-format on
@@ -336,6 +329,7 @@ int Cmdline_use_last_pilot = 0;
// Graphics related
cmdline_parm fov_arg("-fov", "Vertical field-of-view factor", AT_FLOAT); // Cmdline_fov -- comand line FOV -Bobboau
cmdline_parm fov_cockpit_arg("-fov_cockpit", "Vertical field-of-view factor for Cockpits", AT_FLOAT);
cmdline_parm clip_dist_arg("-clipdist", "Changes the distance from the viewpoint for the near-clipping plane", AT_FLOAT); // Cmdline_clip_dist
cmdline_parm ambient_power_arg("-ambient", "Multiplies the brightness of all ambient light", AT_FLOAT);
cmdline_parm light_power_arg("-light", "Multiplies the brightness of all light", AT_FLOAT);
cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all ambient light", AT_FLOAT);
@@ -357,7 +351,6 @@ cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
cmdline_parm deprecated_fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-2), requires post-processing and -fxaa", AT_INT);
cmdline_parm deprecated_smaa_arg("-smaa", nullptr, AT_NONE);
cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), requires post-processing and -smaa", AT_INT);
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);
@@ -367,6 +360,7 @@ cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline
cmdline_parm deferred_lighting_cockpit_arg("-deferred_cockpit", nullptr, AT_NONE);
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
float Cmdline_clip_dist = Default_min_draw_distance;
float Cmdline_ambient_power = 1.0f;
float Cmdline_emissive_power = 0.0f;
float Cmdline_light_power = 1.0f;
@@ -385,7 +379,6 @@ bool Cmdline_force_lightshaft_off = false;
int Cmdline_no_deferred_lighting = 0;
bool Cmdline_deferred_lighting_cockpit = false;
int Cmdline_aniso_level = 0;
int Cmdline_msaa_enabled = 0;
// Game Speed related
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
@@ -411,9 +404,7 @@ cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3
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
@@ -421,10 +412,8 @@ int Cmdline_ship_choice_3d = 0;
int Cmdline_weapon_choice_3d = 0;
int Cmdline_autopilot_interruptable = 1;
int Cmdline_stretch_menu = 0;
bool Cmdline_capture_mouse = false;
int Cmdline_no_screenshake = 0;
int Cmdline_deadzone = -1;
bool Cmdline_enable_vr = false;
// Audio related
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
@@ -453,16 +442,13 @@ char *Cmdline_gateway_ip = nullptr;
// Launcher related options
cmdline_parm portable_mode("-portable_mode", NULL, AT_NONE);
cmdline_parm joy_info("-joy_info", "Outputs SDL joystick info", AT_NONE);
cmdline_parm lang_arg("-language", "Language name as defined in strings.tbl", AT_STRING);
bool Cmdline_portable_mode = false;
SCP_string Cmdline_lang;
// Troubleshooting
cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE); // Cmdline_load_all_weapons
cmdline_parm nomovies_arg("-nomovies", NULL, AT_NONE); // Cmdline_nomovies -- Allows video streaming
cmdline_parm no_set_gamma_arg("-no_set_gamma", NULL, AT_NONE); // Cmdline_no_set_gamma
cmdline_parm no_ingame_options_arg("-no_ingame_options", NULL, AT_NONE); // Cmdline_no_ingame_options
cmdline_parm no_fbo_arg("-disable_fbo", NULL, AT_NONE); // Cmdline_no_fbo
cmdline_parm no_pbo_arg("-disable_pbo", NULL, AT_NONE); // Cmdline_no_pbo
cmdline_parm mipmap_arg("-mipmap", NULL, AT_NONE); // Cmdline_mipmap
@@ -478,7 +464,6 @@ cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
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);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -486,7 +471,6 @@ cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
int Cmdline_load_all_weapons = 0;
int Cmdline_nomovies = 0;
int Cmdline_no_set_gamma = 0;
bool Cmdline_no_ingame_options = false;
int Cmdline_no_fbo = 0;
int Cmdline_no_pbo = 0;
int Cmdline_ati_color_swap = 0;
@@ -501,7 +485,6 @@ bool Cmdline_noshadercache = false;
bool Cmdline_prefer_ipv4 = false;
bool Cmdline_prefer_ipv6 = false;
bool Cmdline_dump_packet_type = false;
bool Cmdline_no_bsp_align = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -521,9 +504,7 @@ cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
cmdline_parm window_arg("-window", NULL, AT_NONE); // Cmdline_window
cmdline_parm fullscreen_window_arg("-fullscreen_window", "Fullscreen/borderless window (Windows only)", AT_NONE);
cmdline_parm deprecated_res_arg("-res", "Deprecated, resolution, formatted like 1600x900", AT_STRING);
cmdline_parm render_res_arg("-render_res", "Resolution, formatted like 1600x900", AT_STRING);
cmdline_parm window_res_arg("-window_res", "Window resolution, formatted like 1600x900.", AT_STRING);
cmdline_parm res_arg("-res", "Resolution, formatted like 1600x900", AT_STRING);
cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, formatted like 1600x900", AT_STRING);
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
@@ -544,7 +525,6 @@ cmdline_parm fixed_seed_rand("-seed", nullptr, AT_INT); // Cmdline_rng_seed,Cmdl
cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmdline_lua_devmode
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
cmdline_parm vulkan("-vulkan", nullptr, AT_NONE);
char *Cmdline_start_mission = NULL;
int Cmdline_dis_collisions = 0;
@@ -561,7 +541,6 @@ int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
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;
@@ -581,7 +560,6 @@ bool Cmdline_slow_frames_ok = false;
bool Cmdline_lua_devmode = false;
bool Cmdline_override_data = false;
bool Cmdline_show_imgui_debug = false;
bool Cmdline_vulkan = false;
// Other
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
@@ -849,7 +827,7 @@ void os_validate_parms(int argc, char *argv[])
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
printf("Website: https://scp.indiegames.us\n");
printf("Website: http://scp.indiegames.us\n");
printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
printf("Usage: fs2_open [options]\n");
@@ -1209,133 +1187,93 @@ bool cmdline_parm::has_param() {
}
#ifdef SCP_UNIX
extern void normalize_directory_separators(SCP_string &str);
static SCP_string get_real_mod_path(const char *mod)
// Return a vector with all filesystem names of "parent/dir" relative to parent.
// dir must not contain a slash.
static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
{
DIR *dirp;
SCP_string fullpath;
SCP_string mod_path = mod;
SCP_vector<SCP_string> ret;
normalize_directory_separators(mod_path);
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
fullpath += mod_path;
// check if path already exists
dirp = opendir(fullpath.c_str());
if (dirp) {
// found it, return unchanged
closedir(dirp);
return mod_path;
DIR *dp;
if ((dp = opendir(parent.c_str())) == NULL) {
Warning(LOCATION, "Can't open directory '%s' when searching mod paths. Ignoring. errno=%d", parent.c_str(), errno);
return ret;
}
// not found, check for a difference in case
SCP_string new_mod_path;
SCP_string part;
struct dirent *dir;
SCP_string::size_type separator;
SCP_string::size_type offset = 0;
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
do {
separator = mod_path.find(DIR_SEPARATOR_CHAR, offset);
if (separator != SCP_string::npos) {
part = mod_path.substr(offset, separator-offset);
offset += separator-offset + 1;
} else {
part = mod_path.substr(offset);
offset += part.length();
dirent *dirp;
while ((dirp = readdir(dp)) != NULL) {
if (!stricmp(dirp->d_name, dir.c_str())) {
ret.push_back(dirp->d_name);
}
}
(void)closedir(dp);
dirp = opendir(fullpath.c_str());
return ret;
}
if ( !dirp ) {
break;
}
// Return a vector with all filesystem names of "parent/dir" relative to parent.
// Recurses to deal with slashes in dir.
static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
{
size_t slash = dir.find_first_of("/\\");
while ((dir = readdir(dirp)) != nullptr) {
if (stricmp(dir->d_name, part.c_str())) {
continue;
}
SCP_string fn = fullpath + dir->d_name;
// make sure it accessible and a directory
struct stat buf;
if (stat(fn.c_str(), &buf) == -1) {
continue;
}
if ( !S_ISDIR(buf.st_mode) ) {
continue;
}
if ( !new_mod_path.empty() ) {
new_mod_path += DIR_SEPARATOR_STR;
}
new_mod_path += dir->d_name;
fullpath += dir->d_name;
fullpath += DIR_SEPARATOR_STR;
break;
}
if (dirp) {
closedir(dirp);
}
} while (offset < mod_path.length());
// Append anything left from mod_path onto the new path. This will catch trailing separators
// as well as mod folders which don't exist so that the mod string remains unchanged except
// for the directory name case.
if (new_mod_path.length() != mod_path.length()) {
new_mod_path += mod_path.substr(new_mod_path.length());
// no subdirectories, no need to recurse
if (slash == std::string::npos) {
return unix_get_single_dir_names(parent, dir);
}
return new_mod_path;
// get the names of the first component of dir
SCP_vector<SCP_string> this_dir_names = unix_get_single_dir_names(parent, dir.substr(0, slash));
SCP_string rest = dir.substr(slash + 1);
SCP_vector<SCP_string> ret;
// search for the rest of dir in each of these
SCP_vector<SCP_string>::iterator ii, end = this_dir_names.end();
for (ii = this_dir_names.begin(); ii != end; ++ii) {
SCP_string this_dir_path = parent + "/" + *ii;
SCP_vector<SCP_string> mod_path = unix_get_dir_names(this_dir_path, rest);
// add all found paths relative to parent
SCP_vector<SCP_string>::iterator ii2, end2 = mod_path.end();
for (ii2 = mod_path.begin(); ii2 != end2; ++ii2) {
ret.push_back(*ii + "/" + *ii2);
}
}
return ret;
}
// For case sensitive filesystems (e.g. Linux/BSD) perform case-insensitive dir matches.
//
// NOTE: Aside from change in case no alterations should be made to the modlist. Missing
// mod folders should be left in place and no errors or warnings should be generated.
// There should be no difference between Windows and non-Windows modlist handling.
static void handle_unix_modlist(char **modlist, size_t *len)
{
// search filesystem for given paths
SCP_vector<SCP_string> mod_paths;
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ",")) {
SCP_string path = get_real_mod_path(cur_mod);
mod_paths.push_back(path);
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
{
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
// Ignore non-existing mods for unit tests
if (!running_unittests && this_mod_paths.empty()) {
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
}
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
}
// create new char[] to replace modlist
size_t total_len = 0;
for (auto &path : mod_paths) {
total_len += path.length() + 1;
SCP_vector<SCP_string>::iterator ii, end = mod_paths.end();
for (ii = mod_paths.begin(); ii != end; ++ii) {
total_len += ii->length() + 1;
}
char *new_modlist = new char[total_len + 1];
memset(new_modlist, 0, total_len + 1);
for (auto &path : mod_paths) {
strcat_s(new_modlist, total_len + 1, path.c_str());
strcat_s(new_modlist, total_len + 1, ",");
end = mod_paths.end();
for (ii = mod_paths.begin(); ii != end; ++ii) {
strcat_s(new_modlist, total_len + 1, ii->c_str());
strcat_s(new_modlist, total_len + 1, ","); // replace later with NUL
}
// remove trailing comma
new_modlist[total_len-1] = '\0';
// make the rest of the modlist manipulation unaware that anything happened here
delete [] *modlist;
*modlist = new_modlist;
@@ -1700,7 +1638,7 @@ bool SetCmdlineParams()
// be sure that this string fits in our limits
if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d characters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
}
}
@@ -1764,48 +1702,31 @@ bool SetCmdlineParams()
// d3d windowed
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");
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
Cmdline_window = 1;
}
if ( fullscreen_window_arg.found( ) )
{
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
Cmdline_fullscreen_window = 1;
Cmdline_window = 0; /* Make sure no-one sets both */
}
if(render_res_arg.found() || deprecated_res_arg.found()){
if (render_res_arg.found()) {
Cmdline_res = render_res_arg.str();
}
else {
Cmdline_res = deprecated_res_arg.str();
mprintf(("Deprecated -res argument. Use -render_res instead...\n"));
}
if(res_arg.found()){
Cmdline_res = res_arg.str();
/*int width = 0;
int width = 0;
int height = 0;
if (sscanf(Cmdline_res, "%dx%d", &width, &height) == 2) {
if ( sscanf(Cmdline_res, "%dx%d", &width, &height) == 2 ) {
SCP_string override;
sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
} else {
Warning(LOCATION, "Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res);
}*/
}
if(window_res_arg.found()){
int width = 0;
int height = 0;
if ( sscanf(window_res_arg.str(), "%dx%d", &width, &height) == 2 ) {
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
} else {
Warning(LOCATION, "Failed to parse -window_res parameter \"%s\". Must be in format \"<width>x<height>\".\n", window_res_arg.str());
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res));
}
}
if(center_res_arg.found()){
Cmdline_center_res = center_res_arg.str();
}
@@ -1840,7 +1761,7 @@ bool SetCmdlineParams()
if(mod_arg.found() ) {
Cmdline_mod = mod_arg.str();
// strip off blank space if it's there
// strip off blank space it it's there
if ( Cmdline_mod[strlen(Cmdline_mod)-1] == ' ' ) {
Cmdline_mod[strlen(Cmdline_mod)-1] = '\0';
}
@@ -1900,7 +1821,7 @@ bool SetCmdlineParams()
if (val > 0.1) {
VIEWER_ZOOM_DEFAULT = val;
} else {
VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
VIEWER_ZOOM_DEFAULT = 0.75f;
}
}
@@ -1914,12 +1835,8 @@ bool SetCmdlineParams()
}
}
if (vr.found()) {
Cmdline_enable_vr = true;
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...");
}
openxr_prepare();
if( clip_dist_arg.found() ) {
Min_draw_distance = Cmdline_clip_dist = clip_dist_arg.get_float();
}
if (orb_radar.found())
@@ -1950,10 +1867,6 @@ bool SetCmdlineParams()
if ( stretch_menu.found() ) {
Cmdline_stretch_menu = 1;
}
if ( capture_mouse.found() ) {
Cmdline_capture_mouse = true;
}
// new lighting lines
if ( ambient_power_arg.found() )
Cmdline_ambient_power = ambient_power_arg.get_float();
@@ -1977,10 +1890,6 @@ bool SetCmdlineParams()
Cmdline_no_set_gamma = 1;
}
if (no_ingame_options_arg.found()) {
Cmdline_no_ingame_options = true;
}
if(no_vsync_arg.found() )
{
Gr_enable_vsync = false;
@@ -2024,21 +1933,6 @@ bool SetCmdlineParams()
}
}
if (msaa_enabled_arg.found()) {
Cmdline_msaa_enabled = msaa_enabled_arg.get_int();
switch (Cmdline_msaa_enabled) {
case 0:
case 4:
case 8:
case 16:
break;
default:
Warning(LOCATION, "Requested illegal MSAA sample count %d. Allowed are: 0, 4, 8, 16. Setting to 0.", Cmdline_msaa_enabled);
Cmdline_msaa_enabled = 0;
break;
}
}
if ( glow_arg.found() )
Cmdline_glow = 0;
@@ -2106,15 +2000,6 @@ bool SetCmdlineParams()
{
Cmdline_portable_mode = true;
}
if (lang_arg.found())
{
Cmdline_lang = lang_arg.str();
}
if (no_bsp_align_arg.found()) {
Cmdline_no_bsp_align = true;
}
#ifdef WIN32
if (fix_registry.found()) {
@@ -2315,10 +2200,6 @@ bool SetCmdlineParams()
Cmdline_show_video_info = true;
}
if (vulkan.found()) {
Cmdline_vulkan = true;
}
//Deprecated flags - CommanderDJ
if (deprecated_no_emissive_arg.found()) {
Cmdline_emissive = 0;
+2 -9
View File
@@ -6,13 +6,12 @@
* source.
*
*/
*/
#ifndef FS_CMDLINE_HEADER_FILE
#define FS_CMDLINE_HEADER_FILE
#include <tl/optional.hpp>
int parse_cmdline(int argc, char *argv[]);
@@ -47,13 +46,13 @@ extern int Cmdline_use_last_pilot;
extern int Cmdline_window;
extern int Cmdline_fullscreen_window;
extern char *Cmdline_res;
extern tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
extern char *Cmdline_center_res;
// FSO OPTIONS -------------------------------------------------
// Graphics related
extern float Cmdline_clip_dist;
extern float Cmdline_ambient_power;
extern float Cmdline_emissive_power;
extern float Cmdline_light_power;
@@ -71,7 +70,6 @@ extern int Cmdline_no_deferred_lighting;
extern bool Cmdline_deferred_lighting_cockpit;
extern int Cmdline_emissive;
extern int Cmdline_aniso_level;
extern int Cmdline_msaa_enabled;
// Game Speed related
extern int Cmdline_NoFPSCap;
@@ -88,10 +86,8 @@ extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_autopilot_interruptable;
extern int Cmdline_stretch_menu;
extern bool Cmdline_capture_mouse;
extern int Cmdline_no_screenshake;
extern int Cmdline_deadzone;
extern bool Cmdline_enable_vr;
// Audio related
extern int Cmdline_voice_recognition;
@@ -108,13 +104,11 @@ extern char *Cmdline_gateway_ip;
// Launcher related options
extern bool Cmdline_portable_mode;
extern SCP_string Cmdline_lang;
// Troubleshooting
extern int Cmdline_load_all_weapons;
extern int Cmdline_nomovies; // WMC Toggles movie playing support
extern int Cmdline_no_set_gamma;
extern bool Cmdline_no_ingame_options;
extern int Cmdline_no_fbo;
extern int Cmdline_no_pbo;
extern int Cmdline_mipmap;
@@ -162,7 +156,6 @@ extern bool Cmdline_slow_frames_ok;
extern bool Cmdline_lua_devmode;
extern bool Cmdline_override_data;
extern bool Cmdline_show_imgui_debug;
extern bool Cmdline_vulkan;
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
extern WeaponSpewType Cmdline_spew_weapon_stats;
-8
View File
@@ -51,14 +51,6 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
objp->phys_info.max_vel.xyz.z = -25.0f;
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
weapon* wp = &Weapons[objp->instance];
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
wp->trail_ptr->vel[0] = objp->phys_info.vel;
wp->trail_ptr->vel[1] = objp->phys_info.vel;
}
}
/**
File diff suppressed because it is too large. Load diff
+4 -121
View File
@@ -433,26 +433,6 @@ private:
short btn = -1; //!< The button, key combo, or axis that's bound.
};
/**
* @struct cc_line
* @brief Defines an interactable line to display control names and their bindings
*/
struct cc_line {
const char* label;
int cc_index; // index into Control_config of item
int y; // Y coordinate of line
int kx, kw, jx, jw; // x start and width of keyboard and joystick bound text
};
/**
* @struct conflict
* @brief Defines an conflict between bindings
*/
struct conflict {
int first = -1; // index of other control in conflict with this one
int second = -1; // index of other control in conflict with this one
};
/*!
* A pair of bindings.
* @note Please don't set the bindings directly, use ::take() instead.
@@ -661,15 +641,6 @@ private:
SCP_vector<CCI>& ControlConfig;
};
enum class selItem : int {
selItem_REND, // Must be first to allow cycling
None,
Primary,
Secondary,
selItem_END // Must be last to allow cycling
};
extern int Failed_key_index;
@@ -678,9 +649,6 @@ extern int Joy_sensitivity;
extern int Control_config_overlay_id;
extern SCP_vector<cc_line> Cc_lines; //!< Stores the keyboard details for the UI
extern SCP_vector<conflict> Conflicts; //!< Stores conflict data for the keybinds
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.
@@ -721,7 +689,7 @@ void control_config_common_close();
/*!
* @brief init config menu
*/
void control_config_init(bool API_Access = false);
void control_config_init();
/*!
* @brief do a frame of the config menu
@@ -731,73 +699,12 @@ void control_config_do_frame(float frametime);
/*!
* @brief close config menu
*/
void control_config_close(bool API_Access = false);
/*!
* @brief setup for binding a control
*/
void control_config_do_bind(bool API_Access = false);
/*!
* @brief setup for searching a control
*/
void control_config_do_search(bool API_Access = false);
/**
* @brief Unbinds the selected control
*/
bool control_config_remove_binding(int ctrl, selItem item, bool API_Access = false);
/**
* @brief Clears all conflicting control bindings, except the selected control
*/
bool control_config_clear_other(int ctrl, bool API_Access = false);
/**
* @brief Unbinds ALL controls
* TODO: unbind axes and reset inversion
*/
bool control_config_clear_all(bool API_Access = false);
/**
* @brief Reverts all bindings to their preset. If already default, cycle to the next presets.
*/
bool control_config_do_reset(bool cycle = true, bool API_Access = false);
/**
* @brief Toggles a modifier on or off for a control binding
*/
bool control_config_toggle_modifier(int bit, int ctrl, bool API_Access = false);
/**
* @brief Toggles inversion for the selected axis control
*/
bool control_config_toggle_invert(int ctrl, selItem item, bool API_Access = false);
/*!
* @brief Performs a single undo opration, reverting the most recent change to bindings, if any
*/
void control_config_do_undo(bool API_Access = false);
/*!
*@brief Runs every frame to check for input and binds the input if appropriate
*/
int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access = false);
/*!
*@brief Runs every frame to check for input. Returns the index of the item the key is bound to or -1 if nothing.
*/
int control_config_search_key_on_frame(bool API_Access = false);
/*!
* Does a cursory conflict check, then accepts changes to the bindings, if any, and request the menu to close.
*/
bool control_config_accept(bool API_Access = false);
void control_config_close();
/*!
* @brief Cancel configuration of controls, revert any changes, return to previous menu/game state
*/
void control_config_cancel_exit(bool API_Access = false);
void control_config_cancel_exit();
/*!
* @brief Copies all bindings within preset into Control_config
@@ -828,30 +735,6 @@ bool control_config_use_preset_by_name(const SCP_string &name);
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic = false);
/*!
* @brief Deletes the preset
*
* @returns TRUE if successful
* @returns FALSE if the preset is default or currently selected
*/
bool control_config_delete_preset(CC_preset preset);
/*!
* @brief Clones a preset
*
* @returns TRUE if successful
* @returns FALSE if the preset already exists with that name
*/
bool control_config_clone_preset(CC_preset preset, SCP_string name);
/*!
* @brief Saves a preset with the current controls
*
* @returns TRUE if successful
* @returns FALSE if the preset already exists with that name
*/
bool control_config_create_new_preset(SCP_string name);
/*!
* Returns the IoActionId (index within Control_config[]) of a control bound to the given key
*
@@ -947,7 +830,7 @@ int check_control(int id, int key = -1);
void control_get_axes_readings(int *axis_v, float frame_time);
/**
* @brief Marks the given control (by IoActionId) as used
* @brief Markes the given control (by IoActionId) as used
*
* @details Updates the ::used timestamp, triggers a script hook, and marks ::continous_ongoing as true
*/
+36 -44
View File
@@ -45,31 +45,27 @@ int Failed_key_index;
// Joystick configuration
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))
.range(0, 45)
.level(options::ExpertLevel::Beginner)
.default_val(10)
.bind_to(&Joy_dead_zone_size)
.importance(1)
.flags({options::OptionFlags::RetailBuiltinOption})
.finish();
auto DeadZoneOption =
options::OptionBuilder<int>("Input.JoystickDeadZone", "Deadzone", "The deadzone of the selected joystick.")
.category("Input")
.range(0, 45)
.level(options::ExpertLevel::Beginner)
.default_val(10)
.bind_to(&Joy_dead_zone_size)
.importance(1)
.finish();
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))
.range(0, 9)
.level(options::ExpertLevel::Beginner)
.default_val(9)
.bind_to(&Joy_sensitivity)
.importance(2)
.flags({options::OptionFlags::RetailBuiltinOption})
.finish();
auto SensitivityOption =
options::OptionBuilder<int>("Input.JoystickSensitivity", "Sensitivity", "The sentitivity of the selected joystick.")
.category("Input")
.range(0, 9)
.level(options::ExpertLevel::Beginner)
.default_val(9)
.bind_to(&Joy_sensitivity)
.importance(2)
.finish();
//! arrays which hold the key mappings. The array index represents a key-independent action.
//! please use SPACES for aligning the fields of this array
@@ -162,8 +158,8 @@ void control_config_common_init_bindings() {
// flight controls (flight modes)
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 0, "Glide When Pressed", CC_TYPE_CONTINUOUS)
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 0, "Toggle Gliding", CC_TYPE_TRIGGER)
// flight controls (axes)
(JOY_HEADING_AXIS, JOY_X_AXIS, MOUSE_X_AXIS, SHIP_TAB, 1016, "Turn (Yaw) Axis", CC_TYPE_AXIS_REL)
@@ -177,7 +173,7 @@ void control_config_common_init_bindings() {
(FIRE_SECONDARY, KEY_SPACEBAR, 1, WEAPON_TAB, 1, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS)
(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_SEQUENCE, KEY_O, -1, WEAPON_TAB, 0, "Cycle Primary Weapon Firing Rate", 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)
@@ -213,8 +209,8 @@ void control_config_common_init_bindings() {
(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)
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 0, "Top-Down View", CC_TYPE_TRIGGER)
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 0, "Target Padlock View", CC_TYPE_TRIGGER)
(RADAR_RANGE_CYCLE, KEY_RAPOSTRO, -1, COMPUTER_TAB, 1, "Cycle Radar Range", CC_TYPE_TRIGGER)
(SQUADMSG_MENU, KEY_C, -1, COMPUTER_TAB, 1, "Communications Menu", CC_TYPE_TRIGGER)
@@ -239,8 +235,8 @@ void control_config_common_init_bindings() {
// Navigation and Autopilot
(SHOW_NAVMAP, -1, -1, NO_TAB, 1, "Show Nav Map", CC_TYPE_TRIGGER, true)
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 1779, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 1780, "Cycle Nav Points", CC_TYPE_TRIGGER)
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 0, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 0, "Cycle Nav Points", CC_TYPE_TRIGGER)
// Escort
(ADD_REMOVE_ESCORT, KEY_ALTED | KEY_E, -1, COMPUTER_TAB, 1, "Add or Remove Escort", CC_TYPE_TRIGGER)
@@ -262,15 +258,15 @@ void control_config_common_init_bindings() {
// HUD
(TOGGLE_HUD, KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, 1, "Toggle HUD", CC_TYPE_TRIGGER)
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 0, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
// Custom Controls
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 1784, "Custom Control 1", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_2, KEY_ALTED | KEY_SHIFTED | KEY_2, -1, COMPUTER_TAB, 1785, "Custom Control 2", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 1786, "Custom Control 3", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 1787, "Custom Control 4", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 1788, "Custom Control 5", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 0, "Custom Control 1", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_2, KEY_ALTED | KEY_SHIFTED | KEY_2, -1, COMPUTER_TAB, 0, "Custom Control 2", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 0, "Custom Control 3", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 0, "Custom Control 4", CC_TYPE_TRIGGER, true)
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 0, "Custom Control 5", CC_TYPE_TRIGGER, true)
.end(); // Builder
// init default preset
@@ -453,7 +449,7 @@ const char* Joy_button_text_french_u[] = {
"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"
"Bouton 31", "Bouton 32", "Chapeau Arri\xc3\xa8""re", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
};
const char* Joy_button_text_polish_u[] = {
@@ -462,7 +458,7 @@ const char* Joy_button_text_polish_u[] = {
"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"
"Przyc.31", "Przyc.32", "Hat Ty\xc5\x82", "Hat Prz\xc3\xb3""d", "Hat Lewo", "Hat Prawo"
};
const char* Joy_button_text_english_u[] = {
@@ -647,9 +643,7 @@ const char *translate_key(char *key)
if (!first.empty() && !second.empty()) {
strcpy_s(text, first.textify().c_str());
strcat_s(text, " ");
strcat_s(text, XSTR("or", 1672));
strcat_s(text, " ");
strcat_s(text, " or ");
strcat_s(text, second.textify().c_str());
} else if (!first.empty()) {
@@ -659,7 +653,7 @@ const char *translate_key(char *key)
strcpy_s(text, second.textify().c_str());
} else {
strcpy_s(text, XSTR("None", 1673));
strcpy_s(text, "None");
}
return text;
@@ -670,7 +664,7 @@ const char *textify_scancode(int code)
static char text[BTN_MSG_LEN];
if (code < 0)
return XSTR("None", 1673);
return "None";
int keycode = code & KEY_MASK;
@@ -803,8 +797,6 @@ void control_config_common_init()
Mouse_button_text[6] = vm_strdup(XSTR("Wheel Down", 1656));
Mouse_button_text[7] = vm_strdup(XSTR("Wheel Left", 1657));
Mouse_button_text[8] = vm_strdup(XSTR("Wheel Right", 1658));
Script_system.OnStateDestroy.add([](lua_State*) -> void { Lua_hooks.clear(); });
}
/*
+2 -28
View File
@@ -35,7 +35,7 @@ Section lookupSectionValue(const char* name) {
return Section::Invalid;
}
void load_preset_files(SCP_string clone) {
void load_preset_files() {
SCP_vector<SCP_string> filelist;
cf_get_file_list(filelist, CF_TYPE_PLAYER_BINDS, NOX("*.json"), CF_SORT_NAME, nullptr,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
@@ -128,8 +128,7 @@ void load_preset_files(SCP_string clone) {
// Done with the file
auto it = preset_find_duplicate(preset);
// If we just cloned the file, then allow the duplicate. Just this once.
if ((clone == preset.name) || (it == Control_config_presets.end())) {
if (it == Control_config_presets.end()) {
Control_config_presets.push_back(preset);
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
@@ -148,31 +147,6 @@ bool preset_file_exists(SCP_string name) {
return cf_exists(name.c_str(), CF_TYPE_PLAYER_BINDS) != 0;
}
bool delete_preset_file(CC_preset preset) {
// can't remove the default preset!
if (preset.name == "default") {
return false;
}
auto it = control_config_get_current_preset();
// can't remove the currently loaded preset either!
if (preset.name == it->name) {
return false;
}
SCP_string filename = preset.name + ".json";
cf_delete(filename.c_str(), CF_TYPE_PLAYER_BINDS, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
// Reload the presets from file.
Control_config_presets.resize(1);
load_preset_files();
return true;
}
bool save_preset_file(CC_preset preset, bool overwrite) {
// Must have a name
if (preset.name.empty()) {
+1 -13
View File
@@ -209,24 +209,12 @@ private:
*/
bool save_preset_file(CC_preset preset, bool overwrite);
/**
* @brief Deletes the given preset to file.
* @param[in] preset The preset to delete
*
* @returns True if successful, or
* @returns False Preset is default, or
* @returns False Preset file is the currently selected preset
*/
bool delete_preset_file(CC_preset preset);
/**
* @brief Loads in all preset .json files from 'players/presets'
* @details If a preset file is unique, it is loaded into the game and available for use by the player. However, if
* a preset is a duplicate of another preset, it is ignored, and the player is warned of it
*
* @param[in] clone Used to check if we just cloned a particular preset and allows just that clone in without warning
*/
void load_preset_files(SCP_string clone = "");
void load_preset_files();
/**
* @brief Checks if the given preset is a duplicate within Control_config_presets vector
+1 -2
View File
@@ -52,7 +52,6 @@ struct MovieProperties {
FrameSize size;
float fps = -1.0f;
float duration = 0.0f;
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
};
@@ -109,7 +108,7 @@ class Decoder {
* @note A implementation should initialize the datastructures required for decoding here.
*
* @param fileName The name of the file that should be opened
* @return @c true if the initialization was successful, @c false otherwise
* @return @c true if the initialization was successfull, @c false otherwise
*/
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
+2 -17
View File
@@ -25,8 +25,6 @@
extern int Cmdline_nomovies;
bool Movie_active = false;
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage",
@@ -62,18 +60,6 @@ static cutscene_info *get_cutscene_pointer(char *cutscene_filename)
return NULL;
}
int get_cutscene_index_by_name(const char* name)
{
for (int i = 0; i < static_cast<int>(Cutscenes.size()); i++) {
if (!stricmp(name, Cutscenes[i].name)) {
return i;
}
}
// Didn't find anything.
return -1;
}
static void cutscene_info_init(cutscene_info *csni)
{
csni->filename[0] = '\0';
@@ -189,9 +175,6 @@ void parse_cutscene_table(const char* filename)
if (flag)
csnp->flags.set(Cutscene::Cutscene_Flags::Never_viewable);
}
if (optional_string("$Custom data:")) {
parse_string_map(csnp->custom_data, "$end_custom_data", "+Val:");
}
}
@@ -236,6 +219,7 @@ void cutscene_mark_viewable(const char* filename)
// change to lower case
strlwr(file);
int i = 0;
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
{
// change the cutscene file name to lower case
@@ -248,6 +232,7 @@ void cutscene_mark_viewable(const char* filename)
cut->flags.set(Cutscene::Cutscene_Flags::Viewable);
return;
}
i++;
}
Warning(LOCATION, "Could not find cutscene '%s' in listing; cannot mark it viewable...", filename);
-5
View File
@@ -32,13 +32,10 @@ typedef struct cutscene_info
char name[NAME_LENGTH];
char* description;
flagset<Cutscene::Cutscene_Flags> flags;
SCP_map<SCP_string, SCP_string> custom_data;
} cutscene_info;
extern SCP_vector<cutscene_info> Cutscenes;
extern bool Movie_active;
// initializa table data
void cutscene_init();
@@ -50,6 +47,4 @@ void cutscenes_screen_do_frame();
void cutscene_mark_viewable(const char* filename);
int get_cutscene_index_by_name(const char* name);
#endif
-1
View File
@@ -503,7 +503,6 @@ MovieProperties FFMPEGDecoder::getProperties() const
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
props.duration = static_cast<float>(m_status->videoStream->duration * av_q2d(m_status->videoStream->time_base));
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
+3 -11
View File
@@ -174,15 +174,10 @@ void determine_display_positions(Player* player, PlaybackState* state) {
void initialize_player_state(Player* player, PlaybackState* state) {
determine_display_positions(player, state);
if (!Movie_subtitle_font.empty()) {
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
}
else if (font::FontManager::numberOfFonts() > 0) {
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
}
@@ -278,7 +273,6 @@ bool play(const char* name) {
// clear the screen and hide the mouse cursor
io::mouse::CursorManager::get()->pushStatus();
io::mouse::CursorManager::get()->showCursor(false);
Movie_active = true;
gr_reset_clip();
gr_set_color(255, 255, 255);
gr_set_clear_color(0, 0, 0);
@@ -305,8 +299,6 @@ bool play(const char* name) {
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
}
Movie_active = false;
// show the mouse cursor again
io::mouse::CursorManager::get()->popStatus();
+30 -31
View File
@@ -251,10 +251,10 @@ void debris_process_post(object * obj, float frame_time)
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
vec3d v1 = submodel_get_random_point(db->model_num, db->submodel_num);
vec3d v2 = submodel_get_random_point(db->model_num, db->submodel_num);
vec3d v3 = submodel_get_random_point(db->model_num, db->submodel_num);
vec3d v4 = submodel_get_random_point(db->model_num, db->submodel_num);
vec3d v1, v2, v3, v4;
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v3, &v4);
n = 0;
@@ -327,7 +327,11 @@ void debris_process_post(object * obj, float frame_time)
// Maybe move a vertex.... 20% of the time maybe?
int mr = Random::next();
if ( mr < Random::MAX_VALUE/5 ) {
db->arc_pts[i][mr % 2] = submodel_get_random_point(db->model_num, db->submodel_num);
vec3d v1, v2;
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
db->arc_pts[i][mr % 2] = v1;
}
}
}
@@ -359,7 +363,7 @@ int debris_find_oldest()
}
#define DEBRIS_ROTVEL_SCALE 5.0f
void calc_debris_physics_properties( physics_info *pi, vec3d *min, vec3d *max, float density );
void calc_debris_physics_properties( physics_info *pi, vec3d *min, vec3d *max );
MONITOR(NumSmallDebris)
MONITOR(NumHullDebris)
@@ -374,9 +378,8 @@ MONITOR(NumHullDebris)
* @param exp_center Explosion center in global coordinates
* @param hull_flag Whether this debris is a chunk of a ship's hull (as opposed to shrapnel)
* @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, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, 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)
{
int parent_objnum;
object *obj;
@@ -394,7 +397,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
obj = debris_create_only(parent_objnum, shipp->ship_info_index, shipp->alt_type_index, shipp->team, -1.0f, -1, model_num, submodel_num, pos, nullptr, hull_flag, vaporize, shipp->debris_damage_type_idx);
if (obj != nullptr)
{
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force, source_subsys);
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force);
debris_create_fire_hook(obj, source_obj);
}
@@ -501,11 +504,11 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
}
else if (vaporize) {
db->model_num = Debris_vaporize_model;
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
db->submodel_num = Random::next(Debris_num_submodels);
}
else {
db->model_num = Debris_model;
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
db->submodel_num = Random::next(Debris_num_submodels);
}
}
else {
@@ -644,7 +647,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
if (spark_timeout >= 0) {
db->fire_timeout = _timestamp(spark_timeout);
} else if (parent_objnum >= 0) {
float t = 1000*Objects[parent_objnum].radius/3 + (fl2i(1000*3*Objects[parent_objnum].radius) == 0 ? 0 : Random::next(fl2i(1000*3*Objects[parent_objnum].radius)));
float t = 1000*Objects[parent_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[parent_objnum].radius));
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
} else {
db->fire_timeout = TIMESTAMP::immediate();
@@ -666,7 +669,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
return obj;
}
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys)
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force)
{
auto obj = &Objects[db->objnum];
auto source_obj = (source_shipp == nullptr) ? nullptr : &Objects[source_shipp->objnum];
@@ -687,8 +690,7 @@ void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_cente
vec3d *min, *max;
min = &pm->submodel[db->submodel_num].min;
max = &pm->submodel[db->submodel_num].max;
float density = source_subsys != nullptr ? source_subsys->system_info->density : Ship_info[source_shipp->ship_info_index].debris_density;
calc_debris_physics_properties( &obj->phys_info, min, max, density);
calc_debris_physics_properties( &obj->phys_info, min, max );
}
else {
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from blast center (non-hull)
@@ -771,7 +773,7 @@ void debris_create_fire_hook(object *obj, object *source_obj)
* Alas, poor debris_obj got whacked. Fortunately, we know who did it, where and how hard, so we
* can do something about it.
*/
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage, vec3d* force)
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage)
{
debris *debris_p = &Debris[debris_obj->instance];
@@ -811,11 +813,6 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
damage = 0.0f;
}
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_debris]) {
vec3d rel_hit_pos = *hitpos - debris_obj->pos;
physics_calculate_and_apply_whack(force, &rel_hit_pos, &debris_obj->phys_info, &debris_obj->orient, &debris_obj->phys_info.I_body_inv);
}
debris_obj->hull_strength -= damage;
if (debris_obj->hull_strength < 0.0f) {
@@ -836,6 +833,7 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, collision_info_struct *debris_hit_info, vec3d* hitNormal)
{
mc_info mc;
mc_info_init(&mc);
Assert( pdebris->type == OBJ_DEBRIS );
@@ -875,7 +873,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
weapon *wp = &Weapons[other_obj->instance];
wp->collisionInfo = new mc_info; // The weapon will free this memory later
*wp->collisionInfo = mc;
memcpy(wp->collisionInfo, &mc, sizeof(mc_info));
return mc.num_hits;
}
@@ -926,9 +924,10 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE);
// copy important data
int orig_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
vec3d orig_p0 = *mc.p0;
vec3d orig_p1 = *mc.p1;
int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
vec3d copy_p0, copy_p1;
copy_p0 = *mc.p0;
copy_p1 = *mc.p1;
// first test against the sphere - if this fails then don't do any submodel tests
mc.flags = MC_ONLY_SPHERE | MC_CHECK_SPHERELINE;
@@ -954,7 +953,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
}
// Only check single submodel now, since children of moving submodels are handled as moving as well
mc.flags = orig_flags | MC_SUBMODEL;
mc.flags = copy_flags | MC_SUBMODEL;
if (Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod > -1) {
mc.lod = Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod;
@@ -1004,9 +1003,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
}
// Now complete base model collision checks that do not take into account rotating submodels.
mc.flags = orig_flags;
mc.p0 = &orig_p0;
mc.p1 = &orig_p1;
mc.flags = copy_flags;
*mc.p0 = copy_p0;
*mc.p1 = copy_p1;
mc.orient = &heavy_obj->orient;
// usual ship_ship collision test
@@ -1116,7 +1115,7 @@ int debris_get_team(object *objp)
/**
* Fills in debris physics properties when created, specifically mass and moment of inertia
*/
void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs, float density )
void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs )
{
float dx, dy, dz, mass;
dx = maxs->xyz.x - mins->xyz.x;
@@ -1125,7 +1124,7 @@ void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs,
// John, with new bspgen, just set pi->mass = mass
mass = 0.12f * dx * dy * dz;
pi->mass = (float) pow(mass, 0.6666667f) * 4.65f * density;
pi->mass = (float) pow(mass, 0.6666667f) * 4.65f;
pi->I_body_inv.vec.rvec.xyz.x = 12.0f / (pi->mass * (dy*dy + dz*dz));
pi->I_body_inv.vec.rvec.xyz.y = 0.0f;
+3 -3
View File
@@ -71,19 +71,19 @@ 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, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, 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 );
// 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, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx);
// Set velocity after debris creation
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys = nullptr);
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force);
// 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 );
void debris_hit( object * debris_obj, object * other_obj, vec3d * hitpos, float damage );
int debris_get_team(object *objp);
void debris_add_to_hull_list(debris *db);
+2 -2
View File
@@ -220,8 +220,8 @@ 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]) {
+1 -4
View File
@@ -72,10 +72,7 @@ $Player Damage Factor: 0.25, 0.5, 0.65, 0.85, 1
;; factor applied to subsystem damage suffered by the player
;; (in addition to Player Damage Factor)
$Player Subsys Damage Factor: 0.2, 0.4, 0.6, 0.8, 1
;; factor applied to damage inflicted by the player
$Player Damage Inflicted Factor: 1, 1, 1, 1, 1
$Player Subsys Damage Factor: 0.2, 0.4, 0.6, 0.8, 1
;; measure of time (in F1_0 units) after which the AI will recalculate
;; the position of its target
+1 -1
View File
@@ -119,7 +119,7 @@
* half-rate linear filtering on GCN.
*
* If SMAA is applied to 64-bit color buffers, switching to point filtering
* when accessing them will increase the performance. Search for
* when accesing them will increase the performance. Search for
* 'SMAASamplePoint' to see which textures may benefit from point
* filtering, and where (which is basically the color input in the edge
* detection and resolve passes).
+1 -2
View File
@@ -15,8 +15,7 @@ layout (std140) uniform genericData {
void main()
{
float y = fragTexCoord.y / fragTexCoord.w;
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.x, y, fragTexCoord.z));
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
baseColor.rgb = srgb_to_linear(baseColor.rgb);
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
+1 -1
View File
@@ -17,7 +17,7 @@ layout (std140) uniform genericData {
void main()
{
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragColor = vertColor * color;
gl_Position = projMatrix * modelViewMatrix * vertPosition;
fragTexCoord = vertTexCoord;
}
-17
View File
@@ -1,17 +0,0 @@
in vec4 fragTexCoord;
out vec4 fragOut0;
#ifdef COPY_ARRAY
uniform sampler2DArray tex;
#else
uniform sampler2D tex;
#endif
void main()
{
#ifdef COPY_ARRAY
fragOut0 = texture(tex, vec3(fragTexCoord.xy, 0));
#else
fragOut0 = texture(tex, fragTexCoord.xy);
#endif
}
@@ -3,7 +3,6 @@ out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
out vec4 fragOut5;
void main()
{
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
@@ -11,5 +10,4 @@ void main()
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
fragOut5 = vec4(0.0, 0.0, 0.0, 1.0); // composite
}
+21 -27
View File
@@ -3,6 +3,8 @@
#include "shadows.sdr" //! #include "shadows.sdr"
in vec3 beamVec;
in vec3 lightPosition;
out vec4 fragOut0;
uniform sampler2D ColorBuffer;
@@ -24,13 +26,6 @@ layout (std140) uniform globalDeferredData {
float invScreenWidth;
float invScreenHeight;
float nearPlane;
};
layout (std140) uniform matrixData {
mat4 modelViewMatrix;
mat4 projMatrix;
};
layout (std140) uniform lightData {
@@ -68,24 +63,23 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
}
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation)
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDir, out float attenuation, out float area_normalisation)
{
if (lightType == LT_DIRECTIONAL) {
lightDirOut = normalize(lightDir);
lightDir = normalize(lightPosition);
attenuation = 1.0;
area_normalisation = 1.0;
} else {
vec3 lightPosition = modelViewMatrix[3].xyz;
// Positional light source
if (lightType == LT_POINT) {
lightDirOut = lightPosition - position.xyz;
float dist = length(lightDirOut);
lightDir = lightPosition - position.xyz;
float dist = length(lightDir);
// this chunk is unnecessary if sourceRadius= 0.0, but let's avoid a branch.
// given a sphere of radius sourceRadius centered at lightDirOut,
// move lightDirOut towards the ray defined by reflectDir
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
dist = length(lightDirOut);
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
// given a sphere of radius sourceRadius centered at lightDir,
// move lightDir towards the ray defined by reflectDir
lightDir = ExpandLightSize(lightDir, reflectDir);
dist = length(lightDir);
// Energy conservation term
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
area_normalisation = alpha/alpha_adjust;
@@ -99,7 +93,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
else if (lightType == LT_TUBE) { // Tube light
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
vec3 beamDir = normalize(beamVec);
//The actual 'lighting element' is shorter than the light volume cylinder
//To compensate the light is moved forward along the beam one radius and the length shortened
@@ -119,15 +113,15 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
vec3 r = d - a_t * dot(d, a_t) - c * dot(d,c);
float neardist = dot(r, r)/dot(b_t, r);
// Move along the beam by the distance we calculated
lightDirOut = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
lightDir = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
// Somebody with a symbolic expression simplifier or a wrinklier brain than me
// should figure out how to optimise these calcs - qaz
// this chunk is unnecessary if sourceRadius = 0.0, but let's avoid a branch.
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
// Same principle as in LT_POINT, treat chosen location as a spherelight.
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
float dist = length(lightDirOut);
lightDir = ExpandLightSize(lightDir, reflectDir);
float dist = length(lightDir);
// Energy conservation term
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
area_normalisation = alpha/alpha_adjust;
@@ -140,9 +134,9 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
else if (lightType == LT_CONE) {
lightDirOut = lightPosition - position.xyz;
float coneDot = dot(normalize(-lightDirOut), coneDir);
float dist = length(lightDirOut);
lightDir = lightPosition - position.xyz;
float coneDot = dot(normalize(-lightDir), coneDir);
float dist = length(lightDir);
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
area_normalisation = 1.0;
@@ -161,7 +155,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
}
}
attenuation *= attenuation;
lightDirOut = normalize(lightDirOut);
lightDir = normalize(lightDir);
}
}
@@ -170,7 +164,7 @@ void main()
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
vec3 position = texture(PositionBuffer, screenPos).xyz;
if(abs(dot(position, position)) < nearPlane * nearPlane)
if(abs(dot(position, position)) < 0.1)
discard;
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
@@ -27,11 +27,17 @@ layout (std140) uniform lightData {
float sourceRadius;
};
out vec3 lightPosition;
out vec3 beamVec;
void main()
{
if (lightType == LT_DIRECTIONAL) {
gl_Position = vec4(vertPosition.xyz, 1.0);
lightPosition = lightDir;
} else {
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
lightPosition = modelViewMatrix[3].xyz;
if(lightType == LT_TUBE)
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ in vec4 fragTexCoord;
out vec4 fragOut0;
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
const vec3 points[128] = vec3[128](
vec3(-0.2268, 0.6185, 0.7523),
vec3( 0.9958, -0.0871, -0.0277),
+2 -2
View File
@@ -33,7 +33,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
// Distribution Term - Trowbridge-Reitz GGX
@@ -49,7 +49,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
// Smith's method:
// Microsurfaces block light rays coming in from the light
// AND block light rays reflecting to the camera.
// Hence, model both separately and multiply.
// Hence, model both seperately and multiply.
float g1vNL = GeometrySchlickGGX(dotNL, k);
float g1vNV = GeometrySchlickGGX(dotNV, k);
float geometry = g1vNL * g1vNV;
+265 -257
View File
@@ -2,14 +2,12 @@
#include "shadows.sdr" //! #include "shadows.sdr"
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "model_shader_flags.h"
#define MAX_LIGHTS 8
#define LT_DIRECTIONAL 0
#define LT_POINT 1
#define LT_TUBE 2
#define LT_TUBE 2
struct model_light {
vec4 position;
@@ -56,14 +54,21 @@ layout (std140) uniform modelData {
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse_;
vec3 diffuseClr_;
bool overrideGlow_;
vec3 glowClr_;
bool overrideSpec_;
vec3 specClr_;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec_;
int effect_num;
int sBasemapIndex;
vec4 fogColor;
@@ -83,6 +88,8 @@ layout (std140) uniform modelData {
float middist;
float fardist;
vec2 normalAlphaMinMax_;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
@@ -91,40 +98,64 @@ layout (std140) uniform modelData {
int sMiscmapIndex;
float alphaMult;
int flags;
};
in VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
mat3 tangentMatrix;
#endif
mat3 tangentMatrix;
#ifdef FLAG_FOG
float fogDist;
#endif
vec4 position;
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertIn;
#ifdef FLAG_DIFFUSE_MAP
uniform sampler2DArray sBasemap;
#endif
#ifdef FLAG_GLOW_MAP
uniform sampler2DArray sGlowmap;
#endif
#ifdef FLAG_SPEC_MAP
uniform sampler2DArray sSpecmap;
#endif
#ifdef FLAG_ENV_MAP
uniform samplerCube sEnvmap;
uniform samplerCube sIrrmap;
#endif
#ifdef FLAG_NORMAL_MAP
uniform sampler2DArray sNormalmap;
#endif
#ifdef FLAG_AMBIENT_MAP
uniform sampler2DArray sAmbientmap;
#endif
#ifdef FLAG_ANIMATED
uniform sampler2D sFramebuffer;
#endif
#ifdef FLAG_TEAMCOLOR
vec4 teamMask;
#endif
#ifdef FLAG_MISC_MAP
uniform sampler2DArray sMiscmap;
#endif
#ifdef FLAG_SHADOWS
uniform sampler2DArray shadow_map;
#endif
out vec4 fragOut0;
#ifndef FLAG_SHADOW_MAP
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
#endif
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
{
@@ -185,72 +216,81 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#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);
#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);
if (true) {
return;
#else
}
#endif
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
vec2 texCoord = vertIn.texCoord.xy;
// setup our baseline values for base, emissive, fresnel, gloss, AO and normal
// default specular value is set below, as it depends on the diffuse color
vec4 baseColor = color;
vec4 specColor = vec4(0.0, 0.0, 0.0, 1.0);
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
float fresnelFactor = 0.0;
float glossData = defaultGloss;
vec2 aoFactors = vec2(1.0, 1.0);
#ifdef FLAG_AMBIENT_MAP
// 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;
#endif
vec3 unitNormal = normalize(vertIn.normal);
vec3 normal = unitNormal;
#ifdef FLAG_NORMAL_MAP
// Normal map - convert from DXT5nm
vec2 normalSample;
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
normal = vertIn.tangentMatrix * normal;
float norm = length(normal);
// prevent breaking of normal maps
if (norm > 0.0)
normal /= norm;
else
normal = unitNormal;
#endif
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;
}
#ifdef FLAG_ANIMATED
vec2 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;
#endif
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;
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
normal = vertIn.tangentMatrix * normal;
float norm = length(normal);
// prevent breaking of normal maps
if (norm > 0.0)
normal /= norm;
else
normal = unitNormal;
}
#ifdef FLAG_DIFFUSE_MAP
vec2 diffuseTexCoord = texCoord;
#ifdef FLAG_ANIMATED
if (effect_num == 2) {
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
}
#endif
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
vec2 distort = vec2(0.0, 0.0);
#ifdef FLAG_ALPHA_MULT
baseColor.a *= alphaMult;
#endif
if (effect_num >= 0) {
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;
}
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)));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = srgb_to_linear(baseColor.rgb);
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
baseColor.a *= alphaMult;
}
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;
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;
#endif
specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
#ifdef FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
#endif
#ifdef FLAG_SPEC_MAP
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
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;
}
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
// 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
@@ -260,208 +300,176 @@ void main()
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
glossData = min(glossData, glossGeo);
// 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);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
specColor *= alphaMult;
}
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;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
specColor.rgb = srgb_to_linear(specColor.rgb);
}
}
#ifdef FLAG_MISC_MAP
#ifdef FLAG_TEAMCOLOR
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
vec4 teamMask = vec4(0.0);
vec3 team_color_glow = vec3(0.0);
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
vec3 team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
#ifdef FLAG_HDR
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
#endif
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
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));
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
}
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));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
}
}
}
#ifdef FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
#endif
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
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;
} 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;
}
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
}
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
float shadow = 1.0;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
}
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
} 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;
}
}
}
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.
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
// so let s = (2/alpha^2 - 2)
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
float mip_bias = REZ_BIAS - rough_bias;
// Sample light, using mip bias to blur it.
vec3 light_dir = reflect(-eyeDir, normal);
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
vec3 halfVec = normal;
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
// or properly calculating IBL levels.
// Fresnel calculation as with standard lights.
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
// Pseudo-IBL, so use k_IBL
float k = alpha * alpha/ 2.0f;
float NdotL = max(dot(light_dir, normal),0);
float g1vNL = GeometrySchlickGGX(NdotL, k);
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
vec3 kD = vec3(1.0)-fresnel;
kD *= (vec3(1.0) - specColor.rgb);
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
}
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_GLOW)) {
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
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;
}
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
}
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
}
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;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vec3 finalFogColor = fogColor.rgb;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
finalFogColor = srgb_to_linear(finalFogColor);
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
if(blend_alpha == 1) finalFogColor *= baseColor.a;
}
// 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;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
if(desaturate == 1) {
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
}
}
if (effect_num == 0) {
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
emissiveColor.rgb += vec3(shinefactor);
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
} else if (effect_num == 1) {
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
emissiveColor.rgb += vec3(shinefactor);
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);
}
} 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;
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));
} 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));
}
}
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;
#ifdef FLAG_DEFERRED
#ifdef 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;
#else
#ifdef FLAG_SPEC_MAP
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#endif
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
#endif
#else
#ifdef FLAG_LIGHT
float shadow = 1.0;
#ifdef FLAG_SHADOWS
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
#endif
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
#else
#ifdef FLAG_SPEC_MAP
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
#endif
#endif
#endif
#ifdef FLAG_ENV_MAP
#ifdef FLAG_LIGHT
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
// to determine the mip bias.
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
// so let s = (2/alpha^2 - 2)
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
float mip_bias = REZ_BIAS - rough_bias;
// Sample light, using mip bias to blur it.
vec3 light_dir = reflect(-eyeDir, normal);
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
vec3 halfVec = normal;
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
// or properly calculating IBL levels.
// Fresnel calculation as with standard lights.
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
// Pseudo-IBL, so use k_IBL
float k = alpha * alpha/ 2.0f;
float NdotL = max(dot(light_dir, normal),0);
float g1vNL = GeometrySchlickGGX(NdotL, k);
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
vec3 kD = vec3(1.0)-fresnel;
kD *= (vec3(1.0) - specColor.rgb);
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
#endif
#endif
#ifdef FLAG_GLOW_MAP
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
#ifdef FLAG_MISC_MAP
#ifdef 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;
#endif
#endif
#ifdef FLAG_HDR
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
#endif
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
#endif
#ifdef FLAG_FOG
vec3 finalFogColor = fogColor.rgb;
#ifdef FLAG_HDR
finalFogColor = srgb_to_linear(finalFogColor);
#endif
#ifdef FLAG_DIFFUSE_MAP
if(blend_alpha == 1) finalFogColor *= baseColor.a;
#endif
// 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;
#endif
#ifdef FLAG_DIFFUSE_MAP
if(desaturate == 1) {
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
}
#endif
#ifdef FLAG_ANIMATED
if (effect_num == 0) {
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
emissiveColor.rgb += vec3(shinefactor);
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
}
if (effect_num == 1) {
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
emissiveColor.rgb += vec3(shinefactor);
#ifndef FLAG_LIGHT
// ATI Wireframe fix *grumble*
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
#endif
}
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;
#ifdef 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));
#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));
#endif
}
#endif
#ifndef 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;
#endif
fragOut0 = baseColor;
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;
}
#endif
}
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
#endif
}
+128 -106
View File
@@ -1,12 +1,10 @@
#extension GL_ARB_gpu_shader5: enable
#include "model_shader_flags.h"
#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(FLAG_SHADOW_MAP)
#else
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#endif
@@ -63,13 +61,21 @@ layout (std140) uniform modelData {
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse_;
vec3 diffuseClr_;
bool overrideGlow_;
vec3 glowClr_;
bool overrideSpec_;
vec3 specClr_;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec_;
int effect_num;
int sBasemapIndex;
vec4 fogColor;
@@ -89,6 +95,8 @@ layout (std140) uniform modelData {
float middist;
float fardist;
vec2 normalAlphaMinMax_;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
@@ -97,146 +105,160 @@ layout (std140) uniform modelData {
int sMiscmapIndex;
float alphaMult;
int flags;
};
in VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
mat3 tangentMatrix;
float fogDist;
#endif
mat3 tangentMatrix;
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
float clipModel;
#endif
#else
vec4 position;
#endif
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertIn[];
out VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
mat3 tangentMatrix;
#endif
mat3 tangentMatrix;
#ifdef FLAG_FOG
float fogDist;
#endif
vec4 position;
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertOut;
#ifdef FLAG_SHADOW_MAP
void main(void)
void main(void)
{
#ifdef GL_ARB_gpu_shader5
int instanceID = gl_InvocationID;
#else
int instanceID = int(vertIn[0].instance);
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
#ifdef GL_ARB_gpu_shader5
int instanceID = gl_InvocationID;
#else
int instanceID = int(vertIn[0].instance);
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
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;
}
} else {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
}
if(gl_Position.z < -1.0)
#ifdef 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;
}
#else
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
#endif
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
vertOut.position = gl_in[vert].gl_Position;
vertOut.position = gl_in[vert].gl_Position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#endif
#ifdef FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#endif
#ifdef 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;
#endif
#if defined(FLAG_CLIP)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
EmitVertex();
}
EndPrimitive();
}
#elif defined(FLAG_THICK_OUTLINE)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
vec2(1.0, -1.0),
vec2(0.0, -1.0)
);
void main(void)
{
for(int vert = 0; vert < gl_in.length(); vert++)
{
int nextVert = (vert + 1) % gl_in.length();
vec4 clip = gl_in[vert].gl_Position;
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
for (int lineVert = 0; lineVert < 4; ++lineVert)
{
// This is the pixel offset along the normal axis
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
// This is the final offset in clip space
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
vertOut.position = vertIn[vert].position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
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];
}
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#endif
#ifdef FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#endif
#ifdef 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;
#endif
#if defined(FLAG_CLIP)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
EmitVertex();
}
EndPrimitive();
}
#elif defined(FLAG_THICK_OUTLINE)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
vec2(1.0, -1.0),
vec2(0.0, -1.0)
);
void main(void)
{
for(int vert = 0; vert < gl_in.length(); vert++)
{
int nextVert = (vert + 1) % gl_in.length();
vec4 clip = gl_in[vert].gl_Position;
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
for (int lineVert = 0; lineVert < 4; ++lineVert)
{
// This is the pixel offset along the normal axis
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
// This is the final offset in clip space
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
vertOut.position = vertIn[vert].position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
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];
}
EmitVertex();
}
EndPrimitive();
}
}
}
#endif
+83 -66
View File
@@ -2,7 +2,6 @@
#extension GL_ARB_gpu_shader5: enable
#include "shadows.sdr"
#include "model_shader_flags.h"
in vec4 vertPosition;
in vec4 vertTexCoord;
@@ -57,13 +56,21 @@ layout (std140) uniform modelData {
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse_;
vec3 diffuseClr_;
bool overrideGlow_;
vec3 glowClr_;
bool overrideSpec_;
vec3 specClr_;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec_;
int effect_num;
int sBasemapIndex;
vec4 fogColor;
@@ -83,6 +90,8 @@ layout (std140) uniform modelData {
float middist;
float fardist;
vec2 normalAlphaMinMax_;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
@@ -91,32 +100,41 @@ layout (std140) uniform modelData {
int sMiscmapIndex;
float alphaMult;
int flags;
};
#ifdef FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
#endif
out VertexOutput {
#ifdef FLAG_ENV_MAP
vec3 envReflect;
mat3 tangentMatrix;
#endif
mat3 tangentMatrix;
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
// This flag is needed to let the geometry shader know that it doesn't need to apply the
// shadow projection to gl_Position
float clipModel;
#endif
#else
vec4 position;
#endif
vec3 normal;
vec4 texCoord;
#ifdef FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#endif
} vertOut;
#ifdef FLAG_TRANSFORM
#define TEXELS_PER_MATRIX 4
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
@@ -127,7 +145,7 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
invisible = transform[3].w >= 0.9;
transform[3].w = 1.0;
}
#endif
void main()
{
vec4 position;
@@ -135,77 +153,76 @@ void main()
vec4 texCoord;
mat4 orient = mat4(1.0);
mat4 scale = mat4(1.0);
bool clipModel = false;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
}
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#endif
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_THRUSTER)) {
if(vertex.z < -1.5) {
vertex.z *= thruster_scale;
}
#ifdef FLAG_THRUSTER
if(vertex.z < -1.5) {
vertex.z *= thruster_scale;
}
// Transform the normal into eye space and normalize the result.
#endif
// Transform the normal into eye space and normalize the result.
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
position = modelViewMatrix * orient * vertex;
#ifdef FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
vertOut.instance = float(gl_InstanceIDARB);
#else
vertOut.instance = float(gl_InstanceID);
#endif
#endif
#else
gl_Position = projMatrix * position;
#endif
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);
}
#ifdef FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
vertOut.instance = float(gl_InstanceIDARB);
#else
vertOut.instance = float(gl_InstanceID);
#endif
#endif
#else
gl_Position = projMatrix * position;
#endif
#ifdef 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);
#endif
// 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);
// 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);
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));
#ifdef FLAG_ENV_MAP
// Environment mapping reflection vector.
vec3 envReflect = reflect(normalize(position.xyz), normal);
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
#endif
#ifdef FLAG_FOG
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#endif
#ifdef FLAG_TRANSFORM
if (clipModel) {
// Clip this model by moving all vertices outside the clip volume
gl_Position = vec4(vec3(-2.0), 1.0);
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
}
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 FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
}
#ifdef FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
#endif
#ifdef FLAG_CLIP
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#else
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#endif
#endif
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#else
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#endif
}
@@ -1,19 +0,0 @@
#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)
#define FLAG_ACTIVE(flag) (flags & flag) != 0
-197
View File
@@ -1,197 +0,0 @@
in vec4 fragTexCoord;
out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
out vec4 fragOut5;
uniform sampler2DMS texColor;
uniform sampler2DMS texPos;
uniform sampler2DMS texNormal;
uniform sampler2DMS texSpecular;
uniform sampler2DMS texEmissive;
uniform sampler2DMS texDepth;
layout (std140) uniform genericData {
int samples;
float fov;
};
const float voxelDepth = 2.5f;
const float voxelDepthFalloff = 2.5f;
#define SORT(a, b) if (a > b) { float t = dists[a]; dists[a] = dists[b]; dists[b] = t; }
//The following sorting networks for median calculation are NOT complete. Calculations that don't affect the
//median entry are removed, and thus, while the median element is correct, the rest of the array is NOT fully sorted
#ifdef SAMPLES_4
float getMedianDist(ivec2 texel) {
float dists[4];
for(int i = 0; i < 4; i++) {
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 2)
SORT(1, 3)
SORT(0, 1)
SORT(2, 3)
SORT(1, 2)
return dists[1];
}
#else
#ifdef SAMPLES_8
float getMedianDist(ivec2 texel) {
float dists[8];
for(int i = 0; i < 8; i++) {
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 4)
SORT(1, 5)
SORT(2, 6)
SORT(3, 7)
SORT(0, 2)
SORT(1, 3)
SORT(4, 6)
SORT(5, 7)
SORT(2, 4)
SORT(3, 5)
SORT(0, 1)
SORT(2, 3)
SORT(4, 5)
SORT(6, 7)
SORT(1, 4)
SORT(3, 6)
SORT(3, 4)
return dists[3];
}
#else
#ifdef SAMPLES_16
float getMedianDist(ivec2 texel) {
float dists[16];
for(int i = 0; i < 16; i++) {
dists[i] = texelFetch(texPos, texel, i).z;
}
SORT(0, 1)
SORT(2, 3)
SORT(4, 5)
SORT(6, 7)
SORT(8, 9)
SORT(10, 11)
SORT(12, 13)
SORT(14, 15)
SORT(0, 2)
SORT(4, 6)
SORT(8, 10)
SORT(12, 14)
SORT(1, 3)
SORT(5, 7)
SORT(9, 11)
SORT(13, 15)
SORT(0, 4)
SORT(1, 5)
SORT(2, 6)
SORT(3, 7)
SORT(8, 12)
SORT(9, 13)
SORT(10, 14)
SORT(11, 15)
SORT(0, 8)
SORT(1, 9)
SORT(2, 10)
SORT(3, 11)
SORT(4, 12)
SORT(5, 13)
SORT(6, 14)
SORT(7, 15)
SORT(5, 10)
SORT(6, 9)
SORT(3, 12)
SORT(13, 14)
SORT(7, 11)
SORT(1, 2)
SORT(4, 8)
SORT(7, 13)
SORT(2, 8)
SORT(5, 6)
SORT(9, 10)
SORT(3, 8)
SORT(6, 8)
SORT(3, 5)
SORT(7, 9)
SORT(5, 6)
SORT(7, 8)
SORT(6, 7)
return dists[7];
}
#else
//Fallback, do front first
float getMedianDist(ivec2 texel) {
float minDist = -1000000;
for(int i = 0; i < samples; i++) {
minDist = max(minDist, texelFetch(texPos, texel, i).z);
}
return minDist;
}
#endif //SAMPLES_16
#endif //SAMPLES_8
#endif //SAMPLES_4
void main()
{
vec2 texSize = textureSize(texColor);
ivec2 texel = ivec2(texSize * fragTexCoord.xy);
float texelWidthFactor = tan(fov / texSize.y);
float dist = getMedianDist(texel);
float weight = 0.0f;
vec4 color = vec4(0);
vec4 pos = vec4(0);
vec4 normal = vec4(0);
vec4 specular = vec4(0);
vec4 emissive = vec4(0);
float depth = 0;
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
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)
);
pos += localPos * localWeight;
color += texelFetch(texColor, texel, i) * localWeight;
normal += texelFetch(texNormal, texel, i) * localWeight;
specular += texelFetch(texSpecular, texel, i) * localWeight;
emissive += texelFetch(texEmissive, texel, i) * localWeight;
depth += texelFetch(texDepth, texel, i).x * localWeight;
weight += localWeight;
}
fragOut0 = color / weight;
fragOut1 = pos / weight;
fragOut2 = normalize(normal);
fragOut3 = specular / weight;
fragOut4 = emissive / weight;
gl_FragDepth = depth / weight;
}
Loaded 100 of 1211 files, more files were not shown because too many files have changed in this diff. Show more