Compare commits

..
Author SHA1 Message Date
SirKnightly cf5f207ca6 Automated build commit 2022-04-01 21:30:46 +00:00
1653 changed files with 131114 additions and 285966 deletions

No files matched your search

+7 -1
View File
@@ -1,5 +1,11 @@
ci/ @asarium @z64555
cmake/ @asarium
code/executor/ @asarium
code/scpui/ @asarium
code/scripting/ @asarium
code/controlconfig/ @z64555
+53 -177
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-11e553c
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
@@ -95,36 +109,31 @@ jobs:
name: Checkout
with:
submodules: true
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- 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=ON -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
@@ -209,128 +210,3 @@ jobs:
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
build_mac:
strategy:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
name: Mac
runs-on: macos-latest
steps:
# - name: Cache Qt
# id: cache-qt-mac
# 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-mac.outputs.cache-hit }}
# 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: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"]
- 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
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
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
- name: Upload build result
uses: actions/upload-artifact@v3
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
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
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
with:
name: mac-FastDebug-${{ matrix.arch }}
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
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
+132 -200
View File
@@ -6,7 +6,7 @@ on:
- 'release_*'
env:
QT_VERSION: 5.12.12
QT_VERSION: 5.12.9
jobs:
create_release:
@@ -34,6 +34,23 @@ jobs:
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Store upload URL
run: |
echo -n "${{ steps.create_release.outputs.upload_url }}" > upload_url
- name: Persist upload URL
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.
# warn Display a warning but do not fail the action
# error Display an error and fail the action
# ignore No display, No fail
# retention-days=0 Days to keep the artifact.
# 0 Use default retention policy of the repo
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
with:
name: upload_url # name of artifact
path: ${{ github.workspace }}/upload_url # source location of artifact to upload
build_linux:
strategy:
@@ -44,19 +61,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-11e553c
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,16 +133,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
# 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.
# warn Display a warning but do not fail the action
# error Display an error and fail the action
# ignore No display, No fail
# retention-days=0 Days to keep the artifact.
# 0 Use default retention policy of the repo
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
uses: actions/upload-artifact@v2
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -100,16 +148,30 @@ jobs:
with:
submodules: true
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
ref: '${{ github.ref }}'
- name: Download upload URL
uses: actions/download-artifact@v1
# Downloads and extracts uploaded artifact by name
# github_token default ${{secrets.GITHUB_TOKEN}}
# name name of artifact to download
# latest Download latest artifact (default true)
# path Where to save the artifact, (default extract_here)
# repo Source repo of artifact (default ${{github.repository}})
with:
name: upload_url
path: .
- name: Extract upload URL
# Extract the URL from file and stuff it into a shell variable
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- 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 +182,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,40 +209,34 @@ jobs:
name: Checkout
with:
submodules: true
ref: '${{ github.ref }}'
# - name: Cache Qt
# # Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# # Install Qt 32bit if matrix.arch == Win32
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# # Install Qt 64bit if matrix.arch == x64
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
- name: Cache Qt
# Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
# Install Qt 32bit if matrix.arch == Win32
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
# Install Qt 64bit if matrix.arch == x64
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -191,19 +247,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=ON -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 +268,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 +290,25 @@ jobs:
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download upload URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: .
- name: Extract upload URL
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- 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 +323,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 }}
@@ -285,137 +343,11 @@ jobs:
${{ steps.generate_package.outputs.package_path }}
${{ steps.generate_package.outputs.debug_path }}
build_mac:
strategy:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
name: Mac
needs: create_release
runs-on: macos-latest
steps:
# - name: Cache Qt
# id: cache-qt-mac
# 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-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
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
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
- name: Upload build result
uses: actions/upload-artifact@v3
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
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
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
with:
name: mac-FastDebug-${{ matrix.arch }}
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
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
- name: Publish result package
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: ${{ steps.generate_package.outputs.package_path }}
post_build:
name: Post builds to Nebula and Forum
needs: [linux_zip, windows_zip, mac_zip]
needs: [linux_zip, windows_zip]
uses: ./.github/workflows/post-build-release.yaml
with:
linux_result: ${{ needs.linux_zip.result }}
windows_result: ${{ needs.windows_zip.result }}
mac_result: ${{ needs.mac_zip.result }}
linux_result: ${{ needs.build_linux.result }}
windows_result: ${{ needs.build_windows.result }}
releaseTag: ${{ github.ref_name }}
secrets: inherit
+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 }}
+53 -176
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-11e553c
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
@@ -108,36 +122,31 @@ jobs:
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- 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=ON -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
@@ -223,127 +224,3 @@ jobs:
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
build_mac:
strategy:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64, arm64]
name: Mac
runs-on: macos-latest
steps:
# - name: Cache Qt
# id: cache-qt-mac
# 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-mac.outputs.cache-hit }}
# 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: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
- name: Configure CMake
env:
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
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
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
- name: Upload build result
uses: actions/upload-artifact@v3
with:
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
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
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v3
with:
name: mac-Release-${{ matrix.arch }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v3
with:
name: mac-FastDebug-${{ matrix.arch }}
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
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
+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-11e553c
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
+8 -26
View File
@@ -6,13 +6,10 @@ on:
inputs:
linux_result: # job.result; either success, failure, canceled or skipped
required: true
type: string
type: boolean
windows_result: # job.result
required: true
type: string
mac_result: # job.result
required: true
type: string
type: boolean
releaseTag:
required: true
type: string
@@ -33,40 +30,26 @@ env:
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ inputs.releaseTag }}
RELEASE_TAG: ${{ github.event.inputs.releaseTag }}
jobs:
post_builds:
name: Post builds on Nebula and the forums
runs-on: ubuntu-latest
steps:
- name: Caller
# Name of what called this yaml. Used to debug auto/manual step being triggered
run: echo "github.event_name= ${{ github.event_name }}"
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: '0'
ref: ${{ env.RELEASE_TAG }}
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
- name: Post Builds (Auto trigger)
if: ${{ (github.event_name == 'workflow_call') || (github.event_name == 'push') }}
if: ${{ github.event_name == 'workflow_call' }}
env:
LINUX_RESULT: ${{ inputs.linux_result }}
WINDOWS_RESULT: ${{ inputs.windows_result }}
MAC_RESULT: ${{ inputs.mac_result }}
GITHUB_REPO: ${{ github.repository }} # repo this workflow was called from
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
NEBULA_USER: ${{ secrets.NEBULA_USER }}
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ inputs.releaseTag }}
LINUX_RESULT: ${{ github.event.inputs.linux_result }}
WINDOWS_RESULT: ${{ github.event.inputs.windows_result }}
run: python ci/post/main.py release
- name: Post Builds (Manual trigger)
@@ -75,8 +58,7 @@ jobs:
env:
LINUX_RESULT: success
WINDOWS_RESULT: success
MAC_RESULT: success
run: |
echo "releaseTag= ${{ env.RELEASE_TAG }}"
echo "releaseTag= ${{ github.event.inputs.releaseTag }}"
echo "repository= ${{ github.repository }}"
python ci/post/main.py release
python ci/post/main.py release
+50 -128
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-11e553c
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-')
@@ -82,36 +89,31 @@ jobs:
name: Checkout
with:
submodules: true
# - name: Cache Qt
# id: cache-qt-win
# uses: actions/cache@v1
# with:
# path: ${{ github.workspace }}/../Qt
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
# - name: Install Qt (32 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win32_msvc2017
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
# - name: Install Qt (64 bit)
# uses: jurplel/install-qt-action@v2
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
# with:
# version: ${{ env.QT_VERSION }}
# dir: ${{ github.workspace }}/..
# arch: win64_msvc2017_64
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
# aqtversion: ==0.8
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
- name: Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win32_msvc2017
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
uses: jurplel/install-qt-action@v2
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
arch: win64_msvc2017_64
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- 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=ON -T "v142" -A "$ARCHITECTURE" ..
fi
- name: Compile
working-directory: ./build
@@ -165,72 +156,3 @@ jobs:
else
"./bin/$CONFIGURATION/unittests" --gtest_shuffle
fi
build_mac:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [clang]
arch: [x86_64, arm64]
cmake_options: [""]
name: Mac
runs-on: macos-latest
steps:
# - name: Cache Qt
# id: cache-qt-mac
# 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-mac.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
# py7zrversion: '==0.19.*'
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- 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
- 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
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
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
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
if: startsWith(matrix.compiler, 'clang-')
run: $GITHUB_WORKSPACE/ci/linux/clang_tidy.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Process clang-tidy warnings
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
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*
-1
View File
@@ -4,4 +4,3 @@
[submodule "lib/libRocket"]
path = lib/libRocket
url = https://github.com/asarium/libRocket.git
+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
+16 -18
View File
@@ -39,14 +39,21 @@ endif(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
# Override standard CMake configurations
set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available configurations" FORCE)
set(FSO_LANGUAGES C CXX)
PROJECT(FS2_Open)
if(APPLE)
set(FSO_LANGUAGES ${FSO_LANGUAGES} OBJC OBJCXX)
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
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()
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
IF(CMAKE_CROSSCOMPILING)
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
@@ -75,11 +82,9 @@ IF(RESET_INSTALL_PREFIX)
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
ENDIF(RESET_INSTALL_PREFIX)
IF(WIN32 OR APPLE)
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" ON)
ENDIF(WIN32 OR APPLE)
IF (WIN32)
OPTION(FSO_USE_SPEECH "Use Windows specific text-to-speach libraries" ON)
OPTION(FSO_USE_VOICEREC "Enable voice recognition support" ON)
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
@@ -123,11 +128,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 +142,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)
@@ -207,10 +207,8 @@ include(package)
include(doxygen)
# Print used options to log
IF(WIN32 OR APPLE)
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
ENDIF()
IF (WIN32)
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
elseif(UNIX)
-617
View File
@@ -3,618 +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
```
Changelog note:
As of this version, in an attempt to make the changelog easier to navigate and read,
each section will have collapsible subsections, ordered alphabetically by topic.
Headlining features will always be on top.
```
### Added
<details><summary> <b>Big Feature: SEXP Containers</b> </summary>
> As opposed to a SEXP variable, which stores only one value, a SEXP container stores a collection of values.
> Consequently, containers allow for handling data in much more sophisticated ways than variables.
> Containers come in two types:
> * List container - an ordered sequence of values, sort of a cross between Python lists and deques
> * Map container - pairs of keys associated with data, like Lua tables or Python dictionaries
> Further details in the [SEXP Containers announcement thread](https://www.hard-light.net/forums/index.php?topic=98209.0)
</details>
<details><summary> <b>Big Feature: LuaAI</b> </summary>
> LuaAI allows scripters to add a new AI Goal (like ai-chase) that will run script instead of internal logic.
> Adding a Lua AI section in a -sexp.tbm and a few functions to a corresponding -sct.tbm to define the AI logic in certain conditions. More documentation on these functions is available in the LuaAISEXP-Object of the Scripting Docs.
</details>
<details><summary>AI:</summary>
- `$AI ignores aspect lock for leading:` Flag, which lets AI continue to lead their target while performing an Aspect Lock
</details>
<details><summary>Animation: </summary>
- `pause on reverse` Flag
</details>
<details><summary>Controls: </summary>
- Handle international keyboard layouts
- Re-Add `-joy-info` command line flag, for slightly quicker Joystick GUID retrieval
- Add `-controlconfig_tbl` command line flag to print out a template controlconfigdefaults.tbl
</details>
<details><summary>FRED: </summary>
- Support the full number of nebula poofs using a multi-select list
- Add the ability to edit nebula fog colors, since that previously was not part of the FRED UI
- Flags `same-arrival-warp-when-docked` and `same-departure-warp-when-docked` to allow docked ships to still use custom warp parameters
- Allow highlighting custom-colored events by drawing a border on them
- Can now rotate objects relative to other objects in the Object Editor
- Dialog to calculate relative distance and orientation between ships
- Flag "Point using uvec" to point ships while incorporating the ship's uvec
- `ai-attackable-if-no-collide` flag, which prevents turrets from ignoring a target with `no_collide`
</details>
<details><summary>QtFRED: </summary>
- Reinforcements Dialog
- Implemented Replace Data for Number and String
- Texture Replacement Dialog
- TBL Viewer in the Ship Editor
</details>
<details><summary>Graphics: </summary>
- Allow particles to use a random chance for spawning through the `+Chance` parameter
- Command-line parameter `-fov_cockpit` which allows setting an FoV for the cockpit model separately from the viewport FoV. This allows using custom FoVs without distorting the cockpit
- Allow user to export environment map to a PNG from the F3 Lab by pressing M
- Weapon lights: Configurable lighting data for weapons, both on a per-weapon basis and globally via lighting profiles
- Implemented debug sphere queuing and rendering
</details>
<details><summary>Localization: </summary>
- Make strings for Match Speed Indicator, Glide Indicator, and Afterburner Indicator translateable
</details>
<details><summary>Modding: </summary>
- `game_settings.tbl` setting `$Supernova hits at zero:`, which causes Supernovae to hit when the timer gets to 0, instead of the default of hitting 5 seconds before the time is up
- `game_settings.tbl` settings `$Show-subtitle uses pixels:` and `$Show-subtitle base resolution:`, which can be used in conjunction to scale subtitles
- `game_settings.tbl` setting `$Always warn player about unbound keys used in Directives Gauge:`, to show such warning to players when needed (without it these warnings only apply to Training Missions)
- Ship flags `fail-sound-locked-primary` and `fail-sound-locked-secondary` to allow the firing fail sound to play if the player tries to fire weapons that are locked
- Subsystem Flag "hide turret from loadout stats"
- Allow weapon to override turret name with `$Turret Name:`
</details>
<details><summary>Multiplayer: </summary>
- Save PXO stats to local pilot file
</details>
<details><summary>Performance: </summary>
- Preload subspace tunnel if the `mission-set-subspace` SEXP is used in the mission
</details>
<details><summary>SEXPs: </summary>
- `cancel-future-waves`, for stopping wings that still had waves queued from spawning
- Added optional flag to `show-subtitle-text` and `show-subtitle-image` to not change the subtitle aspect ratio
- `set-nav-color` and `set-nav-visited-color`, which allows setting custom colors to Navpoints in a mission
</details>
<details><summary>Scripting: </summary>
- Support for decals (see `decaldefinition` in the Scripting documentation)
- Missile list iterator: `mn.getMissileList()`
- Campaign Start hook: `On Campaign Begin`
- Player Loaded hook: `On Player Loaded`
- Added a few functions to get information on HUD gauges (check `HudGauge` in the Scripting documentation)
- Function `ship.checkVisibility` which checks if a ship can appear on the viewer's radar
- Function `hu.flashTargetBox` which causes the target box to flash
- Function `hu.getTargetDistance` to return the distance to target as reported by the HUD
- Function `mn.hasLineOfSight` which checks if one point has line of sight to the other
- Function `mn.getLineOfSightFirstIntersect` which checks for line of sight and returns the distance of the first interruption if not
- Variable `gr.CurrentResizeMode`, which can get or set the scaling mode to be used by the `gr.*` drawing methods
- Function `gr.draw3dLine`, which draws a line in space between two points
- Allow SCPUI to run `$On Briefing Stage:` hooks
- New bindings to allow proper hooking into control actions based on the control's enumeration name
- Allow scripted controls to override hardcoded functionality
- Fennel script support
- Lua BitOp 1.0.2 extension library, allowing the usage of bit operations
</details>
<details><summary>Technical: </summary>
- Class encapsulation for Volition's linked list
- Improve a debug console message to be more informative
- Type-safe `TIMESTAMP` class
- Add `timestamp_since()` function
- Add methods to compare timestamps, calculate deltas from an existing timestamp and a number of milliseconds, and to calculate deltas between timestamps
- Create a command line option for logging data packets
- Add more information to Multi-related debug logging
- Enable Doxygen for QTFred
- Set up Mac builds on CI, allowing builds to be published automatically for Mac
- Add some logging to `waitAsync`
</details>
### Changed
<details><summary>Game: </summary>
- Only display one popup when the player gets to the main hall
- Allow an unlimited number of ship flags to be parsed at once
</details>
<details><summary>AI: </summary>
- Improve Player Orders to allow for a nearly unlimited number of player orders, as opposed to the 32 before
- Update `ai_turn_towards_vector` to use a target velocity for banking
</details>
<details><summary>Audio: </summary>
- Allow unlimited soundtracks and spooled music (Previously limited to 30 and 50 respectively)
- Allow unlimited sound effects
- Dynamically set the maximum number of audio channels based on how many the user's system can support
</details>
<details><summary>FRED: </summary>
- CTRL+V is now add-paste (used to be CTRL+P)
- CTRL+SHIFT+V is now overwrite-paste (used to be CTRL+V)
- Replace `Always_show_goals` with `Toggle_showing_goals` which toggles whether the goals are shown, and works in any mission (instead of only Training Missions)
- No longer disable icon dropdowns for models that have their own icons
- No longer change the ship class when the icon type is a special popup
- Make the number of player orders FRED can handle dynamic
- Restore original Error Checking behavior where the function would exit after one check (for consistency)
- Exclude player ships from Error Checking for ships in a wing sharing the same orders
- Split "No subsystems found" and "Not all subsystems have a record in ships.tbl" warnings into two different warning flags
</details>
<details><summary>Graphics: </summary>
- Improved light attenuation to look more real
- Increase POF vertex limit, allowing up to `2^32 - 1` vertices to be used by a single subobject
</details>
<details><summary>Performance: </summary>
- Delay `ai_new_maybe_reposition_attack_subsys` to only run once a second. Before this change, it could take around 13% of runtime in crowded missions
- Cached subsystem indexing, speeding up subsystem lookups, which run for multiple ships, multiple times per frame
</details>
<details><summary>Scripting: </summary>
- Enhance help text for Lua SEXPs
- Converted the following Lua Hooks to the new format to add documentation: `On Death`, `On Game Init`, `On Ship Collision`
</details>
<details><summary>Technical: </summary>
- Turn `insertion_sort` into a templated function that uses assignment
- CMake: Update `PREBUILT_VERSION_NAME` to latest (mac libs)
- Optimized space used in the new POF version
- Cleanup model code
- Cleanup beam light functions by consolidating some duplicated code and removing unreachable logic
- Cleanup wing wave code
- Move special parsing functions into new `parsehi.cpp` and `parsehi.h` files
- Actually clear delayed SSM parsing data when it's no longer needed
- Allow C++ to interact more with LuaTables, allowing it to extract userdata like objects or ships from them
- Use `SCP_string` for constructing multi/event log lines
- Replace `+Orders Accepted:` Bitfield with flag list
- Handle deprecated command line flags programmatically, avoiding lots of code duplication
- Set up debug_filter.cfg to have default filters that can be turned off
</details>
### Removed
<details><summary>FRED: </summary>
- Remove the `Allow Daisy-Chained Docking` mission flag
- Remove "Delete Item" from the right-click menu in the Event Editor
</details>
<details><summary>Technical: </summary>
- Remove light filtering data which didn't work and increased code complexity
- Remove a pointless assert that checked if `SEXP_NODE_INCREMENT` (a define, set at 250) was greater than zero
</details>
### Fixed
<details><summary>Game: </summary>
- Missing whitespace in credits
- Stopped destroyed submodels from showing in Techroom
- Prevent a crash when an object dies in the same frame as their goal
- Always record primary bank ammo capacity during ship creation, preventing situations where a ballistic weapon would accidentally be set to zero ammo
- Properly remove ships from the Techroom when they're not in the Tech Database
- Load the correct Techroom data after a Tech Database Reset
- Don't tick Supernova timer while the game is paused
- Make `set-camera-facing` use default identity orientation when the `$Use host orientation` flag is active and no host is present
- When a hotkey text replacement string refers to an unbound control, use the name of the binding instead of "none"
- Fix usage of default tech database flags
- Prevent a crash in the loadout screen with a weapons-locked ship
- Fix two crashes in the F3 lab
- End the campaign properly when a mission is skipped, preventing crashing in some situations
- Prevent a crash when a message is sent from an invalid source
- Prevent a broken campaign state if the player quits the game from the options menu during the debriefing
- Add some checks before converting a message to Command
- Prevent accidentally skipping cutscenes caused by hitting the spacebar during a loading screen
- Fixed an issue where ships would start with the wrong hull values in Red Alert missions
</details>
<details><summary>AI: </summary>
- Fix turret swarm weapons by removing a few checks that are no longer valid
- Fix a few issues with maneuvers
</details>
<details><summary>Animations: </summary>
- Fix broken turret animations in the Techroom
</details>
<details><summary>Audio: </summary>
- Fix cockpit engine sound volume changing unexpectedly
- Fix a timing bug that would sometimes prevent music from being initialized when re-playing a mission
- Check all possible extensions for audio files
</details>
<details><summary>Controls: </summary>
- Flush the mouse state after toggling between `Use_mouse_to_fly` states, preventing situations where a stale mouse state would be used
- Fix a conflict between Free Look View controls and directional thrust controls
</details>
<details><summary>FRED: </summary>
- Prevent Ship Select Dialog from crashing if there are too many IFFs
- Support saving nebula fog colors
- Properly save `nav-carry-status` flag
- Don't treat a bare `<argument>` as an error
- Prevent adding duplicated variables and display an error to the user when they try
- Clean up some parse problems
- Fix assignment of alt-name when using the hash
- Guard against off-by-one errors in `replace_one` and `replace_all`
- Improve error checking of campaign loop branches
- Improve error reporting for bad SEXP nodes
- Prevent a crash with paste/add-paste when the clipboard was empty
- Prevent rounding/conversion issues that caused FRED to think an angle or position was modified when it wasn't
- Skip absent ships or wings when running `clear-goals`, instead of stopping the whole operation
</details>
<details><summary>Graphics: </summary>
- Disable Lightshafts while the Supernova glare effect is active. This partial fix ensures the glare shows up with the correct brightness
- Update and correctly load environment maps in F3 Lab
- Correctly set textures and Team Colors with `change-ship-class`
- Fixes Team Colors not working with `show-ship`
- Correct positioning and angles for background bitmaps and suns
- Clean up ship arrival and departure effects
- Fix clearing a skybox model when it isn't the mission default
- Fix an assertion with Fireball LODs which would wrongly trigger if the number of LODs was the same as the maximum
</details>
<details><summary>HUD: </summary>
- Make HUD Target distance consistent
- Fix a crash with scripted HUDs
- Correctly update RTT Cockpit Gauges with `change-ship-class`
- Ignore HUD brackets with a size of zero or less (instead of just crashing)
- Squad menu wasn't scrolling properly with PageDown in some cases
- Fix issues with loading of hud config presets
- Fix parsing issues with HUD color presets
- Continue parsing remaining gauges if one isn't found
- Use translated strings both when saving and loading
- Fix an issue where a target's orders would be displayed wrongly in the target box
- Fix asteroid brackets disappearing or displaying wrong values
</details>
<details><summary>Modding: </summary>
- Delay processing `$Player Weapon Precedence:` until after parsing, avoiding ships starting with the wrong weapons in some situations
- Make the `$Player Weapon Precedence:` list actually give precedence
- Empty `+Orders Accepted List:` entries were causing the ship to accept the default orders, instead of no orders as would be correct
- Show a Warning if a turret submodel is not an immediate child of the base object and handle it as a single-part object to prevent a crash
</details>
<details><summary>Multiplayer: </summary>
- Limit client collisions to prevent bugs, such as flinging players with high pings who collided multiple times between packet updates
- Fix multiple timestamp issues
- Multi messaging and multi pause screen
- Make sure maintenance stuff (pings, voice, file xfer, etc.) isn't affected by pausing or time compression
- Sync issues caused by options menu and screenshots
- Prevent an error with long messages in PXO Chat by using proper buffer size
- Fix some issues with Multiplayer SEXPs
- Try to handle incompatible sexp packets better
- Fix operator name issue with debug messages
- Enable the new show-subtitle-text options
- Improve interpolation, fixing the jerkiness that used to occur when the interpolation code basically guessed the timing on when packets were coming in
- Fix rollback primary collisions, vastly improving accuracy on moving targets even at high pings
- Fix the standalone ship being added to ship list
- Stop non-printable keys adding text to multi message buffer
- Prevent the standalone from crashing if a player tried to switch secondaries in a ship that doesn't have secondaries
- Fix a standalone crash from disabled uniform buffer manager
- Prevent a crash related to Observer-type players
- Fix network issues on MacOS
</details>
<details><summary>Scripting: </summary>
- Make hook conditions consistent and handle combinations that didn't work properly before
- Fix `maybePlayCutscene` arguments
- Add `isActive` checks for new-style script hooks
- Sync the two `VIRTVAR`s for Orientation in subsystems and submodel instances, which behaved in different ways
- Fixed a few timing and framerate related issues for playing movies via script
- Ensure the Lua interpreter has enough space in its stack, and allow reserving more space if necessary
- Fixed an memory leak in the Lua interpreter caused by string-eval sexps, which never cleaned up the generated code
</details>
<details><summary>SEXPs: </summary>
- Avoid setting .rest for `Locked_sexp_true/false` with malformed SEXPs
- Fix some memory management problems in the `for-*` operators, avoiding a memory leak
- Fix crash when removing form-on-wing order with `remove-goal`
- Fix `show-subtitle` SEXP which was missing the `width` argument
- Reset volumes changed via `adjust-audio-volume` when the mission closes
- Prevent too many dynamic SEXPs from breaking the SEXP system
</details>
<details><summary>Technical: </summary>
- Check if index is valid before accessing `Weapon_info`, preventing CTDs under certain conditions
- When `weapon_create` was called while `MAX_WEAPONS` was reached, the previous algorithm didn't achieve desired results, and simply locked up the game. Instead, we now simply won't allow a new weapon to be created in such condition
- Refactored Supernova code and fixed some state transition issues in it
- Prevent crashes in the event of a subsystem mismatch during `change_ship_type`
- Change include order to fix compilation of unit tests on Mac
- Patch freeing of SEXP nodes, preventing a crash in certain conditions
- Fix a memory leak in model code
- Fix a crash in the Ship Creation code if a ship's name was exactly the maximum allowed length
- Removed vestigial bit-depth asserts for aabitmaps, preventing crashes with certain image types
- Prevent a crash when Escort Priority was parsed for a ship not present in the Escort List
- Fix a bunch of graphics functions to respect GR_STUB, preventing problems in standalone server
- Clean up line endings in several files (replaced CRLF with LF basically everywhere)
- Fixed a timestamp issue which helps lay the groundwork to add In-Game Joining to multiplayer
- Prevent pilot and campaign files from having invalid values, by clamping them within the expected ranges when saving and loading
- Also warn the player if such an invalid value was detected, telling them which setting had the wrong value and what it was reset to
- Try to avoid assertions by preventing invalid types from being handled by `obj_team()`
- Shut down the SEXP system before the Scripting system, otherwise a crash could happen if the SEXP system held references to Lua
</details>
----
## [22.0.0] - 2022-04-01 ([Thread](https://www.hard-light.net/forums/index.php?topic=98125.0))
### Changed
- Controls5 PR (aka multi-joy)
- Timing system upgrade
- Model animation code upgrades
## [21.4.0] - 2021-09-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97802.0))
### Changed
- Multiple features; see thread
- Multiple bugfixes; see thread
### Deprecations
- `script-eval` has been deprecated in favor of `script-eval-block`
- renamed `hud-set-retail-gauge-active` to `hud-set-builtin-gauge-active`
## [21.2.0] - 2021-05-02 ([Thread](https://www.hard-light.net/forums/index.php?topic=97561.0))
### Changed
- Added a dynamic action system for more modder control of effects
- Removed fireball limit
- Fixed bomb intercept in multiplayer
- Changed nebula fog distance from a linear to exponential model
- Turrets on moving subobjects enabled
- LZ4 Compression added for game files
## [21.0.0] - 2021-01-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97293.0))
### Changed
- More OpenGL optimizations
- Full type information output for Lua documentation. Very useful for writing Lua scripts.
- A new -weaponspew command-line option for printing MediaVP-style statistics, plus a weapon comparison spreadsheet, to the debug log.
- Improved ship lookup behavior in SEXPs for improved performance.
- BPTC/BC7 texture compression support
- Refactoring and new features for the ship lab.
- Missile multi-lock. It's finally in an official build!
- Enhancements to the model code in preparation for cool features in 21.2.
- IPv6 support for multiplayer
- A lot of general fixes for multiplayer.
### Deprecated
- Dropped support for Windows XP
- Scripting:
- `ba.getFrametime()`: The parameter value was used incorrectly inside the implementation. To avoid breaking existing scripts and to improve readability this has been split into `ba.getMissionFrametime()` and `ba.getRealFrametime()`.
- `gr.drawMonochromeImage()`: `gr.drawImage()` got a new parameter for drawing monochrome images and is more flexible in general so the monochrome variant is no longer needed.
## [19.0.0] - 2020-01-25 ([Thread](https://www.hard-light.net/forums/index.php?topic=96226.0))
### Meta
- With this release we decided to drop the "`3.Major_revision.Minor_revision`" versioning scheme in favor of a year based scheme since the Major and Minor versions did not have much meaning anymore. Instead the scheme will now be "`<year>.<number that is incremented every release>.0`". The last 0 is still there because some of our systems expect that. It will be gone at some point.
@@ -637,7 +25,6 @@ Headlining features will always be on top.
### Fixed
- Refactored bitmap slot handling and removed the fixed upper limit on the number of bitmaps. No more bmpman corruption!
## [3.8.0] - 2017-08-22 ([Release Thread](https://www.hard-light.net/forums/index.php?topic=93812.0))
### Added
- Support for APNG animations: [APNG](https://en.wikipedia.org/wiki/APNG) is a variant of the established PNG format which allows to store animations instead of single frames in a PNG file. This change allows to use these animation files in FSO which significantly improves usability for modders since they no longer have to store all individual frames as separate images.
@@ -662,7 +49,6 @@ Headlining features will always be on top.
### Fixed
- "Tons" of bugfixes
## [3.7.2] - 2015-04-23 ([Release thread](http://www.hard-light.net/forums/index.php?topic=89597.0))
### Added
- MediaVPS 2014 Support
@@ -693,19 +79,16 @@ Headlining features will always be on top.
- Raised the per-model debris limit to 48 (previously 32).
- Increased the per-frame debris limit to 96 (previously 64)
## [3.6.18] - 2013-03-01 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83889.0))
### Fixed
- Critical damage bug which caused heavy balance issues in the game
## [3.6.16] - 2013-01-31 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83577.0))
### Added
- Diaspora TC support
### Changed
- Performance Improvements
## [3.6.14] - 2012-10-23 - ([Release thread](https://www.hard-light.net/forums/index.php?topic=82648.0))
### Added
- Objecttype tables support for deciding how enemies respond to ship classes when disabled
+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=ON `
-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=ON -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
}
}
+1 -1
View File
@@ -19,5 +19,5 @@ BASE_COMMIT=$(git merge-base $1 $2)
echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-regex '(code(?!\/graphics\/shaders\/compiled)|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+16 -38
View File
@@ -1,41 +1,26 @@
#!/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"
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
fi
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
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
@@ -45,14 +30,7 @@ export CXXFLAGS
export CFLAGS
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 ..
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_BUILD_APPIMAGE=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON \
-DSHADERS_ENABLE_COMPILATION=ON ..
+9 -15
View File
@@ -10,27 +10,21 @@ 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
elif [ "$OS" = "Mac" ]; then
tar -cvzf "$(get_package_name)-builds-Mac-$ARCH.tar.gz" *.app
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=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")"
else
echo "Invalid OS: $OS"
fi
+1 -8
View File
@@ -5,14 +5,7 @@ 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
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
else
+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
-169
View File
@@ -1,169 +0,0 @@
# Retrives a log of commit messages and attempts to pretty them into a human-readbile format
import argparse
import os
import re
import requests
import sys
from datetime import datetime
from subprocess import check_output
MAX_PAGES = 100 # maximum number of PR pages to go through
warnings = 0
def get_last_page(response: requests.Response) -> int:
"""
@brief Extract the last page number from the response header
@param[in] response The response from a GET call
@returns The page number of the last page, or MAX_PAGES
"""
# The link header is a dictionary in string form, and for that matter the
# value is in front of the key. It is of the form '<<url1>>; rel=<key1>, <url2>, <key2>'
link = response.headers['link']
link = link.split(',')
for x in link:
y = x.split(';') # <url>; rel=<key>
if "last" not in y[1]: # look for rel='last'
continue
# grab the page number from the URL
# group(0) is `page=123`, group(1) is `123`
last_page = int( re.search(r'page=(\d+)', y[0]).group(1) )
if not last_page:
print("Error: Could not find page number in url! URL: %s", y[0])
sys.exit(1)
if last_page > MAX_PAGES:
return MAX_PAGES
else:
return last_page
def main():
parser = argparse.ArgumentParser(description="Retrieves a log of commit messages and attempts to pretty them into a human-readable format")
parser.add_argument("start_date",
help="Day of the earliest commit to add to the log.")
parser.add_argument("-u", "--user", nargs=2, metavar=("NAME", "TOKEN"), default=["", ""],
help="Github username and token/password")
args = parser.parse_args()
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
start_date = datetime.strptime(args.start_date, "%Y-%m-%d")
print("start_date: {}".format(start_date))
# Retrive the git log for master, since start date, order by date, in ascending order, use YYYY-MM-DD date format,
# each line is of the form "<author short date> | <message>", only grab commits from master,
# output to `fsofordigest.txt`,
# check_output(("git log master", "--after=2021-09-15", "--date-order", "--reverse", "--date=short",
# "--pretty=\"%as | %s\"", "--first-parent",
# "--output fsofordigest.txt"), text=True)
# The commit messages are either of the form "<body> (#<PR_number>)" or "Merge pull request #<PR_number> from <source_repo>"
# For our purposes, we want them be all of the form "<body> (#<PR_number>)"
# Typically, the second form does not have a usable body, so we'll have to pull the PR title from github
# Github's REST API allows us to retrieve PR's, but due to it being HTTP requests it has to page in the data.
# We can loop over the GET request and check for a merge date.
# The GET request doesn't have sorting by merge date, but does have sorting by the last time it was updated... which is usually
# also the merge date but not always.
# Key attributes within the PR JSON objects:
# "merged_at: <date>" # Date the PR was merged in
# "merged: <bool>" # If the PR was merged yet
# "html_url: <string>" # URL of the PR's HEAD commit, used by some clients to pull in the PR branch
# "number: <int>" # The PR id number
# "title: <string>" # Title of the PR
# "body: <string>" # The body paragraph detailing the PR
# "labels: [label_object]" # All labels attached to this PR
changelog = {}
url = "https://api.github.com/repos/scp-fs2open/fs2open.github.com/pulls"
page = 1
last_page = MAX_PAGES
while page <= last_page:
# GET <url>?base=master&sort=updated&direction=desc&state=closed&page=1
response = requests.get(url,
auth=(args.user[0], args.user[1]),
params={
"base": "master",
"direction": "desc",
"page": page,
"state": "closed",
"sort": "updated"
})
# Check if good response
if (response.status_code != 200) :
print("Error: ", response.status_code)
print(response.json()['message'])
sys.exit(1)
else:
print("Request successful: 200")
print("page={}".format(page))
# Update the last_page index at first iteration and possibly last iteration
# This should cover the edge case of a new PR being added to the database before this script is finished
if (page == 1) or (page == last_page):
last_page = get_last_page(response)
print("last_page={}".format(last_page))
# assume pulls are organized from newest to oldest
for pull in response.json():
if (pull['state'] != 'closed'):
# This pull is not merged, so ignore
print("Found irrelevant pull, skipping...")
print("state: {}; number: {}".format(pull['state'], pull['number']))
continue
if (pull['merged_at'] == None):
# This pull wasn't merged, skip
print("Found closed pull #{} ({}), skipping...".format(pull['number'], pull['closed_at']))
continue
merge_date = datetime.strptime(pull['merged_at'], "%Y-%m-%dT%H:%M:%SZ")
updated_date = datetime.strptime(pull['updated_at'], "%Y-%m-%dT%H:%M:%SZ")
if (merge_date < start_date) and (updated_date >= start_date):
# This pull is too old, but was updated within our timeframe. skip
print("Found old pull #{} ({}), skipping...".format(pull['number'], pull['merged_at']))
continue
if (updated_date < start_date):
# This pull is too old
print("Found old pull #{} ({}), stopping loop...".format(pull['number'], pull['updated_at']))
page = last_page + 1
break
# Add the pull to the changelog, indexed by its pull.number
if pull['number'] not in changelog:
# only add if the key isn't there already
changelog[pull['number']] = {
"date": merge_date,
"title": pull['title'],
"labels": pull['labels'],
"url": pull['html_url']
}
print("Added pull #{} ({})".format(pull['number'], merge_date))
# Else, silently ignore duplicate (for now...)
page += 1 # iterate to next page
# Write the changelog to file
# 2021-09-28 | (#3661) Fix homing child weapons in niche circumstances
print("Writing to change.log...")
str = ''
for key, value in changelog.items():
str += "{} | (#{}) {} \n".format(value['date'].strftime("%Y-%m-%d"), key, value['title'])
with open("change.log", "w") as file:
file.write(str)
print("Done!")
main()
+4 -42
View File
@@ -8,27 +8,12 @@ from file_list import ReleaseFile
class ForumAPI:
POST_SIZE_MAX = 50000
"""!
Maximum number of characters allowed in a post, including BBCode (03/17/2022)
Check with HLP admins occasionally to verify this limit, they can set it in the forum's admin panel
"""
def __init__(self, config):
self.config = config
def create_post(self, title, content, board):
"""!
@brief Create a post on the forums
@param[in] title Title of the post
@param[in] content Body of the post
@param[in] board Which board/forum to post to
@returns { "thread_url": <url_of_created_thread> }
"""
print(self.config["hlp"]["api"])
print(self.config["hlp"]["key"])
if (self.config["hlp"]["api"] == "") or (self.config["hlp"]["key"] == ""):
print("Post failed! No API or API_KEY given!")
return
@@ -40,21 +25,10 @@ class ForumAPI:
"body": content
})
if resp.status_code != 200:
if resp.text != "OK":
print("Post failed! Response: %s" %resp.text)
return resp.json()
def post_nightly(self, date, revision, files, log, success):
"""!
@brief Post a new Nightly topic on the forums using nightly.mako
@param[in] date The date to use
@param[in] version The build's version
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
@param[in] sources URL's of builds on github or fs2net
"""
print("Posting nightly thread...")
title = "Nightly: {} - Revision {}".format(date, revision)
@@ -72,17 +46,6 @@ class ForumAPI:
self.create_post(title, rendered, self.config["nightly"]["hlp_board"])
def post_release(self, date, version: semantic_version.Version, groups, sources):
"""!
@brief Post a new Release topic on the forums using release.mako.
@param[in] date The date to use
@param[in] version The build's version
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
@param[in] sources URL's of builds on github or fs2net
@returns If Successful, the URL of the created post
"""
print("Posting release thread...")
title = "Release: {}".format(version)
@@ -99,5 +62,4 @@ class ForumAPI:
print("Creating post...")
json = self.create_post(title, rendered, self.config["release"]["hlp_board"])
return json["thread_url"]
self.create_post(title, rendered, self.config["release"]["hlp_board"])
-85
View File
@@ -1,85 +0,0 @@
# Class for use with interfacing with github via HTTP requests
import requests
from util import retry_multi, GLOBAL_TIMEOUT
class GithubAPI:
headers = {
"Accept": "application/vnd.github.v3+json"
}
url_root = "https://api.github.com"
def __init__(self, config):
self.config = config
@retry_multi(5)
def get(self, path):
"""!
@brief Performs a GET request with the given path. To be used with Github's REST API.
@returns If successful, returns a .JSON object
"""
url = self.url_root + path
# GET https://api.github.com/<path> Accept: "application/vnd.github.v3+json"
response = requests.get(url, headers=self.headers, timeout=GLOBAL_TIMEOUT)
response.raise_for_status() # Raise a RequestException if we failed, and trigger retry
return response.json()
def get_release(self, tag_name):
"""!
@brief Retrieves the Github Release metadata as a JSON object
@see https://docs.github.com/en/rest/reference/releases#get-a-release-by-tag-name
"""
return self.get("/repos/{}/releases/tags/{}".format(self.config["github"]["repo"], tag_name))
def patch(self, path, data):
"""!
@brief Performs a PATCH request with the given path and body data (as dictionary)
@returns If successful, returns a .JSON object
"""
url = self.url_root + path
response = requests.patch(url, headers=self.headers, timeout=GLOBAL_TIMEOUT, data=data)
response.raise_for_status()
return response.json()
def update_release(self, release_id, tag_name="", name="", body="", draft=None, prerelease=None):
"""!
@brief Updates a Github Release
@param[in] release_id The id of the release, as obtained by get_release()
@param[in] tag_name (optional) The git tag this release is associated with
@param[in] name (optional) The name of the release
@param[in] body (optional) Body text describing the release
@param[in] draft (optional) If true, the release is marked as a "draft"
@param[in] prerelease (optional) If true, the release is marked as a "prerelease"
@note If an optional argument is not provided, then its associated data is not changed
"""
path = "/repos/{}/releases/{}".format(self.config["github"]["repo"], release_id)
# Add to the data JSON if options are specified
data = {}
if tag_name != "":
data["tag_name"] = tag_name
if name != "":
data["name"] = name
if body != "":
data["body"] = body
if draft != None:
data["draft"] = data
if prerelease != None:
data["prerelease"] = prerelease
self.patch(path, data)
+44 -93
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
@@ -38,11 +38,9 @@ import nebula
import forum
# Compile regexes for extracting version components
MAJOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_BUILD (\d+)\)")
REVISION_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION (\d+)\)")
REVISION_STR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION_STR (\w*)\)")
MAJOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_BUILD (\d+)\)")
LOG_FORMAT = """
------------------------------------------------------------------------%n
@@ -62,64 +60,45 @@ def _match_version_number(text, regex):
"""
match = regex.search(text)
return int(match.group(1))
def _match_version_str(text, regex):
"""! Extracts the version component represented by `regex` from `text`
@param [in] `text` Filename with version string 'MAJOR.MINOR.BUILD'
@param [in] `regex` Regex pattern of component to look for
@return The version component as integer
"""
match = regex.search(text)
return match.group(1)
def get_source_version(date_version: datetime, tag_name: str) -> semantic_version.Version:
"""! Retrieves the version string from version_override.cmake (and version.cmake)
"""! Retrieves the build's version from `version.cmake`, forms it as a string, and appends the date
@param[in] `date_version` Date this build is published for release
@param[in] `tag_name` Tag of this release, used to determine if release, rc, or nightly
@return If release: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD`
@return If rc: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR`
@return If nightly: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR` (uses both version_override.cmake and version.cmake)
@note This is the version used to identify in Nebula and the forums. version_override.cmake is used for the builds
made by CI tools and version.cmake is used for builds made by devs.
@return If release: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from version.cmake, or
@return If rc: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from tag_name, or
@return If nightly: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION-date` from version.cmake
"""
with open(os.path.join("..", "..", "version_override.cmake"), "r") as f:
major = minor = build = version = 0
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
filetext = f.read()
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
# revision = _match_version_number(filetext, REVISION_VERSION_PATTERN)
revision_str = _match_version_str(filetext, REVISION_STR_VERSION_PATTERN)
print("Parsing version_override.cmake...")
if "rc" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
# Release candidates idenfity with their unstable version (ex: 21.5.0-03052022) within the game and the logs, but
# the builds are named with the target release version (ex: 22.0.0). Since this script works on the builds we
# need to grab the target release version from tag_name
x = tag_name.upper().split("_")
# "release" = x[0], year = x[1], major = x[2], minor = x[3], build = x[4],
version = semantic_version.Version("{}.{}.{}-{}".format(x[1], x[2], x[3], x[4]))
elif "release" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}".format(major, minor, build))
elif "nightly" in tag_name.lower():
# Nightly's version_override.cmake only has FSO_VERSION_REVISION and FSO_VERSION_REVISION_STR set
# So, we have to pull the rest of the version string from version.cmake
print("Parsing version.cmake...")
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, date_version))
else:
print(" ERROR: malformed tag_name %s" % tag_name)
print("ERROR: malformed tag_name %s" % tag_name)
sys.exit(1)
print(" version: {}".format(version))
print(" version.prerelease: {}".format(version.prerelease))
print("version: {}".format(version))
print("version.prerelease: {}".format(version.prerelease))
return version
@@ -137,8 +116,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": {
@@ -166,43 +145,17 @@ def main():
print("ERROR: Invalid release mode %s passed. Expected release or nightly!" % sys.argv[1])
sys.exit(1)
linux_success = os.environ["LINUX_RESULT"] == "success"
windows_success = os.environ["WINDOWS_RESULT"] == "success"
if (sys.argv[1] == "release"):
if not (linux_success and windows_success):
# bail if this is a release and either build workflow failed
print("ERROR: One or more builds failed to publish! Cannot post release.")
sys.exit(1)
else:
if not (linux_success or windows_success):
# bail if this is a nightly build and both build workflows failed
print("ERROR: All builds failed to publish! Cannot post nightly.")
sys.exit(1)
# bail if tag_name doesn't match with sys.argv[1]
tag_name = os.environ["RELEASE_TAG"] ##!< commit tag string
if (sys.argv[1] == "release") and (not tag_name.startswith("release_")):
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
if (sys.argv[1] == "nightly") and (not tag_name.startswith("nightly_")):
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
# bail if tag_name does not exist in the repo
if not check_output(("git", "show-ref", "--tags", "refs/tags/%s" % tag_name), text=True):
print("ERROR: Couldn't find tag %s in repo (git show-ref)!" % tag_name)
sys.exit(1)
# Populate version and date
date = datetime.now() ##!< current date
version = get_source_version(date.strftime(DATEFORMAT_VERSION), tag_name) ##!< form full version string
# find the previous tag release (used by nightly)
success = os.environ["LINUX_RESULT"] == "success" and os.environ["WINDOWS_RESULT"] == "success" ##!< true if both linux and windows builds successful
# check that tag_name is actually in the git repo and find the previous tag release
tags = check_output(("git", "for-each-ref", "--sort=-taggerdate", "--format='%(tag)'", "refs/tags"), text=True).splitlines() # retrieve all tags in the repo by using git on the shell
# NOTE: check_output returns canonical string representation. use repr() on strings its being compared to
previous_tag = None
found = False
for tag in tags:
if found:
# Look for the "previous" tag with the same configuration ('release_' or 'nightly_')
@@ -216,20 +169,24 @@ def main():
if not found:
# couldn't find tag, bail
print("ERROR: Couldn't find tag %s in repo! (git for-each-ref)" % tag_name)
print("ERROR: Couldn't find tag %s in repo!" % tag_name)
sys.exit(1)
if (sys.argv[1] == "nightly") and (not previous_tag):
if not previous_tag:
# couldn't find previous tag, bail
print("ERROR: Could not find a previous tag for %s!" % tag_name)
sys.exit(1)
if sys.argv[1] == "release":
# Release specific action
print("Retrieving file list...")
if not tag_name.startswith("release_"):
# Safety check tag is from a release
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
files, sources = file_list.get_release_files(tag_name, config)
print("Hashing files...")
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
@@ -260,36 +217,35 @@ 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))
# Publish release builds to Nebula
print("Publishing to Nebula...")
nebula.submit_release(
nebula.render_nebula_release(version, "rc" if version.prerelease else "stable", files, config),
config)
# Publish forum post, using the release.mako template
print("Publishing to Hard-light.net...")
fapi = forum.ForumAPI(config)
fapi.post_release(date.strftime(DATEFORMAT_FORUM), version, groups, sources)
else:
# Dead for now, nightly publish is done elsewhere
# Nightly specific action
print("Retrieving file list...")
if not tag_name.startswith("nightly_"):
# safety check tag is from a nightly
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
print("Retrieving file list")
files = file_list.get_ftp_files("nightly", tag_name, config)
print("Hashing files...")
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
print("Publishing to Nebula...")
# Publish nightly builds to Nebula
nebula.submit_release(
nebula.render_nebula_release(version, "nightly", files, config),
config)
@@ -298,12 +254,7 @@ def main():
log = check_output(("git", "log", "%s^..%s^" % (previous_tag, tag_name), "--no-merges", "--stat", "--pretty=format:\"%s\"" % LOG_FORMAT.strip()))
# Publish forum post, using the nighty.mako template
print("Publishing to Hard-light.net...")
fapi = forum.ForumAPI(config)
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, (linux_success and windows_success))
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, success)
print("Done!")
if __name__ == "__main__":
main()
main()
+19 -30
View File
@@ -7,14 +7,6 @@ import requests
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"
WIN32_SSE2_KEY = "Win32-SSE2"
WIN64_SSE2_KEY = "Win64-SSE2"
WIN32_AVX_KEY = "Win32-AVX"
WIN64_AVX_KEY = "Win64-AVX"
metadata = {
'type': 'engine',
'title': 'FSO',
@@ -34,30 +26,28 @@ metadata = {
}
platforms = {
LINUX_KEY: 'linux',
MACOSX_X64_KEY: 'macosx',
MACOSX_ARM64_KEY: 'macosx',
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows',
WIN32_AVX_KEY: 'windows',
WIN64_AVX_KEY: 'windows'
'Linux': 'linux',
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows',
'Win32-AVX': 'windows',
'Win64-AVX': 'windows'
}
envs = {
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
MACOSX_X64_KEY: 'macosx && x86_64',
MACOSX_ARM64_KEY: 'macosx && arm64',
WIN32_SSE2_KEY: 'windows',
WIN64_SSE2_KEY: 'windows && x86_64',
WIN32_AVX_KEY: 'windows && avx',
WIN64_AVX_KEY: 'windows && avx && x86_64'
'Linux': 'linux && x86_64', # Linux only has 64bit builds
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows && x86_64',
'Win32-AVX': 'windows && avx',
'Win64-AVX': 'windows && avx && x86_64'
}
subdirs = {
WIN32_SSE2_KEY: 'x86',
WIN64_SSE2_KEY: 'x64',
WIN32_AVX_KEY: 'x86_avx',
WIN64_AVX_KEY: 'x64_avx'
'Win32-SSE2': 'x86',
'Win64-SSE2': 'x64',
'Win32-AVX': 'x86_avx',
'Win64-AVX': 'x64_avx'
}
@@ -113,7 +103,7 @@ def render_nebula_release(version, stability, files, config):
'filename': dest_fn
})
if group == LINUX_KEY and fn.endswith('.AppImage'):
if group == 'Linux' and fn.endswith('.AppImage'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
@@ -138,7 +128,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' and fn.startswith(os.path.basename(fn) + '.app/'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
@@ -151,8 +141,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,
+16 -24
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=97293.0]21.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=http://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
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]
Windows: [url=http://scp.fsmods.net/files/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=http://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
OS X: Soulstorm's [url=http://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=http://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=http://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)}
@@ -40,37 +40,29 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler.[/size]
[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!
[url=http://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://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)}
These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
These builds use a mechanism called [url=http://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
[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=http://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]
[li][url=https://github.com/scp-fs2open/fs2open.github.com/issues]Github issues[/url] and [url=https://github.com/scp-fs2open/fs2open.github.com/pulls]pending pull requests[/url][/li]
[li]See the list of [url=https://github.com/scp-fs2open/fs2open.github.com/projects/8]bugs ranked by priority[/url][/li]
[li]See the list of [url=http://scp.indiegames.us/mantis/search.php?project_id=1&status_id%5B%5D=10&status_id%5B%5D=20&status_id%5B%5D=30&status_id%5B%5D=40&status_id%5B%5D=50&priority_id%5B%5D=40&priority_id%5B%5D=50&priority_id%5B%5D=60&sticky_issues=on&sortby=last_updated&dir=DESC&per_page=200&hide_status_id=-2]Fix for next release[/url] bugs - mark a bug as an elevated priority (high, urgent, immediate) to get it included in that filter.[/li]
[/list]
+2 -2
View File
@@ -1,3 +1,3 @@
Mako==1.2.2
requests==2.31.0
Mako==1.1.5
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=ON ..
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
-16
View File
@@ -1,16 +0,0 @@
buildType:
default: release
description: R
choices:
release:
short: Release
long: Release builds
buildType: Release
fastDebug:
short: FastDebug
long: Debug with optimizations
buildType: FastDebug
debug:
short: Debug
long: Debug without optimizations
buildType: Debug
+1 -1
View File
@@ -8,7 +8,7 @@ if(DOXYGEN_FOUND)
FILE(TO_NATIVE_PATH ${OUTPUT_DIR} OUTPUT_DIR)
SET(OUTPUT_DIR \"${OUTPUT_DIR}\")
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2" "${CMAKE_CURRENT_SOURCE_DIR}/qtfred")
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2")
SET(INPUT_DIRS)
FOREACH(DIR IN LISTS INPUTS)
-2
View File
@@ -9,8 +9,6 @@ if (WIN32)
if (NOT HAVE_SAPI_H)
message(SEND_ERROR "sapi.h could not be found on your platform. Please disable speech support.")
endif()
elseif(APPLE)
# it should just work
else()
message(SEND_ERROR "Text to Speech is not supported on this platform!")
endif()
-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
@@ -10,7 +10,6 @@ SET(WIN32_LIBS
winmm
ws2_32
psapi
shlwapi
)
IF (MINGW)
-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 0)
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 -39
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)
@@ -71,25 +68,6 @@ target_link_libraries(code PUBLIC variant)
target_link_libraries(code PUBLIC any)
target_link_libraries(code PUBLIC optional)
target_link_libraries(code PUBLIC anl)
target_link_libraries(code PUBLIC hidapi::hidapi)
target_link_libraries(code PUBLIC imgui)
IF(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 +90,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)
@@ -137,6 +106,3 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYM
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
suppress_file_warnings(scripting/lua/bitop/bit.c)
+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;
}
+1 -1
View File
@@ -18,7 +18,7 @@ struct ProgramLocals {
matrix localOrient = vmd_identity_matrix;
int hostSubobject = -1;
TIMESTAMP waitTimestamp = TIMESTAMP::invalid();
int waitTimestamp = 0;
expression::ProgramVariables variables;
};
+2 -2
View File
@@ -1,11 +1,11 @@
#pragma once
#include "actions/expression/nodes/AbstractExpression.h"
#include "globalincs/pstypes.h"
#include "ParseContext.h"
#include "actions/expression/nodes/AbstractExpression.h"
namespace actions {
namespace expression {
@@ -1,11 +1,11 @@
#pragma once
#include <Parser.h>
#include <Token.h>
#include "actions/expression/ParseContext.h"
#include "actions/expression/Value.h"
#include <Parser.h>
#include <Token.h>
namespace actions {
namespace expression {
namespace nodes {
+3 -3
View File
@@ -20,7 +20,7 @@ WaitAction::~WaitAction() = default;
ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
{
if (!locals.waitTimestamp.isValid()) {
if (!timestamp_valid(locals.waitTimestamp)) {
auto waitTime = _waitTimeExpression.execute(locals.variables);
// Catch errors in the expression
@@ -28,7 +28,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
waitTime = 0.001f;
}
locals.waitTimestamp = _timestamp(fl2i(waitTime * MILLISECONDS_PER_SECOND));
locals.waitTimestamp = timestamp(fl2i(waitTime * TIMESTAMP_FREQUENCY));
}
if (!timestamp_elapsed(locals.waitTimestamp)) {
// Wait until the timestamp is elapsed
@@ -36,7 +36,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
}
// Timestamp is elapsed. The timestamp is elapsed so that timestamp_valid above returns false for the next wait
// action
locals.waitTimestamp = TIMESTAMP::invalid();
locals.waitTimestamp = 0;
return ActionResult::Finished;
}
std::unique_ptr<Action> WaitAction::clone() const
+28
View File
@@ -52,6 +52,34 @@ void ai_free_slot(int ai_index)
Ai_info[ai_index].shipnum = -1;
}
int get_wingnum(int objnum)
{
int shipnum, ai_index;
shipnum = Objects[objnum].instance;
ai_index = Ships[shipnum].ai_index;
return Ai_info[ai_index].wing;
}
void set_wingnum(int objnum, int wingnum)
{
int shipnum, ai_index;
Assert(Objects[objnum].type == OBJ_SHIP);
shipnum = Objects[objnum].instance;
Assert((shipnum >= 0) && (shipnum < MAX_SHIPS));
ai_index = Ships[shipnum].ai_index;
Assert( (ai_index >= 0) && (ai_index < MAX_AI_INFO) );
Ai_info[ai_index].wing = wingnum;
}
const char *ai_get_goal_target_name(const char *name, int *index)
{
Assertion(name != nullptr && index != nullptr, "Arguments cannot be null!");
+82 -47
View File
@@ -12,13 +12,11 @@
#ifndef _AI_H
#define _AI_H
#include "ai/aigoals.h"
#include "ai/ai_profiles.h"
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "object/waypoint.h"
#include "parse/sexp.h"
#include "physics/physics.h"
#include "ship/ship_flags.h"
@@ -34,14 +32,8 @@ 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;
#define MAX_AI_FLAG_NAMES 2
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.
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
@@ -56,19 +48,66 @@ 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
#define MAX_AI_GOALS 5
// types of ai goals -- tyese types will help us to determination on which goals should
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
// goal to a ship in that wing). We would probably use this type in conjunction with
// goal priority to establish which goal to follow
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
#define AIG_TYPE_DYNAMIC 5 // created on the fly
// 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
#define AITTV_IGNORE_BANK (1<<2) // Goober5000 - ignore bank when turning
#define AITTV_SLOW_BANK_ACCEL (1<<3) // Asteroth - used by formation flying
#define AITTV_FORCE_DELTA_BANK (1<<4) // Lafiel - Always use the provided delta bank and override calculated values
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
// individual AI modes aka AI behaviors
// structure for AI goals
typedef struct ai_goal {
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
int ai_mode; // one of the AIM_* modes for this goal
int ai_submode; // maybe need a submode
int type; // one of the AIG_TYPE_* values above
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
fix time; // time at which this goal was issued.
int priority; // how important is this goal -- number 0 - 100
const char *target_name; // name of the thing that this goal acts upon
int target_name_index; // index of goal_target_name in Goal_target_names[][]
waypoint_list *wp_list; // waypoints that this ship might fly.
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
// unions for docking stuff.
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
union {
const char *name;
int index;
} docker;
union {
const char *name;
int index;
} dockee;
} ai_goal;
#define AIM_CHASE 0
#define AIM_EVADE 1
#define AIM_GET_BEHIND 2 // This mode is not actually implemented.
#define AIM_GET_BEHIND 2
#define AIM_STAY_NEAR 3 // Stay near another ship.
#define AIM_STILL 4 // Sit still. Don't move. Hold your breath. Don't blink.
#define AIM_GUARD 5 // Guard an object
@@ -87,15 +126,15 @@ 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_LUA 22 // Generic Lua-based AI mode
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
#define MAX_AI_BEHAVIORS 22 // Number of AIM_xxxx types
#define MAX_WAYPOINTS_PER_LIST 20
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
#define MAX_AI_GOALS 5
#define AI_GOAL_NONE -1
#define AI_ACTIVE_GOAL_DYNAMIC 999
typedef struct ai_class {
@@ -180,12 +219,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
@@ -234,12 +267,13 @@ extern pnode *Ppfp; // Free pointer in path points.
// Goober5000 (based on the "you can only remember 7 things in short-term memory" assumption)
#define MAX_IGNORE_NEW_OBJECTS 7
#define AI_DYNAMIC_PATH_RECHECK_DELAY 1*1000
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 type; //
int wing; // Member of what wing? -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 +311,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,12 +341,8 @@ 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
vec3d last_dynamic_path_goal; //ETP: Remebers last target location in ai_new_maybe_reposition_attack_subsys
//SUSHI: like last_predicted_enemy_pos, but for aiming (which currently ignores predicted position)
//Unlike the predicted position stuff, also takes into account velocity
//Only used against small ships
@@ -373,6 +403,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
@@ -458,13 +493,8 @@ typedef struct ai_info {
int multilock_check_timestamp; // when to check for multilock next
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
ai_lua_parameters lua_ai_target;
} ai_info;
int ai_maybe_autoscale(int absolute_index = -1);
int ai_get_autoscale_index(int absolute_index = -1);
// Goober5000
typedef struct {
vec3d docker_point;
@@ -489,6 +519,11 @@ typedef struct {
extern int Mission_all_attack; // !0 means all teams attack all teams.
extern void update_ai_info_for_hit(int hitter_obj, int hit_obj);
extern void ai_frame_all(void);
extern int find_guard_obj(void);
extern ai_info Ai_info[];
extern ai_info *Player_ai;
@@ -499,8 +534,7 @@ extern int Num_ai_classes;
extern int Ai_firing_enabled;
extern const char *Skill_level_names(int skill_level, int translate = 1);
extern control_info AI_ci;
extern int Ai_goal_signature;
// need access to following data in AiBig.cpp
extern object *Pl_objp;
@@ -522,6 +556,9 @@ void ai_object_init(object * obj, int ai_index);
// Called once a frame
void ai_process( object * obj, int ai_index, float frametime );
int get_wingnum(int objnum);
void set_wingnum(int objnum, int wingnum);
const char *ai_get_goal_target_name(const char *name, int *index);
void ai_clear_goal_target_names();
@@ -533,11 +570,10 @@ 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 +596,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 +625,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 +654,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);
@@ -633,7 +671,4 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
#endif
+4 -20
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,
@@ -147,19 +144,6 @@ namespace AI {
Fighterbay_departures_use_carrier_orient,
Prevent_negative_turret_ammo,
Fix_keep_safe_distance,
Ignore_aspect_when_leading,
Fix_good_rearm_time_bug,
No_continuous_turn_on_attack,
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 -68
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);
@@ -605,31 +598,6 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$fix keep-safe-distance:", AI::Profile_Flags::Fix_keep_safe_distance);
set_flag(profile, "$AI ignores aspect lock for leading:", AI::Profile_Flags::Ignore_aspect_when_leading);
set_flag(profile, "$fix good-rearm-time bug:", AI::Profile_Flags::Fix_good_rearm_time_bug);
set_flag(profile, "$no continuous turn on attack:", AI::Profile_Flags::No_continuous_turn_on_attack);
set_flag(profile, "$remove-goal properly removes play-dead order:", AI::Profile_Flags::Fixed_removing_play_dead_order);
set_flag(profile, "$bay arrivals not time limited:", AI::Profile_Flags::Disable_bay_emerge_timeout);
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 +640,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 +699,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 +748,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 +758,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);
}
@@ -812,15 +766,4 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::Prevent_negative_turret_ammo);
flags.set(AI::Profile_Flags::Fix_keep_safe_distance);
}
if (mod_supports_version(23, 0, 0)) {
flags.set(AI::Profile_Flags::Fix_good_rearm_time_bug);
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 -2
View File
@@ -21,7 +21,7 @@
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
#define MAX_AI_PROFILES 8
#define MAX_AI_PROFILES 5
class ai_profile_t {
public:
@@ -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
+136 -161
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,80 +549,72 @@ 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 tgt2pl = Pl_objp->pos - target_objp->pos;
vec3d tgt2subsys = gsubpos - target_objp->pos;
float pl_dist = vm_vec_mag(&tgt2pl);
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
float angle2goal = angle2subsys;
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
angle2goal = 1.2f;
// we'll start by travelling along the sphere at our current distance around the ship
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
vec3d goal_pos, cross;
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
vm_vec_normalize(&cross);
vm_vec_negate(&cross);
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;
// 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;
vec3d tgt2subsys = gsubpos - target_objp->pos;
float pl_dist = vm_vec_mag(&tgt2pl);
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
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;
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
float angle2goal = angle2subsys;
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
angle2goal = 1.2f;
// we'll start by travelling along the sphere at our current distance around the ship
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
vec3d goal_pos, cross;
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
vm_vec_normalize(&cross);
vm_vec_negate(&cross);
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
// then scale in (or out) towards our subsys
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;
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
// ok best case won't work
if (pl_dist > subsys_dist) {
//we're farther away than the subsys, let's try at our current distance
world_goal_pos = goal_pos + target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// ok, let's start moving it away and see if that's better
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
if (good_pos)
break;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
world_goal_pos += target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// welp this sucks, just run away i guess
if (!good_pos) {
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
world_goal_pos *= target_objp->radius + pl_dist;
world_goal_pos += target_objp->pos;
vec3d* good_pos = nullptr;
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
// ok best case won't work
if (pl_dist > subsys_dist) {
//we're farther away than the subsys, let's try at our current distance
world_goal_pos = goal_pos + target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
}
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;
// ok, let's start moving it away and see if that's better
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
if (good_pos)
break;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
world_goal_pos += target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// welp this sucks, just run away i guess
if (!good_pos) {
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
world_goal_pos *= target_objp->radius + pl_dist;
world_goal_pos += target_objp->pos;
good_pos = &world_goal_pos;
}
}
else{ //Not enough time has passed till recheck.
good_pos = &aip->last_dynamic_path_goal;
}
else
good_pos = &world_goal_pos;
ai_turn_towards_vector(good_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
float subsys_distance = vm_vec_dist(&Pl_objp->pos, &gsubpos);
@@ -617,17 +623,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;
}
@@ -649,17 +653,16 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
// are near
if ( sip->is_small_ship() ) {
if ( timestamp_elapsed(aip->scan_for_enemy_timestamp) ) {
ship_obj *so;
object *test_objp;
ship *test_sp;
float dist_squared;
aip->scan_for_enemy_timestamp = timestamp(SCAN_FIGHTERS_INTERVAL);
// iterate through ships, and see if any fighter/bomber from opposite team are near
for (auto so: list_range(&Ship_obj_list)) {
so = GET_FIRST(&Ship_obj_list);
while( so != END_OF_LIST(&Ship_obj_list) ) {
test_objp = &Objects[so->objnum];
if (test_objp->flags[Object::Object_Flags::Should_be_dead])
continue;
test_sp = &Ships[test_objp->instance];
if ( iff_x_attacks_y(Ships[Pl_objp->instance].team, test_sp->team) ) {
@@ -670,6 +673,7 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
}
}
}
so = GET_NEXT(so);
}
}
}
@@ -694,9 +698,6 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
if (Pl_objp->phys_info.speed < 3.0f) {
object *objp;
for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
if (objp->flags[Object::Object_Flags::Should_be_dead])
continue;
if ((objp->type == OBJ_WEAPON) && (iff_x_attacks_y(Ships[Pl_objp->instance].team, Weapons[objp->instance].team)))
if (Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_LASER) {
vec3d in_vec;
@@ -747,7 +748,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 +840,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;
@@ -860,9 +859,9 @@ void ai_big_chase_ct()
ai_chase_ct();
}
extern bool ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
extern void ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst);
extern bool ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time, float time_scale = 1.f);
extern void maybe_cheat_fire_synaptic(object *objp);
@@ -893,7 +892,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
// Chance of hitting ship is based on dot product of firing ship's forward vector with vector to ship
// and also the size of the target relative to distance to target.
if (dot_to_enemy > std::max(0.5f, 0.90f + aip->ai_accuracy / 10.0f - En_objp->radius / std::max(1.0f, dist_to_enemy))) {
if (dot_to_enemy > MAX(0.5f, 0.90f + aip->ai_accuracy/10.0f - En_objp->radius/MAX(1.0f,dist_to_enemy))) {
ship *temp_shipp;
temp_shipp = &Ships[Pl_objp->instance];
@@ -913,13 +912,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))) {
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
int current_bank = tswp->current_secondary_bank;
if (current_bank > -1 && valid_secondary) {
if (current_bank > -1) {
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]) {
@@ -1012,8 +1011,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
aip->submode_start_time = Missiontime;
}
extern weapon_info* ai_get_weapon(ship_weapon* swp);
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
void ai_big_chase()
{
@@ -1033,38 +1030,16 @@ void ai_big_chase()
player_pos = Pl_objp->pos;
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 valid_ballistic_trajectory = true;
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
if (En_objp->phys_info.speed > 3.0f) {
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
vm_vec_sub2(&enemy_pos, &En_objp->pos);
} else
predicted_enemy_pos = En_objp->pos;
if (!ballistic_aiming) {
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
if (En_objp->phys_info.speed > 3.0f) {
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
vm_vec_sub2(&enemy_pos, &En_objp->pos);
} else
predicted_enemy_pos = En_objp->pos;
if (aip->targeted_subsys != NULL) {
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
}
} else {
if (aip->targeted_subsys != NULL) {
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
}
vec3d gravity = The_mission.gravity * wip->gravity_const;
vec3d target;
valid_ballistic_trajectory =
physics_lead_ballistic_trajectory(&player_pos, &enemy_pos, &En_objp->phys_info.vel, wip->max_speed, &gravity, &target);
if (valid_ballistic_trajectory) {
enemy_pos = Pl_objp->pos + target * vm_vec_dist(&Pl_objp->pos, &enemy_pos);
predicted_enemy_pos = enemy_pos;
} else {
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
}
if (aip->targeted_subsys != NULL) {
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
}
dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
@@ -1095,7 +1070,7 @@ void ai_big_chase()
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
} else if (aip->targeted_subsys != NULL && !ballistic_aiming) {
} else if (aip->targeted_subsys != NULL) {
Assert(aip->targeted_subsys != NULL);
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
@@ -1127,7 +1102,7 @@ void ai_big_chase()
}
}
if (!aip->ai_profile_flags[AI::Profile_Flags::No_continuous_turn_on_attack] && aip->target_time < 2.0f)
if (aip->target_time < 2.0f)
if ((dot_to_enemy < 0.9f) || (dist_to_enemy > 300.0f)) {
aip->submode = SM_CONTINUOUS_TURN;
aip->submode_start_time = Missiontime - fl2f(2.75f); // This backdated start time allows immediate switchout.
@@ -1335,7 +1310,7 @@ void ai_big_chase()
// I noticed AI ships firing inappropriately when following a path near a big ship.
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
// a big ship
if (aip->mode != AIM_EVADE && aip->path_start == -1 && (!ballistic_aiming || valid_ballistic_trajectory)) {
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
} else {
if (flFrametime < 1.0f)
@@ -1841,7 +1816,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()
+949 -1487
View File
File diff suppressed because it is too large. Load diff
+339 -496
View File
File diff suppressed because it is too large. Load diff
+10 -78
View File
@@ -12,30 +12,15 @@
#ifndef _AIGOALS_H
#define _AIGOALS_H
#include "ai/ai_flags.h"
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
#include "parse/sexp.h"
#include "scripting/lua/LuaTypes.h"
#include "scripting/lua/LuaValue.h"
struct wing;
struct ai_info;
struct ai_goal;
// macros for goals which get set via sexpressions in the mission code
// types of ai goals -- tyese types will help us to determination on which goals should
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
// goal to a ship in that wing). We would probably use this type in conjunction with
// goal priority to establish which goal to follow
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
#define AIG_TYPE_DYNAMIC 5 // created on the fly
#define AI_GOAL_NONE -1
// IMPORTANT! If you add a new AI_GOAL_x define, be sure to update the functions
// ai_update_goal_references() and query_referenced_in_ai_goals() or else risk breaking
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
@@ -73,17 +58,14 @@ 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
// 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 )
@@ -100,53 +82,6 @@ struct ai_info;
#define MAX_AI_DOCK_NAMES 25
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
struct ai_lua_parameters {
object_ship_wing_point_team target;
luacpp::LuaValueList arguments;
};
// structure for AI goals
typedef struct ai_goal {
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
int ai_mode; // one of the AIM_* modes for this goal
int ai_submode; // maybe need a submode
int type; // one of the AIG_TYPE_* values above
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
fix time; // time at which this goal was issued.
int priority; // how important is this goal -- number 0 - 100
const char *target_name; // name of the thing that this goal acts upon
int target_name_index; // index of goal_target_name in Goal_target_names[][]
waypoint_list *wp_list; // waypoints that this ship might fly.
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
// extra goal-specific data
int int_data;
float float_data;
// unions for docking stuff.
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
union {
const char *name;
int index;
} docker;
union {
const char *name;
int index;
} dockee;
ai_lua_parameters lua_ai_target;
} ai_goal;
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, int ai_mode = AI_GOAL_NONE, int ai_submode = -1, int type = -1);
typedef flag_def_list ai_goal_list;
extern ai_goal_list Ai_goal_names[];
@@ -155,10 +90,7 @@ extern int Num_ai_goals;
extern int Num_ai_dock_names;
extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
extern const char *Ai_goal_text(int goal, int submode);
// every goal in a mission gets a unique signature
extern int Ai_goal_signature;
extern const char *Ai_goal_text(int goal);
// extern function definitions
extern void ai_post_process_mission();
@@ -168,17 +100,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_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 );
extern void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum );
extern void ai_remove_ship_goal( ai_info *aip, int index );
extern void ai_clear_ship_goals( ai_info *aip );
@@ -189,8 +121,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
-414
View File
@@ -1,414 +0,0 @@
#include "ai/ailua.h"
#include "hud/hudsquadmsg.h"
#include "iff_defs/iff_defs.h"
#include "parse/sexp/sexp_lookup.h"
#include "parse/sexp/LuaAISEXP.h"
#include "scripting/api/objs/ai_helper.h"
#include "scripting/api/objs/enums.h"
#include "scripting/api/objs/oswpt.h"
#include "scripting/api/objs/ship.h"
#include "scripting/scripting.h"
static std::unordered_map<int, ai_mode_lua> Lua_ai_modes;
static std::unordered_map<int, player_order_lua> Lua_player_orders;
void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
Lua_ai_modes.emplace(sexp_op, 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.back().localize();
Lua_player_orders.emplace(sexp_op, std::move(order));
return true;
}
bool ai_lua_has_mode(int sexp_op){
return Lua_ai_modes.count(sexp_op) > 0;
}
const ai_mode_lua* ai_lua_find_mode(int sexp_op){
auto aiLuaMode = Lua_ai_modes.find(sexp_op);
if(aiLuaMode == Lua_ai_modes.end())
return nullptr;
else
return &aiLuaMode->second;
}
const player_order_lua* ai_lua_find_player_order(int sexp_op) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return nullptr;
else
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,
"Lua AI SEXP called without a valid action function! A script probably failed to set the action for some reason.");
return;
}
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())));
}
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
}
for (const auto& additionalParam : aip->lua_ai_target.arguments) {
luaParameters.push_back(additionalParam);
}
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);
}
}
}
}
void ai_lua(ai_info* aip){
Assertion(aip->mode == AIM_LUA, "Tried to invoke LuaAI on a ship not in LuaAI-Mode");
const auto& lua_ai = Lua_ai_modes.at(aip->submode);
const auto& lua_ai_sexp = lua_ai.sexp;
const auto& action = lua_ai_sexp.getAction();
run_ai_lua_action(action, lua_ai, aip);
}
void ai_lua_start(ai_goal* aigp, object* objp){
Assert(objp->type == OBJ_SHIP);
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
ai_info *aip = &Ai_info[Ships[objp->instance].ai_index];
aip->mode = AIM_LUA;
aip->submode = aigp->ai_submode;
aip->lua_ai_target = aigp->lua_ai_target;
aip->submode_start_time = Missiontime;
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
const auto& lua_ai_sexp = lua_ai.sexp;
const auto& action = lua_ai_sexp.getActionEnter();
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];
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
switch (order.targetRestrictions) {
case player_order_lua::target_restrictions::TARGET_ALL:
return true;
case player_order_lua::target_restrictions::TARGET_OWN:
return target->team == self->team;
case player_order_lua::target_restrictions::TARGET_ALLIES:
return !iff_x_attacks_y(self->team, target->team);
case player_order_lua::target_restrictions::TARGET_ENEMIES:
return iff_x_attacks_y(self->team, target->team);
case player_order_lua::target_restrictions::TARGET_SAME_WING:
return target->wingnum != -1 && self->wingnum == target->wingnum;
case player_order_lua::target_restrictions::TARGET_PLAYER_WING:
return target->wingnum != -1 && Ships[Player_obj->instance].wingnum == target->wingnum;
case player_order_lua::target_restrictions::TARGET_ALL_CAPS:
return Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_ALLIED_CAPS:
return !iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_ENEMY_CAPS:
return iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_NOT_SELF:
return self->objnum != target_objnum;
}
return false;
}
bool ai_lua_is_valid_target_lua(const ai_mode_lua& mode, int target_objnum, ship* self) {
const auto& action = mode.sexp.getTargetRestrict();
if (!action.isValid())
return true;
luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[self->objnum]))));
if (mode.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]))));
}
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
return retVals[0].getValue<bool>();
}
else {
Error(LOCATION, "LuaAI target restriction function did not return a valid boolean!");
}
return true;
}
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order) {
const ai_mode_lua& mode = *ai_lua_find_mode(sexp_op);
//All targetless AI modes are fine
if (mode.needsTarget) {
//No target is then not valid
if (target_objnum == -1)
return false;
//As of now, only accept ships
if (Objects[target_objnum].type != OBJ_SHIP)
return false;
if (!ai_lua_is_valid_target_intrinsic(sexp_op, target_objnum, self))
return false;
// check if this order can be issued against the target
ship *shipp = &Ships[Objects[target_objnum].instance];
if (shipp->orders_allowed_against.find(order) == shipp->orders_allowed_against.end()) {
return false;
}
}
//If we haven't bailed yet, query the custom callback
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);
const auto& action = lua_ai.sexp.getAchievable();
if (!action.isValid())
return ai_achievability::ACHIEVABLE;
luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[objnum]))));
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aigp->lua_ai_target.target)));
}
for (const auto& additionalParam : aigp->lua_ai_target.arguments) {
luaParameters.push_back(additionalParam);
}
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
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()) {
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
return ai_achievability::ACHIEVABLE;
}
switch (enumData.index) {
case scripting::api::LE_LUAAI_ACHIEVABLE:
return ai_achievability::ACHIEVABLE;
case scripting::api::LE_LUAAI_NOT_YET_ACHIEVABLE:
return ai_achievability::NOT_KNOWN;
case scripting::api::LE_LUAAI_UNACHIEVABLE:
return ai_achievability::NOT_ACHIEVABLE;
default:
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
return ai_achievability::ACHIEVABLE;
}
}
else {
Error(LOCATION, "LuaAI SEXP achievability hook did not return any avilability enum!");
}
return ai_achievability::ACHIEVABLE;
}
-49
View File
@@ -1,49 +0,0 @@
#pragma once
#include "ai/ai.h"
#include "ai/aigoals.h"
#include "mission/missionmessage.h"
#include "ship/ship.h"
#include "parse/sexp.h"
#include "globalincs/globals.h"
namespace sexp { class LuaAISEXP; }
struct ai_mode_lua {
const sexp::LuaAISEXP& sexp;
bool needsTarget;
const char* hudText;
};
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;
};
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);
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);
+278 -309
View File
File diff suppressed because it is too large. Load diff
+7 -2
View File
@@ -397,6 +397,8 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
t1 = timer_get_fixed_seconds();
for ( i = 0; i < frame_diff; i++ ) {
anim_check_for_palette_change(instance);
// if we're playing backwards, every frame must be a keyframe and we set the data ptr here
if(instance->direction == ANIM_DIRECT_REVERSE){
if ( anim_instance_is_streamed(instance) ) {
@@ -641,7 +643,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
if (diff != 0) {
if (ptr->height > 16) {
nprintf(("ANI","ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
mprintf(("ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
}
}
#endif
@@ -670,7 +672,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)
{
@@ -788,6 +790,9 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
cfclose(fp);
// store screen signature, so we can tell if palette changes
ptr->screen_sig = gr_screen.signature;
anim_set_palette(ptr);
}
+12 -3
View File
@@ -18,23 +18,30 @@
const int packer_code = PACKER_CODE;
const int transparent_code = 254;
void anim_check_for_palette_change(anim_instance *instance) {
if ( instance->parent->screen_sig != gr_screen.signature ) {
instance->parent->screen_sig = gr_screen.signature;
anim_set_palette(instance->parent);
}
}
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;
}
}
@@ -90,6 +97,8 @@ ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap
return NULL;
}
anim_check_for_palette_change(inst);
if ( anim_instance_is_streamed(inst) ) {
if ( xlate_pal ){
inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
+2
View File
@@ -58,6 +58,7 @@ typedef struct anim {
ubyte xparent_g; // green component for the transparent color in source image
ubyte xparent_b; // blue component for the transparent color in source image
int flags;
uint screen_sig;
int file_offset; // file offset to start of frame data
int cache_file_offset;
ubyte *cache;
@@ -104,6 +105,7 @@ anim_instance *init_anim_instance(anim *ptr, int bpp);
void free_anim_instance(anim_instance *inst);
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp);
void anim_set_palette(anim *a);
void anim_check_for_palette_change(anim_instance *inst);
#endif /* __PACKUNPACK_H__ */
+310 -782
View File
File diff suppressed because it is too large. Load diff
+28 -39
View File
@@ -14,29 +14,34 @@
#include "globalincs/globals.h" // for NAME_LENGTH
#include "globalincs/pstypes.h"
#include "io/timer.h"
class object;
class polymodel;
struct collision_info_struct;
class model_draw_list;
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
#define MAX_ASTEROIDS 512
#define NUM_ASTEROID_SIZES 3
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
#define NUM_DEBRIS_SIZES 3
#define NUM_DEBRIS_POFS 3 // Number of POFs per debris size
#define ASTEROID_TYPE_DEBRIS -1
#define ASTEROID_TYPE_SMALL 0
#define ASTEROID_TYPE_MEDIUM 1
#define ASTEROID_TYPE_LARGE 2
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
#define MAX_ACTIVE_DEBRIS_TYPES NUM_DEBRIS_SIZES
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
#define MAX_ASTEROID_DETAIL_LEVELS 5
// whether to do retail behavior, just throw at the first big ship in the field
// must be explicitly opted out of by the mission
extern bool Default_asteroid_throwing_behavior;
extern SCP_vector<SCP_string> Asteroid_target_ships;
// Data structure to track the active asteroids
typedef struct asteroid_obj {
asteroid_obj *next, *prev;
@@ -48,22 +53,19 @@ extern asteroid_obj Asteroid_obj_list;
// Data structure for determining a type and amount of other asteroids an
// asteroid will split to when destroyed.
typedef struct asteroid_split_info {
int asteroid_type; //index position
char name[NAME_LENGTH]; //asteroid name
int min; //minimum asteroids to spawn
int max; //maximum asteroids to spawn
int asteroid_type;
int min;
int max;
} asteroid_split_info;
class asteroid_info
{
public:
char name[NAME_LENGTH]; // name for the asteroid
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
char pof_files[NUM_DEBRIS_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
int num_detail_levels; // number of detail levels for this ship
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
float max_speed; // cap on speed for asteroid
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
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
@@ -72,30 +74,27 @@ public:
float blast; // maximum blast impulse from area effect explosion
float initial_asteroid_strength; // starting strength of asteroid
SCP_vector< asteroid_split_info > split_info;
polymodel *modelp[NUM_ASTEROID_POFS];
int model_num[NUM_ASTEROID_POFS];
polymodel *modelp[NUM_DEBRIS_POFS];
int model_num[NUM_DEBRIS_POFS];
SCP_vector<int> explosion_bitmap_anims;
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
float gravity_const; // multiplier for mission gravity
asteroid_info( )
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
rotational_vel_multiplier(1), damage_type_idx(0),
: 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 )
fireball_radius_multiplier( -1 )
{
name[ 0 ] = 0;
display_name = "";
memset( detail_distance, 0, sizeof( detail_distance ) );
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
for (int i = 0; i < NUM_DEBRIS_POFS; i++)
{
modelp[i] = NULL;
model_num[i] = -1;
pof_files[i][0] = '\0';
pof_files[i][0] = 0;
}
}
};
@@ -109,9 +108,9 @@ typedef struct asteroid {
int model_instance_num;
int asteroid_type; // 0..MAX_DEBRIS_TYPES
int asteroid_subtype; // Index in asteroid_info for modelnum and modelp
TIMESTAMP check_for_wrap; // timestamp to check for asteroid wrapping around field
TIMESTAMP check_for_collide; // timestamp to check for asteroid colliding with escort ships
TIMESTAMP final_death_time; // timestamp to swap in new models after explosion starts
int check_for_wrap; // timestamp to check for asteroid wrapping around field
int check_for_collide; // timestamp to check for asteroid colliding with escort ships
int final_death_time; // timestamp to swap in new models after explosion starts
int collide_objnum; // set to objnum that asteroid will be impacting soon
int collide_objsig; // object signature corresponding to collide_objnum
vec3d death_hit_pos; // hit pos that caused death
@@ -122,7 +121,7 @@ typedef struct asteroid {
// TYPEDEF FOR DEBRIS TYPE
typedef enum {
DG_ASTEROID,
DG_DEBRIS
DG_SHIP
} debris_genre_t;
// TYPEDEF FOR FIELD TYPE
@@ -135,7 +134,7 @@ typedef struct asteroid_field {
vec3d min_bound; // Minimum range of field.
vec3d max_bound; // Maximum range of field.
float bound_rad;
bool has_inner_bound;
int has_inner_bound;
vec3d inner_min_bound;
vec3d inner_max_bound;
vec3d vel; // Average asteroid moves at this velocity.
@@ -145,9 +144,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;
extern SCP_vector< asteroid_info > Asteroid_info;
@@ -161,28 +157,21 @@ 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_render(object* obj, model_draw_list* scene);
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);
// need to extern for multiplayer
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
+49 -72
View File
@@ -47,9 +47,10 @@ NavMessage NavMsgs[NP_NUM_MESSAGES];
int audio_handle;
int NavLinkDistance;
// time offsets for autonav events
TIMESTAMP LockAPConv;
TIMESTAMP EndAPCinematic;
TIMESTAMP MoveCamera;
int LockAPConv;
int EndAPCinematic;
int MoveCamera;
int camMovingTime;
//float CameraSpeed;
bool CinematicStarted, CameraMoving;
vec3d cameraPos, cameraTarget;
@@ -150,9 +151,6 @@ bool CanAutopilot(const vec3d *targetPos, bool send_msg)
for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
{
object *other_objp = &Objects[so->objnum];
if (other_objp->flags[Object::Object_Flags::Should_be_dead])
continue;
// attacks player?
if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
&& !(Ship_info[Ships[other_objp->instance].ship_info_index].flags[Ship::Info_Flags::Cargo])) // ignore cargo
@@ -208,9 +206,8 @@ bool StartAutopilot()
{
// Check for support ship and dismiss it if it is not doing anything.
// If the support ship is doing something then tell the user such.
for (auto so: list_range(&Ship_obj_list))
for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
{
auto objp = &Objects[so->objnum];
if ((objp->type == OBJ_SHIP) && !(objp->flags[Object::Object_Flags::Should_be_dead]))
{
Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
@@ -265,9 +262,9 @@ bool StartAutopilot()
}
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
LockAPConv = _timestamp(); // lock convergence instantly
LockAPConv = timestamp(); // lock convergence instantly
else
LockAPConv = _timestamp(3 * MILLISECONDS_PER_SECOND); // 3 seconds before we lock convergence
LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
Player_use_ai = 1;
set_time_compression(1);
lock_time_compression(true);
@@ -405,7 +402,7 @@ bool StartAutopilot()
&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
{
ai_info *aip = &Ai_info[Ships[i].ai_index];
int wingnum = Ships[i].wingnum, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
vec3d goal_point;
object *leader_objp = get_wing_leader(wingnum);
@@ -831,8 +828,9 @@ bool StartAutopilot()
//CameraMoving = false;
EndAPCinematic = _timestamp((10 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE); // 10 objective seconds before end of cinematic
MoveCamera = _timestamp(fl2i(5.5 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE);
EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic
MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
camMovingTime = int(4.5*float(tc_factor));
set_time_compression((float)tc_factor);
}
@@ -869,7 +867,7 @@ void EndAutoPilot()
Assert( CurrentNav >= 0 );
int goal = 0;
const char *goal_name = NULL;
char *goal_name = NULL;
if (Navs[CurrentNav].flags & NP_WAYPOINT)
{
@@ -925,7 +923,10 @@ void EndAutoPilot()
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
&& (aigp->ai_mode == goal) )
{
ai_goal_reset(aigp);
aigp->ai_mode = AI_GOAL_NONE;
aigp->signature = -1;
aigp->priority = -1;
aigp->flags.reset();
}
}
}
@@ -946,7 +947,10 @@ void EndAutoPilot()
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
&& (aigp->ai_mode == goal) )
{
ai_goal_reset(aigp);
aigp->ai_mode = AI_GOAL_NONE;
aigp->signature = -1;
aigp->priority = -1;
aigp->flags.reset();
}
}
}
@@ -1011,7 +1015,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 +1024,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();
}
// ********************************************************************************************
@@ -1050,13 +1053,15 @@ void NavSystem_Do()
if(cam != NULL)
cam->set_rotation_facing(&Player_obj->pos);
if (timestamp_elapsed(MoveCamera) && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
if (timestamp() >= MoveCamera && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
{
//Free_camera->set_position(&cameraTarget, float(camMovingTime), float(camMovingTime)/2.0f);
//Free_camera->set_translation_velocity(&cameraTarget);
CameraMoving = true;
}
if (timestamp_elapsed(EndAPCinematic) || !CanAutopilot())
if (timestamp() >= EndAPCinematic || !CanAutopilot())
{
nav_warp();
EndAutoPilot();
@@ -1184,10 +1189,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);
}
// ********************************************************************************************
@@ -1217,7 +1218,7 @@ void send_autopilot_msg(const char *msg, const char *snd)
}
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
message_training_queue("autopilot builtin message", TIMESTAMP::immediate(), 5); // display message for five seconds
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
}
// ********************************************************************************************
@@ -1227,15 +1228,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 +1235,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 +1249,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 +1260,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 +1291,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);
}
@@ -1589,18 +1581,3 @@ bool IsVisited(int nav)
return 1;
return 0;
}
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b)
{
int n = FindNav(nav);
if (n >= 0 && n < MAX_NAVPOINTS)
{
auto rgb = visited ? Navs[n].visited_color : Navs[n].normal_color;
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
}
}
+5 -18
View File
@@ -29,30 +29,19 @@
class NavPoint
{
public:
char m_NavName[32] = { 0 };
int flags = 0;
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };
char m_NavName[32];
int flags;
const void *target_obj = nullptr;
int waypoint_num = -1; //only used when flags & NP_WAYPOINT
const void *target_obj;
int waypoint_num; //only used when flags & NP_WAYPOINT
const vec3d *GetPosition();
// these assignments should match the initialization
void clear()
{
m_NavName[0] = 0;
flags = 0;
normal_color[0] = 0x80;
normal_color[1] = 0x80;
normal_color[2] = 0xFF;
visited_color[0] = 0xFF;
visited_color[1] = 0xFF;
visited_color[2] = 0x00;
target_obj = nullptr;
waypoint_num = -1;
}
@@ -79,7 +68,7 @@ extern bool AutoPilotEngaged;
extern int CurrentNav;
extern NavPoint Navs[MAX_NAVPOINTS];
extern NavMessage NavMsgs[NP_NUM_MESSAGES];
extern TIMESTAMP LockAPConv;
extern int LockAPConv;
extern SCP_map<int,int> autopilot_wings;
// Cycles through the NavPoint List
@@ -166,8 +155,6 @@ unsigned int DistanceTo(int nav);
bool IsVisited(const char *nav);
bool IsVisited(int nav);
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b);
void send_autopilot_msg(const char *msg, const char *snd=nullptr);
void send_autopilot_msgID(int msgid);
#endif
+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;
+23 -108
View File
@@ -53,7 +53,6 @@ MONITOR(SizeBitmapPage)
// --------------------------------------------------------------------------------------------------------------------
// Definition of public variables (declared as extern in bmpman.h).
int ENVMAP = -1;
int IRRMAP = -1;
size_t bm_texture_ram = 0;
int Bm_paging = 0;
@@ -425,7 +424,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 +584,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;
@@ -647,9 +592,12 @@ void bm_convert_format(bitmap *bmp, ushort flags) {
return;
if (Is_standalone) {
Assert(bmp->bpp == 8);
return;
} else {
if(!(flags & BMP_AABITMAP))
if (flags & BMP_AABITMAP)
Assert(bmp->bpp == 8);
else
Assert((bmp->bpp == 16) || (bmp->bpp == 32));
}
@@ -682,7 +630,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 +686,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 +894,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 +1409,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 +1519,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
@@ -1613,7 +1533,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
cfclose(img_cfp);
return -1;
} else {
nprintf(("BmpMan","BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
mprintf(("BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
}
if (anim_fps == 0) {
Error(LOCATION, "animation (%s) has invalid fps of 0, fix this!", filename);
@@ -1682,18 +1602,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
throw e;
}
else {
nprintf(("apng","Failed to load apng: %s\n", e.what()));
mprintf(("Failed to load apng: %s\n", e.what()));
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);
@@ -1925,7 +1837,7 @@ int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool
}
int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type);
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, false);
// could not be found, or is invalid for some reason
if (!res.found)
@@ -1963,7 +1875,9 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
}
// otherwise do it as normal
else {
if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
if (flags & BMP_AABITMAP) {
Assert(bpp == 8);
} else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
} else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5) || (flags & BMP_TEX_BC7)) {
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
@@ -1973,6 +1887,8 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
(be->type == BM_TYPE_CUBEMAP_DXT3) ||
(be->type == BM_TYPE_CUBEMAP_DXT5));
Assert(bpp >= 16);
} else {
Assert(0); //?
}
}
@@ -2478,7 +2394,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 +2434,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 +2518,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);
@@ -2714,7 +2629,7 @@ void bm_page_in_stop() {
}
}
nprintf(("BmpMan","BMPMAN: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
mprintf(("Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
#endif
Bm_paging = 0;
@@ -3222,7 +3137,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;
}
+2 -28
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
@@ -119,7 +116,6 @@ extern const char *bm_ani_ext_list[]; //!< List of extensions for those types
extern const int BM_ANI_NUM_TYPES; //!< Calculated number of bitmap animation types
extern int ENVMAP; //!< References a map that is for environment mapping -Bobboau
extern int IRRMAP; //!< References a filtered envmap for diffuse environment lighting - qazwsxal
/**
* @brief Initilizes the bitmap manager
@@ -220,19 +216,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 +372,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
*
@@ -573,6 +546,7 @@ void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, u
*/
void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
extern int ENVMAP; //this holds a reference to a map that is for environment mapping -Bobboau
/**
* @brief Returns the compression type of the bitmap indexed by handle
+60 -208
View File
@@ -9,13 +9,11 @@
#include "model/model.h" //polymodel, model_get
#include "options/Option.h"
#include "parse/parselo.h"
#include "parse/sexp_container.h"
#include "playerman/player.h" //player_get_padlock_orient
#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 Sexp_fov = 0.0f;
warp_camera Warp_camera;
@@ -27,36 +25,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 +32,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 +83,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 +102,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 +112,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 ) )
@@ -312,16 +241,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
{
vec3d position;
matrix orient_buf;
matrix *orient = nullptr;
if (Use_host_orientation_for_set_camera_facing)
{
// we want to retrieve the camera's orientation, so provide a buffer for it
orient = &orient_buf;
// reset the camera's orientation state because if we have no host object, that is what the camera will default to
c_ori = vmd_identity_matrix;
}
auto orient = Use_host_orientation_for_set_camera_facing ? &orient_buf : nullptr;
this->get_info(&position, orient, false);
@@ -341,7 +261,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 +284,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 +297,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 +308,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 +330,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 +339,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 +401,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 +438,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)
{
@@ -680,46 +597,11 @@ void warp_camera::get_info(vec3d *position, matrix *orientation)
#define MAX_SUBTITLE_LINES 64
subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char* in_imageanim, float in_display_time,
float in_fade_time, const color* in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded, int in_line_height_modifier, bool in_adjust_wh)
: display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), line_height_modifier(0),
image_id(-1), time_displayed(-1.0f), time_displayed_end(-1.0f), post_shaded(false), do_screen_scaling(false)
float in_fade_time, const color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded, float in_line_height_factor)
: display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), line_height_factor(1.0f),
image_id(-1), time_displayed(-1.0f), time_displayed_end(-1.0f), post_shaded(false)
{
if ((in_text == nullptr || *in_text == '\0') && (in_imageanim == nullptr || *in_imageanim == '\0'))
return;
auto screen_w = gr_screen.center_w;
auto screen_h = gr_screen.center_h;
// we might be doing screen scaling
if (Show_subtitle_screen_base_res[0] > 0 && Show_subtitle_screen_base_res[1] > 0)
{
// The way this works is we specify our subtitle coordinates relative to a base resolution, e.g. 1024x768.
// The base resolution is adjusted behind the scenes to match the aspect ratio of the current resolution
// (and the subtitle coordinates are adjusted as well). Then the adjusted subtitles are resized by the
// graphics code when they are drawn to the screen.
do_screen_scaling = true;
// we might need to adjust the coordinates for aspect ratio
if (in_adjust_wh)
{
if (Show_subtitle_screen_base_res[0] != Show_subtitle_screen_adjusted_res[0])
{
in_x_pos = in_x_pos * Show_subtitle_screen_adjusted_res[0] / Show_subtitle_screen_base_res[0];
in_width = in_width * Show_subtitle_screen_adjusted_res[0] / Show_subtitle_screen_base_res[0];
}
if (Show_subtitle_screen_base_res[1] != Show_subtitle_screen_adjusted_res[1])
{
in_y_pos = in_y_pos * Show_subtitle_screen_adjusted_res[1] / Show_subtitle_screen_base_res[1];
in_height = in_height * Show_subtitle_screen_adjusted_res[1] / Show_subtitle_screen_base_res[1];
}
}
// use these because we will be scaling the subtitle when it is displayed
screen_w = Show_subtitle_screen_adjusted_res[0];
screen_h = Show_subtitle_screen_adjusted_res[1];
}
// Initialize color
gr_init_color(&text_color, 0, 0, 0);
@@ -730,11 +612,13 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
memset( &text_pos, 0, 2*sizeof(int) );
memset( &image_pos, 0, 4*sizeof(int) );
if ( ((in_text != NULL) && (strlen(in_text) <= 0)) && ((in_imageanim != NULL) && (strlen(in_imageanim) <= 0)) )
return;
if (in_text != NULL && in_text[0] != '\0')
{
text_buf = in_text;
sexp_replace_variable_names_with_values(text_buf);
sexp_container_replace_refs_with_values(text_buf);
in_text = text_buf.c_str();
}
@@ -760,7 +644,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
else
gr_init_alphacolor(&text_color, 255, 255, 255, 255);
text_fontnum = in_text_fontnum;
line_height_modifier = in_line_height_modifier;
line_height_factor = in_line_height_factor;
//Setup display and fade time
display_time = fl_abs(in_display_time);
@@ -794,20 +678,12 @@ 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;
if (line_height_modifier != 0.0f)
{
if (Show_subtitle_uses_pixels)
h = line_height_modifier;
else
h = fl2i(h * line_height_modifier / 100.0f);
}
th += h;
th += fl2i(line_height_factor * h);
}
// restore old font
@@ -832,20 +708,20 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
//Center it?
if(center_x)
image_pos.x = (screen_w - tw)/2;
image_pos.x = (gr_screen.center_w - tw)/2 + gr_screen.center_offset_x;
if(center_y)
image_pos.y = (screen_h - th)/2;
image_pos.y = (gr_screen.center_h - th)/2 + gr_screen.center_offset_y;
}
if(in_x_pos < 0 && !center_x)
image_pos.x += screen_w + in_x_pos;
image_pos.x += gr_screen.center_offset_x + gr_screen.center_w + in_x_pos;
else if(!center_x)
image_pos.x += in_x_pos;
image_pos.x += gr_screen.center_offset_x + in_x_pos;
if(in_y_pos < 0 && !center_y)
image_pos.y += screen_h + in_y_pos;
image_pos.y += gr_screen.center_offset_y + gr_screen.center_h + in_y_pos;
else if(!center_y)
image_pos.y += in_y_pos;
image_pos.y += gr_screen.center_offset_y + in_y_pos;
image_pos.w = in_width;
image_pos.h = in_height;
@@ -901,35 +777,24 @@ void subtitle::do_frame(float frametime)
int x = text_pos.x;
int y = text_pos.y;
auto sizing_mode = do_screen_scaling ? GR_RESIZE_FULL : GR_RESIZE_NONE;
if (do_screen_scaling)
{
gr_set_screen_scale(Show_subtitle_screen_adjusted_res[0], Show_subtitle_screen_adjusted_res[1]);
gr_set_clip(0, 0, Show_subtitle_screen_adjusted_res[0], Show_subtitle_screen_adjusted_res[1]);
}
// do the actual drawing ---------------------
for(SCP_vector<SCP_string>::iterator line = text_lines.begin(); line != text_lines.end(); ++line)
{
gr_string(x, y, (char*)line->c_str(), sizing_mode);
gr_string(x, y, (char*)line->c_str(), GR_RESIZE_NONE);
y += fl2i(line_height_factor * font_height);
}
if (line_height_modifier != 0.0f)
{
if (Show_subtitle_uses_pixels)
font_height = line_height_modifier;
else
font_height = fl2i(font_height * line_height_modifier / 100.0f);
}
y += font_height;
// restore old font
if (old_fontnum >= 0)
{
font::set_font(old_fontnum);
}
if(image_id >= 0)
{
gr_set_bitmap(image_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, text_color.alpha/255.0f);
// image scaling?
// scaling?
if (image_pos.w > 0 || image_pos.h > 0)
{
int orig_w, orig_h;
@@ -941,28 +806,16 @@ void subtitle::do_frame(float frametime)
scale.xyz.z = 1.0f;
gr_push_scale_matrix(&scale);
gr_bitmap(fl2i(image_pos.x / scale.xyz.x), fl2i(image_pos.y / scale.xyz.y), sizing_mode);
gr_bitmap(fl2i(image_pos.x / scale.xyz.x), fl2i(image_pos.y / scale.xyz.y), GR_RESIZE_NONE);
gr_pop_scale_matrix();
}
// no scaling
else
{
gr_bitmap(image_pos.x, image_pos.y, sizing_mode);
gr_bitmap(image_pos.x, image_pos.y, GR_RESIZE_NONE);
}
}
// finished the actual drawing ---------------
if (do_screen_scaling)
{
gr_reset_screen_scale();
gr_reset_clip();
}
// restore old font
if (old_fontnum >= 0)
font::set_font(old_fontnum);
time_displayed += frametime;
}
@@ -979,7 +832,7 @@ void subtitle::clone(const subtitle &sub)
{
text_lines = sub.text_lines;
text_fontnum = sub.text_fontnum;
line_height_modifier = sub.line_height_modifier;
line_height_factor = sub.line_height_factor;
// copy the structs
text_pos = sub.text_pos;
@@ -1002,7 +855,6 @@ void subtitle::clone(const subtitle &sub)
time_displayed_end = sub.time_displayed_end;
post_shaded = sub.post_shaded;
do_screen_scaling = sub.do_screen_scaling;
}
subtitle& subtitle::operator=(const subtitle &sub)
@@ -1051,7 +903,7 @@ int camid::getSignature()
return sig;
}
bool camid::isValid() const
bool camid::isValid()
{
if(idx >= Cameras.size())
return false;
@@ -1243,7 +1095,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 +1103,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 +1116,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);
}
+6 -24
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
@@ -138,7 +123,7 @@ private:
float fade_time;
color text_color;
int text_fontnum;
int line_height_modifier;
float line_height_factor;
//Done with set
char imageanim[MAX_FILENAME_LEN];
@@ -152,13 +137,11 @@ private:
float time_displayed_end;
bool post_shaded;
bool do_screen_scaling;
public:
subtitle(int in_x_pos, int in_y_pos, const char* in_text = NULL, const char* in_imageanim = NULL,
float in_display_time = 0, float in_fade_time = 0.0f, const color *in_text_color = NULL, int in_text_fontnum = -1,
bool center_x = false, bool center_y = false, int in_width = 0, int in_height = 0, bool post_shaded = false,
int in_line_height_modifier = 0, bool in_adjust_wh = true);
float in_line_height_factor = 1.0f);
~subtitle();
subtitle(const subtitle &sub) { clone(sub); }
@@ -170,8 +153,7 @@ 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 Sexp_fov;
//Helpful functions
+78 -101
View File
@@ -59,6 +59,8 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm .lua", CF_TYPE_DATA },
{ CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS },
{ CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS },
{ CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA },
{ CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg", CF_TYPE_VOICE },
@@ -68,16 +70,15 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", /* DON'T add pilot files here!! */ CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA },
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
@@ -85,16 +86,21 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
{ CF_TYPE_INTERFACE_CSS, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "css", ".rcss", CF_TYPE_INTERFACE },
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
};
// 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;
@@ -323,21 +329,22 @@ static int _cfile_chdir(const char *new_dir, const char *cur_dir __UNUSED)
*/
int cfile_push_chdir(int type)
{
SCP_string dir;
char dir[CFILE_ROOT_DIRECTORY_LEN];
char OriginalDirectory[CFILE_ROOT_DIRECTORY_LEN];
_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, sizeof(dir) - 1, type, NULL);
return _cfile_chdir(dir, OriginalDirectory);
}
/**
@@ -360,16 +367,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 +442,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];
@@ -465,26 +469,26 @@ const char *cf_add_ext(const char *filename, const char *ext)
*/
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
{
SCP_string longname;
char longname[MAX_PATH_LEN];
Assert(CF_TYPE_SPECIFIED(path_type));
cf_create_default_path_string(longname, path_type, filename, location_flags);
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
return (_unlink(longname.c_str()) != -1);
return (_unlink(longname) != -1);
}
// Same as _access function to read a file's access bits
int cf_access(const char *filename, int dir_type, int mode)
{
SCP_string longname;
char longname[MAX_PATH_LEN];
Assert( CF_TYPE_SPECIFIED(dir_type) );
cf_create_default_path_string(longname, dir_type, filename);
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, filename );
return access(longname.c_str(), mode);
return access(longname,mode);
}
@@ -529,18 +533,18 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
#ifdef _WIN32
void cf_attrib(const char *filename, int set, int clear, int dir_type)
{
SCP_string longname;
char longname[MAX_PATH_LEN];
Assert( CF_TYPE_SPECIFIED(dir_type) );
cf_create_default_path_string(longname, dir_type, filename);
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, filename );
FILE *fp = fopen(longname.c_str(), "rb");
FILE *fp = fopen(longname, "rb");
if (fp) {
fclose(fp);
DWORD z = GetFileAttributes(longname.c_str());
SetFileAttributes(longname.c_str(), z | (set & ~clear));
DWORD z = GetFileAttributes(longname);
SetFileAttributes(longname, z | (set & ~clear));
}
}
@@ -551,13 +555,13 @@ int cf_rename(const char *old_name, const char *name, int dir_type)
Assert( CF_TYPE_SPECIFIED(dir_type) );
int ret_code;
SCP_string old_longname;
SCP_string new_longname;
char old_longname[_MAX_PATH];
char new_longname[_MAX_PATH];
cf_create_default_path_string(old_longname, dir_type, old_name);
cf_create_default_path_string(new_longname, dir_type, name);
cf_create_default_path_string( old_longname, sizeof(old_longname)-1, dir_type, old_name );
cf_create_default_path_string( new_longname, sizeof(old_longname)-1, dir_type, name );
ret_code = rename(old_longname.c_str(), new_longname.c_str());
ret_code = rename(old_longname, new_longname );
if(ret_code != 0){
switch(errno){
case EACCES :
@@ -601,7 +605,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
{
int num_dirs = 0;
int dir_tree[CF_MAX_PATH_TYPES];
SCP_string longname;
char longname[MAX_PATH_LEN];
struct stat statbuf;
Assertion( CF_TYPE_SPECIFIED(dir_type), "Invalid dir_type passed to cf_create_directory." );
@@ -619,10 +623,10 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
int i;
for (i=num_dirs-1; i>=0; i-- ) {
cf_create_default_path_string(longname, dir_tree[i], nullptr, location_flags);
if (stat(longname.c_str(), &statbuf) != 0) {
mprintf(( "CFILE: Creating new directory '%s'\n", longname.c_str() ));
mkdir_recursive(longname.c_str());
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
if (stat(longname, &statbuf) != 0) {
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
mkdir_recursive(longname);
}
}
}
@@ -631,7 +635,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
//
// parameters: *filepath ==> name of file to open (may be path+name)
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
// passing NULL to mode triggers an assert and returns NULL
// passing NULL to mode deletes the file if it exists and returns NULL
// type ==> one of: CFILE_NORMAL
// CFILE_MEMORY_MAPPED
// dir_type => override extension check, value is one of CF_TYPE* #defines
@@ -644,7 +648,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
//
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
bool /* localize */, uint32_t location_flags)
bool localize, uint32_t location_flags)
{
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
if( strlen(file_path) > 31 )
@@ -671,23 +675,21 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
// the harddisk. No fancy packfile stuff here!
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
SCP_string longname;
char longname[_MAX_PATH];
auto last_separator = strrchr(file_path, DIR_SEPARATOR_CHAR);
// For write-only files, require a full path or a path type
if ( last_separator ) {
// Full path given?
longname = file_path;
strcpy_s(longname, file_path );
} 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);
cf_create_default_path_string(longname, dir_type, file_path, location_flags);
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
}
Assert( !(type & CFILE_MEMORY_MAPPED) );
@@ -726,7 +728,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
strcpy_s(happy_mode, mode);
}
FILE *fp = fopen(longname.c_str(), happy_mode);
FILE *fp = fopen(longname, happy_mode);
if (fp) {
return cf_open_fill_cfblock(source, line, last_separator ? (last_separator + 1) : file_path, fp, dir_type);
}
@@ -737,8 +739,10 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
//================================================
// Search for file on disk, on cdrom, or in a packfile
auto find_res = cf_find_file_location(file_path, dir_type, location_flags);
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
strcpy_s(copy_file_path, file_path);
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
if ( find_res.found ) {
// Fount it, now create a cfile out of it
@@ -778,7 +782,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
//
// parameters: *filepath ==> name of file to open (may be path+name)
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
// passing NULL to mode triggers an assert and returns NULL
// passing NULL to mode deletes the file if it exists and returns NULL
// dir_type => override extension check, value is one of CF_TYPE* #defines
//
@@ -1235,17 +1239,15 @@ void cfread_string(char *buf, int n, CFILE *file)
} while (c != 0 );
}
void cfread_string_len(char *buf, int buffer_size, CFILE *file)
void cfread_string_len(char *buf,int n, CFILE *file)
{
int len;
len = cfread_int(file);
Assertion( (len <= buffer_size), "String cannot fit in buffer, len: %i, buffer: %i", len, buffer_size);
if (len) {
Assertion( (len < n), "len: %i, n: %i", len, n );
if (len)
cfread(buf, len, 1, file);
Assertion(len != buffer_size || buf[len - 1] == 0, "Unterminated string does not fit in buffer");
}
buf[MIN(len, buffer_size - 1)] = 0;
buf[len] = 0;
}
SCP_string cfread_string_len(CFILE *file)
@@ -1844,53 +1846,28 @@ int cfile_get_path_type(const SCP_string& dir)
{
SCP_string buf = dir;
// remove leading and trailing slashes
if ( !buf.empty() ) {
auto start = buf.find_first_not_of("\\/");
auto end = buf.find_last_not_of("\\/");
if (start == SCP_string::npos) {
buf = "";
} else if ( (start > 0) || (end < buf.length()-1) ) {
buf = buf.substr(start, end-start+1);
}
// Remove trailing slashes; avoid buffer overflow on 1-char strings
while (buf.size() > 0 && (buf[buf.size() - 1] == '\\' || buf[buf.size() - 1] == '/')) {
buf.resize(buf.size() - 1);
}
if (buf.empty()) {
return CF_TYPE_ROOT;
// Remove leading slashes
while (buf.size() > 0 && (buf[0] == '\\' || buf[0] == '/')) {
buf = buf.substr(1);
}
// Use official DIR_SEPARATOR_CHAR
extern void normalize_directory_separators(SCP_string &str);
normalize_directory_separators(buf);
// identify path type
auto best_match = CF_TYPE_INVALID;
for (auto& Pathtype : Pathtypes) {
if ( !Pathtype.path ) {
continue;
}
// skip root, it should have been detected before getting here
if (Pathtype.index == CF_TYPE_ROOT) {
continue;
}
// don't allow unknown subdirs directly under data
if (Pathtype.index == CF_TYPE_DATA) {
if (buf == Pathtype.path) {
best_match = CF_TYPE_DATA;
}
continue;
}
// for everything else just find closest match, allowing for unknown subdirectories
if ( !strnicmp(buf.c_str(), Pathtype.path, strlen(Pathtype.path)) ) {
best_match = Pathtype.index;
for (char& c : buf) {
if (c == '\\' || c == '/') {
c = DIR_SEPARATOR_CHAR;
}
}
return best_match;
for (auto& Pathtype : Pathtypes) {
if (Pathtype.path != nullptr && buf == Pathtype.path) {
return Pathtype.index;
}
}
return CF_TYPE_INVALID;
}
+41 -38
View File
@@ -49,38 +49,42 @@ typedef struct {
#define CF_TYPE_MODELS 5
#define CF_TYPE_TABLES 6
#define CF_TYPE_SOUNDS 7
#define CF_TYPE_VOICE 8
#define CF_TYPE_VOICE_BRIEFINGS 9
#define CF_TYPE_VOICE_CMD_BRIEF 10
#define CF_TYPE_VOICE_DEBRIEFINGS 11
#define CF_TYPE_VOICE_PERSONAS 12
#define CF_TYPE_VOICE_SPECIAL 13
#define CF_TYPE_VOICE_TRAINING 14
#define CF_TYPE_MUSIC 15
#define CF_TYPE_MOVIES 16
#define CF_TYPE_INTERFACE 17
#define CF_TYPE_FONT 18
#define CF_TYPE_EFFECTS 19
#define CF_TYPE_HUD 20
#define CF_TYPE_PLAYERS 21
#define CF_TYPE_PLAYER_IMAGES 22
#define CF_TYPE_SQUAD_IMAGES 23
#define CF_TYPE_SINGLE_PLAYERS 24
#define CF_TYPE_MULTI_PLAYERS 25
#define CF_TYPE_PLAYER_BINDS 26
#define CF_TYPE_CACHE 27
#define CF_TYPE_MULTI_CACHE 28
#define CF_TYPE_MISSIONS 29
#define CF_TYPE_CONFIG 30
#define CF_TYPE_DEMOS 31
#define CF_TYPE_CBANIMS 32
#define CF_TYPE_INTEL_ANIMS 33
#define CF_TYPE_SCRIPTS 34
#define CF_TYPE_FICTION 35
#define CF_TYPE_FREDDOCS 36
#define CF_TYPE_SOUNDS_8B22K 8
#define CF_TYPE_SOUNDS_16B11K 9
#define CF_TYPE_VOICE 10
#define CF_TYPE_VOICE_BRIEFINGS 11
#define CF_TYPE_VOICE_CMD_BRIEF 12
#define CF_TYPE_VOICE_DEBRIEFINGS 13
#define CF_TYPE_VOICE_PERSONAS 14
#define CF_TYPE_VOICE_SPECIAL 15
#define CF_TYPE_VOICE_TRAINING 16
#define CF_TYPE_MUSIC 17
#define CF_TYPE_MOVIES 18
#define CF_TYPE_INTERFACE 19
#define CF_TYPE_FONT 20
#define CF_TYPE_EFFECTS 21
#define CF_TYPE_HUD 22
#define CF_TYPE_PLAYERS 23
#define CF_TYPE_PLAYER_IMAGES 24
#define CF_TYPE_SQUAD_IMAGES 25
#define CF_TYPE_SINGLE_PLAYERS 26
#define CF_TYPE_MULTI_PLAYERS 27
#define CF_TYPE_CACHE 28
#define CF_TYPE_MULTI_CACHE 29
#define CF_TYPE_MISSIONS 30
#define CF_TYPE_CONFIG 31
#define CF_TYPE_DEMOS 32
#define CF_TYPE_CBANIMS 33
#define CF_TYPE_INTEL_ANIMS 34
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_FREDDOCS 37
#define CF_TYPE_INTERFACE_MARKUP 38
#define CF_TYPE_INTERFACE_CSS 39
#define CF_TYPE_PLAYER_BINDS 40
#define CF_MAX_PATH_TYPES \
37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
41 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
// TRUE if type is specified and valid
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
@@ -171,7 +175,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);
@@ -322,17 +326,15 @@ void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt = nullptr);
// to n characters.
void cfread_string(char *buf,int n, CFILE *file);
/**
* @brief Read a fixed length string that is not null-terminated, with the length stored in file.
* @brief Read a fixed length string that is not null-terminated, with the length stored in file
*
* If it is not null-terminated, the length of the string *must* be less than the size of the buffer (to make room for one)
*
* @param buf Pre-allocated array to store string
* @param buffer_size Size of pre-allocated array
* @param n Size of pre-allocated array
* @param file File to read from
*
* @note Appends NULL character to string (buf)
*/
void cfread_string_len(char *buf,int buffer_size, CFILE *file);
void cfread_string_len(char *buf,int n, CFILE *file);
/**
* @brief Read a string from the file where the length is stored in the file
@@ -391,7 +393,7 @@ struct CFileLocation {
// size - File size
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns 0.
CFileLocation cf_find_file_location(const char* filespec, int pathtype,
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
struct CFileLocationExt : public CFileLocation {
@@ -415,7 +417,8 @@ struct CFileLocationExt : public CFileLocation {
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns -1, else returns offset into ext_list.
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype);
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
bool localize = false);
// Functions to change directories
int cfile_chdir(const char *dir);
+335 -662
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -42,8 +42,8 @@ bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
// Output: path - Fully qualified pathname.
//Returns 0 if result would be too long (invalid result)
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
uint32_t location_flags = CF_LOCATION_ALL);
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr,
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
#endif //_CFILESYSTEM_H
-186
View File
@@ -1,186 +0,0 @@
#include "cheats_table.h"
#include "parse/parselo.h"
void cheat_table_init() {
customCheats.clear();
if (cf_exists_full("cheats.tbl", CF_TYPE_TABLES)) {
parse_cheat_table("cheats.tbl");
}
parse_modular_table("*-cht.tbm", parse_cheat_table);
}
bool CustomCheat::canUseCheat() {
return !requireCheatsEnabled || Cheats_enabled;
}
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());
scripting::hooks::OnCheat->run(scripting::hook_param_list(scripting::hook_param("Cheat", 's', cheatCode)));
CheatUsed = cheatCode;
}
void SpawnShipCheat::runCheat() {
CustomCheat::runCheat();
if (canUseCheat() && (Game_mode & GM_IN_MISSION) && Player_obj != nullptr) {
extern void prevent_spawning_collision(object *new_obj);
ship_subsys *ptr;
char name[NAME_LENGTH];
int ship_idx, ship_class;
// if not found, then don't create it :(
ship_class = ship_info_lookup(shipClassName.c_str());
if (ship_class < 0)
return;
vec3d pos = Player_obj->pos;
matrix orient = Player_obj->orient;
pos.xyz.x += frand_range(-700.0f, 700.0f);
pos.xyz.y += frand_range(-700.0f, 700.0f);
pos.xyz.z += frand_range(-700.0f, 700.0f);
int objnum = ship_create(&orient, &pos, ship_class);
if (objnum < 0)
return;
ship *shipp = &Ships[Objects[objnum].instance];
shipp->ship_name[0] = '\0';
shipp->display_name.clear();
for (size_t j = 0; j < Player_orders.size(); j++)
shipp->orders_accepted.insert(j);
// Goober5000 - stolen from support ship creation
// create a name for the ship with a number. look for collisions until one isn't found anymore
ship_idx = 1;
do {
sprintf(name, "%s %d", shipName.c_str(), ship_idx);
if ( (ship_name_lookup(name) == -1) && (ship_find_exited_ship_by_name(name) == -1) )
{
strcpy_s(shipp->ship_name, name);
break;
}
ship_idx++;
} while(1);
shipp->flags.set(Ship::Ship_Flags::Escort);
shipp->escort_priority = 1000 - ship_idx;
// now make sure we're not colliding with anyone
prevent_spawning_collision(&Objects[objnum]);
// Goober5000 - beam free
for (ptr = GET_FIRST(&shipp->subsys_list); ptr != END_OF_LIST(&shipp->subsys_list); ptr = GET_NEXT(ptr))
{
// mark all turrets as beam free
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));
}
}
// Cyborg17 to prevent a nullptr...
ship_set_warp_effects(&Objects[objnum]);
// warpin
shipfx_warpin_start(&Objects[objnum]);
}
}
void parse_cheat_table(const char* filename) {
try {
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
optional_string("#CUSTOM CHEATS");
while (optional_string("$Cheat:")) {
SCP_string code, msg, shipClass, shipName;
bool requireCheats = false;
bool shipSpawn = false;
required_string("+Code:");
stuff_string(code, F_RAW);
//We are limited to the buffer size used for the traditional cheats. We can still use short cheats, though.
if (code.length() > CHEAT_BUFFER_LEN) {
Warning(LOCATION, "Cheat code %s is too long. It will be cut off to maximum length (%i characters).", code.c_str(), CHEAT_BUFFER_LEN);
code = code.substr(0, CHEAT_BUFFER_LEN);
}
if (optional_string("+Message:")) {
stuff_string(msg, F_MESSAGE);
}
if (optional_string("+RequireCheats:")) {
stuff_boolean(&requireCheats);
}
if (optional_string("+SpawnShip:")) {
shipSpawn = true;
required_string("+Name:");
stuff_string(shipName, F_NAME);
required_string("+Class:");
stuff_string(shipClass, F_NAME);
int shipClassInfo = ship_info_lookup(shipClass.c_str());
if (shipClassInfo < 0) {
shipSpawn = false;
Warning(LOCATION, "There is no ship class named '%s'. The '%s' cheat won't summon a ship.", shipClass.c_str(), code.c_str());
}
}
if (shipSpawn) {
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, msg, requireCheats, shipClass, shipName));
if(customCheats.count(code) == 1) {
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
customCheats[code] = std::move(shipCheat);
} else {
customCheats.emplace(code, std::move(shipCheat));
}
} else {
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, msg, requireCheats));
if(customCheats.count(code) == 1) {
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
customCheats[code] = std::move(cheat);
} else {
customCheats.emplace(code, std::move(cheat));
}
}
}
required_string("#END");
}
catch (const parse::ParseException& e) {
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
bool checkForCustomCheats(const char* buffer, int buffer_length) {
const char* check_buffer = buffer;
for (int i = 0; i < buffer_length; i++) {
if (*check_buffer == '\0') {
check_buffer++;
}
else {
break;
}
}
// Loop through our map of custom cheats and check if the code is within the buffer.
// We don't just check for equality, as the player may have typed other characters before the cheat.
for (auto &ccheat : customCheats) {
auto found = std::strstr(check_buffer, ccheat.first.c_str());
if (found != nullptr) {
ccheat.second->runCheat();
return true;
}
}
return false;
}
-49
View File
@@ -1,49 +0,0 @@
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "io/key.h"
#include "hud/hudmessage.h"
#include "hud/hudsquadmsg.h"
#include "scripting/global_hooks.h"
#include "scripting/hook_api.h"
#include "ship/ship.h"
#include "ship/shipfx.h"
#define CHEAT_BUFFER_LEN 17
class CustomCheat {
public:
SCP_string cheatCode;
SCP_string cheatMsg;
bool requireCheatsEnabled;
CustomCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled) :
cheatCode(std::move(cheat_code)),
cheatMsg(std::move(cheat_msg)),
requireCheatsEnabled(require_cheats_enabled) { }
virtual ~CustomCheat() = default;
virtual void runCheat();
bool canUseCheat();
};
class SpawnShipCheat : public CustomCheat {
protected:
SCP_string shipClassName;
SCP_string shipName;
public:
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(cheat_code, cheat_msg, require_cheats_enabled),
shipClassName(std::move(class_name)),
shipName(std::move(ship_name)) { }
void runCheat() override;
};
static SCP_map<SCP_string, std::unique_ptr<CustomCheat>> customCheats;
void cheat_table_init();
void parse_cheat_table(const char* filename);
bool checkForCustomCheats(const char* converted_buffer, int buffer_length);
+239 -352
View File
File diff suppressed because it is too large. Load diff
+8 -17
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,16 +46,17 @@ 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_ambient_power;
extern float Cmdline_emissive_power;
extern float Cmdline_light_power;
extern float Cmdline_clip_dist;
extern float static_light_factor;
extern float static_point_factor;
extern float static_tube_factor;
extern int Cmdline_ambient_factor;
extern int Cmdline_env;
extern int Cmdline_glow;
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
@@ -68,10 +68,8 @@ extern int Cmdline_softparticles;
extern int Cmdline_bloom_intensity;
extern bool Cmdline_force_lightshaft_off;
extern int Cmdline_no_deferred_lighting;
extern bool Cmdline_deferred_lighting_cockpit;
extern int Cmdline_emissive;
extern int Cmdline_aniso_level;
extern int Cmdline_msaa_enabled;
// Game Speed related
extern int Cmdline_NoFPSCap;
@@ -82,16 +80,16 @@ extern int Cmdline_ballistic_gauge;
extern int Cmdline_dualscanlines;
extern int Cmdline_orb_radar;
extern int Cmdline_rearm_timer;
extern int Cmdline_targetinfo;
// Gameplay related
extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_warp_flash;
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 +106,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;
@@ -129,7 +125,6 @@ extern bool Cmdline_nograb;
extern bool Cmdline_noshadercache;
extern bool Cmdline_prefer_ipv4;
extern bool Cmdline_prefer_ipv6;
extern bool Cmdline_dump_packet_type;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -159,10 +154,6 @@ extern bool Cmdline_debug_window;
extern bool Cmdline_graphics_debug_output;
extern bool Cmdline_log_to_stdout;
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
+39 -262
View File
@@ -12,7 +12,6 @@
#define CONTROLS_CONFIG_H
#include "globalincs/pstypes.h"
#include "scripting/scripting.h"
#define CONTROL_CONFIG_XSTR 507
@@ -22,8 +21,6 @@
#define CCF_AXIS 0x08 //!< btn is an axis
#define CCF_HAT 0x04 //!< btn is a hat
#define CCF_BALL 0x02 //!< btn is a ball
#define CCF_BUTTON 0x01 //!< btn is actually a button
#define CCF_NONE 0x00 //!< No flags. Alias is "NONE"
/*!
* These are used to index a corresponding axis value from an array.
@@ -295,8 +292,6 @@ enum IoActionId : int {
JOY_ABS_THROTTLE_AXIS = 127,
JOY_REL_THROTTLE_AXIS = 128,
TOGGLE_HUD_SHADOWS,
/*!
* This must always be below the last defined item
*/
@@ -325,15 +320,6 @@ enum {
};
}
/*!
* Where the preset is located in memory
*/
enum class Preset_t {
hardcode, // Preset is defined hardcode
tbl, // Preset is defined in controlconfigdefaults.tbl
pst // Preset is defined in a .json
};
class CCB;
/*!
@@ -375,16 +361,6 @@ public:
*/
bool empty() const;
/**
* Takes the given binding.
*/
void take(CID _cid, short _btn, char _flags = 0);
/**
* Validates the binding, clearing it if necassary
*/
void validate();
/*!
* Returns a copy of ::btn
*/
@@ -400,6 +376,16 @@ public:
*/
char get_flags() const;
/**
* Takes the given binding.
*/
void take(CID _cid, short _btn, char _flags = 0);
/**
* Validates the binding, clearing it if necassary
*/
void validate();
/*!
* Returns a human-readable string of this binding
*/
@@ -433,26 +419,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.
@@ -502,12 +468,12 @@ public:
/*!
* Checks if the given CCB is exactly equal to this
*/
bool operator==(const CCB&) const;
bool operator==(const CCB&);
/*!
* Checks if the given CCB differs from this
*/
bool operator!=(const CCB&) const;
bool operator!=(const CCB&);
/*!
* Returns True if this CCB's first isn't empty and the given CCB has a binding that can conflict with it
@@ -533,21 +499,6 @@ public:
* Returns a pointer to first, or second, whichever has *all* flags in the given mask
*/
CC_bind* find_flags(const char);
/*!
* Sets the inversion state of both bindings
*/
void invert(bool);
/*!
* Toggles the inversion state of Primary and copies it to Secondary
*/
void invert_toggle();
/*!
* Is true if both bindings are inverted, false otherwise
*/
bool is_inverted() const;
};
/*!
@@ -557,13 +508,8 @@ class CC_preset {
public:
SCP_vector<CCB> bindings;
SCP_string name;
Preset_t type;
public:
CC_preset() = default;
CC_preset(const CC_preset& A) = default;
CC_preset& operator=(const CC_preset&);
/*!
* Checks if the given preset is a duplicate of this one
*/
@@ -588,12 +534,8 @@ public:
CC_type type; //!< manner control should be checked in
// Items used during gameplay
TIMESTAMP digital_used; //!< has control been used yet in mission? If so, this is the timestamp.
// Note this is not a UI timestamp because this is purely for mission timing purposes.
int analog_value; // For axes, this denotes the last frame's value
int used; //!< has control been used yet in mission? If so, this is the timestamp
bool disabled = true; //!< whether this action should be available at all
bool locked = false; //!< whether this action will be triggered by the respectively bound key
bool scriptEnabledByDefault = false; //!< whether this binding will execute it's registered hooks if triggered. Resets each mission
bool continuous_ongoing; //!< whether this action is a continuous one and is currently ongoing
public:
@@ -661,15 +603,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,15 +611,11 @@ 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 **Scan_code_text;
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
extern bool Generate_controlconfig_table;
// string table constants for labels and stuff.
#define NUM_AXIS_TEXT JOY_NUM_AXES
#define NUM_MOUSE_TEXT MOUSE_NUM_BUTTONS
@@ -721,7 +650,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 +660,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
@@ -822,36 +690,9 @@ bool control_config_use_preset_by_name(const SCP_string &name);
*
* @returns an iterator to the current preset, or
* @returns ::iterator Control_config_presets.end() if current bindings are not in a preset
*
* @note Similar to preset_find_duplicate, this function has additional logic in its search to ignore disabled controls
*/
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
*
@@ -885,9 +726,10 @@ int translate_key_to_index(const char *key, bool find_override=true);
const char *translate_key(char *key);
/**
* @brief Converts the specified key code to a human readable string, according to the selected locale and keyboard layout
* @brief Converts the specified key code to a human readable string, according to the selected locale
*
* @param[in] code The key scancode to convert
* @param[in] code The key code to convert
* @param[in] use_default_locale If true, return the default locale (English) translation of the key
*
* @return The text representation of the code.
*
@@ -895,18 +737,7 @@ const char *translate_key(char *key);
*
* @note The return value is translated according to localization settings
*/
const char *textify_scancode(int code);
/**
* @brief Converts the specified key code to a human readable string. Uses the English locale and QWERTY layout.
*
* @param[in] code The key scancode to convert
*
* @return The text representation of the code
*
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
*/
const char *textify_scancode_universal(int code);
const char *textify_scancode(int code, bool use_default_locale = false);
/*!
* @brief Checks how long a control has been active
@@ -947,41 +778,12 @@ 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
*/
void control_used(int id);
/**
* @brief Runs a given controlbindings lua hook added in ccd.tbl
*
* @return Whether the control should be overridden
*/
bool control_run_lua(IoActionId id, int value);
/**
* @brief Resets the cache for script evaluations for continuous buttons. Should be called once per frame.
*
*/
void control_reset_lua_cache();
/**
* @brief Registers a new hook for the keybinding action system.
* Parameters set if it is a normal or an override function, as well as if it is enabled by default or needs to be enabled manually each mission
*/
void control_register_hook(IoActionId id, const luacpp::LuaFunction& hook, bool is_override, bool enabledByDefault);
/**
* @brief Enables or disables the respective Lua hook
*/
void control_enable_hook(IoActionId id, bool enable);
/**
* @brief Resets every hooks enable state to the tabled value. Call on Mission start
*/
void control_reset_hook();
/**
* @brief Clears the bindings of all controls
*/
@@ -1034,17 +836,18 @@ CID CIDToVal(const char * str);
/**
* Reverse lookups the CID to get its stringified name
* @return The stringified name of the CID, or
* @return "NONE" if not found
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found
*/
SCP_string ValToCID(CID id);
const char * ValToCID(CID id);
/**
* Reverse lookups the CID to get its stringified name
* @return The stringified name of the CID, or
* @return "NONE" if not found, or invalid id
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found, or invalid id
*/
SCP_string ValToCID(int id);
const char * ValToCID(int id);
/**
* Lookups the given stringified enum to find its value
*/
@@ -1052,8 +855,8 @@ char CCFToVal(const char * str);
/**
* Constructs a enum string from the CCF_FLAGS
* @return The stringified name of the CCF, or
* @return "NONE" if not found, or invalid id
* @return Pointer to the stringified name of the CCF, or
* @return nullptr if not found, or invalid id
*/
SCP_string ValToCCF(char id);
@@ -1065,8 +868,8 @@ short InputToVal(CID cid, const char * str);
/**
* Constructs a enumstring from the input binding, depending on the CID
*
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
*/
@@ -1080,8 +883,8 @@ short MouseToVal(const char * str);
/**
* Constructs a enum string from the mouse input
*
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* TODO XSTR
*
* @note This requires a CCB due to the way things are encoded
@@ -1096,8 +899,8 @@ short KeyboardToVal(const char * str);
/**
* Constructs an enum string from the key binding
*
* @return The stringified name of the input, or
* @return "NONE" f not found, or invalid CC_bind
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
@@ -1112,37 +915,11 @@ short JoyToVal(const char * str);
/**
* Constructs a enum string from the Joystick input
*
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
*/
SCP_string ValToJoy(const CC_bind &bind);
/**
* Lookups the given string to find its tab value
*/
char CCTabToVal(const char *str);
/**
* Reverse lookups the given tab in mCCTabToVal to retrieve the string name
*
* @return The stringified name of the input, or
* @return nullptr if not found, or invalid tab
*
*/
SCP_string ValToCCTab(char tab);
/**
* Lookups the given string to find its CC_type value. =
*/
CC_type CCTypeToVal(const char *str);
/**
* Reverse lookups the given CC_type to retrieve the string name
*/
SCP_string ValToCCType(CC_type type);
#endif
File diff suppressed because it is too large. Load diff
+15 -59
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);
@@ -47,7 +47,7 @@ void load_preset_files(SCP_string clone) {
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!fp) {
mprintf(("PST => Unable to open '%s' for loading!\n", file.c_str()));
mprintf(("PLR => Unable to open '%s' for loading!\n", file.c_str()));
// try next
continue;
}
@@ -55,7 +55,7 @@ void load_preset_files(SCP_string clone) {
try {
handler.reset(new PresetFileHandler(fp, true));
} catch (const std::exception& e) {
mprintf(("PST => Failed to open JSON: `%s`\n", e.what()));
mprintf(("PLR => Failed to open JSON: `%s`\n", e.what()));
continue;
}
@@ -74,7 +74,6 @@ void load_preset_files(SCP_string clone) {
// Start reading in data
CC_preset preset;
preset.name = file;
preset.type = Preset_t::pst;
preset.bindings.resize(Control_config.size());
size_t size;
@@ -105,7 +104,6 @@ void load_preset_files(SCP_string clone) {
str = handler->readString("input");
auto btn = InputToVal(cid, str.c_str());
item.first.take(cid, btn, flags);
handler->endSectionRead(); // Primary
@@ -126,17 +124,21 @@ void load_preset_files(SCP_string clone) {
handler->endArrayRead(); // Actions
// Done with the file
auto it = preset_find_duplicate(preset);
bool unique = true;
auto it = Control_config_presets.begin();
for (; it != Control_config_presets.end(); ++it) {
if (preset.is_duplicate_of(*it)) {
unique = false;
break;
}
}
// If we just cloned the file, then allow the duplicate. Just this once.
if ((clone == preset.name) || (it == Control_config_presets.end())) {
if (unique) {
Control_config_presets.push_back(preset);
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
// Complain and ignore if the preset names or the type differs
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
} else {
Warning(LOCATION, "Preset '%s' is a duplicate of '%s', ignoring", preset.name.c_str(), it->name.c_str());
}
} // else, silent ignore
}
}
@@ -148,31 +150,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()) {
@@ -243,27 +220,6 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
return true;
}
SCP_vector<CC_preset>::iterator preset_find_duplicate(const CC_preset& new_preset) {
SCP_vector<CC_preset>::iterator it = Control_config_presets.begin(); // NOLINT(modernize-use-auto)
for (; it != Control_config_presets.end(); ++it) {
size_t i;
for (i = 0; i < it->bindings.size(); ++i) {
if (new_preset.bindings[i] != it->bindings[i]) {
// These two differ, check the next in the vector
break;
}
}
if (i == it->bindings.size()) {
// These two are equal
break;
}
}
return it;
}
PresetFileHandler::PresetFileHandler(CFILE* cfp, bool reading) : _cfp(cfp) {
Assertion(cfp != nullptr, "File pointer must be valid!");
+1 -21
View File
@@ -209,32 +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 = "");
/**
* @brief Checks if the given preset is a duplicate within Control_config_presets vector
* @returns iterator to the duplicate if found, or
* @returns iterator to Control_config_presets.end() otherwise
*/
SCP_vector<CC_preset>::iterator preset_find_duplicate(const CC_preset& new_preset);
void load_preset_files();
/**
* @brief Returns true if a preset file with the given name exists.
+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;
+3 -19
View File
@@ -95,7 +95,7 @@ void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
}
}
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2, float alpha) {
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
GR_DEBUG_SCOPE("Draw video frame");
movie_vertex vertex_data[4];
@@ -127,26 +127,10 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2, float
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
switch (_properties.pixelFormat) {
case FramePixelFormat::YUV420:
material_set_movie(&_movie_material,
_planeTextureHandles[0],
_planeTextureHandles[1],
_planeTextureHandles[2],
alpha);
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
break;
case FramePixelFormat::BGR:
material_set_unlit(&_rgb_material, _planeTextureHandles[0], alpha, false, false);
} else {
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
break;
case FramePixelFormat::BGRA:
material_set_unlit(&_rgb_material, _planeTextureHandles[0], alpha, true, false);
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ class VideoPresenter {
void uploadVideoFrame(const VideoFramePtr& frame);
void displayFrame(float x1, float y1, float x2, float y2, float alpha = 1.0f);
void displayFrame(float x1, float y1, float x2, float y2);
};
}
}
+24 -116
View File
@@ -25,8 +25,6 @@
extern int Cmdline_nomovies;
bool Movie_active = false;
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
"ViewFootage",
@@ -50,113 +48,38 @@ void cutscene_close()
}
}
static cutscene_info *get_cutscene_pointer(char *cutscene_filename)
{
for (int i = 0; i < (int)Cutscenes.size(); i++) {
if (!stricmp(cutscene_filename, Cutscenes[i].filename)) {
return &Cutscenes[i];
}
}
// Didn't find anything.
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';
csni->name[0] = '\0';
csni->description = NULL;
csni->flags = {};
}
// initialization stuff for cutscenes
void parse_cutscene_table(const char* filename)
void cutscene_init()
{
atexit(cutscene_close);
char buf[MULTITEXT_LENGTH];
cutscene_info csnt;
cutscene_info_init(&csnt);
cutscene_info *csnp;
bool create_if_not_found = true;
cutscene_info cutinfo;
try
{
read_file_text(filename, CF_TYPE_TABLES);
read_file_text("cutscenes.tbl", CF_TYPE_TABLES);
reset_parse();
// parse in all the cutscenes
Cutscenes.clear();
skip_to_string("#Cutscenes");
ignore_white_space();
bool isFirstCutscene = true;
while (required_string_either("#End", "$Filename:"))
{
bool csn_new = false;
required_string("$Filename:");
stuff_string(csnt.filename, F_PATHNAME, MAX_FILENAME_LEN);
stuff_string(cutinfo.filename, F_PATHNAME, MAX_FILENAME_LEN);
if (optional_string("+nocreate")) {
if (!Parsing_modular_table) {
Warning(LOCATION, "+nocreate flag used for cutscene in non-modular table\n");
}
create_if_not_found = false;
}
required_string("$Name:");
stuff_string(cutinfo.name, F_NAME, NAME_LENGTH);
// Does this cutscene exist already?
// If so, load this new info into it
csnp = get_cutscene_pointer(csnt.filename);
if (csnp != NULL) {
if (!Parsing_modular_table) {
error_display(1,
"Error: Cutscene %s already exists. All cutscene names must be unique.",
csnt.filename);
}
} else {
// Don't create cutscene 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("$Filename:", "#End")) {
error_display(1, "Missing [#End] or [$Filename] after cutscene %s", csnt.filename);
}
continue;
}
Cutscenes.push_back(csnt);
csn_new = true;
csnp = &Cutscenes[Cutscenes.size() -1];
}
//If $Name is not found use the $Filename instead because this field needs data
//but only do this if if we're parsing the tbl and not a tbm
if (optional_string("$Name:")) {
stuff_string(csnp->name, F_NAME, NAME_LENGTH);
mprintf(("Adding cutscene %s\n", csnp->name));
} else if (strlen(csnp->name) == 0) {
strcpy_s(csnp->name, csnt.filename);
mprintf(("Missing $Name: in cutscene.tbl. Using filename %s instead.\n", csnt.filename));
}
//If $Description is not found we can leave it blank
if (optional_string("$Description:")) {
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
csnp->description = vm_strdup(buf);
}
required_string("$Description:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
cutinfo.description = vm_strdup(buf);
if (optional_string("$cd:"))
{
@@ -165,14 +88,13 @@ void parse_cutscene_table(const char* filename)
stuff_int(&junk);
}
if (csn_new) {
csnp->flags.reset();
}
cutinfo.flags.reset();
if (Cutscenes.empty())
if (isFirstCutscene)
{
isFirstCutscene = false;
// The original code assumes the first movie is the intro, so make it viewable
csnp->flags.set(Cutscene::Cutscene_Flags::Viewable);
cutinfo.flags.set(Cutscene::Cutscene_Flags::Viewable);
}
if (optional_string("$Always Viewable:"))
@@ -180,19 +102,17 @@ void parse_cutscene_table(const char* filename)
bool flag;
stuff_boolean(&flag);
if (flag)
csnp->flags.set(Cutscene::Cutscene_Flags::Always_viewable);
cutinfo.flags.set(Cutscene::Cutscene_Flags::Always_viewable);
}
if (optional_string("$Never Viewable:"))
{
bool flag;
stuff_boolean(&flag);
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:");
cutinfo.flags.set(Cutscene::Cutscene_Flags::Never_viewable);
}
Cutscenes.push_back(cutinfo);
}
required_string("#End");
@@ -204,20 +124,6 @@ void parse_cutscene_table(const char* filename)
}
}
void cutscene_init()
{
atexit(cutscene_close);
Cutscenes.clear();
// first parse the default table
parse_cutscene_table("cutscenes.tbl");
// parse any modular tables
parse_modular_table("*-csn.tbm", parse_cutscene_table);
}
// marks a cutscene as viewable
void cutscene_mark_viewable(const char* filename)
{
@@ -236,6 +142,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 +155,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);
Loaded 100 of 1653 files, more files were not shown because too many files have changed in this diff. Show more