mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
Compare commits
141
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3043e1ee2d | ||
|
|
7a7841c30a | ||
|
|
d5653674f1 | ||
|
|
d74627ba61 | ||
|
|
ed20982b32 | ||
|
|
e21cc10c5e | ||
|
|
b5fe16081d | ||
|
|
41bff809e3 | ||
|
|
f119f3d370 | ||
|
|
a90a0a55bd | ||
|
|
d08d8b4b02 | ||
|
|
f1292ad15a | ||
|
|
eb911c8ca2 | ||
|
|
125de7f131 | ||
|
|
78d0bddbe1 | ||
|
|
b009991fae | ||
|
|
f2806dc77a | ||
|
|
6cbf0fbbf8 | ||
|
|
3a48613a2d | ||
|
|
99875810c6 | ||
|
|
13420121dd | ||
|
|
26c5152d4a | ||
|
|
5066e498a3 | ||
|
|
4bf806c485 | ||
|
|
2403f13483 | ||
|
|
8e98cddd6e | ||
|
|
30cabc4174 | ||
|
|
8a3b36d921 | ||
|
|
b74824f793 | ||
|
|
6a26ca5061 | ||
|
|
d34570ae90 | ||
|
|
a0f4c4d2b3 | ||
|
|
63990c54a9 | ||
|
|
6593565165 | ||
|
|
af93922ba5 | ||
|
|
daeb1a7940 | ||
|
|
f56cbc59f1 | ||
|
|
79418a073d | ||
|
|
ce2e165510 | ||
|
|
e9ee311709 | ||
|
|
7576d4f2fe | ||
|
|
866b06ca35 | ||
|
|
f3d15f8ddc | ||
|
|
c9fe191d31 | ||
|
|
bad255fffb | ||
|
|
be260ef74c | ||
|
|
0ac3d52261 | ||
|
|
f7df03c654 | ||
|
|
a7e1a27e36 | ||
|
|
ab319a631c | ||
|
|
7c2950480e | ||
|
|
a80bc26bfc | ||
|
|
ead3c62d23 | ||
|
|
5cd502fb79 | ||
|
|
905d777e18 | ||
|
|
66deb83980 | ||
|
|
de3e382180 | ||
|
|
0190fda7ee | ||
|
|
9651dc1598 | ||
|
|
743cf779bf | ||
|
|
89a6e2aa7d | ||
|
|
84033d901c | ||
|
|
4b49123070 | ||
|
|
213bcbc80b | ||
|
|
0da34f0bc8 | ||
|
|
8fcf385e7e | ||
|
|
4f4722ccad | ||
|
|
7d94561ea5 | ||
|
|
248cec7cf9 | ||
|
|
e987d1cd7b | ||
|
|
f1aa29551b | ||
|
|
76734fb5ed | ||
|
|
fb0a62c400 | ||
|
|
1403301b65 | ||
|
|
1d1eb5ec4d | ||
|
|
7283412880 | ||
|
|
1d2ca8eb5a | ||
|
|
130ddb41f1 | ||
|
|
9462241c0b | ||
|
|
14bba9aea1 | ||
|
|
c7b43b0e0e | ||
|
|
1355c484fe | ||
|
|
1866c6adb5 | ||
|
|
a11517984e | ||
|
|
f207d2d12c | ||
|
|
4970252e9f | ||
|
|
d789e9b33a | ||
|
|
292f7d3b03 | ||
|
|
3bfc37172a | ||
|
|
2bb1c10557 | ||
|
|
40fac5dd5f | ||
|
|
2a33e374c2 | ||
|
|
d48d00d946 | ||
|
|
562875130c | ||
|
|
4401101fea | ||
|
|
509f887f6c | ||
|
|
266079997a | ||
|
|
f4a3903478 | ||
|
|
f4202df450 | ||
|
|
e619c0c3d3 | ||
|
|
ff0b79b6be | ||
|
|
701d20c112 | ||
|
|
9a45c9fd05 | ||
|
|
146102e82c | ||
|
|
be2c18d608 | ||
|
|
c9644cdcae | ||
|
|
d088e895f8 | ||
|
|
f1a9b2639b | ||
|
|
a1690dcb90 | ||
|
|
2c4088efdd | ||
|
|
da3725a3ac | ||
|
|
81b7460e57 | ||
|
|
c9a1127764 | ||
|
|
6eb9ae2aec | ||
|
|
d3d9ee3092 | ||
|
|
f66fc92859 | ||
|
|
94cbc350a4 | ||
|
|
550e9ec5b2 | ||
|
|
de3463958d | ||
|
|
03d7845124 | ||
|
|
661dceb0d8 | ||
|
|
202686dab6 | ||
|
|
b8da1106eb | ||
|
|
43f7921121 | ||
|
|
f4669db41c | ||
|
|
b3df3364e4 | ||
|
|
b6a76b788d | ||
|
|
e21b07662e | ||
|
|
9b4b0b552b | ||
|
|
bdab7a0c55 | ||
|
|
e269cdab6e | ||
|
|
edc76bcb40 | ||
|
|
cbde5a8e85 | ||
|
|
7fcfc35820 | ||
|
|
f852421d76 | ||
|
|
2321311725 | ||
|
|
733e1adcba | ||
|
|
485eb16fe3 | ||
|
|
a493f07333 | ||
|
|
e543c1aea2 | ||
|
|
0d1d6fdf44 |
No files matched your search
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-5ac6f70
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
@@ -269,6 +269,18 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -44,7 +44,7 @@ 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-5ac6f70
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
@@ -339,6 +339,18 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-5ac6f70
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
@@ -282,6 +282,18 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-5, gcc-13, clang-16]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-5ac6f70
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-5, gcc-13, clang-16]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-5ac6f70
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -2,13 +2,13 @@ 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!
|
||||
|
||||
# This mode is for testing
|
||||
#This mode is for testing
|
||||
#on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
on:
|
||||
schedule:
|
||||
- cron: "1 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
@@ -19,23 +19,16 @@ jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install ninja-build
|
||||
sudo apt install cmake libsdl2-dev g++
|
||||
sudo apt-get install libopenal-dev
|
||||
sudo apt-get install -y libudev-dev
|
||||
sudo apt-get install doxygen
|
||||
sudo apt install graphviz
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
@@ -51,17 +44,10 @@ jobs:
|
||||
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
|
||||
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
|
||||
|
||||
- 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 for FSO
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
compiler: gcc-5
|
||||
compiler: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$COMPILER" = "gcc-5" ]; then
|
||||
export CC=gcc-5
|
||||
export CXX=g++-5
|
||||
if [ "$COMPILER" = "gcc-9" ]; then
|
||||
export CC=gcc-9
|
||||
export CXX=g++-9
|
||||
fi
|
||||
if [ "$COMPILER" = "gcc-13" ]; then
|
||||
export CC=gcc-13
|
||||
|
||||
@@ -7,15 +7,15 @@ 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. 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.
|
||||
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods, we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. Any features listed under Deprecations will be removed or changed when the target version of a mod is at least the version released in this post.
|
||||
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=98682.0]23.0.0 Release Thread[/url][/size]
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=99238.0]24.0.1 Release Thread[/url][/size]
|
||||
|
||||
Launchers, if you don't have one already:
|
||||
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
|
||||
[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.
|
||||
|
||||
[hidden=Alternative Launchers]
|
||||
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
|
||||
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)
|
||||
[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
|
||||
@@ -41,7 +41,7 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
|
||||
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
|
||||
[url=https://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
|
||||
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url] and it will download the best build specifically for your PC!
|
||||
Don't want to deal with that? Use [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
|
||||
+2
-2
@@ -597,8 +597,8 @@ extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, v
|
||||
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(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);
|
||||
float ai_get_weapon_speed(const ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
|
||||
// function to change rearm status for ai ships (called from sexpression code)
|
||||
extern void ai_set_rearm_status( int team, int new_status );
|
||||
|
||||
+6
-6
@@ -76,7 +76,7 @@ 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(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)
|
||||
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)
|
||||
{
|
||||
float nearest_dist;
|
||||
vec3d result_point, best_point;
|
||||
@@ -193,7 +193,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(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
|
||||
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)
|
||||
{
|
||||
if (!timestamp_elapsed(ssp->turret_pick_big_attack_point_timestamp)) {
|
||||
vec3d result_point;
|
||||
@@ -213,7 +213,7 @@ void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
// 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(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
|
||||
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov)
|
||||
{
|
||||
Assert(objp->instance > -1);
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
@@ -411,7 +411,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
}
|
||||
}
|
||||
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 1) ) {
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, true) ) {
|
||||
subsys_in_sight = 1;
|
||||
}
|
||||
}
|
||||
@@ -541,7 +541,7 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
get_subsystem_pos(&gsubpos, target_objp, aip->targeted_subsys);
|
||||
|
||||
// you're in sight! shoot it!
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, false))
|
||||
return false;
|
||||
|
||||
// not in sight, gotta get there
|
||||
@@ -1034,7 +1034,7 @@ void ai_big_chase()
|
||||
ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
|
||||
|
||||
weapon_info* wip = ai_get_weapon(&shipp->weapons);
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip->gravity_const != 0.0f;
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip && wip->gravity_const != 0.0f;
|
||||
bool valid_ballistic_trajectory = true;
|
||||
|
||||
if (!ballistic_aiming) {
|
||||
|
||||
+2
-2
@@ -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(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);
|
||||
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);
|
||||
|
||||
// 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()
|
||||
|
||||
+22
-24
@@ -1021,7 +1021,7 @@ void ai_level_init()
|
||||
/**
|
||||
* Check if object is a stealth ship
|
||||
*/
|
||||
bool is_object_stealth_ship(object* objp)
|
||||
bool is_object_stealth_ship(const object *objp)
|
||||
{
|
||||
if (objp->type == OBJ_SHIP) {
|
||||
if (Ships[objp->instance].flags[Ship::Ship_Flags::Stealth]) {
|
||||
@@ -1109,7 +1109,7 @@ float get_skill_stealth_dot_scaler()
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
int ai_is_stealth_visible(object *viewer_objp, object *stealth_objp)
|
||||
int ai_is_stealth_visible(const object *viewer_objp, const object *stealth_objp)
|
||||
{
|
||||
ship *shipp;
|
||||
vec3d vec_to_stealth;
|
||||
@@ -1905,7 +1905,7 @@ int Player_attacking_enabled = 1;
|
||||
/**
|
||||
* Determine whether an object is targetable within a nebula
|
||||
*/
|
||||
int object_is_targetable(object *target, ship *viewer)
|
||||
bool object_is_targetable(const object *target, const ship *viewer)
|
||||
{
|
||||
// if target is ship, check if visible by team
|
||||
if (target->type == OBJ_SHIP)
|
||||
@@ -2413,7 +2413,7 @@ int find_nearby_threat(int objnum, int enemy_team_mask, float range, int *count)
|
||||
/**
|
||||
* Number of live turrets with target_objnum
|
||||
*/
|
||||
int num_turrets_attacking(object *turret_parent, int target_objnum)
|
||||
int num_turrets_attacking(const object *turret_parent, int target_objnum)
|
||||
{
|
||||
ship_subsys *ss;
|
||||
ship *shipp;
|
||||
@@ -3636,7 +3636,7 @@ int Debug_k = 0;
|
||||
*
|
||||
* Return this value. Return value of 0.0f means no collision is possible.
|
||||
*/
|
||||
float compute_collision_time(vec3d *targpos, vec3d *targvel, vec3d *attackpos, float weapon_speed)
|
||||
float compute_collision_time(const vec3d *targpos, const vec3d *targvel, const vec3d *attackpos, float weapon_speed)
|
||||
{
|
||||
vec3d vec_to_target;
|
||||
float pos_dot_vel;
|
||||
@@ -6305,7 +6305,7 @@ int ai_fire_primary_weapon(object *objp)
|
||||
// threshold => max distance from pos to be considered "near"
|
||||
//
|
||||
// exit: number of ships within threshold units of pos
|
||||
int num_nearby_fighters(int enemy_team_mask, vec3d *pos, float threshold)
|
||||
int num_nearby_fighters(int enemy_team_mask, const vec3d *pos, float threshold)
|
||||
{
|
||||
ship_obj *so;
|
||||
object *ship_objp;
|
||||
@@ -6476,7 +6476,7 @@ bool ai_select_secondary_weapon(object *objp, ship_weapon *swp, flagset<Weapon::
|
||||
/**
|
||||
* @return number of objects homing on object *target_objp
|
||||
*/
|
||||
int compute_num_homing_objects(object *target_objp)
|
||||
int compute_num_homing_objects(const object *target_objp)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
@@ -6558,7 +6558,7 @@ float compute_incoming_payload(object *target_objp)
|
||||
// OR: secondary los flag is set but no line of sight is availabe
|
||||
// Note: If player is attacking a ship, that ship is allowed to fire at player. Otherwise, we get in a situation in which
|
||||
// player is attacking a large ship, but that large ship is not defending itself with missiles.
|
||||
int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int secondary_bank, ship_subsys* turret)
|
||||
bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int secondary_bank, const vec3d *firing_pos_global)
|
||||
{
|
||||
int num_homers = 0;
|
||||
|
||||
@@ -6574,8 +6574,8 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int second
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Require_exact_los] || wip->wi_flags[Weapon::Info_Flags::Require_exact_los]) {
|
||||
//Check if th AI has Line of Sight and is allowed to fire
|
||||
if (!check_los(objnum, target_objnum, 10.0f, -1, secondary_bank, turret)) {
|
||||
return 0;
|
||||
if (!check_los(objnum, target_objnum, 10.0f, -1, secondary_bank, firing_pos_global)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6589,14 +6589,14 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int second
|
||||
// At Easy, 2/7...at Expert, 5/7
|
||||
int t = ((Missiontime /(65536*10)) ^ target_objnum ^ 0x01) % (NUM_SKILL_LEVELS+2);
|
||||
if (t > Ai_info[Ships[tobjp->instance].ai_index].ai_chance_to_use_missiles_on_plr) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int swarmers = 0;
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Swarm])
|
||||
swarmers = 2; // Note, always want to be able to fire swarmers if no currently incident homers.
|
||||
if (The_mission.ai_profile->max_allowed_player_homers[Game_skill_level] < num_homers + swarmers) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
} else if (num_homers > 3) {
|
||||
float incoming_payload;
|
||||
@@ -6604,22 +6604,22 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int second
|
||||
incoming_payload = compute_incoming_payload(&Objects[target_objnum]);
|
||||
|
||||
if (incoming_payload > tobjp->hull_strength) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Returns true if *aip has a line of sight to its current target.
|
||||
// threshold defines the minimum radius for an object to be considered relevant for LoS
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret) {
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, const vec3d *firing_pos_global) {
|
||||
|
||||
//Do both checks over an XOR-Check for more detailed messages
|
||||
int sources = (primary_bank != -1 ? 1 : 0) + (secondary_bank != -1 ? 1 : 0) + (turret != nullptr ? 1 : 0);
|
||||
int sources = (primary_bank != -1 ? 1 : 0) + (secondary_bank != -1 ? 1 : 0) + (firing_pos_global != nullptr ? 1 : 0);
|
||||
Assertion(sources >= 1, "Cannot check line of sight from a model with neither a primar bank, nor secondary bank nor a turret set as a source.");
|
||||
Assertion(sources <= 1, "Cannot check line of sight from a model with more than one source set.");
|
||||
|
||||
@@ -6627,10 +6627,8 @@ bool check_los(int objnum, int target_objnum, float threshold, int primary_bank,
|
||||
|
||||
object* firing_ship = &Objects[objnum];
|
||||
|
||||
if (turret != nullptr) {
|
||||
vec3d turret_fvec;
|
||||
//It doesn't like not having an fvec output vector, so give it a dummy vector
|
||||
ship_get_global_turret_gun_info(firing_ship, turret, &start, &turret_fvec, 1, nullptr);
|
||||
if (firing_pos_global != nullptr) {
|
||||
start = *firing_pos_global;
|
||||
} else {
|
||||
bool is_primary = secondary_bank == -1;
|
||||
ship *shipp = &Ships[firing_ship->instance];
|
||||
@@ -6942,7 +6940,7 @@ float ai_get_weapon_dist(ship_weapon *swp)
|
||||
return MIN((Weapon_info[weapon_num].max_speed * Weapon_info[weapon_num].lifetime), Weapon_info[weapon_num].weapon_range);
|
||||
}
|
||||
|
||||
float ai_get_weapon_speed(ship_weapon *swp)
|
||||
float ai_get_weapon_speed(const ship_weapon *swp)
|
||||
{
|
||||
int bank_num, weapon_num;
|
||||
|
||||
@@ -6986,7 +6984,7 @@ weapon_info* ai_get_weapon(ship_weapon *swp)
|
||||
// Also, stuff globals G_predicted_pos, G_collision_time and G_fire_pos.
|
||||
// *pobjp object firing the weapon
|
||||
// *eobjp object being fired upon
|
||||
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)
|
||||
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)
|
||||
{
|
||||
ship *shipp = &Ships[pobjp->instance];
|
||||
float range_time;
|
||||
@@ -10243,7 +10241,7 @@ void guard_object_was_hit(object *guard_objp, object *hitter_objp)
|
||||
}
|
||||
|
||||
// don't attack if you can't see him
|
||||
if ( awacs_get_level(hitter_objp, &Ships[aip->shipnum], 1) < 1 ) {
|
||||
if ( awacs_get_level(hitter_objp, &Ships[aip->shipnum], true) < 1.0f ) {
|
||||
// if he's a stealth and visible, but not targetable, ok to attack.
|
||||
if ( is_object_stealth_ship(hitter_objp) ) {
|
||||
if ( ai_is_stealth_visible(guard_objp, hitter_objp) != STEALTH_IN_FRUSTUM ) {
|
||||
@@ -15812,7 +15810,7 @@ void maybe_set_dynamic_chase(ai_info *aip, int hitter_objnum)
|
||||
}
|
||||
|
||||
// only set as target if can be targeted.
|
||||
if (awacs_get_level(&Objects[hitter_objnum], &Ships[aip->shipnum], 1) < 1) {
|
||||
if (awacs_get_level(&Objects[hitter_objnum], &Ships[aip->shipnum], true) < 1.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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(object* objp);
|
||||
bool is_object_stealth_ship(const object* objp);
|
||||
|
||||
//Number of live turrets on the object attacking
|
||||
int num_turrets_attacking(object *turret_parent, int target_objnum);
|
||||
int num_turrets_attacking(const object *turret_parent, int target_objnum);
|
||||
|
||||
//Determine whether an object is targetable within a nebula (checks for stealth)
|
||||
int object_is_targetable(object *target, ship *viewer);
|
||||
bool object_is_targetable(const object *target, const ship *viewer);
|
||||
|
||||
//Returns the number of enemy fighters within threshold of pos.
|
||||
int num_nearby_fighters(int enemy_team_mask, vec3d *pos, float threshold);
|
||||
int num_nearby_fighters(int enemy_team_mask, const vec3d *pos, float threshold);
|
||||
|
||||
//Returns true if OK for *aip to fire its current weapon at its current target.
|
||||
int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int secondary_bank, ship_subsys* turret);
|
||||
bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int secondary_bank, const vec3d *firing_pos_global);
|
||||
|
||||
//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, ship_subsys* turret);
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, const vec3d *firing_pos_global);
|
||||
|
||||
//Does all the stuff needed to aim and fire a turret.
|
||||
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss);
|
||||
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss);
|
||||
|
||||
#endif
|
||||
+142
-192
@@ -118,7 +118,7 @@ void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num,
|
||||
* @param tpos Turret initial position
|
||||
* @param dist Distance from turret to center point of object
|
||||
*
|
||||
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
|
||||
* @return true if objp is in fov of the specified turret. Otherwise return false.
|
||||
*/
|
||||
bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d *tvec, const vec3d *tpos, float dist)
|
||||
{
|
||||
@@ -175,9 +175,9 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
|
||||
* @param bomb_objp Bomb specified
|
||||
* @param ship_objp Ship specified
|
||||
*
|
||||
* @return 1 if bomb_objp is headed towards ship_objp
|
||||
* @return true if bomb_objp is headed towards ship_objp
|
||||
*/
|
||||
int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
bool bomb_headed_towards_ship(const object *bomb_objp, const object *ship_objp)
|
||||
{
|
||||
float dot;
|
||||
vec3d bomb_to_ship_vector;
|
||||
@@ -185,11 +185,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
vm_vec_normalized_dir(&bomb_to_ship_vector, &ship_objp->pos, &bomb_objp->pos);
|
||||
dot = vm_vec_dot(&bomb_objp->orient.vec.fvec, &bomb_to_ship_vector);
|
||||
|
||||
if ( dot > 0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ( dot > 0 );
|
||||
}
|
||||
|
||||
// Set active weapon for turret
|
||||
@@ -201,7 +197,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
* @note All non-negative return values are expressed in what I like to call "widx"s.
|
||||
* @return -1 if unable to find a weapon for the target at all.
|
||||
*/
|
||||
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
|
||||
int turret_select_best_weapon(const ship_subsys *turret, const object * /*target*/)
|
||||
{
|
||||
//TODO: Fill this out with extraodinary gun-picking algorithms
|
||||
if(turret->weapons.num_primary_banks > 0)
|
||||
@@ -335,7 +331,7 @@ bool turret_weapon_has_subtype(const ship_weapon *swp, int subtype)
|
||||
*
|
||||
* @return a pointer to the Weapon_info for weapon_num
|
||||
*/
|
||||
weapon_info *get_turret_weapon_wip(ship_weapon *swp, int weapon_num)
|
||||
const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
Assert(weapon_num >= 0);
|
||||
@@ -352,7 +348,7 @@ weapon_info *get_turret_weapon_wip(ship_weapon *swp, int weapon_num)
|
||||
return &Weapon_info[wi_index];
|
||||
}
|
||||
|
||||
int get_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num)
|
||||
int get_turret_weapon_next_fire_stamp(const ship_weapon *swp, int weapon_num)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
Assert(weapon_num >= 0);
|
||||
@@ -379,7 +375,7 @@ void set_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num, int del
|
||||
*
|
||||
* @todo This function is kinda slow
|
||||
*/
|
||||
float longest_turret_weapon_range(ship_weapon *swp)
|
||||
float longest_turret_weapon_range(const ship_weapon *swp)
|
||||
{
|
||||
float longest_range_so_far = 0.0f;
|
||||
float weapon_range;
|
||||
@@ -770,10 +766,10 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
* @param laser_flag
|
||||
* @param missile_flag
|
||||
*/
|
||||
int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subsys, int enemy_team_mask, vec3d *tpos, vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
|
||||
int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turret_subsys, int enemy_team_mask, const vec3d *tpos, const vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
|
||||
{
|
||||
eval_enemy_obj_struct eeo;
|
||||
ship_weapon *swp = &turret_subsys->weapons;
|
||||
auto swp = &turret_subsys->weapons;
|
||||
|
||||
// list of stuff to go thru
|
||||
ship_obj *so;
|
||||
@@ -1067,7 +1063,7 @@ DCF_BOOL(use_parent_target, Use_parent_target)
|
||||
* @param tvec Forward vector of turret (world coords)
|
||||
* @param current_enemy Objnum of current turret target
|
||||
*/
|
||||
int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d *tvec, int current_enemy)
|
||||
int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d *tpos, const vec3d *tvec, int current_enemy)
|
||||
{
|
||||
int enemy_team_mask, enemy_objnum;
|
||||
ship_info *sip;
|
||||
@@ -1188,8 +1184,6 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
|
||||
}
|
||||
|
||||
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
|
||||
|
||||
/**
|
||||
* Given an object and a turret on that object, return the actual firing point of the gun and its normal.
|
||||
*
|
||||
@@ -1200,86 +1194,44 @@ void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
|
||||
* @param objp Pointer to object
|
||||
* @param ssp Pointer to turret subsystem
|
||||
* @param gpos Absolute position of gun firing point
|
||||
* @param avg_origin Use virtual gun pos corresponding to the average of the firing points
|
||||
* @param gvec Vector from *gpos to *targetp
|
||||
* @param use_angles Use current angles
|
||||
* @param targetp Pointer to target object
|
||||
* @param targetp Absolute position of target object
|
||||
*/
|
||||
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp)
|
||||
void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp, vec3d *gpos, bool avg_origin, vec3d *gvec, bool use_angles, const vec3d *targetp)
|
||||
{
|
||||
vec3d * gun_pos;
|
||||
vec3d *gun_pos;
|
||||
model_subsystem *tp = ssp->system_info;
|
||||
polymodel_instance *pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
polymodel *pm = model_get(pmi->model_num);
|
||||
|
||||
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
|
||||
vec3d avg_gun_pos;
|
||||
if (avg_origin) {
|
||||
vm_vec_avg_n(&avg_gun_pos, tp->turret_num_firing_points, tp->turret_firing_point);
|
||||
gun_pos = &avg_gun_pos;
|
||||
} else {
|
||||
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
|
||||
}
|
||||
|
||||
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
// we might not need to calculate this
|
||||
if (!gvec)
|
||||
return;
|
||||
|
||||
if (use_angles) {
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
|
||||
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
|
||||
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
|
||||
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
|
||||
|
||||
model_instance_local_to_global_point(&tmp_pos, &avg, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
if (targetp == nullptr) {
|
||||
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship name %s is invalid.", ssp->turret_enemy_objnum, ssp->sub_name, shipp->ship_name);
|
||||
object *lep = &Objects[ssp->turret_enemy_objnum];
|
||||
|
||||
int best_weapon_tidx = turret_select_best_weapon(ssp, lep);
|
||||
|
||||
//This turret doesn't have any good weapons
|
||||
if (best_weapon_tidx < 0)
|
||||
return;
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ssp->weapons, best_weapon_tidx);
|
||||
|
||||
float weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
|
||||
if ((ssp->targeted_subsys != nullptr) && !(ssp->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
vm_vec_unrotate(&enemy_point, &ssp->targeted_subsys->system_info->pnt, &Objects[ssp->turret_enemy_objnum].orient);
|
||||
vm_vec_add2(&enemy_point, &ssp->last_aim_enemy_pos);
|
||||
} else {
|
||||
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
|
||||
// the turret norm here is from the perspective of the base submodel, not the gun submodel
|
||||
model_instance_local_to_global_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
|
||||
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
|
||||
}
|
||||
else {
|
||||
enemy_point = ssp->last_aim_enemy_pos;
|
||||
}
|
||||
}
|
||||
|
||||
vec3d target_moving_direction = ssp->last_aim_enemy_vel;
|
||||
|
||||
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
|
||||
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
set_predicted_enemy_pos_turret(&tmp_target, &tmp_pos, objp, &enemy_point, &target_moving_direction, wip->max_speed, ssp->turret_time_enemy_in_range * (weapon_system_strength + 1.0f) / 2.0f);
|
||||
} else {
|
||||
tmp_target = *targetp;
|
||||
}
|
||||
|
||||
vm_vec_normalized_dir(gvec, &tmp_target, &tmp_pos);
|
||||
} else {
|
||||
//vector gun_pos2;
|
||||
//vm_vec_add(&gun_pos2, gpos, gun_pos);
|
||||
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
|
||||
vm_vec_normalized_dir(gvec, targetp, gpos);
|
||||
}
|
||||
|
||||
// per firingpoint based changes go here for turrets
|
||||
}
|
||||
|
||||
/**
|
||||
* Update turret aiming data based on max turret aim update delay
|
||||
*/
|
||||
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss)
|
||||
void turret_ai_update_aim(const ai_info *aip, const object *En_Objp, ship_subsys *ss)
|
||||
{
|
||||
if (Missiontime >= ss->next_aim_pos_time)
|
||||
{
|
||||
@@ -1294,26 +1246,15 @@ void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate a turret towards an enemy.
|
||||
*
|
||||
* Some obscure model thing only John Slagel knows about.
|
||||
* Sets predicted enemy position.
|
||||
* Sets predicted enemy position. Previously done at the beginning of aifft_rotate_turret.
|
||||
* If the turret (*ss) has a subsystem targeted, the subsystem is used as the predicted point.
|
||||
*
|
||||
* @return TRUE if caller should use angles in subsequent rotations.
|
||||
*/
|
||||
int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep, vec3d *predicted_enemy_pos, vec3d *gvec)
|
||||
void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const object *lep, vec3d *predicted_enemy_pos)
|
||||
{
|
||||
int ret_val __UNUSED = 0; // to be used in future, see comment @ end of function
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
vec3d gun_pos, gun_vec, target_vel;
|
||||
//float weapon_speed;
|
||||
vec3d target_vel;
|
||||
float weapon_system_strength;
|
||||
//HACK HACK HACK -WMC
|
||||
//This should use the best weapon variable
|
||||
@@ -1322,15 +1263,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
|
||||
//This turret doesn't have any good weapons
|
||||
if (best_weapon_tidx < 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
|
||||
auto wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
|
||||
|
||||
// weapon_system_strength scales time enemy in range in 0..1. So, the lower this is, the worse the aiming will be.
|
||||
weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
|
||||
ship_get_global_turret_info(objp, tp, &gun_pos, &gun_vec);
|
||||
|
||||
//Update "known" position and velocity of target. Only matters if max_aim_update_delay is set.
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ss->turret_enemy_objnum], ss);
|
||||
|
||||
@@ -1344,7 +1283,7 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
}
|
||||
} else {
|
||||
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
|
||||
ai_big_pick_attack_point_turret(lep, ss, &gun_pos, &gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
|
||||
ai_big_pick_attack_point_turret(lep, ss, global_gun_pos, global_gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
|
||||
} else {
|
||||
enemy_point = ss->last_aim_enemy_pos;
|
||||
}
|
||||
@@ -1357,25 +1296,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
vm_vec_scale_sub2(&target_vel, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
|
||||
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
|
||||
vec3d temp;
|
||||
ship_get_global_turret_gun_info(objp, ss, &gun_pos, &temp, 1, nullptr);
|
||||
}
|
||||
|
||||
if (IS_VEC_NULL(&The_mission.gravity) || wip->gravity_const == 0.0f)
|
||||
set_predicted_enemy_pos_turret(predicted_enemy_pos, &gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
|
||||
set_predicted_enemy_pos_turret(predicted_enemy_pos, global_gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
|
||||
else {
|
||||
vec3d shoot_vec;
|
||||
vec3d gravity_vec = The_mission.gravity * wip->gravity_const;
|
||||
if (physics_lead_ballistic_trajectory(&gun_pos, &enemy_point, &target_vel, wip->max_speed, &gravity_vec, &shoot_vec)) {
|
||||
*predicted_enemy_pos = gun_pos + shoot_vec * 1000.0f;
|
||||
} else {
|
||||
if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
}
|
||||
return ret_val;
|
||||
if (physics_lead_ballistic_trajectory(global_gun_pos, &enemy_point, &target_vel, wip->max_speed, &gravity_vec, &shoot_vec)) {
|
||||
*predicted_enemy_pos = *global_gun_pos + shoot_vec * 1000.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1387,36 +1314,54 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
// Add to predicted_enemy_pos value in .45 to 1.5x radius of enemy ship, so will often miss, but not by a huge amount.
|
||||
vm_vec_scale_add2(predicted_enemy_pos, &rand_vec, (1.0f - weapon_system_strength)*1.5f * lep->radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a turret towards an enemy.
|
||||
*
|
||||
* Some obscure model thing only John Slagel knows about.
|
||||
*
|
||||
* @return TRUE if caller should use angles in subsequent rotations.
|
||||
*/
|
||||
bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const vec3d *predicted_enemy_pos)
|
||||
{
|
||||
bool ret_val __UNUSED = false; // to be used in future, see comment @ end of function
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
|
||||
//Get the normalized dir between the turret and the predicted enemy position.
|
||||
//If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, &gun_pos);
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
|
||||
|
||||
bool in_fov;
|
||||
|
||||
in_fov = turret_fov_test(ss, gvec, &v2e);
|
||||
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
|
||||
|
||||
if (in_fov) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
|
||||
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
|
||||
// but we need to keep retail behavior by default, which means always returning 0 unless a special
|
||||
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
|
||||
// but we need to keep retail behavior by default, which means always returning false unless a special
|
||||
// flag is used. the "ret_val" stuff is here is needed/wanted at a later date however.
|
||||
//return ret_val;
|
||||
|
||||
// return 0 by default (to preserve retail behavior) but allow for a per-subsystem option
|
||||
// return false by default (to preserve retail behavior) but allow for a per-subsystem option
|
||||
// for using the turret normals for firing
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1424,7 +1369,7 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
*
|
||||
* @return Dot product of vector from point abs_gunposp to *enemy_subsysp, if hittable
|
||||
*/
|
||||
float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunposp, ship_subsys *turret_subsysp, ship_subsys *enemy_subsysp)
|
||||
float aifft_compute_turret_dot(const object *objp, const object *enemy_objp, const vec3d *abs_gunposp, const ship_subsys *turret_subsysp, const ship_subsys *enemy_subsysp)
|
||||
{
|
||||
float dot_out;
|
||||
vec3d subobj_pos, vector_out;
|
||||
@@ -1432,7 +1377,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
|
||||
vm_vec_unrotate(&subobj_pos, &enemy_subsysp->system_info->pnt, &enemy_objp->orient);
|
||||
vm_vec_add2(&subobj_pos, &enemy_objp->pos);
|
||||
|
||||
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
|
||||
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, true, &dot_out, &vector_out)) {
|
||||
vec3d turret_norm;
|
||||
|
||||
model_instance_local_to_global_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
|
||||
@@ -1486,7 +1431,7 @@ DCF(mf, "Adjusts the maximum number of tries an AI may do when trying to pick a
|
||||
*
|
||||
* @return Dot product from turret to subsystem in *dot_out
|
||||
*/
|
||||
ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *enemy_objp, float *dot_out)
|
||||
ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp, const vec3d *global_gun_pos, const object *enemy_objp, float *dot_out)
|
||||
{
|
||||
ship *eshipp, *shipp;
|
||||
ship_info *esip;
|
||||
@@ -1503,10 +1448,6 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
float best_dot = 0.0f;
|
||||
*dot_out = best_dot;
|
||||
|
||||
// Compute absolute gun position.
|
||||
vec3d abs_gun_pos;
|
||||
ship_get_global_turret_info(objp, ssp->system_info, &abs_gun_pos, nullptr);
|
||||
|
||||
// Only pick a turret to attack on large ships.
|
||||
if (!esip->is_big_or_huge())
|
||||
return best_subsysp;
|
||||
@@ -1572,7 +1513,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
}
|
||||
|
||||
for(idx=offset; idx<aifft_list_size; idx+=stride){
|
||||
dot = aifft_compute_turret_dot(objp, enemy_objp, &abs_gun_pos, ssp, aifft_list[idx]);
|
||||
dot = aifft_compute_turret_dot(objp, enemy_objp, global_gun_pos, ssp, aifft_list[idx]);
|
||||
|
||||
if ((dot - dot_fov_modifier)* aifft_rank[idx] > best_dot) {
|
||||
best_dot = (dot - dot_fov_modifier)*aifft_rank[idx];
|
||||
@@ -1587,34 +1528,17 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
}
|
||||
|
||||
/**
|
||||
* @return !0 if the specified target should scan for a new target, otherwise return 0
|
||||
* @return true if the specified target should scan for a new target, otherwise return false
|
||||
*/
|
||||
int turret_should_pick_new_target(ship_subsys *turret)
|
||||
bool turret_should_pick_new_target(ship_subsys *turret)
|
||||
{
|
||||
// int target_type;
|
||||
|
||||
if ( timestamp_elapsed(turret->turret_next_enemy_check_stamp) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
if ( turret->turret_enemy_objnum == -1 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
target_type = Objects[turret->turret_enemy_objnum].type;
|
||||
if ( (target_type != OBJ_SHIP) && (target_type != OBJ_ASTEROID) ) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
|
||||
return timestamp_elapsed(turret->turret_next_enemy_check_stamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the next fire timestamp for a turret, based on weapon type and ai class
|
||||
*/
|
||||
void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsys *turret, ai_info *aip)
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
float wait = 1000.0f;
|
||||
@@ -1727,13 +1651,13 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
/**
|
||||
* Decide if a turret should launch an aspect seeking missile
|
||||
*/
|
||||
int turret_should_fire_aspect(ship_subsys *turret, weapon_info *wip, bool in_sight)
|
||||
bool turret_should_fire_aspect(const ship_subsys *turret, const weapon_info *wip, bool in_sight)
|
||||
{
|
||||
if ( in_sight && (turret->turret_time_enemy_in_range >= MIN(wip->min_lock_time,AICODE_TURRET_MAX_TIME_IN_RANGE)) ) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1755,9 +1679,9 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
|
||||
/**
|
||||
* Fire a weapon from a turret
|
||||
*/
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
{
|
||||
matrix turret_orient;
|
||||
matrix firing_orient;
|
||||
int weapon_objnum;
|
||||
ai_info *parent_aip;
|
||||
ship *parent_ship;
|
||||
@@ -1819,16 +1743,21 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, turret)) {
|
||||
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, orig_firing_pos)) {
|
||||
auto turret_enemy_objp = (turret->turret_enemy_objnum >= 0) ? &Objects[turret->turret_enemy_objnum] : nullptr;
|
||||
|
||||
ship_weapon* swp = &turret->weapons;
|
||||
turret->turret_last_fire_direction = *firing_vec;
|
||||
turret->turret_last_fire_direction = *orig_firing_vec;
|
||||
|
||||
if (turret->turret_inaccuracy > 0.0f)
|
||||
vm_vec_random_cone(firing_vec, firing_vec, turret->turret_inaccuracy);
|
||||
const vec3d *firing_vec = orig_firing_vec;
|
||||
vec3d firing_vec_buf;
|
||||
|
||||
vm_vector_2_matrix(&turret_orient, firing_vec, nullptr, nullptr);
|
||||
if (turret->turret_inaccuracy > 0.0f) {
|
||||
vm_vec_random_cone(&firing_vec_buf, firing_vec, turret->turret_inaccuracy);
|
||||
firing_vec = &firing_vec_buf;
|
||||
}
|
||||
|
||||
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
|
||||
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
|
||||
int old_burst_seed = swp->burst_seed[weapon_num];
|
||||
@@ -2007,11 +1936,15 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3d firing_pos_buf;
|
||||
const vec3d *firing_pos = &firing_pos_buf;
|
||||
|
||||
// zookeeper - Firepoints should cycle normally between shots,
|
||||
// so we need to get the position info separately for each shot
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, turret_pos, firing_vec, 1, nullptr);
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
|
||||
|
||||
weapon_objnum = weapon_create( turret_pos, &turret_orient, turret_weapon_class, parent_objnum, -1, 1, 0,0.0f, turret);
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
|
||||
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
|
||||
|
||||
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
|
||||
@@ -2043,7 +1976,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if(predicted_pos != NULL)
|
||||
{
|
||||
// pick a firing range so that it detonates properly
|
||||
flak_pick_range(objp, turret_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
flak_pick_range(objp, firing_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
|
||||
// determine what that range was
|
||||
flak_range = flak_get_range(objp);
|
||||
@@ -2056,7 +1989,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
// do mflash if the weapon has it
|
||||
if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(turret_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
}
|
||||
|
||||
// in multiplayer (and the master), then send a turret fired packet.
|
||||
@@ -2075,7 +2008,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if ( play_sound && wip->launch_snd.isValid() ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), firing_pos, &View_position );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2107,7 +2040,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
{
|
||||
int weapon_objnum;
|
||||
matrix turret_orient;
|
||||
matrix firing_orient;
|
||||
vec3d turret_pos, turret_fvec;
|
||||
|
||||
// parent not alive, quick out.
|
||||
@@ -2120,7 +2053,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
tsi->turret->turret_next_fire_pos = tsi->weapon_num;
|
||||
|
||||
// change firing point
|
||||
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, &turret_fvec, 1, NULL);
|
||||
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, false, &turret_fvec, true, nullptr);
|
||||
tsi->turret->turret_next_fire_pos++;
|
||||
|
||||
//check if this really is a swarm. If not, how the hell did it get here?
|
||||
@@ -2135,11 +2068,11 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
turret_fvec = tsi->turret->turret_last_fire_direction;
|
||||
}
|
||||
|
||||
// make turret_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix(&turret_orient, &turret_fvec, NULL, NULL);
|
||||
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
|
||||
|
||||
// create weapon and homing info
|
||||
weapon_objnum = weapon_create(&turret_pos, &turret_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
|
||||
|
||||
// do other cool stuff if weapon is created.
|
||||
@@ -2198,7 +2131,7 @@ int Num_turrets_fired = 0;
|
||||
* all turret movement and resetting when idle
|
||||
*/
|
||||
extern int Nebula_sec_range;
|
||||
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
{
|
||||
float weapon_firing_range;
|
||||
float weapon_min_range; // *Weapon minimum firing range -Et1
|
||||
@@ -2282,12 +2215,21 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
objp = &Objects[shipp->objnum];
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
|
||||
// Use the turret info for all guns, not one gun in particular.
|
||||
vec3d gvec, gpos;
|
||||
ship_get_global_turret_info(objp, tp, &gpos, &gvec);
|
||||
vec3d global_gun_pos, global_gun_vec;
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
|
||||
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
|
||||
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, true, nullptr);
|
||||
} else {
|
||||
// Use the turret info for all guns, not one gun in particular.
|
||||
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
|
||||
}
|
||||
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
|
||||
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
|
||||
int use_angles = aifft_rotate_turret(objp, shipp, ss, lep, &predicted_enemy_pos, &gvec);
|
||||
bool use_angles = aifft_rotate_turret(objp, shipp, ss, &global_gun_pos, &global_gun_vec, &predicted_enemy_pos);
|
||||
|
||||
// Multiplayer clients are now able to try to track their targets and also reset to their idle positions.
|
||||
// But everything after this point is turret firing, so we need to bail here.
|
||||
@@ -2311,18 +2253,20 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
float dist_to_enemy = 0.0f;
|
||||
if (lep) {
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos));
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos));
|
||||
else
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos) - lep->radius);
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
|
||||
}
|
||||
|
||||
// count the number of enemies, in case we have a spawning weapon
|
||||
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &gpos, 1500.0f);
|
||||
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &global_gun_pos, 1500.0f);
|
||||
|
||||
// some flags considering there may be different weapon types on this turret
|
||||
bool we_did_non_spawning_logic = false;
|
||||
bool tentative_return = false;
|
||||
|
||||
float turret_barrel_length = -1.0f;
|
||||
|
||||
//WMC - go through all valid weapons. Fire spawns if there are any.
|
||||
int valid_weapons[MAX_SHIP_WEAPONS];
|
||||
int num_valid = 0;
|
||||
@@ -2354,7 +2298,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
{
|
||||
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
|
||||
turret_fire_weapon(i, ss, parent_objnum, &gpos, &ss->turret_last_fire_direction);
|
||||
turret_fire_weapon(i, ss, parent_objnum, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
} else {
|
||||
// Regardless of firing rate, don't check whether should fire for awhile.
|
||||
if (tp->flags[Model::Subsystem_Flags::Use_multiple_guns])
|
||||
@@ -2402,10 +2346,16 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// If the barrel of this turret is long, we shouldn't try to fire if the enemy is under the gun.
|
||||
// Note that this isn't the same thing as min_range, which is unrelated to barrel length.
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
vec3d fpoint, fvec;
|
||||
ship_get_global_turret_gun_info(objp, ss, &fpoint, &fvec, use_angles, &predicted_enemy_pos);
|
||||
auto barrel_length = vm_vec_dist(&fpoint, &gpos);
|
||||
if (dist_to_enemy < barrel_length) continue;
|
||||
if (turret_barrel_length < 0.0f) {
|
||||
if (tp->turret_gun_sobj >= 0) {
|
||||
auto pm = model_get(tp->model_num);
|
||||
auto submodel = &pm->submodel[tp->turret_gun_sobj];
|
||||
turret_barrel_length = 2 * submodel->rad;
|
||||
} else {
|
||||
turret_barrel_length = 0.0f;
|
||||
}
|
||||
}
|
||||
if (dist_to_enemy < turret_barrel_length) continue;
|
||||
}
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range (or within min range)
|
||||
@@ -2523,7 +2473,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// Maybe pick a new enemy, unless targeting has been taken over by scripting
|
||||
if ( turret_should_pick_new_target(ss) && !ss->scripting_target_override && !(ss->flags[Ship::Subsystem_Flags::Forced_target])) {
|
||||
Num_find_turret_enemy++;
|
||||
int objnum = find_turret_enemy(ss, parent_objnum, &gpos, &gvec, ss->turret_enemy_objnum);
|
||||
int objnum = find_turret_enemy(ss, parent_objnum, &global_gun_pos, &global_gun_vec, ss->turret_enemy_objnum);
|
||||
|
||||
if (objnum >= 0) {
|
||||
if (ss->turret_enemy_objnum == -1) {
|
||||
@@ -2545,7 +2495,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
float dot = 1.0f;
|
||||
lep = &Objects[ss->turret_enemy_objnum];
|
||||
if (( lep->type == OBJ_SHIP ) && !(ss->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, lep, &dot);
|
||||
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, &global_gun_pos, lep, &dot);
|
||||
}
|
||||
// recheck in 2-3 seconds
|
||||
ss->turret_next_enemy_check_stamp = timestamp((int)((MAX(dot, 0.5f) * The_mission.ai_profile->turret_target_recheck_time) + (The_mission.ai_profile->turret_target_recheck_time / 2.0f)));
|
||||
@@ -2593,7 +2543,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
//This can't happen. See above code
|
||||
//Assert(ss->turret_enemy_objnum != -1);
|
||||
|
||||
bool in_fov = turret_fov_test(ss, &gvec, &v2e);
|
||||
bool in_fov = turret_fov_test(ss, &global_gun_vec, &v2e);
|
||||
bool something_was_ok_to_fire = false;
|
||||
|
||||
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
|
||||
@@ -2648,13 +2598,13 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
|
||||
// We're ready to fire... now get down to specifics, like where is the
|
||||
// actual gun point and normal, not just the one for whole turret.
|
||||
ship_get_global_turret_gun_info(objp, ss, &gpos, &gvec, use_angles, &predicted_enemy_pos);
|
||||
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, use_angles, &predicted_enemy_pos);
|
||||
|
||||
// Fire in the direction the turret is facing, not right at the target regardless of turret dir.
|
||||
// [Yet this retail comment precedes the calculation of vector-to-enemy...]
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &gpos);
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = vm_vec_normalize(&v2e);
|
||||
float dot = vm_vec_dot(&v2e, &gvec);
|
||||
float dot = vm_vec_dot(&v2e, &global_gun_vec);
|
||||
|
||||
// (flak jitter moved to after we obtain shoot_vector below)
|
||||
|
||||
@@ -2719,7 +2669,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// Check if turret should fire and enemy's engines are
|
||||
// in line of sight
|
||||
if (turret_should_fire_aspect(ss, wip, in_sight) &&
|
||||
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &gpos))
|
||||
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &global_gun_pos))
|
||||
{
|
||||
ok_to_fire = true;
|
||||
}
|
||||
@@ -2729,14 +2679,14 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
if ( ok_to_fire && (tp->flags[Model::Subsystem_Flags::Turret_hull_check]) ) {
|
||||
int model_num = Ship_info[shipp->ship_info_index].model_num;
|
||||
vec3d end;
|
||||
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
|
||||
vm_vec_scale_add(&end, &global_gun_pos, &global_gun_vec, model_get_radius(model_num));
|
||||
|
||||
mc_info hull_check;
|
||||
hull_check.model_instance_num = shipp->model_instance_num;
|
||||
hull_check.model_num = model_num;
|
||||
hull_check.orient = &objp->orient;
|
||||
hull_check.pos = &objp->pos;
|
||||
hull_check.p0 = &gpos;
|
||||
hull_check.p0 = &global_gun_pos;
|
||||
hull_check.p1 = &end;
|
||||
hull_check.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
|
||||
|
||||
@@ -2776,7 +2726,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// (Despite the retail comment above, retail actually fired toward the enemy; v2e = vector-to-enemy)
|
||||
vec3d shoot_vector = v2e;
|
||||
if (tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
shoot_vector = gvec;
|
||||
shoot_vector = global_gun_vec;
|
||||
|
||||
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
|
||||
// to make a cool visual effect and make them less lethal
|
||||
@@ -2784,7 +2734,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
flak_jitter_aim(&shoot_vector, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
|
||||
}
|
||||
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &gpos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1049,6 +1049,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
*/
|
||||
static void maybe_throw_asteroid()
|
||||
{
|
||||
Assertion(Asteroid_field.num_used_field_debris_types > 0, "maybe_throw_asteroid() called while num_used_field_debris_types was 0; this should never happen, get a coder!");
|
||||
|
||||
for (asteroid_target& target : Asteroid_targets) {
|
||||
if (!timestamp_elapsed(target.throw_stamp))
|
||||
@@ -2584,6 +2585,11 @@ void asteroid_frame()
|
||||
return;
|
||||
}
|
||||
|
||||
// If no asteroid types are defined for the field, abort.
|
||||
if (Asteroid_field.num_used_field_debris_types <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are no explicit targets, fall back to default retail targeting behavior
|
||||
if (Asteroid_field.target_names.empty()) {
|
||||
int objnum = set_asteroid_throw_objnum();
|
||||
|
||||
@@ -1211,7 +1211,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, &normal_cache, 1, NULL);
|
||||
ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, true, &normal_cache, true, nullptr);
|
||||
vec3d offset = vmd_zero_vector;
|
||||
offset.xyz.x = 0.0001f;
|
||||
vm_vec_add2(pos, &offset); // prevent beam turrets from crashing with a nullvec
|
||||
|
||||
+17
-17
@@ -91,12 +91,10 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#define CFILE_STACK_MAX 8
|
||||
|
||||
int cfile_inited = 0;
|
||||
static int Cfile_stack_pos = 0;
|
||||
|
||||
static char Cfile_stack[CFILE_STACK_MAX][CFILE_ROOT_DIRECTORY_LEN];
|
||||
static SCP_vector<SCP_string> Cfile_stack;
|
||||
|
||||
std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
|
||||
|
||||
@@ -330,17 +328,16 @@ int cfile_push_chdir(int type)
|
||||
|
||||
_getcwd(OriginalDirectory, CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
|
||||
Assert(Cfile_stack_pos < CFILE_STACK_MAX);
|
||||
|
||||
if (Cfile_stack_pos >= CFILE_STACK_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
|
||||
|
||||
cf_create_default_path_string(dir, type, NULL);
|
||||
|
||||
return _cfile_chdir(dir.c_str(), OriginalDirectory);
|
||||
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);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,13 +360,16 @@ int cfile_chdir(const char *dir)
|
||||
|
||||
int cfile_pop_dir()
|
||||
{
|
||||
Assert(Cfile_stack_pos);
|
||||
|
||||
if ( !Cfile_stack_pos )
|
||||
if (Cfile_stack.empty())
|
||||
return -1;
|
||||
|
||||
Cfile_stack_pos--;
|
||||
return cfile_chdir(Cfile_stack[Cfile_stack_pos]);
|
||||
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;
|
||||
}
|
||||
|
||||
// flush (delete all files in) the passed directory (by type), return the # of files deleted
|
||||
|
||||
+102
-61
@@ -40,6 +40,7 @@
|
||||
#ifdef SCP_UNIX
|
||||
#include "osapi/osapi.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
@@ -1208,93 +1209,133 @@ bool cmdline_parm::has_param() {
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
// dir must not contain a slash.
|
||||
static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
extern void normalize_directory_separators(SCP_string &str);
|
||||
|
||||
static SCP_string get_real_mod_path(const char *mod)
|
||||
{
|
||||
SCP_vector<SCP_string> ret;
|
||||
DIR *dirp;
|
||||
SCP_string fullpath;
|
||||
SCP_string mod_path = mod;
|
||||
|
||||
DIR *dp;
|
||||
if ((dp = opendir(parent.c_str())) == NULL) {
|
||||
Warning(LOCATION, "Can't open directory '%s' when searching mod paths. Ignoring. errno=%d", parent.c_str(), errno);
|
||||
return ret;
|
||||
normalize_directory_separators(mod_path);
|
||||
|
||||
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
|
||||
fullpath += mod_path;
|
||||
|
||||
// check if path already exists
|
||||
dirp = opendir(fullpath.c_str());
|
||||
|
||||
if (dirp) {
|
||||
// found it, return unchanged
|
||||
closedir(dirp);
|
||||
|
||||
return mod_path;
|
||||
}
|
||||
|
||||
dirent *dirp;
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
if (!stricmp(dirp->d_name, dir.c_str())) {
|
||||
ret.push_back(dirp->d_name);
|
||||
// not found, check for a difference in case
|
||||
SCP_string new_mod_path;
|
||||
SCP_string part;
|
||||
struct dirent *dir;
|
||||
SCP_string::size_type separator;
|
||||
SCP_string::size_type offset = 0;
|
||||
|
||||
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
|
||||
|
||||
do {
|
||||
separator = mod_path.find(DIR_SEPARATOR_CHAR, offset);
|
||||
|
||||
if (separator != SCP_string::npos) {
|
||||
part = mod_path.substr(offset, separator-offset);
|
||||
offset += separator-offset + 1;
|
||||
} else {
|
||||
part = mod_path.substr(offset);
|
||||
offset += part.length();
|
||||
}
|
||||
}
|
||||
(void)closedir(dp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
dirp = opendir(fullpath.c_str());
|
||||
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
// Recurses to deal with slashes in dir.
|
||||
static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
{
|
||||
size_t slash = dir.find_first_of("/\\");
|
||||
|
||||
// no subdirectories, no need to recurse
|
||||
if (slash == std::string::npos) {
|
||||
return unix_get_single_dir_names(parent, dir);
|
||||
}
|
||||
|
||||
// get the names of the first component of dir
|
||||
SCP_vector<SCP_string> this_dir_names = unix_get_single_dir_names(parent, dir.substr(0, slash));
|
||||
|
||||
SCP_string rest = dir.substr(slash + 1);
|
||||
|
||||
SCP_vector<SCP_string> ret;
|
||||
|
||||
// search for the rest of dir in each of these
|
||||
SCP_vector<SCP_string>::iterator ii, end = this_dir_names.end();
|
||||
for (ii = this_dir_names.begin(); ii != end; ++ii) {
|
||||
SCP_string this_dir_path = parent + "/" + *ii;
|
||||
SCP_vector<SCP_string> mod_path = unix_get_dir_names(this_dir_path, rest);
|
||||
|
||||
// add all found paths relative to parent
|
||||
SCP_vector<SCP_string>::iterator ii2, end2 = mod_path.end();
|
||||
for (ii2 = mod_path.begin(); ii2 != end2; ++ii2) {
|
||||
ret.push_back(*ii + "/" + *ii2);
|
||||
if ( !dirp ) {
|
||||
break;
|
||||
}
|
||||
|
||||
while ((dir = readdir(dirp)) != nullptr) {
|
||||
if (stricmp(dir->d_name, part.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SCP_string fn = fullpath + dir->d_name;
|
||||
|
||||
// make sure it accessible and a directory
|
||||
struct stat buf;
|
||||
|
||||
if (stat(fn.c_str(), &buf) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !S_ISDIR(buf.st_mode) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !new_mod_path.empty() ) {
|
||||
new_mod_path += DIR_SEPARATOR_STR;
|
||||
}
|
||||
|
||||
new_mod_path += dir->d_name;
|
||||
|
||||
fullpath += dir->d_name;
|
||||
fullpath += DIR_SEPARATOR_STR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirp) {
|
||||
closedir(dirp);
|
||||
}
|
||||
} while (offset < mod_path.length());
|
||||
|
||||
// Append anything left from mod_path onto the new path. This will catch trailing separators
|
||||
// as well as mod folders which don't exist so that the mod string remains unchanged except
|
||||
// for the directory name case.
|
||||
if (new_mod_path.length() != mod_path.length()) {
|
||||
new_mod_path += mod_path.substr(new_mod_path.length());
|
||||
}
|
||||
|
||||
return ret;
|
||||
return new_mod_path;
|
||||
}
|
||||
|
||||
// For case sensitive filesystems (e.g. Linux/BSD) perform case-insensitive dir matches.
|
||||
//
|
||||
// NOTE: Aside from change in case no alterations should be made to the modlist. Missing
|
||||
// mod folders should be left in place and no errors or warnings should be generated.
|
||||
// There should be no difference between Windows and non-Windows modlist handling.
|
||||
static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
{
|
||||
// search filesystem for given paths
|
||||
SCP_vector<SCP_string> mod_paths;
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
|
||||
{
|
||||
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
|
||||
// Ignore non-existing mods for unit tests
|
||||
if (!running_unittests && this_mod_paths.empty()) {
|
||||
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
|
||||
}
|
||||
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
|
||||
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ",")) {
|
||||
SCP_string path = get_real_mod_path(cur_mod);
|
||||
mod_paths.push_back(path);
|
||||
}
|
||||
|
||||
// create new char[] to replace modlist
|
||||
size_t total_len = 0;
|
||||
SCP_vector<SCP_string>::iterator ii, end = mod_paths.end();
|
||||
for (ii = mod_paths.begin(); ii != end; ++ii) {
|
||||
total_len += ii->length() + 1;
|
||||
|
||||
for (auto &path : mod_paths) {
|
||||
total_len += path.length() + 1;
|
||||
}
|
||||
|
||||
char *new_modlist = new char[total_len + 1];
|
||||
memset(new_modlist, 0, total_len + 1);
|
||||
end = mod_paths.end();
|
||||
for (ii = mod_paths.begin(); ii != end; ++ii) {
|
||||
strcat_s(new_modlist, total_len + 1, ii->c_str());
|
||||
strcat_s(new_modlist, total_len + 1, ","); // replace later with NUL
|
||||
|
||||
for (auto &path : mod_paths) {
|
||||
strcat_s(new_modlist, total_len + 1, path.c_str());
|
||||
strcat_s(new_modlist, total_len + 1, ",");
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
new_modlist[total_len-1] = '\0';
|
||||
|
||||
// make the rest of the modlist manipulation unaware that anything happened here
|
||||
delete [] *modlist;
|
||||
*modlist = new_modlist;
|
||||
@@ -1799,7 +1840,7 @@ bool SetCmdlineParams()
|
||||
if(mod_arg.found() ) {
|
||||
Cmdline_mod = mod_arg.str();
|
||||
|
||||
// strip off blank space it it's there
|
||||
// strip off blank space if it's there
|
||||
if ( Cmdline_mod[strlen(Cmdline_mod)-1] == ' ' ) {
|
||||
Cmdline_mod[strlen(Cmdline_mod)-1] = '\0';
|
||||
}
|
||||
|
||||
@@ -947,7 +947,7 @@ int check_control(int id, int key = -1);
|
||||
void control_get_axes_readings(int *axis_v, float frame_time);
|
||||
|
||||
/**
|
||||
* @brief Markes the given control (by IoActionId) as used
|
||||
* @brief Marks the given control (by IoActionId) as used
|
||||
*
|
||||
* @details Updates the ::used timestamp, triggers a script hook, and marks ::continous_ongoing as true
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
extern int Cmdline_nomovies;
|
||||
|
||||
bool Movie_active = false;
|
||||
|
||||
|
||||
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage",
|
||||
@@ -60,6 +62,18 @@ static cutscene_info *get_cutscene_pointer(char *cutscene_filename)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_cutscene_index_by_name(const char* name)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(Cutscenes.size()); i++) {
|
||||
if (!stricmp(name, Cutscenes[i].name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find anything.
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void cutscene_info_init(cutscene_info *csni)
|
||||
{
|
||||
csni->filename[0] = '\0';
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct cutscene_info
|
||||
|
||||
extern SCP_vector<cutscene_info> Cutscenes;
|
||||
|
||||
extern bool Movie_active;
|
||||
|
||||
// initializa table data
|
||||
void cutscene_init();
|
||||
|
||||
@@ -48,4 +50,6 @@ void cutscenes_screen_do_frame();
|
||||
|
||||
void cutscene_mark_viewable(const char* filename);
|
||||
|
||||
int get_cutscene_index_by_name(const char* name);
|
||||
|
||||
#endif
|
||||
@@ -278,6 +278,7 @@ bool play(const char* name) {
|
||||
// clear the screen and hide the mouse cursor
|
||||
io::mouse::CursorManager::get()->pushStatus();
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
Movie_active = true;
|
||||
gr_reset_clip();
|
||||
gr_set_color(255, 255, 255);
|
||||
gr_set_clear_color(0, 0, 0);
|
||||
@@ -304,6 +305,8 @@ bool play(const char* name) {
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
}
|
||||
|
||||
Movie_active = false;
|
||||
|
||||
// show the mouse cursor again
|
||||
io::mouse::CursorManager::get()->popStatus();
|
||||
|
||||
|
||||
@@ -501,11 +501,11 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
}
|
||||
else if (vaporize) {
|
||||
db->model_num = Debris_vaporize_model;
|
||||
db->submodel_num = Random::next(Debris_num_submodels);
|
||||
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
|
||||
}
|
||||
else {
|
||||
db->model_num = Debris_model;
|
||||
db->submodel_num = Random::next(Debris_num_submodels);
|
||||
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -644,7 +644,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
if (spark_timeout >= 0) {
|
||||
db->fire_timeout = _timestamp(spark_timeout);
|
||||
} else if (parent_objnum >= 0) {
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[parent_objnum].radius));
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + (fl2i(1000*3*Objects[parent_objnum].radius) == 0 ? 0 : Random::next(fl2i(1000*3*Objects[parent_objnum].radius)));
|
||||
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
} else {
|
||||
db->fire_timeout = TIMESTAMP::immediate();
|
||||
|
||||
@@ -118,10 +118,13 @@ uniform sampler2DArray sMiscmap;
|
||||
uniform sampler2DArray shadow_map;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
#endif
|
||||
|
||||
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
|
||||
{
|
||||
@@ -185,10 +188,9 @@ void main()
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
// need depth and depth squared for variance shadow maps
|
||||
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
#else
|
||||
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
|
||||
vec2 texCoord = vertIn.texCoord.xy;
|
||||
|
||||
@@ -461,4 +463,5 @@ void main()
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -5,7 +5,6 @@ out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
out vec4 fragOut5;
|
||||
out float gl_FragDepth;
|
||||
|
||||
uniform sampler2DMS texColor;
|
||||
uniform sampler2DMS texPos;
|
||||
|
||||
@@ -1052,7 +1052,7 @@ float fireball_wormhole_intensity(fireball *fb)
|
||||
rad = (float)pow((fb->total_time - t) / fb->warp_close_duration, 0.4f);
|
||||
}
|
||||
return rad;
|
||||
}
|
||||
}
|
||||
|
||||
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id);
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#define MAX_POLYGON_MODELS 300
|
||||
|
||||
// object.h
|
||||
//If this value exceeds 2^16-1, this will break collision pair caching as is. Proceed with caution.
|
||||
#define MAX_OBJECTS 5000 //Increased from 3500 to 5000 in 2022
|
||||
|
||||
// from weapon.h (and beam.h)
|
||||
|
||||
@@ -453,7 +453,7 @@ public:
|
||||
// - is not "none"
|
||||
// - is not "<none>"
|
||||
inline bool VALID_FNAME(const char* x) {
|
||||
return strlen((x)) && stricmp((x), "none") != 0 && stricmp((x), "<none>") != 0;
|
||||
return (x[0] != '\0') && stricmp(x, "none") != 0 && stricmp(x, "<none>") != 0;
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the specified string may be a valid file name
|
||||
|
||||
+28
-14
@@ -460,7 +460,7 @@ static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.
|
||||
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
@@ -1754,17 +1754,6 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
return true;
|
||||
}
|
||||
|
||||
void gr_force_windowed()
|
||||
{
|
||||
if ( !Gr_inited ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Os_debugger_running ) {
|
||||
os_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
int gr_activated = 0;
|
||||
void gr_activate(int active)
|
||||
{
|
||||
@@ -1779,7 +1768,7 @@ void gr_activate(int active)
|
||||
}
|
||||
|
||||
if (active) {
|
||||
if (Cmdline_fullscreen_window || Cmdline_window) {
|
||||
if (gr_is_viewport_window()) {
|
||||
os::getMainViewport()->restore();
|
||||
} else {
|
||||
os::getMainViewport()->setState(os::ViewportState::Fullscreen);
|
||||
@@ -1789,7 +1778,7 @@ void gr_activate(int active)
|
||||
}
|
||||
|
||||
if (active) {
|
||||
if (!Cmdline_fullscreen_window && !Cmdline_window) {
|
||||
if (!gr_is_viewport_window()) {
|
||||
gr_set_gamma(Gr_gamma);
|
||||
}
|
||||
}
|
||||
@@ -2968,3 +2957,28 @@ void gr_get_post_process_effect_names(SCP_vector<SCP_string>& names)
|
||||
names.push_back(eff.name);
|
||||
}
|
||||
}
|
||||
|
||||
bool gr_is_viewport_window()
|
||||
{
|
||||
if (Fred_running) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
switch (Gr_configured_window_state)
|
||||
{
|
||||
case os::ViewportState::Windowed:
|
||||
case os::ViewportState::Borderless:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (Cmdline_window || Cmdline_fullscreen_window) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1428,6 +1428,8 @@ void gr_set_gamma(float gamma);
|
||||
|
||||
void gr_get_post_process_effect_names(SCP_vector<SCP_string> &names);
|
||||
|
||||
bool gr_is_viewport_window();
|
||||
|
||||
// Include this last to make the 2D rendering function available everywhere
|
||||
#include "graphics/render.h"
|
||||
|
||||
|
||||
+5
-8
@@ -1697,7 +1697,7 @@ void hud_render_preprocess(float frametime)
|
||||
|
||||
if ( hud_disabled() ) {
|
||||
// if the hud is disabled, we still need to make sure that the indicators are properly handled
|
||||
hud_do_lock_indicators(flFrametime);
|
||||
hud_do_lock_indicators(frametime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1823,15 +1823,15 @@ void hud_maybe_display_supernova()
|
||||
/**
|
||||
* @brief Undertakes main HUD render.
|
||||
*/
|
||||
void hud_render_all()
|
||||
void hud_render_all(float frametime)
|
||||
{
|
||||
int i;
|
||||
|
||||
hud_render_gauges();
|
||||
hud_render_gauges(-1, frametime);
|
||||
|
||||
// start rendering cockpit dependent gauges if possible
|
||||
for ( i = 0; i < (int)Player_displays.size(); ++i ) {
|
||||
hud_render_gauges(i);
|
||||
hud_render_gauges(i, frametime);
|
||||
}
|
||||
|
||||
hud_clear_msg_buffer();
|
||||
@@ -1840,7 +1840,7 @@ void hud_render_all()
|
||||
font::set_font(font::FONT1);
|
||||
}
|
||||
|
||||
void hud_render_gauges(int cockpit_display_num)
|
||||
void hud_render_gauges(int cockpit_display_num, float frametime)
|
||||
{
|
||||
size_t j, num_gauges;
|
||||
ship_info* sip = &Ship_info[Player_ship->ship_info_index];
|
||||
@@ -1866,9 +1866,6 @@ void hud_render_gauges(int cockpit_display_num)
|
||||
}
|
||||
}
|
||||
|
||||
//Since we render things twice in VR mode, frametime needs to be halved for HUD, as the HUD uses the frametime to advance ANI's and crucially, the missile lock...
|
||||
float frametime = openxr_enabled() ? flFrametime * 0.5f : flFrametime;
|
||||
|
||||
// Check if this ship has its own HUD gauges.
|
||||
if ( sip->hud_enabled ) {
|
||||
num_gauges = sip->hud_gauges.size();
|
||||
|
||||
+2
-2
@@ -119,8 +119,8 @@ void hud_close();
|
||||
void hud_level_close();
|
||||
void hud_update_frame(float frametime); // updates hud systems not dependant on rendering
|
||||
void hud_render_preprocess(float frametime); // renders 3d dependant gauges
|
||||
void hud_render_all();
|
||||
void hud_render_gauges(int cockpit_display_num = -1);
|
||||
void hud_render_all(float frametime);
|
||||
void hud_render_gauges(int cockpit_display_num, float frametime);
|
||||
void hud_stop_looped_engine_sounds();
|
||||
|
||||
// set the offset values for this render frame
|
||||
|
||||
@@ -327,8 +327,8 @@ void ssm_create(object *target, vec3d *start, size_t ssm_index, ssm_firing_info
|
||||
// Init the ssm data
|
||||
|
||||
count = Ssm_info[ssm_index].count;
|
||||
if (Ssm_info[ssm_index].max_count != -1) {
|
||||
count += Random::next(count, Ssm_info[ssm_index].max_count);
|
||||
if (Ssm_info[ssm_index].max_count != -1 && (Ssm_info[ssm_index].max_count - count) > 0) {
|
||||
count = Random::next(count, Ssm_info[ssm_index].max_count);
|
||||
}
|
||||
|
||||
// override in multiplayer
|
||||
|
||||
@@ -288,7 +288,7 @@ int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsy
|
||||
}
|
||||
|
||||
// determine if subsystem is on far or near side of the ship
|
||||
int in_sight = ship_subsystem_in_sight(targetp, subsys, &View_position, &subobj_pos, 0);
|
||||
bool in_sight = ship_subsystem_in_sight(targetp, subsys, &View_position, &subobj_pos, false);
|
||||
|
||||
if (draw)
|
||||
{
|
||||
@@ -761,7 +761,7 @@ void HudGaugeBrackets::renderBoundingBracketsSubobject()
|
||||
}
|
||||
|
||||
// determine if subsystem is on far or near side of the ship
|
||||
Player->subsys_in_view = ship_subsystem_in_sight(targetp, subsys, &View_position, &subobj_pos, 0);
|
||||
Player->subsys_in_view = ship_subsystem_in_sight(targetp, subsys, &View_position, &subobj_pos, false) ? 1 : 0;
|
||||
|
||||
// AL 29-3-98: If subsystem is destroyed, draw gray brackets
|
||||
// Goober5000: this will now execute for fighterbays if the bay has been given a
|
||||
|
||||
@@ -1323,10 +1323,8 @@ void hud_config_button_do(int n)
|
||||
break;
|
||||
}
|
||||
|
||||
if (HC_current_file >= (int)HC_preset_filenames.size()) {
|
||||
if ((++HC_current_file) >= static_cast<int> (HC_preset_filenames.size())) {
|
||||
HC_current_file = 0;
|
||||
} else {
|
||||
HC_current_file++;
|
||||
}
|
||||
|
||||
// load em up
|
||||
|
||||
@@ -506,7 +506,7 @@ int hud_lock_on_subsys_ok()
|
||||
vm_vec_add2(&subobj_pos, &target_objp->pos);
|
||||
|
||||
if ( Player->subsys_in_view < 0 ) {
|
||||
in_sight = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos);
|
||||
in_sight = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos) ? 1 : 0;
|
||||
} else {
|
||||
in_sight = Player->subsys_in_view;
|
||||
}
|
||||
@@ -640,7 +640,7 @@ void hud_do_lock_indicator(float frametime)
|
||||
vec3d subobj_pos;
|
||||
vm_vec_unrotate(&subobj_pos, &Player->locking_subsys->system_info->pnt, &tobjp->orient);
|
||||
vm_vec_add2(&subobj_pos, &tobjp->pos);
|
||||
int target_subsys_in_sight = ship_subsystem_in_sight(tobjp, Player->locking_subsys, &Player_obj->pos, &subobj_pos);
|
||||
bool target_subsys_in_sight = ship_subsystem_in_sight(tobjp, Player->locking_subsys, &Player_obj->pos, &subobj_pos);
|
||||
|
||||
if (!target_subsys_in_sight || Player->locking_subsys->system_info->type != SUBSYSTEM_ENGINE) {
|
||||
Player->locking_subsys =
|
||||
@@ -1059,7 +1059,7 @@ void hud_lock_determine_lock_target(lock_info *lock_slot, weapon_info *wip)
|
||||
vm_vec_unrotate(&subobj_pos, &Player->locking_subsys->system_info->pnt, &lock_slot->obj->orient);
|
||||
vm_vec_add2(&subobj_pos, &lock_slot->obj->pos);
|
||||
|
||||
int target_subsys_in_sight = ship_subsystem_in_sight(lock_slot->obj, Player_ai->targeted_subsys, &Player_obj->pos, &subobj_pos);
|
||||
bool target_subsys_in_sight = ship_subsystem_in_sight(lock_slot->obj, Player_ai->targeted_subsys, &Player_obj->pos, &subobj_pos);
|
||||
|
||||
if ( !target_subsys_in_sight || Player->locking_subsys->system_info->type != SUBSYSTEM_ENGINE ) {
|
||||
lock_slot->subsys = ship_get_closest_subsys_in_sight(&Ships[lock_slot->obj->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);
|
||||
@@ -1110,7 +1110,7 @@ void hud_lock_determine_lock_target(lock_info *lock_slot, weapon_info *wip)
|
||||
vm_vec_unrotate(&subobj_pos, &Player_ai->targeted_subsys->system_info->pnt, &lock_slot->obj->orient);
|
||||
vm_vec_add2(&subobj_pos, &lock_slot->obj->pos);
|
||||
|
||||
int target_subsys_in_sight = ship_subsystem_in_sight(lock_slot->obj, Player_ai->targeted_subsys, &Player_obj->pos, &subobj_pos);
|
||||
bool target_subsys_in_sight = ship_subsystem_in_sight(lock_slot->obj, Player_ai->targeted_subsys, &Player_obj->pos, &subobj_pos);
|
||||
|
||||
if ( !target_subsys_in_sight || Player_ai->targeted_subsys->system_info->type != SUBSYSTEM_ENGINE ) {
|
||||
lock_slot->subsys = ship_get_closest_subsys_in_sight(&Ships[lock_slot->obj->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);
|
||||
|
||||
@@ -4688,7 +4688,7 @@ void load_gauge_lock(gauge_settings* settings)
|
||||
stuff_boolean(&loop_locked_anim);
|
||||
}
|
||||
if(optional_string("Blink Locked Animation:")) {
|
||||
stuff_boolean(&loop_locked_anim);
|
||||
stuff_boolean(&blink_locked_anim);
|
||||
}
|
||||
|
||||
hud_gauge->initBitmaps(fname_lock, fname_spin);
|
||||
|
||||
@@ -470,7 +470,7 @@ int hud_target_invalid_awacs(object *objp)
|
||||
}
|
||||
|
||||
// check for invalid status
|
||||
if((Player_ship != NULL) && (awacs_get_level(objp, Player_ship) < 1.0f)){
|
||||
if((Player_ship != nullptr) && (awacs_get_level(objp, Player_ship) < 1.0f)){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -872,7 +872,7 @@ void hud_target_hotkey_select( int k )
|
||||
|
||||
// a simple walk of the list to get the count
|
||||
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ){
|
||||
if (awacs_get_level(hitem->objp, Player_ship, 1) > 1) {
|
||||
if (awacs_get_level(hitem->objp, Player_ship, true) > 1.0f) {
|
||||
visible_count++;
|
||||
}
|
||||
}
|
||||
@@ -894,7 +894,7 @@ void hud_target_hotkey_select( int k )
|
||||
first_target = NULL;
|
||||
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ) {
|
||||
|
||||
if (awacs_get_level(hitem->objp, Player_ship, 1) > 1) {
|
||||
if (awacs_get_level(hitem->objp, Player_ship, true) > 1.0f) {
|
||||
// get the first valid target
|
||||
if (first_target == NULL) {
|
||||
first_target = hitem;
|
||||
@@ -939,7 +939,7 @@ void hud_target_hotkey_select( int k )
|
||||
|
||||
// next is before current target, so search from start of list
|
||||
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ) {
|
||||
if (awacs_get_level(hitem->objp, Player_ship, 1) > 1) {
|
||||
if (awacs_get_level(hitem->objp, Player_ship, true) > 1.0f) {
|
||||
target = hitem;
|
||||
break;
|
||||
}
|
||||
@@ -1830,7 +1830,7 @@ void hud_target_live_turret(int next_flag, int auto_advance, int only_player_tar
|
||||
distance = vm_vec_normalized_dir(&vec_to_subsys, &gsubpos, &View_position);
|
||||
|
||||
// check if facing and in view
|
||||
int facing = ship_subsystem_in_sight(objp, A, &View_position, &gsubpos, 0);
|
||||
bool facing = ship_subsystem_in_sight(objp, A, &View_position, &gsubpos, false);
|
||||
|
||||
if (!auto_advance && get_closest_turret && !only_player_target) {
|
||||
// if within 3 degrees and not previous subsys, use subsys in front
|
||||
@@ -2334,7 +2334,7 @@ void hud_update_closest_turret()
|
||||
}
|
||||
|
||||
// check if facing and in view
|
||||
int facing = ship_subsystem_in_sight(objp, ss, &View_position, &gsubpos, 0);
|
||||
bool facing = ship_subsystem_in_sight(objp, ss, &View_position, &gsubpos, false);
|
||||
|
||||
if (facing) {
|
||||
new_distance *= 0.5f;
|
||||
@@ -3426,7 +3426,7 @@ void hud_show_selection_set()
|
||||
// Goober5000 - don't draw indicators for non-visible ships, per Mantis #1972
|
||||
// (the only way we could get here is if the hotkey set contained a mix of visible
|
||||
// and invisible ships)
|
||||
if (awacs_get_level(targetp, Player_ship, 1) < 1) {
|
||||
if (awacs_get_level(targetp, Player_ship, true) < 1.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3590,7 +3590,7 @@ void hud_show_hostile_triangle()
|
||||
}
|
||||
|
||||
// check if ship is stealthy
|
||||
if (awacs_get_level(&Objects[sp->objnum], Player_ship, 1) < 1) {
|
||||
if (awacs_get_level(&Objects[sp->objnum], Player_ship, true) < 1.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1906,7 +1906,7 @@ int hud_targetbox_subsystem_in_view(object *target_objp, int *sx, int *sy)
|
||||
|
||||
// is it subsystem in view
|
||||
if ( Player->subsys_in_view == -1 ) {
|
||||
rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, 0);
|
||||
rval = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos, false) ? 1 : 0;
|
||||
} else {
|
||||
rval = Player->subsys_in_view;
|
||||
}
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ bool Use_mouse_to_fly = false;
|
||||
static SCP_string mouse_mode_display(bool mode) { return mode ? XSTR("Joy-0", 1699) : XSTR("Mouse", 1774); }
|
||||
|
||||
static auto UseMouseOption __UNUSED = options::OptionBuilder<bool>("Input.UseMouse",
|
||||
std::pair<const char*, int>{"Mouse", 1376},
|
||||
std::pair<const char*, int>{"Mouse", 1373},
|
||||
std::pair<const char*, int>{"Whether or not to use the mouse for flying", 1765})
|
||||
.category("Input")
|
||||
.display(mouse_mode_display)
|
||||
|
||||
@@ -64,7 +64,7 @@ bool *Lcl_unexpected_tstring_check = nullptr;
|
||||
// NOTE: with map storage of XSTR strings, the indexes no longer need to be contiguous,
|
||||
// but internal strings should still increment XSTR_SIZE to avoid collisions.
|
||||
// retail XSTR_SIZE = 1570
|
||||
// #define XSTR_SIZE 1816 // This is the next available ID
|
||||
// #define XSTR_SIZE 1817 // This is the next available ID
|
||||
|
||||
|
||||
// struct to allow for strings.tbl-determined x offset
|
||||
|
||||
@@ -1070,6 +1070,9 @@ void barracks_button_pressed(int n)
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
// we now have a new pilot, so try to load its current campaign, falling back if necessary
|
||||
mission_load_up_campaign(true);
|
||||
|
||||
if (Campaign_file_missing) {
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "The currently active campaign cannot be found. Please select another...", 1600));
|
||||
gameseq_post_event(GS_EVENT_CAMPAIGN_ROOM);
|
||||
@@ -1081,6 +1084,9 @@ void barracks_button_pressed(int n)
|
||||
if (Num_pilots && !barracks_pilot_accepted()) {
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
|
||||
// we now have a new pilot, so try to load its current campaign, falling back if necessary
|
||||
mission_load_up_campaign(true);
|
||||
|
||||
if (Campaign_file_missing) {
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "The currently active campaign cannot be found. Please select another...", 1600));
|
||||
gameseq_post_event(GS_EVENT_CAMPAIGN_ROOM);
|
||||
|
||||
@@ -906,8 +906,7 @@ void main_hall_do(float frametime)
|
||||
Game_mode = GM_NORMAL;
|
||||
|
||||
// see if we have a missing campaign and force the player to select a new campaign if so
|
||||
if (!(Player->flags & PLAYER_FLAGS_IS_MULTI) && Campaign_file_missing &&
|
||||
!Campaign_room_no_campaigns) {
|
||||
if (!(Player->flags & PLAYER_FLAGS_IS_MULTI) && Campaign_file_missing && !Campaign_room_no_campaigns) {
|
||||
int rc = popup(0,
|
||||
3,
|
||||
XSTR("Go to Campaign Room", 1607),
|
||||
@@ -933,7 +932,6 @@ void main_hall_do(float frametime)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
|
||||
gamesnd_play_iface(InterfaceSounds::IFACE_MOUSE_CLICK);
|
||||
}
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
||||
*
|
||||
* All source code herein is the property of Volition, Inc. You may not sell
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "freespace.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "io/key.h"
|
||||
#include "menuui/mainhallmenu.h"
|
||||
#include "menuui/mainhalltemp.h"
|
||||
#include "mission/missioncampaign.h"
|
||||
#include "mission/missionload.h"
|
||||
#include "playerman/player.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------
|
||||
// TEMP MAIN HALL DEFINES/VARS
|
||||
//
|
||||
|
||||
#define MHT_NUM_BUTTONS 6
|
||||
|
||||
const char *Mht_bitmap_fname[GR_NUM_RESOLUTIONS] = {
|
||||
"mht_background", // GR_640
|
||||
"2_mht_background" // GR_1024
|
||||
};
|
||||
|
||||
const char *Mht_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
|
||||
"mht_mask", // GR_640
|
||||
"2_mht_mask" // GR_1024
|
||||
};
|
||||
|
||||
// button defs
|
||||
#define MHT_READY_ROOM 0
|
||||
#define MHT_CAMPAIGN_ROOM 1
|
||||
#define MHT_OPTIONS 2
|
||||
#define MHT_TECH_ROOM 3
|
||||
#define MHT_BARRACKS 4
|
||||
#define MHT_EXIT 5
|
||||
|
||||
UI_WINDOW Mht_window; // the window object for the join screen
|
||||
int Mht_bitmap; // the background bitmap
|
||||
|
||||
ui_button_info Mht_buttons[GR_NUM_RESOLUTIONS][MHT_NUM_BUTTONS] = {
|
||||
{ // GR_640
|
||||
ui_button_info( "MHT_00", 15, 194, -1, -1, 2 ), // ready room
|
||||
ui_button_info( "MHT_01", 15, 222, -1, -1, 5 ), // campaigns
|
||||
ui_button_info( "MHT_02", 14, 251, -1, -1, 4 ), // options
|
||||
ui_button_info( "MHT_03", 14, 280, -1, -1, 3 ), // tech room
|
||||
ui_button_info( "MHT_04", 14, 309, -1, -1, 1 ), // barracks
|
||||
ui_button_info( "MHT_05", 16, 339, -1, -1, 0 ), // exit
|
||||
},
|
||||
{ // GR_1024
|
||||
ui_button_info( "2_MHT_00", 25, 312, -1, -1, 2 ), // ready room
|
||||
ui_button_info( "2_MHT_01", 25, 357, -1, -1, 5 ), // campaigns
|
||||
ui_button_info( "2_MHT_02", 24, 403, -1, -1, 4 ), // options
|
||||
ui_button_info( "2_MHT_03", 24, 450, -1, -1, 3 ), // tech room
|
||||
ui_button_info( "2_MHT_04", 25, 497, -1, -1, 1 ), // barracks
|
||||
ui_button_info( "2_MHT_05", 27, 544, -1, -1, 0 ), // exit
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------
|
||||
// TEMP MAIN HALL FUNCTIONS
|
||||
//
|
||||
|
||||
void mht_check_buttons();
|
||||
void mht_button_pressed(int n);
|
||||
void mht_exit_game();
|
||||
|
||||
void mht_init()
|
||||
{
|
||||
int idx;
|
||||
|
||||
// create the interface window
|
||||
Mht_window.create(0, 0, gr_screen.max_w_unscaled,gr_screen.max_h_unscaled, 0);
|
||||
Mht_window.set_mask_bmap(Mht_bitmap_mask_fname[gr_screen.res]);
|
||||
|
||||
// load the background bitmap
|
||||
Mht_bitmap = bm_load(Mht_bitmap_fname[gr_screen.res]);
|
||||
if(Mht_bitmap < 0){
|
||||
// we failed to load the bitmap - this is very bad
|
||||
Int3();
|
||||
}
|
||||
|
||||
// create the interface buttons
|
||||
for(idx=0; idx<MHT_NUM_BUTTONS; idx++){
|
||||
// create the object
|
||||
Mht_buttons[gr_screen.res][idx].button.create(&Mht_window, "", Mht_buttons[gr_screen.res][idx].x, Mht_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
|
||||
|
||||
// set the sound to play when highlighted
|
||||
Mht_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
|
||||
|
||||
// set the ani for the button
|
||||
Mht_buttons[gr_screen.res][idx].button.set_bmaps(Mht_buttons[gr_screen.res][idx].filename);
|
||||
|
||||
// set the hotspot
|
||||
Mht_buttons[gr_screen.res][idx].button.link_hotspot(Mht_buttons[gr_screen.res][idx].hotspot);
|
||||
}
|
||||
|
||||
// remove any multiplayer flags from the game mode
|
||||
Game_mode &= ~(GM_MULTIPLAYER);
|
||||
|
||||
// initialize the music
|
||||
main_hall_start_music();
|
||||
|
||||
// set the game_mode based on the type of player
|
||||
Assert( Player != NULL );
|
||||
if ( Player->flags & PLAYER_FLAGS_IS_MULTI ){
|
||||
Game_mode = GM_MULTIPLAYER;
|
||||
} else {
|
||||
Game_mode = GM_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
void mht_do()
|
||||
{
|
||||
int k = Mht_window.process();
|
||||
|
||||
// need to ensure ambient is playing, since it may be stopped by a playing movie
|
||||
main_hall_start_ambient();
|
||||
|
||||
// process any keypresses
|
||||
switch(k){
|
||||
case KEY_ESC :
|
||||
mht_exit_game();
|
||||
break;
|
||||
|
||||
case KEY_B:
|
||||
gameseq_post_event( GS_EVENT_BARRACKS_MENU );
|
||||
break;
|
||||
|
||||
case KEY_G:
|
||||
if(Player->flags & PLAYER_FLAGS_IS_MULTI){
|
||||
break;
|
||||
}
|
||||
|
||||
if (Num_recent_missions > 0) {
|
||||
strcpy_s( Game_current_mission_filename, Recent_missions[0] );
|
||||
} else {
|
||||
mission_load_up_campaign();
|
||||
strcpy_s( Game_current_mission_filename, Campaign.missions[0].name );
|
||||
}
|
||||
|
||||
Campaign.current_mission = -1;
|
||||
gameseq_post_event(GS_EVENT_START_GAME_QUICK);
|
||||
break;
|
||||
|
||||
case KEY_L:
|
||||
gameseq_post_event( GS_EVENT_LOAD_MISSION_MENU );
|
||||
break;
|
||||
|
||||
case KEY_F2:
|
||||
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
||||
break;
|
||||
|
||||
case KEY_M:
|
||||
if (Player->flags & PLAYER_FLAGS_IS_MULTI){
|
||||
main_hall_do_multi_ready();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// process button presses
|
||||
mht_check_buttons();
|
||||
|
||||
// draw the background, etc
|
||||
gr_reset_clip();
|
||||
GR_MAYBE_CLEAR_RES(Mht_bitmap);
|
||||
if(Mht_bitmap != -1){
|
||||
gr_set_bitmap(Mht_bitmap);
|
||||
gr_bitmap(0,0,GR_RESIZE_MENU);
|
||||
}
|
||||
Mht_window.draw();
|
||||
|
||||
// flip the buffer
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
void mht_close()
|
||||
{
|
||||
// unload any bitmaps
|
||||
if(!bm_unload(Mht_bitmap)){
|
||||
nprintf(("General","WARNING : could not unload background bitmap %s\n", Mht_bitmap_fname[gr_screen.res]));
|
||||
}
|
||||
|
||||
// destroy the UI_WINDOW
|
||||
Mht_window.destroy();
|
||||
}
|
||||
|
||||
void mht_check_buttons()
|
||||
{
|
||||
int idx;
|
||||
for(idx=0; idx<MHT_NUM_BUTTONS; idx++){
|
||||
// we only really need to check for one button pressed at a time, so we can break after
|
||||
// finding one.
|
||||
if(Mht_buttons[gr_screen.res][idx].button.pressed()){
|
||||
mht_button_pressed(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mht_button_pressed(int n)
|
||||
{
|
||||
switch(n){
|
||||
case MHT_READY_ROOM:
|
||||
if (Player->flags & PLAYER_FLAGS_IS_MULTI){
|
||||
main_hall_do_multi_ready();
|
||||
} else {
|
||||
gameseq_post_event(GS_EVENT_NEW_CAMPAIGN);
|
||||
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
break;
|
||||
|
||||
case MHT_CAMPAIGN_ROOM:
|
||||
gameseq_post_event(GS_EVENT_CAMPAIGN_ROOM);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case MHT_OPTIONS:
|
||||
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case MHT_TECH_ROOM:
|
||||
gameseq_post_event( GS_EVENT_TECH_MENU );
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case MHT_BARRACKS:
|
||||
gameseq_post_event( GS_EVENT_BARRACKS_MENU );
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case MHT_EXIT:
|
||||
mht_exit_game();
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mht_exit_game()
|
||||
{
|
||||
// stop music first
|
||||
main_hall_stop_music(true);
|
||||
main_hall_stop_ambient();
|
||||
gameseq_post_event(GS_EVENT_QUIT_GAME);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
||||
*
|
||||
* All source code herein is the property of Volition, Inc. You may not sell
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __TEMP_MAIN_HALL_MENU_HEADER_FILE
|
||||
#define __TEMP_MAIN_HALL_MENU_HEADER_FILE
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------
|
||||
// TEMP MAIN HALL DEFINES/VARS
|
||||
//
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------
|
||||
// TEMP MAIN HALL FUNCTIONS
|
||||
//
|
||||
|
||||
// initialize the temporary main hall
|
||||
void mht_init();
|
||||
|
||||
// do a frame for the main hall
|
||||
void mht_do();
|
||||
|
||||
// close the temporary main hall
|
||||
void mht_close();
|
||||
|
||||
#endif
|
||||
@@ -917,7 +917,11 @@ int sim_room_button_pressed(int n)
|
||||
|
||||
case CAMPAIGN_TAB:
|
||||
if ( !strlen(Campaign.filename) ) {
|
||||
popup( PF_USE_AFFIRMATIVE_ICON | PF_NO_NETWORKING, 1, POPUP_OK, XSTR( "The currently active campaign cannot be found, unable to switch to campaign mode!", 1612));
|
||||
if (Campaign_load_failure == CAMPAIGN_ERROR_MISSING) {
|
||||
popup(PF_USE_AFFIRMATIVE_ICON | PF_NO_NETWORKING, 1, POPUP_OK, XSTR("The currently active campaign cannot be found. Unable to switch to campaign mode.", 1612));
|
||||
} else {
|
||||
popup(PF_USE_AFFIRMATIVE_ICON | PF_NO_NETWORKING, 1, POPUP_OK, XSTR("The currently active campaign cannot be loaded. Unable to switch to campaign mode.", 1816));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1050,7 +1054,9 @@ void sim_room_init()
|
||||
Campaign.filename[0] = 0;
|
||||
Campaign.num_missions = 0;
|
||||
|
||||
mission_campaign_load_failure_popup();
|
||||
// don't display the popup in the sim room - first because there is already logic to prevent listing campaign missions,
|
||||
// second because there's not much the player can do about it in the sim room, and third because displaying the popup
|
||||
// clears the error code
|
||||
}
|
||||
|
||||
Num_campaign_missions = 0;
|
||||
|
||||
@@ -60,7 +60,7 @@ char *Campaign_names[MAX_CAMPAIGNS] = { NULL };
|
||||
char *Campaign_file_names[MAX_CAMPAIGNS] = { NULL };
|
||||
char *Campaign_descs[MAX_CAMPAIGNS] = { NULL };
|
||||
int Num_campaigns;
|
||||
int Campaign_file_missing;
|
||||
bool Campaign_file_missing = false;
|
||||
int Campaign_load_failure = 0;
|
||||
int Campaign_names_inited = 0;
|
||||
SCP_vector<SCP_string> Ignored_campaigns;
|
||||
@@ -428,7 +428,7 @@ int mission_campaign_load(const char* filename, const char* full_path, player* p
|
||||
char name[NAME_LENGTH], type[NAME_LENGTH], temp[NAME_LENGTH];
|
||||
|
||||
if (campaign_is_ignored(filename)) {
|
||||
Campaign_file_missing = 1;
|
||||
Campaign_file_missing = true;
|
||||
Campaign_load_failure = CAMPAIGN_ERROR_IGNORED;
|
||||
return CAMPAIGN_ERROR_IGNORED;
|
||||
}
|
||||
@@ -634,19 +634,25 @@ int mission_campaign_load(const char* filename, const char* full_path, player* p
|
||||
if ((Game_mode & GM_MULTIPLAYER) && Campaign.num_missions > UINT8_MAX)
|
||||
throw parse::ParseException("Number of campaign missions is too high and breaks multi!");
|
||||
}
|
||||
catch (const parse::ParseException& e)
|
||||
catch (const parse::FileOpenException& foe)
|
||||
{
|
||||
mprintf(("Error parsing '%s'\r\nError message = %s.\r\n", filename, e.what()));
|
||||
mprintf(("Error opening '%s'\r\nError message = %s.\r\n", filename, foe.what()));
|
||||
|
||||
Campaign.filename[0] = 0;
|
||||
Campaign.num_missions = 0;
|
||||
|
||||
if (!Fred_running && !(Game_mode & GM_MULTIPLAYER)) {
|
||||
Campaign_file_missing = 1;
|
||||
Campaign_load_failure = CAMPAIGN_ERROR_MISSING;
|
||||
return CAMPAIGN_ERROR_MISSING;
|
||||
}
|
||||
Campaign_file_missing = true;
|
||||
Campaign_load_failure = CAMPAIGN_ERROR_MISSING;
|
||||
return CAMPAIGN_ERROR_MISSING;
|
||||
}
|
||||
catch (const parse::ParseException& pe)
|
||||
{
|
||||
mprintf(("Error parsing '%s'\r\nError message = %s.\r\n", filename, pe.what()));
|
||||
|
||||
Campaign.filename[0] = 0;
|
||||
Campaign.num_missions = 0;
|
||||
|
||||
Campaign_file_missing = true;
|
||||
Campaign_load_failure = CAMPAIGN_ERROR_CORRUPT;
|
||||
return CAMPAIGN_ERROR_CORRUPT;
|
||||
}
|
||||
@@ -681,7 +687,7 @@ int mission_campaign_load(const char* filename, const char* full_path, player* p
|
||||
}
|
||||
|
||||
// all is good here, move along
|
||||
Campaign_file_missing = 0;
|
||||
Campaign_file_missing = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -721,7 +727,7 @@ void mission_campaign_init()
|
||||
{
|
||||
mission_campaign_clear();
|
||||
|
||||
Campaign_file_missing = 0;
|
||||
Campaign_file_missing = false;
|
||||
|
||||
player_loadout_init();
|
||||
}
|
||||
@@ -1539,26 +1545,31 @@ bool campaign_is_ignored(const char *filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool campaign_reportable_error(int val)
|
||||
{
|
||||
return val != 0 && val != CAMPAIGN_ERROR_MISSING && val != CAMPAIGN_ERROR_IGNORED;
|
||||
}
|
||||
|
||||
// returns 0: loaded, !0: error
|
||||
int mission_load_up_campaign( player *pl )
|
||||
int mission_load_up_campaign(bool fall_back_from_current)
|
||||
{
|
||||
int rc = -1, idx;
|
||||
|
||||
if ( pl == NULL )
|
||||
pl = Player;
|
||||
auto pl = Player;
|
||||
|
||||
// find best campaign to use:
|
||||
// 1) last used
|
||||
// 2) builtin
|
||||
// 3) anything else
|
||||
// Note that in each step we only fall back when the error is benign, e.g. ignored or missing;
|
||||
// if there's some other real error with the campaign file, we report it.
|
||||
// Also note that if we *have* a current campaign, we shouldn't fall back *at all*, lest we repeatedly
|
||||
// reset what the current campaign is, *unless* we are starting a brand new session or loading a new pilot.
|
||||
|
||||
// last used...
|
||||
if ( strlen(pl->current_campaign) ) {
|
||||
if (!campaign_is_ignored(pl->current_campaign)) {
|
||||
return mission_campaign_load(pl->current_campaign, nullptr, pl);
|
||||
}
|
||||
else {
|
||||
Campaign_file_missing = 1;
|
||||
rc = mission_campaign_load(pl->current_campaign, nullptr, pl);
|
||||
if (rc == 0 || !fall_back_from_current || campaign_reportable_error(rc)) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1566,7 +1577,7 @@ int mission_load_up_campaign( player *pl )
|
||||
rc = mission_campaign_load(Default_campaign_file_name, nullptr, pl);
|
||||
|
||||
// everything else...
|
||||
if (rc < 0) {
|
||||
if (rc < 0 && !campaign_reportable_error(rc)) {
|
||||
// no descriptions, no sorting
|
||||
mission_campaign_build_list(false, false);
|
||||
|
||||
|
||||
@@ -161,8 +161,8 @@ extern SCP_vector<SCP_string> Ignored_campaigns;
|
||||
|
||||
extern char Default_campaign_file_name[MAX_FILENAME_LEN - 4];
|
||||
|
||||
// if the campaign file is missing this will get set for us to check against
|
||||
extern int Campaign_file_missing;
|
||||
extern bool Campaign_file_missing; // if the campaign file is missing this will get set for us to check against
|
||||
extern int Campaign_load_failure;
|
||||
|
||||
/*
|
||||
* initialise Player_loadout with default values
|
||||
@@ -218,7 +218,7 @@ int mission_campaign_get_info(const char *filename, char *name, int *type, int *
|
||||
int mission_campaign_get_mission_list(const char *filename, char **list, int max);
|
||||
|
||||
// load up a campaign for the current player.
|
||||
int mission_load_up_campaign( player *p = NULL );
|
||||
int mission_load_up_campaign(bool fall_back_from_current = false);
|
||||
|
||||
// stores mission goals and events in Campaign struct
|
||||
void mission_campaign_store_goals_and_events();
|
||||
|
||||
@@ -1963,7 +1963,9 @@ void debrief_init(bool API_Access)
|
||||
// be backed out if used chooses to replace them.
|
||||
scoring_level_close();
|
||||
|
||||
debrief_ui_init(); // init UI items
|
||||
if (!API_Access) {
|
||||
debrief_ui_init(); // init UI items
|
||||
}
|
||||
debrief_award_init();
|
||||
show_stats_init();
|
||||
debrief_voice_init();
|
||||
@@ -2113,11 +2115,13 @@ void debrief_close(bool API_Access)
|
||||
}
|
||||
|
||||
// unload bitmaps
|
||||
if (Background_bitmap >= 0){
|
||||
// Not used by the API
|
||||
if (!API_Access && Background_bitmap >= 0) {
|
||||
bm_release(Background_bitmap);
|
||||
}
|
||||
|
||||
if (Award_bg_bitmap >= 0){
|
||||
// Not used by the API
|
||||
if (!API_Access && Award_bg_bitmap >= 0) {
|
||||
bm_release(Award_bg_bitmap);
|
||||
}
|
||||
|
||||
|
||||
@@ -1332,7 +1332,7 @@ void wl_load_icons(int weapon_class)
|
||||
|
||||
icon = &Wl_icons[weapon_class];
|
||||
|
||||
if (!Use_3d_weapon_icons || (wip->render_type == WRT_LASER && !strlen(wip->tech_model)))
|
||||
if (!Use_3d_weapon_icons || (wip->render_type == WRT_LASER && !VALID_FNAME(wip->tech_model)))
|
||||
{
|
||||
first_frame = bm_load_animation(Weapon_info[weapon_class].icon_filename, &num_frames, nullptr, nullptr, nullptr, false, CF_TYPE_INTERFACE);
|
||||
|
||||
@@ -1343,9 +1343,9 @@ void wl_load_icons(int weapon_class)
|
||||
|
||||
multi_send_anti_timeout_ping();
|
||||
|
||||
if ( icon->model_index == -1 && ( ( strlen(wip->tech_model) && !strlen(wip->anim_filename) ) || (first_frame == -1) ) )
|
||||
if ( icon->model_index == -1 && ( ( VALID_FNAME(wip->tech_model) && !VALID_FNAME(wip->anim_filename) ) || (first_frame == -1) ) )
|
||||
{
|
||||
if(strlen(wip->tech_model))
|
||||
if(VALID_FNAME(wip->tech_model))
|
||||
{
|
||||
icon->model_index = model_load(wip->tech_model, 0, NULL, 0);
|
||||
}
|
||||
@@ -2742,7 +2742,7 @@ void weapon_select_do(float frametime)
|
||||
weapon_info *wip = &Weapon_info[Selected_wl_class];
|
||||
|
||||
//Get the model
|
||||
if (strlen(wip->tech_model)) {
|
||||
if (VALID_FNAME(wip->tech_model)) {
|
||||
modelIdx = model_load(wip->tech_model, 0, NULL, 0);
|
||||
}
|
||||
if (wip->render_type != WRT_LASER && modelIdx == -1) {
|
||||
|
||||
@@ -162,16 +162,14 @@ static auto DiscordOption __UNUSED = options::OptionBuilder<bool>("Game.Discord"
|
||||
if (!val) {
|
||||
Discord_presence = false;
|
||||
libs::discord::shutdown();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (val) {
|
||||
Discord_presence = true;
|
||||
libs::discord::init();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
|
||||
@@ -299,13 +299,15 @@ namespace animation {
|
||||
|
||||
if (direction == ModelAnimationDirection::RWD) {
|
||||
instanceData.state = ModelAnimationState::RUNNING;
|
||||
instanceData.time -= timeOffset;
|
||||
instanceData.time -= timeOffset;
|
||||
instanceData.canonicalDirection = ModelAnimationDirection::RWD;
|
||||
if (force)
|
||||
instanceData.time = instant ? 0 : instanceData.duration - timeOffset;
|
||||
}
|
||||
else {
|
||||
instanceData.state = ModelAnimationState::RUNNING;
|
||||
instanceData.time += timeOffset;
|
||||
instanceData.canonicalDirection = ModelAnimationDirection::FWD;
|
||||
if (force)
|
||||
instanceData.time = instant ? instanceData.duration : 0 + timeOffset;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1091,7 +1091,7 @@ extern int modelstats_num_sortnorms;
|
||||
#endif
|
||||
|
||||
// Tries to move joints so that the turret points to the point dst.
|
||||
extern int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_subsys *ss, vec3d *dst, bool reset = false);
|
||||
extern bool model_rotate_gun(const object *objp, const polymodel *pm, const polymodel_instance *pmi, ship_subsys *ss, const vec3d *dst);
|
||||
|
||||
// Rotates the angle of a submodel. Use this so the right unlocked axis
|
||||
// gets stuffed.
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Model {
|
||||
Turret_use_ammo, // enables ammo consumption for turrets (DahBlount)
|
||||
Autorepair_if_disabled, // Allows the subsystem to repair itself even if disabled (MageKing17)
|
||||
No_autorepair_if_disabled, // Inversion of the previous; disallows this particular subsystem if the ship-wide flag is set (MageKing17)
|
||||
Share_fire_direction, // (DahBlount) Whenever the turret fires, make all firing points fire in the same direction.
|
||||
Share_fire_direction, // (DahBlount) Whenever the turret fires a beam, make all beams fire in the same direction.
|
||||
No_sparks, // Subsystem does not generate sparks if hit - m!m
|
||||
No_impact_debris, // Don't spawn the small debris on impact - m!m
|
||||
Hide_turret_from_loadout_stats, // Turret is not accounted for in auto-generated "Turrets" line in the ship loadout window --wookieejedi
|
||||
|
||||
@@ -3294,7 +3294,7 @@ void bsp_polygon_data::replace_textures_used(const SCP_map<int, int>& replacemen
|
||||
Num_verts[it->first] -= poly.Num_verts;
|
||||
Num_verts[it->second] += poly.Num_verts;
|
||||
--Num_polies[it->first];
|
||||
++Num_polies[it->first];
|
||||
++Num_polies[it->second];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-15
@@ -2886,6 +2886,8 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
|
||||
|
||||
create_family_tree(pm);
|
||||
|
||||
// Now do submodel movement post-processing. This should come before all other error checking.
|
||||
|
||||
// ---------- submodel movement sanity checks ----------
|
||||
|
||||
for (i = 0; i < pm->n_models; i++) {
|
||||
@@ -2931,6 +2933,16 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
|
||||
}
|
||||
}
|
||||
|
||||
// And now look through all the submodels and set the model flag if any are intrinsic-moving
|
||||
for (i = 0; i < pm->n_models; i++) {
|
||||
if (pm->submodel[i].rotation_type == MOVEMENT_TYPE_INTRINSIC || pm->submodel[i].translation_type == MOVEMENT_TYPE_INTRINSIC) {
|
||||
pm->flags |= PM_FLAG_HAS_INTRINSIC_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Now do any other error checking that validates data in the POF --------------------
|
||||
|
||||
// some dockpoint checks
|
||||
for (i = 0; i < pm->n_docks; i++) {
|
||||
auto dock = &pm->docking_bays[i];
|
||||
@@ -2966,11 +2978,14 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
|
||||
}
|
||||
}
|
||||
|
||||
// And now look through all the submodels and set the model flag if any are intrinsic-moving
|
||||
for (i = 0; i < pm->n_models; i++) {
|
||||
if (pm->submodel[i].rotation_type == MOVEMENT_TYPE_INTRINSIC || pm->submodel[i].translation_type == MOVEMENT_TYPE_INTRINSIC) {
|
||||
pm->flags |= PM_FLAG_HAS_INTRINSIC_MOTION;
|
||||
break;
|
||||
// For several revisions, Pof Tools was writing invalid eyepoint data. We cannot guarantee that this will catch all instances,
|
||||
// but should at least head off potential crashes before they happen
|
||||
for (i = 0; i < pm->n_view_positions; ++i) {
|
||||
if (pm->view_positions[i].parent < 0 || pm->view_positions[i].parent >= pm->n_models) {
|
||||
nprintf(("Warning", "Model %s has an invalid eye position %i. Use a recent version of Pof Tools to fix the model.\n", pm->filename, i));
|
||||
pm->view_positions[i].parent = 0;
|
||||
pm->view_positions[i].norm = {{{1.0f, 0.0f, 0.0f}}};
|
||||
pm->view_positions[i].pnt = ZERO_VECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3244,7 +3259,7 @@ void model_load_texture(polymodel *pm, int i, char *file)
|
||||
//returns the number of the pof tech model if specified, otherwise number of pof model
|
||||
int model_load(ship_info* sip, bool prefer_tech_model)
|
||||
{
|
||||
if (prefer_tech_model && sip->pof_file_tech[0] != '\0') {
|
||||
if (prefer_tech_model && VALID_FNAME(sip->pof_file_tech)) {
|
||||
// This cannot load into sip->subsystems, as this will overwrite the subsystems model_num to the
|
||||
// techroom model, which is decidedly wrong for the mission itself.
|
||||
return model_load(sip->pof_file_tech, 0, nullptr);
|
||||
@@ -3283,6 +3298,11 @@ int model_load(const char* filename, int n_subsystems, model_subsystem* subsyst
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Valid file
|
||||
if (!VALID_FNAME(filename)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE_SCOPE(tracing::LoadModelFile);
|
||||
|
||||
mprintf(( "Loading model '%s' into slot '%i'\n", filename, num ));
|
||||
@@ -4375,16 +4395,16 @@ void submodel_translate(bsp_info *sm, submodel_instance *smi)
|
||||
submodel_canonicalize_translation(sm, smi);
|
||||
}
|
||||
|
||||
// Tries to move joints so that the turret points to the point dst.
|
||||
// Tries to move joints so that the turret points to the point dst. If dst is nullptr, the turret's joints are reset.
|
||||
// turret1 is the angles of the turret, turret2 is the angles of the gun from turret
|
||||
// Returns 1 if rotated gun, 0 if no gun to rotate (rotation handled by AI)
|
||||
int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_subsys *ss, vec3d *dst, bool reset)
|
||||
// Returns true if rotated gun, false if no gun to rotate (rotation handled by AI)
|
||||
bool model_rotate_gun(const object *objp, const polymodel *pm, const polymodel_instance *pmi, ship_subsys *ss, const vec3d *dst)
|
||||
{
|
||||
model_subsystem *turret = ss->system_info;
|
||||
|
||||
// This should not happen
|
||||
if ( turret->turret_gun_sobj < 0 || turret->subobj_num == turret->turret_gun_sobj ) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto base_sm = &pm->submodel[turret->subobj_num];
|
||||
@@ -4401,7 +4421,7 @@ int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_
|
||||
// Find the heading and pitch that the gun needs to turn to
|
||||
float desired_base_angle, desired_gun_angle;
|
||||
|
||||
if (!reset) {
|
||||
if (dst) {
|
||||
vec3d world_axis, world_pos, planar_dst, dir, rotated_vec;
|
||||
matrix save_base_orient;
|
||||
|
||||
@@ -4476,10 +4496,10 @@ int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_
|
||||
float step_size = turret->turret_turning_rate * calc_time;
|
||||
float base_delta, gun_delta;
|
||||
|
||||
if (reset)
|
||||
step_size /= 3.0f;
|
||||
else
|
||||
if (dst)
|
||||
ss->rotation_timestamp = timestamp(turret->turret_reset_delay);
|
||||
else
|
||||
step_size /= 3.0f;
|
||||
|
||||
base_delta = vm_interp_angle(&base_smi->cur_angle, desired_base_angle, step_size, turret->turret_base_fov > -1.0f);
|
||||
gun_delta = vm_interp_angle(&gun_smi->cur_angle, desired_gun_angle, step_size);
|
||||
@@ -4525,7 +4545,7 @@ int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_
|
||||
ss->points_to_target = sqrt((base_delta*base_delta) + (gun_delta*gun_delta));
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-23
@@ -127,7 +127,7 @@ bool read_virtual_model_file(polymodel* pm, const SCP_string& filename, model_pa
|
||||
const auto& virtual_pof = virtual_pof_it->second[depthLocal];
|
||||
depthLocal++;
|
||||
|
||||
read_model_file(pm, filename.c_str(), ferror, deferredTasks, depth);
|
||||
read_model_file(pm, virtual_pof.basePOF.c_str(), ferror, deferredTasks, depth);
|
||||
|
||||
for (const auto& operation : virtual_pof.operationList)
|
||||
operation->process(pm, deferredTasks, depth, virtual_pof);
|
||||
@@ -262,18 +262,14 @@ int reallocate_and_copy_array_vmalloc(T*& array, int& size, size_t to_add) {
|
||||
return size_before;
|
||||
}
|
||||
|
||||
#define REPLACE_IF_EQ(data) if ((data) == source) (data) = dest;
|
||||
#define REPLACE_IF_STRIEQ(data) if (stricmp(data, source.c_str()) == 0) strncpy_s(data, dest.c_str(), dest.size());
|
||||
#define REPLACE_IF_SCPSTRIEQ(data) if (stricmp(data.c_str(), source.c_str()) == 0) data = dest;
|
||||
#define REPLACE_IF_EQ(data) { auto iter = replace.find(data); if (iter != replace.end()) (data) = iter->second; }
|
||||
#define REPLACE_IF_STRIEQ(data) { auto iter = replace.find(data); if (iter != replace.end()) strncpy_s(data, iter->second.c_str(), iter->second.size()); }
|
||||
|
||||
//Generates one function for replacing data in a type, which is a map entry of which the key may be replaced. Takes an rvalue reference, used for making a copy and modifying the temporary to then assign it somewhere
|
||||
#define CHANGE_HELPER_MAP_KEY(name, intype, argtype) template<typename map_t> static typename std::enable_if<std::is_same<typename map_t::value_type, std::pair<const argtype, argtype>>::value, intype>::type name(intype&& pass, map_t replace){ \
|
||||
const auto it = replace.find(pass.first); \
|
||||
intype input = { (it == replace.end() ? pass.first : it->second), pass.second }; \
|
||||
for (const auto& replacement : replace) { \
|
||||
const argtype& source = replacement.first; \
|
||||
const argtype& dest = replacement.second;
|
||||
#define CHANGE_HELPER_MAP_KEY_END } return input; }
|
||||
intype input = { (it == replace.end() ? pass.first : it->second), pass.second };
|
||||
#define CHANGE_HELPER_MAP_KEY_END return input; }
|
||||
|
||||
//Generates two functions for replacing data in a type. One that takes an rvalue reference, used for making a copy and modifying the temporary to then assign it somewhere, and one which takes an lvalue reference for modifying in-place
|
||||
#define CHANGE_HELPER(name, intype, argtype) template<typename map_t> static typename std::enable_if<std::is_same<typename map_t::value_type, std::pair<const argtype, argtype>>::value>::type name(intype& input, map_t replace); \
|
||||
@@ -281,11 +277,8 @@ template<typename map_t> inline static typename std::enable_if<std::is_same<type
|
||||
name<map_t>(input, replace); \
|
||||
return std::move(input); \
|
||||
} \
|
||||
template<typename map_t> static typename std::enable_if<std::is_same<typename map_t::value_type, std::pair<const argtype, argtype>>::value>::type name(intype& input, map_t replace) {\
|
||||
for (const auto& replacement : replace) { \
|
||||
const argtype& source = replacement.first; \
|
||||
const argtype& dest = replacement.second;
|
||||
#define CHANGE_HELPER_END }}
|
||||
template<typename map_t> static typename std::enable_if<std::is_same<typename map_t::value_type, std::pair<const argtype, argtype>>::value>::type name(intype& input, map_t replace) {
|
||||
#define CHANGE_HELPER_END }
|
||||
|
||||
//Change submodel numbers in a submodel
|
||||
CHANGE_HELPER(change_submodel_numbers, bsp_info, int)
|
||||
@@ -324,19 +317,15 @@ CHANGE_HELPER_END
|
||||
|
||||
//Change submodel name in a subsystem definition
|
||||
CHANGE_HELPER_MAP_KEY(change_submodel_name, model_read_deferred_tasks::model_subsystem_pair, SCP_string)
|
||||
SCP_UNUSED(source);
|
||||
SCP_UNUSED(dest);
|
||||
CHANGE_HELPER_MAP_KEY_END
|
||||
|
||||
//Change subsystem name in an engine subsys definition
|
||||
CHANGE_HELPER(change_submodel_name, model_read_deferred_tasks::engine_subsystem_pair, SCP_string)
|
||||
REPLACE_IF_SCPSTRIEQ(input.second.subsystem_name)
|
||||
REPLACE_IF_EQ(input.second.subsystem_name)
|
||||
CHANGE_HELPER_END
|
||||
|
||||
//Change engine numbers in an engine subsys definition
|
||||
CHANGE_HELPER_MAP_KEY(change_engine_numbers, model_read_deferred_tasks::engine_subsystem_pair, int)
|
||||
SCP_UNUSED(source);
|
||||
SCP_UNUSED(dest);
|
||||
CHANGE_HELPER_MAP_KEY_END
|
||||
|
||||
|
||||
@@ -392,15 +381,17 @@ void VirtualPOFOperationAddSubmodel::process(polymodel* pm, model_read_deferred_
|
||||
SCP_vector<int> to_copy_submodels;
|
||||
bool has_name_collision = false;
|
||||
if (copyChildren) {
|
||||
model_iterate_submodel_tree(appendingPM, src_subobj_no, [&to_copy_submodels, &has_name_collision, pm, appendingPM](int submodel, int /*level*/, bool /*isLeaf*/) {
|
||||
model_iterate_submodel_tree(appendingPM, src_subobj_no, [&to_copy_submodels, &has_name_collision, &renameMap, pm, appendingPM](int submodel, int /*level*/, bool /*isLeaf*/) {
|
||||
to_copy_submodels.emplace_back(submodel);
|
||||
if(model_find_submodel_index(pm, appendingPM->submodel[submodel].name) != -1)
|
||||
auto replace_with_name_it = renameMap.find(appendingPM->submodel[submodel].name);
|
||||
if(model_find_submodel_index(pm, replace_with_name_it == renameMap.end() ? appendingPM->submodel[submodel].name : replace_with_name_it->second.c_str()) != -1)
|
||||
has_name_collision = true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
to_copy_submodels.emplace_back(src_subobj_no);
|
||||
if (model_find_submodel_index(pm, appendingPM->submodel[src_subobj_no].name) != -1)
|
||||
auto replace_with_name_it = renameMap.find(appendingPM->submodel[src_subobj_no].name);
|
||||
if(model_find_submodel_index(pm, replace_with_name_it == renameMap.end() ? appendingPM->submodel[src_subobj_no].name : replace_with_name_it->second.c_str()) != -1)
|
||||
has_name_collision = true;
|
||||
}
|
||||
|
||||
@@ -650,7 +641,7 @@ void VirtualPOFOperationAddEngine::process(polymodel* pm, model_read_deferred_ta
|
||||
|
||||
if (subsystemName) {
|
||||
if (renameSubsystem) {
|
||||
const SCP_unordered_map<SCP_string, SCP_string> thrusterSubsysRenameMap{ {*subsystemName, *renameSubsystem} };
|
||||
const VirtualPOFNameReplacementMap thrusterSubsysRenameMap{ {*subsystemName, *renameSubsystem} };
|
||||
deferredTasks.engine_subsystems.emplace(change_submodel_name(
|
||||
change_engine_numbers(model_read_deferred_tasks::engine_subsystem_pair(*it), thrusterReplacementMap),
|
||||
thrusterSubsysRenameMap));
|
||||
|
||||
@@ -736,7 +736,7 @@ void multi_assign_player_ship( int net_player_num, object *objp,int ship_class )
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// create_player() is called when a net player needs to be instantiated. The ship that is created
|
||||
// multi_create_player() is called when a net player needs to be instantiated. The ship that is created
|
||||
// depends on the parameter ship_class. Note that if ship_class is invalid, the ship default_player_ship
|
||||
// is used. Returns 1 on success, 0 otherwise
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ int Num_pairs_checked = 0;
|
||||
|
||||
SCP_vector<int> Collision_sort_list;
|
||||
|
||||
static_assert(1 << collision_cache_bitshift > MAX_OBJECTS, "Collision pair caching currently relies on the highest possible objnum being less than 2^collision_cache_bitshift.");
|
||||
|
||||
class collider_pair
|
||||
{
|
||||
public:
|
||||
@@ -867,7 +869,7 @@ void obj_collide_pair(object *A, object *B)
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
uint key = (OBJ_INDEX(A) << 12) + OBJ_INDEX(B);
|
||||
uint key = (OBJ_INDEX(A) << collision_cache_bitshift) + OBJ_INDEX(B);
|
||||
|
||||
collider_pair* collision_info = &Collision_cached_pairs[key];
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ struct collision_info_struct {
|
||||
#define MIN_LANDING_SOUND_VEL 2.0f
|
||||
#define LANDING_POS_OFFSET 0.05f
|
||||
|
||||
constexpr uint32_t collision_cache_bitshift = 16;
|
||||
|
||||
//===============================================================================
|
||||
// GENERAL COLLISION DETECTION HELPER FUNCTIONS
|
||||
// These are in CollideGeneral.cpp and are used by one or more of the collision-
|
||||
|
||||
@@ -127,10 +127,10 @@ class object
|
||||
public:
|
||||
class object *next, *prev; // for linked lists of objects
|
||||
int signature; // Every object ever has a unique signature...
|
||||
char type; // what type of object this is... robot, weapon, hostage, powerup, fireball
|
||||
char type; // what type of object this is... ship, weapon, debris, asteroid, fireball, see OBJ_* defines above
|
||||
int parent; // This object's parent.
|
||||
int parent_sig; // This object's parent's signature
|
||||
int instance; // which instance. ie.. if type is Robot, then this indexes into the Robots array
|
||||
int instance; // index into the corresponding type array, i.e. if type == OBJ_SHIP then instance indexes the Ships array
|
||||
flagset<Object::Object_Flags> flags; // misc flags. Call obj_set_flags to change this.
|
||||
vec3d pos; // absolute x,y,z coordinate of center of object
|
||||
matrix orient; // orientation of object in world
|
||||
|
||||
@@ -196,4 +196,20 @@ void OptionsManager::loadInitialValues()
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsManager::printValues()
|
||||
{
|
||||
mprintf(("Printing in-game options values!\n"));
|
||||
for (auto& opt : _options) {
|
||||
// If we're not using in-game options and the option is not a retail option, then skip
|
||||
// This ensures we only log options that are actually impacting the current game instance
|
||||
// This code set aside until PR 5895 is merged
|
||||
//if (!Using_in_game_options && !(opt->getFlags()[options::OptionFlags::RetailBuiltinOption])){
|
||||
// continue;
|
||||
//}
|
||||
mprintf(("Option.%s: %s\n",
|
||||
opt->getConfigKey().c_str(),
|
||||
opt->getCurrentValueDescription().display.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace options
|
||||
@@ -54,6 +54,8 @@ class OptionsManager {
|
||||
void discardChanges();
|
||||
|
||||
void loadInitialValues();
|
||||
|
||||
void printValues();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace os
|
||||
//buttons not clickable. So as a hotfix, the dialog has no blocking parent in that case and
|
||||
//is instead rendered as it's own window
|
||||
SDL_Window* getDialogParent() {
|
||||
return !(Cmdline_fullscreen_window || Cmdline_window) ? NULL : os::getSDLMainWindow();
|
||||
return !(gr_is_viewport_window()) ? NULL : os::getSDLMainWindow();
|
||||
}
|
||||
|
||||
void AssertMessage(const char * text, const char * filename, int linenum, const char * format, ...)
|
||||
|
||||
@@ -113,9 +113,7 @@ namespace
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
{
|
||||
if (fAppActive) {
|
||||
if (!Cmdline_no_unfocus_pause) {
|
||||
game_pause();
|
||||
}
|
||||
game_pause();
|
||||
|
||||
fAppActive = false;
|
||||
}
|
||||
@@ -126,9 +124,7 @@ namespace
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
{
|
||||
if (!fAppActive) {
|
||||
if (!Cmdline_no_unfocus_pause) {
|
||||
game_unpause();
|
||||
}
|
||||
game_unpause();
|
||||
|
||||
fAppActive = true;
|
||||
}
|
||||
|
||||
+13
-9
@@ -2104,10 +2104,11 @@ int parse_get_line(char *lineout, int max_line_len, const char *start, int max_s
|
||||
// Goober5000 - added ability to read somewhere other than Parse_text
|
||||
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
|
||||
{
|
||||
// copy the filename
|
||||
Assertion(filename, "Filename must not be null!");
|
||||
if (!filename)
|
||||
throw parse::ParseException("Invalid filename");
|
||||
throw parse::FileOpenException("Filename must not be null!");
|
||||
|
||||
// copy the filename
|
||||
strcpy_s(Current_filename_sub, filename);
|
||||
|
||||
// if we are paused then processed_text and raw_text must not be NULL!!
|
||||
@@ -2231,13 +2232,15 @@ void read_raw_file_text(const char *filename, int mode, char *raw_text)
|
||||
CFILE *mf;
|
||||
int file_is_encrypted;
|
||||
|
||||
Assert(filename);
|
||||
Assertion(filename, "Filename must not be null!");
|
||||
if (!filename)
|
||||
throw parse::FileOpenException("Filename must not be null!");
|
||||
|
||||
mf = cfopen(filename, "rb", CFILE_NORMAL, mode);
|
||||
if (mf == NULL)
|
||||
{
|
||||
nprintf(("Error", "Wokka! Error opening file (%s)!\n", filename));
|
||||
throw parse::ParseException("Failed to open file");
|
||||
throw parse::FileOpenException("Failed to open file");
|
||||
}
|
||||
|
||||
// read the entire file in
|
||||
@@ -2245,7 +2248,7 @@ void read_raw_file_text(const char *filename, int mode, char *raw_text)
|
||||
|
||||
if(!file_len) {
|
||||
nprintf(("Error", "Oh noes!! File is empty! (%s)!\n", filename));
|
||||
throw parse::ParseException("Failed to open file");
|
||||
throw parse::ParseException("File is empty");
|
||||
}
|
||||
|
||||
// For the possible Latin1 -> UTF-8 conversion we need to reallocate the raw_text at some point and we can only do
|
||||
@@ -2469,10 +2472,11 @@ void read_file_bytes(const char *filename, int mode, char *raw_bytes)
|
||||
{
|
||||
CFILE *mf;
|
||||
|
||||
// copy the filename
|
||||
Assertion(filename, "Filename must not be null!");
|
||||
if (!filename)
|
||||
throw parse::ParseException("Invalid filename");
|
||||
throw parse::FileOpenException("Filename must not be null!");
|
||||
|
||||
// copy the filename
|
||||
strcpy_s(Current_filename_sub, filename);
|
||||
|
||||
// if we are paused then raw_bytes must not be NULL!!
|
||||
@@ -2484,7 +2488,7 @@ void read_file_bytes(const char *filename, int mode, char *raw_bytes)
|
||||
if (mf == nullptr)
|
||||
{
|
||||
nprintf(("Error", "Wokka! Error opening file (%s)!\n", filename));
|
||||
throw parse::ParseException("Failed to open file");
|
||||
throw parse::FileOpenException("Failed to open file");
|
||||
}
|
||||
|
||||
// read the entire file in
|
||||
@@ -2492,7 +2496,7 @@ void read_file_bytes(const char *filename, int mode, char *raw_bytes)
|
||||
|
||||
if(!file_len) {
|
||||
nprintf(("Error", "Oh noes!! File is empty! (%s)!\n", filename));
|
||||
throw parse::ParseException("Failed to open file");
|
||||
throw parse::ParseException("File is empty");
|
||||
}
|
||||
|
||||
if (raw_bytes == nullptr) {
|
||||
|
||||
@@ -418,6 +418,13 @@ namespace parse
|
||||
~ParseException() noexcept override = default;
|
||||
};
|
||||
|
||||
class FileOpenException : public ParseException
|
||||
{
|
||||
public:
|
||||
explicit FileOpenException(const std::string& msg) : ParseException(msg) {}
|
||||
~FileOpenException() noexcept override = default;
|
||||
};
|
||||
|
||||
class VersionException : public std::runtime_error
|
||||
{
|
||||
private:
|
||||
|
||||
+423
-344
File diff suppressed because it is too large.
Load diff
@@ -1243,6 +1243,12 @@ enum sexp_error_check
|
||||
SEXP_CHECK_INVALID_BOLT_TYPE,
|
||||
SEXP_CHECK_INVALID_TRAITOR_OVERRIDE,
|
||||
SEXP_CHECK_INVALID_LUA_GENERAL_ORDER,
|
||||
SEXP_CHECK_INVALID_SHIP_POINT,
|
||||
SEXP_CHECK_INVALID_SHIP_WING_SHIPONTEAM_POINT,
|
||||
SEXP_CHECK_INVALID_SHIP_WING_POINT,
|
||||
SEXP_CHECK_INVALID_ORDER_RECIPIENT,
|
||||
SEXP_CHECK_INVALID_SHIP_WING_WHOLETEAM,
|
||||
SEXP_CHECK_MUST_BE_INTEGER,
|
||||
};
|
||||
|
||||
|
||||
@@ -1344,6 +1350,8 @@ typedef struct sexp_node {
|
||||
#define SNF_SPECIAL_ARG_IN_TREE (1<<3)
|
||||
#define SNF_SPECIAL_ARG_NOT_IN_TREE (1<<4)
|
||||
#define SNF_CHECKED_ARG_FOR_VAR (1<<5)
|
||||
#define SNF_CHECKED_NODE_FOR_OPF_POSITIVE (1<<6)
|
||||
#define SNF_NODE_IS_OPF_POSITIVE (1<<7)
|
||||
#define SNF_DEFAULT_VALUE SNF_ARGUMENT_VALID
|
||||
|
||||
typedef struct sexp_variable {
|
||||
|
||||
@@ -68,6 +68,7 @@ ADE_VIRTVAR(MultiLogin, l_Options, "string", "The multiplayer PXO login name", "
|
||||
|
||||
if (ADE_SETTING_VAR && (login != nullptr)) {
|
||||
strcpy_s(Multi_tracker_login, login);
|
||||
os_config_write_string("PXO", "Login", login);
|
||||
}
|
||||
|
||||
return ade_set_args(L, "s", Multi_tracker_login);
|
||||
@@ -80,6 +81,7 @@ ADE_VIRTVAR(MultiPassword, l_Options, "string", "The multiplayer PXO login passw
|
||||
|
||||
if (ADE_SETTING_VAR && (pswd != nullptr)) {
|
||||
strcpy_s(Multi_tracker_passwd, pswd);
|
||||
os_config_write_string("PXO", "Password", pswd);
|
||||
}
|
||||
|
||||
return ade_set_args(L, "b", (strlen(Multi_tracker_passwd) != 0));
|
||||
@@ -92,6 +94,7 @@ ADE_VIRTVAR(MultiSquad, l_Options, "string", "The multiplayer PXO squad name", "
|
||||
|
||||
if (ADE_SETTING_VAR && (squad != nullptr)) {
|
||||
strcpy_s(Multi_tracker_squad_name, squad);
|
||||
os_config_write_string("PXO", "SquadName", squad);
|
||||
}
|
||||
|
||||
return ade_set_args(L, "s", Multi_tracker_squad_name);
|
||||
|
||||
@@ -259,6 +259,11 @@ ADE_FUNC(playCutscene, l_UserInterface, "string Filename, boolean RestartMusic,
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
ADE_FUNC(isCutscenePlaying, l_UserInterface, nullptr, "Checks if a cutscene is playing.", "boolean", "Returns true if cutscene is playing, false otherwise")
|
||||
{
|
||||
return ade_set_args(L, "b", Movie_active);
|
||||
}
|
||||
|
||||
ADE_FUNC(launchURL, l_UserInterface, "string url", "Launches the given URL in a web browser", nullptr, nullptr)
|
||||
{
|
||||
const char* url;
|
||||
@@ -388,6 +393,23 @@ ADE_FUNC(
|
||||
return ade_set_args(L, "b", player_create_new_pilot(callsign, is_multi, copy_from));
|
||||
}
|
||||
|
||||
ADE_FUNC(unloadPilot,
|
||||
l_UserInterface_PilotSelect,
|
||||
nullptr,
|
||||
"Unloads a player file & associated campaign file. Can not be used outside of pilot select!",
|
||||
"boolean",
|
||||
"Returns true if successful, false otherwise")
|
||||
{
|
||||
if (gameseq_get_state() == GS_STATE_INITIAL_PLAYER_SELECT) {
|
||||
Player = nullptr;
|
||||
Campaign.filename[0] = '\0';
|
||||
|
||||
return ADE_RETURN_TRUE;
|
||||
}
|
||||
|
||||
return ADE_RETURN_FALSE;
|
||||
}
|
||||
|
||||
ADE_FUNC(isAutoselect, l_UserInterface_PilotSelect, nullptr,
|
||||
"Determines if the pilot selection screen should automatically select the default user.", "boolean",
|
||||
"true if autoselect is enabled, false otherwise")
|
||||
@@ -1620,12 +1642,28 @@ ADE_LIB_DERIV(l_UserInterface_Cutscenes, "Cutscenes", nullptr, nullptr, l_UserIn
|
||||
ADE_INDEXER(l_UserInterface_Cutscenes,
|
||||
"number Index",
|
||||
"Array of cutscenes",
|
||||
"custscene_info",
|
||||
"cutscene_info",
|
||||
"Cutscene handle, or invalid handle if index is invalid")
|
||||
{
|
||||
int idx;
|
||||
if (!ade_get_args(L, "*i", &idx))
|
||||
return ade_set_error(L, "s", "");
|
||||
const char* name;
|
||||
if (!ade_get_args(L, "*s", &name))
|
||||
return ade_set_error(L, "o", l_TechRoomCutscene.Set(cutscene_info_h(-1)));
|
||||
|
||||
int idx = get_cutscene_index_by_name(name);
|
||||
|
||||
if (idx < 0) {
|
||||
try {
|
||||
idx = std::stoi(name);
|
||||
idx--; // Lua->FS2
|
||||
} catch (const std::exception&) {
|
||||
// Not a number
|
||||
return ade_set_error(L, "o", l_TechRoomCutscene.Set(cutscene_info_h(-1)));
|
||||
}
|
||||
|
||||
if (!SCP_vector_inbounds(Cutscenes, idx)) {
|
||||
return ade_set_error(L, "o", l_TechRoomCutscene.Set(cutscene_info_h(-1)));
|
||||
}
|
||||
}
|
||||
|
||||
return ade_set_args(L, "o", l_TechRoomCutscene.Set(cutscene_info_h(idx)));
|
||||
}
|
||||
|
||||
@@ -15,15 +15,24 @@ dynamic_sexp_enum_list* lua_enum_h::getEnum() const
|
||||
return &Dynamic_enums[lua_enum];
|
||||
}
|
||||
|
||||
bool lua_enum_h::isValid() const
|
||||
{
|
||||
return SCP_vector_inbounds(Dynamic_enums, lua_enum);
|
||||
}
|
||||
|
||||
ADE_OBJ(l_LuaEnum, lua_enum_h, "LuaEnum", "Lua Enum handle");
|
||||
|
||||
ADE_VIRTVAR(Name, l_LuaEnum, "string", "The enum name", "string", "The enum name")
|
||||
ADE_VIRTVAR(Name, l_LuaEnum, "string", "The enum name", "string", "The enum name or nil if handle is invalid")
|
||||
{
|
||||
lua_enum_h lua_enum;
|
||||
const char* enum_name;
|
||||
if (!ade_get_args(L, "o|s", l_LuaEnum.Get(&lua_enum), &enum_name))
|
||||
return ade_set_error(L, "o", l_LuaEnum.Set(lua_enum_h()));
|
||||
|
||||
if (!lua_enum.isValid()) {
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
if (ADE_SETTING_VAR) {
|
||||
LuaError(L, "This property is read only.");
|
||||
}
|
||||
@@ -38,6 +47,10 @@ ADE_INDEXER(l_LuaEnum, "number Index", "Array of enum items", "string", "enum it
|
||||
if (!ade_get_args(L, "o|i", l_LuaEnum.Get(&lua_enum), &idx))
|
||||
return ADE_RETURN_NIL;
|
||||
|
||||
if (!lua_enum.isValid()) {
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
idx--; //Convert from lua 1 based index
|
||||
if ((idx < 0) || (idx >= static_cast<int>(lua_enum.getEnum()->list.size())))
|
||||
return ADE_RETURN_NIL;
|
||||
@@ -45,12 +58,16 @@ ADE_INDEXER(l_LuaEnum, "number Index", "Array of enum items", "string", "enum it
|
||||
return ade_set_args(L, "s", lua_enum.getEnum()->list[idx].c_str());
|
||||
}
|
||||
|
||||
ADE_FUNC(__len, l_LuaEnum, nullptr, "The number of Lua enum items", "number", "The number of Lua enums item.")
|
||||
ADE_FUNC(__len, l_LuaEnum, nullptr, "The number of Lua enum items", "number", "The number of Lua enums item or nil if handle is invalid")
|
||||
{
|
||||
lua_enum_h lua_enum;
|
||||
if (!ade_get_args(L, "o", l_LuaEnum.Get(&lua_enum)))
|
||||
return ade_set_error(L, "i", 0);
|
||||
|
||||
if (!lua_enum.isValid()) {
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
return ade_set_args(L, "i", static_cast<int>(lua_enum.getEnum()->list.size()));
|
||||
}
|
||||
|
||||
@@ -66,6 +83,10 @@ ADE_FUNC(addEnumItem,
|
||||
if (!ade_get_args(L, "os", l_LuaEnum.Get(&lua_enum) , &item_name))
|
||||
return ADE_RETURN_FALSE;
|
||||
|
||||
if (!lua_enum.isValid()) {
|
||||
return ADE_RETURN_FALSE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lua_enum.getEnum()->list.size(); i++) {
|
||||
if (!stricmp(item_name, lua_enum.getEnum()->list[i].c_str())) {
|
||||
return ADE_RETURN_FALSE;
|
||||
@@ -89,6 +110,10 @@ ADE_FUNC(removeEnumItem,
|
||||
if (!ade_get_args(L, "os", l_LuaEnum.Get(&lua_enum), &item_name))
|
||||
return ADE_RETURN_FALSE;
|
||||
|
||||
if (!lua_enum.isValid()) {
|
||||
return ADE_RETURN_FALSE;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < lua_enum.getEnum()->list.size(); i++) {
|
||||
@@ -103,5 +128,14 @@ ADE_FUNC(removeEnumItem,
|
||||
return ADE_RETURN_FALSE;
|
||||
}
|
||||
|
||||
ADE_FUNC(isValid, l_LuaEnum, nullptr, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
|
||||
{
|
||||
lua_enum_h lua_enum;
|
||||
if (!ade_get_args(L, "o", l_LuaEnum.Get(&lua_enum)))
|
||||
return ADE_RETURN_NIL;
|
||||
|
||||
return ade_set_args(L, "b", lua_enum.isValid());
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace scripting
|
||||
@@ -12,6 +12,7 @@ struct lua_enum_h {
|
||||
lua_enum_h();
|
||||
explicit lua_enum_h(int idx);
|
||||
dynamic_sexp_enum_list* getEnum() const;
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
DECLARE_ADE_OBJ(l_LuaEnum, lua_enum_h);
|
||||
|
||||
@@ -1267,10 +1267,10 @@ ADE_FUNC(renderTechModel2, l_Shipclass, "number X1, number Y1, number X2, number
|
||||
|
||||
ADE_FUNC(renderSelectModel,
|
||||
l_Shipclass,
|
||||
"boolean restart, number x, number y, [number width = 629, number height = 355, number = currentEffectSetting]",
|
||||
"boolean restart, number x, number y, [number width = 629, number height = 355, number currentEffectSetting = default, number zoom = 1.3]",
|
||||
"Draws the 3D select ship model with the chosen effect at the specified coordinates. Restart should "
|
||||
"be true on the first frame this is called and false on subsequent frames. Valid selection effects are 1 (fs1) or 2 (fs2), "
|
||||
"defaults to the mod setting or the model's setting.",
|
||||
"defaults to the mod setting or the model's setting. Zoom is a multiplier to the model's closeup_zoom value.",
|
||||
"boolean",
|
||||
"true if rendered, false if error")
|
||||
{
|
||||
@@ -1281,7 +1281,8 @@ ADE_FUNC(renderSelectModel,
|
||||
int x2 = 629;
|
||||
int y2 = 355;
|
||||
int effect = -1;
|
||||
if (!ade_get_args(L, "obii|iii", l_Shipclass.Get(&idx), &restart, &x1, &y1, &x2, &y2, &effect))
|
||||
float zoom = 1.3f;
|
||||
if (!ade_get_args(L, "obii|iiif", l_Shipclass.Get(&idx), &restart, &x1, &y1, &x2, &y2, &effect, &zoom))
|
||||
return ADE_RETURN_NIL;
|
||||
|
||||
if (idx < 0 || idx >= ship_info_size())
|
||||
@@ -1331,7 +1332,7 @@ ADE_FUNC(renderSelectModel,
|
||||
y2,
|
||||
&ShipRot,
|
||||
&sip->closeup_pos,
|
||||
sip->closeup_zoom * 1.3f,
|
||||
sip->closeup_zoom * zoom,
|
||||
rev_rate,
|
||||
MR_AUTOCENTER | MR_NO_FOGGING,
|
||||
GR_RESIZE_NONE,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "network/multiutil.h"
|
||||
|
||||
void sexp_beam_or_turret_free_one(ship_subsys *turret, bool is_beam, bool free);
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true);
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true);
|
||||
|
||||
namespace scripting {
|
||||
namespace api {
|
||||
@@ -865,7 +865,7 @@ ADE_FUNC(fireWeapon, l_Subsystem, "[number TurretWeaponIndex = 1, number FlakRan
|
||||
//Get default turret info
|
||||
vec3d gpos, gvec;
|
||||
|
||||
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, &gvec, 1, NULL);
|
||||
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, false, &gvec, true, nullptr);
|
||||
if (override_gvec != nullptr)
|
||||
gvec = *override_gvec;
|
||||
|
||||
@@ -896,7 +896,7 @@ ADE_FUNC(rotateTurret, l_Subsystem, "vector Pos, boolean reset=false", "Rotates
|
||||
auto pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
int ret_val = model_rotate_gun(objp, pm, pmi, sso->ss, &pos, reset);
|
||||
bool ret_val = model_rotate_gun(objp, pm, pmi, sso->ss, reset ? nullptr : &pos);
|
||||
|
||||
if (ret_val)
|
||||
return ADE_RETURN_TRUE;
|
||||
@@ -961,7 +961,7 @@ ADE_FUNC(
|
||||
|
||||
vec3d gpos, gvec;
|
||||
|
||||
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, &gvec, 1, NULL);
|
||||
ship_get_global_turret_gun_info(sso->objp, sso->ss, &gpos, false, &gvec, true, nullptr);
|
||||
|
||||
return ade_set_args(L, "oo", l_Vector.Set(gpos), l_Vector.Set(gvec));
|
||||
}
|
||||
@@ -1014,9 +1014,9 @@ ADE_FUNC(isInViewFrom, l_Subsystem, "vector from",
|
||||
get_subsystem_world_pos(sso->objp, sso->ss, &world_pos);
|
||||
|
||||
// Disable facing check since the HUD code does the same
|
||||
int in_sight = ship_subsystem_in_sight(sso->objp, sso->ss, from, &world_pos, 0);
|
||||
bool in_sight = ship_subsystem_in_sight(sso->objp, sso->ss, from, &world_pos, false);
|
||||
|
||||
return ade_set_args(L, "b", in_sight != 0);
|
||||
return ade_set_args(L, "b", in_sight);
|
||||
}
|
||||
|
||||
ADE_FUNC(isValid, l_Subsystem, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
|
||||
|
||||
@@ -24,10 +24,10 @@ cutscene_info_h::cutscene_info_h(int scene) : cutscene(scene) {}
|
||||
|
||||
bool cutscene_info_h::IsValid() const
|
||||
{
|
||||
return cutscene >= 0;
|
||||
return SCP_vector_inbounds(Cutscenes, cutscene);
|
||||
}
|
||||
|
||||
cutscene_info* cutscene_info_h::getStage() const
|
||||
cutscene_info* cutscene_info_h::getScene() const
|
||||
{
|
||||
return &Cutscenes[cutscene];
|
||||
}
|
||||
@@ -120,7 +120,7 @@ ADE_VIRTVAR(isCampaignMission, l_TechRoomMission, nullptr, "If the mission is ca
|
||||
}
|
||||
|
||||
//**********HANDLE: tech cutscenes
|
||||
ADE_OBJ(l_TechRoomCutscene, cutscene_info_h, "custscene_info", "Tech Room cutscene handle");
|
||||
ADE_OBJ(l_TechRoomCutscene, cutscene_info_h, "cutscene_info", "Tech Room cutscene handle");
|
||||
|
||||
ADE_VIRTVAR(Name, l_TechRoomCutscene, nullptr, "The name of the cutscene", "string", "The cutscene name")
|
||||
{
|
||||
@@ -133,7 +133,7 @@ ADE_VIRTVAR(Name, l_TechRoomCutscene, nullptr, "The name of the cutscene", "stri
|
||||
LuaError(L, "This property is read only.");
|
||||
}
|
||||
|
||||
return ade_set_args(L, "s", current.getStage()->name);
|
||||
return ade_set_args(L, "s", current.getScene()->name);
|
||||
}
|
||||
|
||||
ADE_VIRTVAR(Filename, l_TechRoomCutscene, nullptr, "The filename of the cutscene", "string", "The cutscene filename")
|
||||
@@ -147,7 +147,7 @@ ADE_VIRTVAR(Filename, l_TechRoomCutscene, nullptr, "The filename of the cutscene
|
||||
LuaError(L, "This property is read only.");
|
||||
}
|
||||
|
||||
return ade_set_args(L, "s", current.getStage()->filename);
|
||||
return ade_set_args(L, "s", current.getScene()->filename);
|
||||
}
|
||||
|
||||
ADE_VIRTVAR(Description, l_TechRoomCutscene, nullptr, "The cutscene description", "string", "The cutscene description")
|
||||
@@ -161,7 +161,7 @@ ADE_VIRTVAR(Description, l_TechRoomCutscene, nullptr, "The cutscene description"
|
||||
LuaError(L, "This property is read only.");
|
||||
}
|
||||
|
||||
return ade_set_args(L, "s", current.getStage()->description);
|
||||
return ade_set_args(L, "s", current.getScene()->description);
|
||||
}
|
||||
|
||||
ADE_VIRTVAR(isVisible,
|
||||
@@ -179,8 +179,8 @@ ADE_VIRTVAR(isVisible,
|
||||
if (ADE_SETTING_VAR) {
|
||||
LuaError(L, "This property is read only.");
|
||||
}
|
||||
if (current.getStage()->flags[Cutscene::Cutscene_Flags::Viewable, Cutscene::Cutscene_Flags::Always_viewable] &&
|
||||
!current.getStage()->flags[Cutscene::Cutscene_Flags::Never_viewable])
|
||||
if (current.getScene()->flags[Cutscene::Cutscene_Flags::Viewable, Cutscene::Cutscene_Flags::Always_viewable] &&
|
||||
!current.getScene()->flags[Cutscene::Cutscene_Flags::Never_viewable])
|
||||
{
|
||||
return ade_set_args(L, "b", true);
|
||||
} else {
|
||||
@@ -202,7 +202,7 @@ ADE_VIRTVAR(CustomData, l_TechRoomCutscene, nullptr, "Gets the custom data table
|
||||
|
||||
auto table = luacpp::LuaTable::create(L);
|
||||
|
||||
for (const auto& pair : current.getStage()->custom_data)
|
||||
for (const auto& pair : current.getScene()->custom_data)
|
||||
{
|
||||
table.addValue(pair.first, pair.second);
|
||||
}
|
||||
@@ -217,9 +217,19 @@ ADE_FUNC(hasCustomData, l_TechRoomCutscene, nullptr, "Detects whether the cutsce
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
bool result = !current.getStage()->custom_data.empty();
|
||||
bool result = !current.getScene()->custom_data.empty();
|
||||
return ade_set_args(L, "b", result);
|
||||
}
|
||||
|
||||
ADE_FUNC(isValid, l_TechRoomCutscene, NULL, "Detects whether cutscene is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
|
||||
{
|
||||
cutscene_info_h current;
|
||||
if (!ade_get_args(L, "o", l_TechRoomCutscene.Get(¤t))) {
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
return ade_set_args(L, "b", current.IsValid());
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace scripting
|
||||
@@ -21,7 +21,7 @@ struct cutscene_info_h {
|
||||
cutscene_info_h();
|
||||
explicit cutscene_info_h(int scene);
|
||||
bool IsValid() const;
|
||||
cutscene_info* getStage() const;
|
||||
cutscene_info* getScene() const;
|
||||
};
|
||||
|
||||
DECLARE_ADE_OBJ(l_TechRoomMission, sim_mission_h);
|
||||
|
||||
@@ -846,11 +846,11 @@ ADE_FUNC(renderTechModel2,
|
||||
|
||||
ADE_FUNC(renderSelectModel,
|
||||
l_Weaponclass,
|
||||
"number x, number y, [number width = 629, number height = 355, number = currentEffectSetting]",
|
||||
"number x, number y, [number width = 629, number height = 355, number currentEffectSetting = default, number zoom = 0.65]",
|
||||
"Draws the 3D select weapon model with the chosen effect at the specified coordinates. Restart should "
|
||||
"be true on the first frame this is called and false on subsequent frames. Note that primary weapons "
|
||||
"will not render anything if they do not have a valid pof model defined! Valid selection effects are 1 (fs1) or 2 (fs2), "
|
||||
"defaults to the mod setting or the model's setting.",
|
||||
"defaults to the mod setting or the model's setting. Zoom is a multiplier to the model's closeup_zoom value.",
|
||||
"boolean",
|
||||
"true if rendered, false if error")
|
||||
{
|
||||
@@ -861,7 +861,8 @@ ADE_FUNC(renderSelectModel,
|
||||
int x2 = 629;
|
||||
int y2 = 355;
|
||||
int effect = -1;
|
||||
if (!ade_get_args(L, "obii|iii", l_Weaponclass.Get(&idx), &restart, &x1, &y1, &x2, &y2, &effect))
|
||||
float zoom = 0.65f;
|
||||
if (!ade_get_args(L, "obii|iiif", l_Weaponclass.Get(&idx), &restart, &x1, &y1, &x2, &y2, &effect, &zoom))
|
||||
return ADE_RETURN_NIL;
|
||||
|
||||
if (idx < 0 || idx >= weapon_info_size())
|
||||
@@ -903,7 +904,7 @@ ADE_FUNC(renderSelectModel,
|
||||
y2,
|
||||
&WepRot,
|
||||
&wip->closeup_pos,
|
||||
wip->closeup_zoom * 0.65f,
|
||||
wip->closeup_zoom * zoom,
|
||||
REVOLUTION_RATE,
|
||||
MR_IS_MISSILE | MR_AUTOCENTER | MR_NO_FOGGING,
|
||||
GR_RESIZE_NONE,
|
||||
|
||||
@@ -12,6 +12,10 @@ const std::shared_ptr<Hook<>> OnGameInit = Hook<>::Factory("On Game Init",
|
||||
tl::nullopt,
|
||||
CHA_GAMEINIT);
|
||||
|
||||
const std::shared_ptr<Hook<>> OnSplashEnd = Hook<>::Factory("On Splash End",
|
||||
"Executed just after the splash screen fades out.",
|
||||
{});
|
||||
|
||||
const std::shared_ptr<Hook<>> OnIntroAboutToPlay = Hook<>::Factory("On Intro About To Play",
|
||||
"Executed just before the intro movie is played.",
|
||||
{});
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace scripting {
|
||||
namespace hooks {
|
||||
|
||||
extern const std::shared_ptr<Hook<>> OnGameInit;
|
||||
extern const std::shared_ptr<Hook<>> OnSplashEnd;
|
||||
extern const std::shared_ptr<Hook<>> OnIntroAboutToPlay;
|
||||
//The On State Start hook previously used to pass OldState to the conditions, but no semantically sensible condition read the value, so we pretend it has no local condition
|
||||
extern const std::shared_ptr<OverridableHook<>> OnStateStart;
|
||||
|
||||
@@ -152,6 +152,9 @@ class HookImpl : public HookBase {
|
||||
template <typename... Args>
|
||||
int run(condition_t condition, detail::HookParameterInstanceList<Args...> argsList = hook_param_list<Args...>()) const
|
||||
{
|
||||
if (!Scripting_game_init_run)
|
||||
return 0;
|
||||
|
||||
SCP_vector<SCP_string> paramNames;
|
||||
argsList.setHookVars(paramNames);
|
||||
|
||||
@@ -183,6 +186,9 @@ class HookImpl<void> : public HookBase {
|
||||
template <typename... Args>
|
||||
int run(detail::HookParameterInstanceList<Args...> argsList = hook_param_list<Args...>()) const
|
||||
{
|
||||
if (!Scripting_game_init_run)
|
||||
return 0;
|
||||
|
||||
SCP_vector<SCP_string> paramNames;
|
||||
argsList.setHookVars(paramNames);
|
||||
|
||||
@@ -239,6 +245,9 @@ class OverridableHookImpl : public Hook<condition_t> {
|
||||
template <typename... Args>
|
||||
bool isOverride(condition_t condition, detail::HookParameterInstanceList<Args...> argsList = hook_param_list<Args...>()) const
|
||||
{
|
||||
if (!Scripting_game_init_run)
|
||||
return false;
|
||||
|
||||
SCP_vector<SCP_string> paramNames;
|
||||
argsList.setHookVars(paramNames);
|
||||
|
||||
@@ -270,6 +279,9 @@ protected:
|
||||
template <typename... Args>
|
||||
bool isOverride(detail::HookParameterInstanceList<Args...> argsList = hook_param_list<Args...>()) const
|
||||
{
|
||||
if (!Scripting_game_init_run)
|
||||
return false;
|
||||
|
||||
SCP_vector<SCP_string> paramNames;
|
||||
argsList.setHookVars(paramNames);
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ void LuaFunction::setReference(const LuaReference& ref) {
|
||||
|
||||
if (lua_type(L, -1) != LUA_TFUNCTION) {
|
||||
lua_pop(L, 1);
|
||||
throw LuaException("Reference does not refere to a function!");
|
||||
throw LuaException("Reference does not refer to a function!");
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
LuaValue::setReference(ref);
|
||||
|
||||
@@ -42,7 +42,7 @@ void LuaTable::setReference(const LuaReference& ref) {
|
||||
|
||||
if (lua_type(L, -1) != LUA_TTABLE) {
|
||||
lua_pop(L, 1);
|
||||
throw LuaException("Reference does not refere to a table!");
|
||||
throw LuaException("Reference does not refer to a table!");
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
LuaValue::setReference(ref);
|
||||
|
||||
@@ -55,7 +55,9 @@ lua_State* getMainThread(lua_State* L)
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
auto state = lua_tothread(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Need to pop both the thread from L and the main thread to return the stack back to neutral
|
||||
lua_pop(L, 2);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ using namespace scripting;
|
||||
script_state Script_system("FS2_Open Scripting");
|
||||
bool Output_scripting_meta = false;
|
||||
bool Output_scripting_json = false;
|
||||
bool Scripting_game_init_run = false;
|
||||
|
||||
flag_def_list Script_conditions[] =
|
||||
{
|
||||
|
||||
@@ -350,6 +350,7 @@ void script_init();
|
||||
extern class script_state Script_system;
|
||||
extern bool Output_scripting_meta;
|
||||
extern bool Output_scripting_json;
|
||||
extern bool Scripting_game_init_run;
|
||||
|
||||
//*************************Conditional scripting*************************
|
||||
|
||||
|
||||
+2
-2
@@ -177,7 +177,7 @@ void awacs_update_all_levels()
|
||||
// < 0.0f : untargetable
|
||||
// 0.0 - 1.0f : marginally targetable
|
||||
// >= 1.0f : fully targetable as normal
|
||||
float awacs_get_level(object *target, ship *viewer, int use_awacs)
|
||||
float awacs_get_level(const object *target, const ship *viewer, bool use_awacs)
|
||||
{
|
||||
Assert(target); // Goober5000
|
||||
Assert(viewer); // Goober5000
|
||||
@@ -461,7 +461,7 @@ void team_visibility_update()
|
||||
|
||||
// Determine is ship is visible by team
|
||||
// Goober5000 - now accounts for primitive sensors
|
||||
int ship_is_visible_by_team(object *target, ship *viewer)
|
||||
int ship_is_visible_by_team(const object *target, const ship *viewer)
|
||||
{
|
||||
Assert(target);
|
||||
Assert(viewer);
|
||||
|
||||
+2
-2
@@ -37,11 +37,11 @@ void awacs_process();
|
||||
// < 0.0f : untargetable
|
||||
// 0.0 - 1.0f : marginally targetable
|
||||
// 1.0f : fully targetable as normal
|
||||
float awacs_get_level(object *target, ship *viewer, int use_awacs=1);
|
||||
float awacs_get_level(const object *target, const ship *viewer, bool use_awacs = true);
|
||||
|
||||
// Determine if ship is visible by team
|
||||
// return 1 if ship is fully visible
|
||||
// return 0 if ship is only partly visible
|
||||
int ship_is_visible_by_team(object *target, ship *viewer);
|
||||
int ship_is_visible_by_team(const object *target, const ship *viewer);
|
||||
|
||||
#endif
|
||||
+34
-18
@@ -2941,7 +2941,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
|
||||
// Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
|
||||
if (replace)
|
||||
if (sip->cockpit_pof_file[0] != '\0')
|
||||
if (VALID_FNAME(sip->cockpit_pof_file))
|
||||
if (!model_exists(temp))
|
||||
valid = false;
|
||||
|
||||
@@ -3021,7 +3021,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
|
||||
// Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
|
||||
if (replace)
|
||||
if (sip->pof_file[0] != '\0')
|
||||
if (VALID_FNAME(sip->pof_file))
|
||||
if (!model_exists(temp))
|
||||
valid = false;
|
||||
|
||||
@@ -3041,7 +3041,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
|
||||
// if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
|
||||
if (replace)
|
||||
if (sip->pof_file_tech[0] != '\0')
|
||||
if (VALID_FNAME(sip->pof_file_tech))
|
||||
if (!cf_exists_full(temp, CF_TYPE_MODELS))
|
||||
valid = false;
|
||||
|
||||
@@ -3102,7 +3102,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
|
||||
// Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
|
||||
if (replace)
|
||||
if (sip->pof_file_hud[0] != '\0')
|
||||
if (VALID_FNAME(sip->pof_file_hud))
|
||||
if (!cf_exists_full(temp, CF_TYPE_MODELS))
|
||||
valid = false;
|
||||
|
||||
@@ -3380,7 +3380,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
bool valid = true;
|
||||
|
||||
if (replace)
|
||||
if (sip->generic_debris_pof_file[0] != '\0')
|
||||
if (VALID_FNAME(sip->generic_debris_pof_file))
|
||||
if (!cf_exists_full(temp, CF_TYPE_MODELS))
|
||||
valid = false;
|
||||
|
||||
@@ -4346,7 +4346,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
{
|
||||
stuff_vec3d(&sip->closeup_pos);
|
||||
}
|
||||
else if (first_time && strlen(sip->pof_file))
|
||||
else if (first_time && VALID_FNAME(sip->pof_file))
|
||||
{
|
||||
//Calculate from the model file. This is inefficient, but whatever
|
||||
int model_idx = model_load(sip->pof_file, 0, NULL);
|
||||
@@ -5077,6 +5077,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
}
|
||||
|
||||
int n_subsystems = 0;
|
||||
int n_excess_subsystems = 0;
|
||||
int cont_flag = 1;
|
||||
model_subsystem subsystems[MAX_MODEL_SUBSYSTEMS] = {}; // see model.h for max_model_subsystems
|
||||
for (auto i=0; i<MAX_MODEL_SUBSYSTEMS; i++) {
|
||||
@@ -5112,7 +5113,8 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
{
|
||||
if( sip->n_subsystems + n_subsystems >= MAX_MODEL_SUBSYSTEMS )
|
||||
{
|
||||
Warning(LOCATION, "Number of subsystems for %s '%s' (%d) exceeds max of %d; only the first %d will be used", info_type_name, sip->name, sip->n_subsystems, n_subsystems, MAX_MODEL_SUBSYSTEMS);
|
||||
n_excess_subsystems++;
|
||||
skip_to_start_of_string_one_of({"$Subsystem:", type_name, "#End"});
|
||||
break;
|
||||
}
|
||||
sp = &subsystems[n_subsystems++]; // subsystems a local -- when done, we will malloc and copy
|
||||
@@ -5465,7 +5467,12 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
default:
|
||||
UNREACHABLE("This should never happen.\n"); // Impossible return value from required_string_one_of.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maybe warn
|
||||
if (n_excess_subsystems > 0) {
|
||||
Warning(LOCATION, "For %s '%s', number of existing subsystems (%d) plus additional subsystems (%d) exceeds max of %d; only the first %d additional subsystems will be used", info_type_name, sip->name, sip->n_subsystems, n_subsystems + n_excess_subsystems, MAX_MODEL_SUBSYSTEMS, n_subsystems);
|
||||
}
|
||||
|
||||
// when done reading subsystems, malloc and copy the subsystem data to the ship info structure
|
||||
int orig_n_subsystems = sip->n_subsystems;
|
||||
@@ -7407,6 +7414,7 @@ void ship_subsys::clear()
|
||||
targeted_subsys = NULL;
|
||||
scripting_target_override = false;
|
||||
last_fired_weapon_info_index = -1;
|
||||
shared_fire_direction_beam_objnum = -1;
|
||||
|
||||
turret_pick_big_attack_point_timestamp = timestamp(0);
|
||||
turret_big_attack_point = vmd_zero_vector;
|
||||
@@ -7603,6 +7611,9 @@ static int subsys_set(int objnum, int ignore_subsys_info)
|
||||
ship_system->disruption_timestamp=timestamp(0);
|
||||
ship_system->turret_pick_big_attack_point_timestamp = timestamp(0);
|
||||
ship_system->scripting_target_override = false;
|
||||
ship_system->last_fired_weapon_info_index = -1;
|
||||
ship_system->shared_fire_direction_beam_objnum = -1;
|
||||
|
||||
vm_vec_zero(&ship_system->turret_big_attack_point);
|
||||
for(j = 0; j < NUM_TURRET_ORDER_TYPES; j++)
|
||||
{
|
||||
@@ -9943,7 +9954,7 @@ static void lethality_decay(ai_info *aip)
|
||||
if ((aip->target_objnum != -1) && (Objects[aip->target_objnum].type == OBJ_SHIP)) {
|
||||
//TODO: put this where it belongs, this would involve recompiling *everything* right now
|
||||
//-WMC
|
||||
int num_turrets_attacking(object *turret_parent, int target_objnum);
|
||||
int num_turrets_attacking(const object *turret_parent, int target_objnum);
|
||||
num_turrets = num_turrets_attacking(&Objects[aip->target_objnum], Ships[aip->shipnum].objnum);
|
||||
}
|
||||
nprintf(("lethality", "Player lethality: %.1f, num turrets targeting player: %d\n", aip->lethality, num_turrets));
|
||||
@@ -10786,15 +10797,20 @@ int ship_create(matrix* orient, vec3d* pos, int ship_type, const char* ship_name
|
||||
shipp->clear();
|
||||
shipp->orders_allowed_against = ship_set_default_orders_against();
|
||||
|
||||
if (!VALID_FNAME(sip->pof_file))
|
||||
{
|
||||
Error(LOCATION, "Cannot create ship %s; pof file is not valid", sip->name);
|
||||
return -1;
|
||||
}
|
||||
sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]); // use the highest detail level
|
||||
|
||||
if(strlen(sip->cockpit_pof_file))
|
||||
if(VALID_FNAME(sip->cockpit_pof_file))
|
||||
{
|
||||
sip->cockpit_model_num = model_load(sip->cockpit_pof_file, 0, NULL);
|
||||
}
|
||||
|
||||
// maybe load an optional hud target model
|
||||
if(strlen(sip->pof_file_hud)){
|
||||
if(VALID_FNAME(sip->pof_file_hud)){
|
||||
// check to see if a "real" ship uses this model. if so, load it up for him so that subsystems are setup properly
|
||||
for(auto it = Ship_info.begin(); it != Ship_info.end(); ++it){
|
||||
if(!stricmp(it->pof_file, sip->pof_file_hud)){
|
||||
@@ -10806,7 +10822,7 @@ int ship_create(matrix* orient, vec3d* pos, int ship_type, const char* ship_name
|
||||
sip->model_num_hud = model_load(sip->pof_file_hud, 0, NULL);
|
||||
}
|
||||
|
||||
if (strlen(sip->generic_debris_pof_file)) {
|
||||
if (VALID_FNAME(sip->generic_debris_pof_file)) {
|
||||
sip->generic_debris_model_num = model_load(sip->generic_debris_pof_file, 0, nullptr);
|
||||
if (sip->generic_debris_model_num >= 0) {
|
||||
polymodel* pm = model_get(sip->generic_debris_model_num);
|
||||
@@ -11037,7 +11053,7 @@ static void ship_model_change(int n, int ship_type)
|
||||
}
|
||||
|
||||
if ( sip->cockpit_model_num == -1 ) {
|
||||
if ( strlen(sip->cockpit_pof_file) ) {
|
||||
if ( VALID_FNAME(sip->cockpit_pof_file) ) {
|
||||
sip->cockpit_model_num = model_load(sip->cockpit_pof_file, 0, NULL);
|
||||
}
|
||||
}
|
||||
@@ -14699,7 +14715,7 @@ void ship_get_eye( vec3d *eye_pos, matrix *eye_orient, object *obj, bool do_slew
|
||||
// element.
|
||||
eye *ep = &(pm->view_positions[shipp->current_viewpoint]);
|
||||
|
||||
if (ep->parent >= 0 && pm->submodel[ep->parent].flags[Model::Submodel_flags::Can_move]) {
|
||||
if (ep->parent >= 0 && ep->parent < pm->n_models && pm->submodel[ep->parent].flags[Model::Submodel_flags::Can_move]) {
|
||||
model_instance_local_to_global_point_orient(eye_pos, eye_orient, &ep->pnt, &vmd_identity_matrix, pm, pmi, ep->parent);
|
||||
vec3d tvec = *eye_pos;
|
||||
vm_vec_unrotate(eye_pos, &tvec, &obj->orient);
|
||||
@@ -16407,7 +16423,7 @@ bool ship_can_bay_depart(ship* sp)
|
||||
// exit: 0 => a valid vector was placed in norm
|
||||
// !0 => an path normal could not be calculated
|
||||
//
|
||||
int ship_return_subsys_path_normal(ship *shipp, ship_subsys *ss, vec3d *gsubpos, vec3d *norm)
|
||||
int ship_return_subsys_path_normal(const ship *shipp, const ship_subsys *ss, const vec3d *gsubpos, vec3d *norm)
|
||||
{
|
||||
if ( ss->system_info->path_num >= 0 ) {
|
||||
polymodel *pm = NULL;
|
||||
@@ -16451,7 +16467,7 @@ int ship_return_subsys_path_normal(ship *shipp, ship_subsys *ss, vec3d *gsubpos,
|
||||
// dot_out => OPTIONAL PARAMETER, output parameter, will return dot between subsys fvec and subsys_to_eye_vec
|
||||
// (only filled in if do_facing_check is true)
|
||||
// vec_out => OPTIONAL PARAMETER, vector from eye_pos to absolute subsys_pos. (only filled in if do_facing_check is true)
|
||||
int ship_subsystem_in_sight(object* objp, ship_subsys* subsys, vec3d *eye_pos, vec3d* subsys_pos, int do_facing_check, float *dot_out, vec3d *vec_out)
|
||||
bool ship_subsystem_in_sight(const object *objp, const ship_subsys *subsys, const vec3d *eye_pos, const vec3d *subsys_pos, bool do_facing_check, float *dot_out, vec3d *vec_out)
|
||||
{
|
||||
float dist, dot;
|
||||
vec3d terminus, eye_to_pos, subsys_fvec, subsys_to_eye_vec;
|
||||
@@ -16532,7 +16548,7 @@ ship_subsys *ship_return_next_subsys(ship *shipp, int type, vec3d *attacker_pos)
|
||||
|
||||
// Returns the closest subsystem of specified type that is in line of sight.
|
||||
// Returns null if all subsystems of that type are destroyed or none is in sight.
|
||||
ship_subsys *ship_get_closest_subsys_in_sight(ship *sp, int subsys_type, vec3d *attacker_pos)
|
||||
ship_subsys *ship_get_closest_subsys_in_sight(const ship *sp, int subsys_type, const vec3d *attacker_pos)
|
||||
{
|
||||
Assert ( subsys_type >= 0 && subsys_type < SUBSYSTEM_MAX );
|
||||
|
||||
@@ -18916,7 +18932,7 @@ void ship_update_artillery_lock()
|
||||
*
|
||||
* May not work if delta box is large and negative (ie, adjusted box crosses over on itself - min > max)
|
||||
*/
|
||||
int check_world_pt_in_expanded_ship_bbox(vec3d *world_pt, object *objp, float delta_box)
|
||||
int check_world_pt_in_expanded_ship_bbox(const vec3d *world_pt, const object *objp, float delta_box)
|
||||
{
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
|
||||
|
||||
+6
-5
@@ -374,6 +374,7 @@ public:
|
||||
ship_subsys *targeted_subsys; // subsystem this turret is attacking
|
||||
bool scripting_target_override;
|
||||
int last_fired_weapon_info_index; // which weapon class was last fired
|
||||
int shared_fire_direction_beam_objnum; // reference beam for shared fire direction
|
||||
|
||||
int turret_pick_big_attack_point_timestamp; // Next time to pick an attack point for this turret
|
||||
vec3d turret_big_attack_point; // local coordinate of point for this turret to attack on enemy
|
||||
@@ -1798,7 +1799,7 @@ extern bool ship_subsystems_blown(const ship *shipp, int type, bool skip_dying_c
|
||||
extern float ship_get_subsystem_strength(const ship *shipp, int type, bool skip_dying_check = false, bool no_minimum_engine_str = false);
|
||||
extern ship_subsys *ship_get_subsys(const ship *shipp, const char *subsys_name);
|
||||
extern int ship_get_num_subsys(ship *shipp);
|
||||
extern ship_subsys *ship_get_closest_subsys_in_sight(ship *sp, int subsys_type, vec3d *attacker_pos);
|
||||
extern ship_subsys *ship_get_closest_subsys_in_sight(const ship *sp, int subsys_type, const vec3d *attacker_pos);
|
||||
|
||||
//WMC
|
||||
char *ship_subsys_get_name(ship_subsys *ss);
|
||||
@@ -1840,8 +1841,8 @@ int ship_navigation_ok_to_warp(ship *sp); // check if ship has navigation power
|
||||
bool ship_can_warp_full_check(ship *sp); // checks both the warp flags and ship_engine_ok_to_warp() and ship_navigation_ok_to_warp() --wookieejedi
|
||||
bool ship_can_bay_depart(ship *sp); // checks to see if a ship has a departure location as a bay and if the mothership is present
|
||||
|
||||
int ship_return_subsys_path_normal(ship *sp, ship_subsys *ss, vec3d *gsubpos, vec3d *norm);
|
||||
int ship_subsystem_in_sight(object* objp, ship_subsys* subsys, vec3d *eye_pos, vec3d* subsys_pos, int do_facing_check=1, float *dot_out=NULL, vec3d *vec_out=NULL);
|
||||
int ship_return_subsys_path_normal(const ship *sp, const ship_subsys *ss, const vec3d *gsubpos, vec3d *norm);
|
||||
bool ship_subsystem_in_sight(const object *objp, const ship_subsys *subsys, const vec3d *eye_pos, const vec3d *subsys_pos, bool do_facing_check = true, float *dot_out = nullptr, vec3d *vec_out = nullptr);
|
||||
ship_subsys *ship_return_next_subsys(ship *shipp, int type, vec3d *attacker_pos);
|
||||
|
||||
// defines and definition for function to get a random ship of a particular team (any ship,
|
||||
@@ -1920,7 +1921,7 @@ int is_support_allowed(object *objp, bool do_simple_check = false);
|
||||
// Stuffs:
|
||||
// *gpos: absolute position of gun firing point
|
||||
// *gvec: vector fro *gpos to *targetp
|
||||
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp);
|
||||
void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp, vec3d *gpos, bool avg_origin, vec3d *gvec, bool use_angles, const vec3d *targetp);
|
||||
|
||||
// Given an object and a turret on that object, return the global position and forward vector
|
||||
// of the turret. The gun normal is the unrotated gun normal, (the center of the FOV cone), not
|
||||
@@ -1977,7 +1978,7 @@ void ship_replace_active_texture(int ship_index, const char* old_name, const cha
|
||||
void ship_update_artillery_lock();
|
||||
|
||||
// checks if a world point is inside the extended bounding box of a ship
|
||||
int check_world_pt_in_expanded_ship_bbox(vec3d *world_pt, object *objp, float delta_box);
|
||||
int check_world_pt_in_expanded_ship_bbox(const vec3d *world_pt, const object *objp, float delta_box);
|
||||
|
||||
// returns true if objp is ship and is tagged
|
||||
int ship_is_tagged(object *objp);
|
||||
|
||||
+18
-17
@@ -612,7 +612,7 @@ static void shipfx_actually_warpout(ship *shipp, object *objp)
|
||||
}
|
||||
}
|
||||
|
||||
void WE_Default::compute_warpout_stuff(float *warp_time, vec3d *warp_pos)
|
||||
void WE_Default::compute_warpout_stuff(float *ship_move_time, vec3d *warp_pos)
|
||||
{
|
||||
Assertion(isValid(), "Warp effect must be valid when compute_warpout_stuff() is called!");
|
||||
|
||||
@@ -678,11 +678,8 @@ void WE_Default::compute_warpout_stuff(float *warp_time, vec3d *warp_pos)
|
||||
ship_move_dist = warp_dist - half_length;
|
||||
}
|
||||
|
||||
// Calculate how long to fly through the effect. Not to get to the effect, just through it.
|
||||
*warp_time = warping_time;
|
||||
|
||||
// Acount for time to get to warp effect, before we actually go through it.
|
||||
*warp_time += ship_move_dist / warping_speed;
|
||||
// Calculate time to get to warp effect, before we actually go through it.
|
||||
*ship_move_time = ship_move_dist / warping_speed;
|
||||
|
||||
if (m_portal_objnum < 0)
|
||||
{
|
||||
@@ -3481,7 +3478,7 @@ int WE_Default::warpStart()
|
||||
|
||||
// done with initial computation; now set up the warp effect
|
||||
|
||||
float effect_time = 0.0f;
|
||||
float open_time, close_time;
|
||||
if (m_direction == WarpDirection::WARP_IN)
|
||||
{
|
||||
// first determine the world center in relation to its position
|
||||
@@ -3491,14 +3488,16 @@ int WE_Default::warpStart()
|
||||
// now project the warp effect forward
|
||||
vm_vec_scale_add( &pos, &pos, &objp->orient.vec.fvec, half_length );
|
||||
|
||||
// Effect time is 'SHIPFX_WARP_DELAY' (1.5 secs) seconds to start, warping_time
|
||||
// for ship to go thru, and 'SHIPFX_WARP_DELAY' (1.5 secs) to go away.
|
||||
effect_time = warping_time + SHIPFX_WARP_DELAY + SHIPFX_WARP_DELAY;
|
||||
// for arrivals, opening and closing times are both SHIPFX_WARP_DELAY
|
||||
open_time = close_time = SHIPFX_WARP_DELAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
compute_warpout_stuff(&effect_time, &pos);
|
||||
effect_time += SHIPFX_WARP_DELAY;
|
||||
// for departures, the opening time is the time it takes for the ship to actually approach the warp effect
|
||||
// (even if Volition likely intended or assumed that the opening time is always SHIPFX_WARP_DELAY, this is a consequence of the warp effect sequence)
|
||||
// and the closing time is SHIPFX_WARP_DELAY as normal
|
||||
compute_warpout_stuff(&open_time, &pos);
|
||||
close_time = SHIPFX_WARP_DELAY;
|
||||
|
||||
// turn off warpin physics in case we're jumping out immediately
|
||||
objp->phys_info.flags &= ~PF_SUPERCAP_WARP_IN;
|
||||
@@ -3509,6 +3508,9 @@ int WE_Default::warpStart()
|
||||
}
|
||||
}
|
||||
|
||||
// Effect time is the time to start, warping_time for ship to go thru, and the time to go away.
|
||||
float effect_time = open_time + warping_time + close_time;
|
||||
|
||||
radius = shipfx_calculate_effect_radius(objp, m_direction);
|
||||
// cap radius to size of knossos
|
||||
if (portal_objp != nullptr)
|
||||
@@ -3525,7 +3527,7 @@ int WE_Default::warpStart()
|
||||
fireball_type = params->warp_type & WT_FLAG_MASK;
|
||||
|
||||
// create fireball
|
||||
int warp_objnum = fireball_create(&pos, fireball_type, FIREBALL_WARP_EFFECT, m_objnum, radius, (m_direction == WarpDirection::WARP_OUT), nullptr, effect_time, m_ship_info_index, nullptr, 0, 0, params->snd_start, params->snd_end);
|
||||
int warp_objnum = fireball_create(&pos, fireball_type, FIREBALL_WARP_EFFECT, m_objnum, radius, (m_direction == WarpDirection::WARP_OUT), nullptr, effect_time, m_ship_info_index, nullptr, 0, 0, params->snd_start, params->snd_end, open_time, close_time);
|
||||
|
||||
//WMC - bail
|
||||
// JAS: This must always be created, if not, just warp the ship in/out
|
||||
@@ -3540,7 +3542,7 @@ int WE_Default::warpStart()
|
||||
stage_time_start = total_time_start = timestamp();
|
||||
if (m_direction == WarpDirection::WARP_IN)
|
||||
{
|
||||
stage_duration[1] = fl2i(SHIPFX_WARP_DELAY*1000.0f);
|
||||
stage_duration[1] = fl2i(open_time*1000.0f);
|
||||
stage_duration[2] = fl2i(warping_time*1000.0f);
|
||||
stage_time_end = timestamp(stage_duration[1]);
|
||||
total_time_end = stage_duration[1] + stage_duration[2];
|
||||
@@ -3556,12 +3558,11 @@ int WE_Default::warpStart()
|
||||
{
|
||||
shipp->flags.set(Ship::Ship_Flags::Depart_warp);
|
||||
|
||||
// Make the warp effect stage 1 last SHIP_WARP_TIME1 seconds.
|
||||
// calculate the time when ship is completely warped out or warped in
|
||||
if ( objp == Player_obj ) {
|
||||
stage_duration[1] = fl2i(fireball_lifeleft(&Objects[warp_objnum])*1000.0f);
|
||||
total_time_end = timestamp(fl2i(effect_time*1000.0f));
|
||||
} else {
|
||||
total_time_end = timestamp(fl2i(effect_time*1000.0f));
|
||||
total_time_end = timestamp(fl2i((open_time+warping_time)*1000.0f));
|
||||
}
|
||||
|
||||
// This is a hack to make the ship go at the right speed to go from it's current position to the warp_effect_pos;
|
||||
|
||||
+1
-1
@@ -235,7 +235,7 @@ private:
|
||||
float warping_time; // time to go through the effect
|
||||
float warping_speed; // speed to go through the effect
|
||||
|
||||
void compute_warpout_stuff(float *warp_time, vec3d *warp_pos);
|
||||
void compute_warpout_stuff(float *ship_move_time, vec3d *warp_pos);
|
||||
|
||||
//Total data
|
||||
int total_time_start;
|
||||
|
||||
+1
-1
@@ -1340,7 +1340,7 @@ void ds_set_pitch(int channel_id, float pitch)
|
||||
*
|
||||
* @return 0 if sound started successfully, -1 if sound could not be played
|
||||
*/
|
||||
ds_sound_handle ds3d_play(int sid, int snd_id, vec3d* pos, vec3d* vel, float min, float max, int looping,
|
||||
ds_sound_handle ds3d_play(int sid, int snd_id, const vec3d* pos, const vec3d* vel, float min, float max, bool looping,
|
||||
float max_volume, float estimated_vol, const EnhancedSoundData* enhanced_sound_data,
|
||||
int priority, bool is_ambient)
|
||||
{
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ int ds_get_sound_index(int channel_id);
|
||||
// Returns the number of channels that are actually playing
|
||||
int ds_get_number_channels();
|
||||
|
||||
ds_sound_handle ds3d_play(int sid, int snd_id, vec3d* pos, vec3d* vel, float min, float max, int looping,
|
||||
ds_sound_handle ds3d_play(int sid, int snd_id, const vec3d* pos, const vec3d* vel, float min, float max, bool looping,
|
||||
float max_volume, float estimated_vol, const EnhancedSoundData* enhanced_sound_data,
|
||||
int priority = DS_MUST_PLAY, bool is_ambient = false);
|
||||
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@
|
||||
// -1 => failure
|
||||
//
|
||||
//
|
||||
int ds3d_update_buffer(int channel_id, float min, float max, vec3d *pos, vec3d *vel)
|
||||
int ds3d_update_buffer(int channel_id, float min, float max, const vec3d *pos, const vec3d *vel)
|
||||
{
|
||||
if (Cmdline_no_3d_sound) {
|
||||
nprintf(("Sound", "Aborting ds3d_update_buffer due to Cmdline_no_3d_sound...\n"));
|
||||
@@ -85,7 +85,7 @@ int ds3d_update_buffer(int channel_id, float min, float max, vec3d *pos, vec3d *
|
||||
// returns: 0 => success
|
||||
// -1 => failure
|
||||
//
|
||||
int ds3d_update_listener(vec3d *pos, vec3d *vel, matrix *orient)
|
||||
int ds3d_update_listener(const vec3d *pos, const vec3d *vel, const matrix *orient)
|
||||
{
|
||||
if (!ds_initialized) {
|
||||
return -1;
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@
|
||||
#ifndef __DS3D_H__
|
||||
#define __DS3D_H__
|
||||
|
||||
int ds3d_update_listener(vec3d *pos, vec3d *vel, matrix *orient);
|
||||
int ds3d_update_buffer(int channel, float min, float max, vec3d *pos, vec3d *vel);
|
||||
int ds3d_update_listener(const vec3d *pos, const vec3d *vel, const matrix *orient);
|
||||
int ds3d_update_buffer(int channel, float min, float max, const vec3d *pos, const vec3d *vel);
|
||||
|
||||
#endif /* __DS3D_H__ */
|
||||
@@ -656,9 +656,9 @@ MONITOR( Num3DSoundsLoaded )
|
||||
// returns: -1 => sound could not be played
|
||||
// n => handle for instance of sound
|
||||
//
|
||||
sound_handle snd_play_3d(game_snd* gs, vec3d* source_pos, vec3d* listen_pos, float radius, vec3d* source_vel,
|
||||
int looping, float vol_scale, int priority, vec3d* /*sound_fvec*/, float range_factor,
|
||||
int force, bool /*is_ambient*/)
|
||||
sound_handle snd_play_3d(game_snd* gs, const vec3d* source_pos, const vec3d* listen_pos, float radius, const vec3d* source_vel,
|
||||
bool looping, float vol_scale, int priority, const vec3d* /*sound_fvec*/, float range_factor,
|
||||
bool force, bool /*is_ambient*/)
|
||||
{
|
||||
vec3d vector_to_sound;
|
||||
loaded_sound* snd;
|
||||
|
||||
+3
-3
@@ -144,9 +144,9 @@ sound_handle snd_play_raw(sound_load_id soundnum, float pan, float vol_scale = 1
|
||||
// Plays a sound with volume between 0 and 1.0, where 0 is the
|
||||
// inaudible and 1.0 is the loudest sound in the game. It scales
|
||||
// the pan and volume relative to the current viewer's location.
|
||||
sound_handle snd_play_3d(game_snd* gs, vec3d* source_pos, vec3d* listen_pos, float radius = 0.0f, vec3d* vel = nullptr,
|
||||
int looping = 0, float vol_scale = 1.0f, int priority = SND_PRIORITY_SINGLE_INSTANCE,
|
||||
vec3d* sound_fvec = nullptr, float range_factor = 1.0f, int force = 0,
|
||||
sound_handle snd_play_3d(game_snd* gs, const vec3d* source_pos, const vec3d* listen_pos, float radius = 0.0f, const vec3d* vel = nullptr,
|
||||
bool looping = false, float vol_scale = 1.0f, int priority = SND_PRIORITY_SINGLE_INSTANCE,
|
||||
const vec3d* sound_fvec = nullptr, float range_factor = 1.0f, bool force = false,
|
||||
bool is_ambient = false);
|
||||
|
||||
// update the given 3d sound with a new position
|
||||
|
||||
@@ -789,8 +789,6 @@ add_file_folder("MenuUI"
|
||||
menuui/fishtank.h
|
||||
menuui/mainhallmenu.cpp
|
||||
menuui/mainhallmenu.h
|
||||
menuui/mainhalltemp.cpp
|
||||
menuui/mainhalltemp.h
|
||||
menuui/optionsmenu.cpp
|
||||
menuui/optionsmenu.h
|
||||
menuui/optionsmenumulti.cpp
|
||||
|
||||
@@ -3011,14 +3011,20 @@ bool stars_background_empty(const background_t &bg)
|
||||
// Goober5000
|
||||
void stars_pack_backgrounds()
|
||||
{
|
||||
// remove all empty backgrounds
|
||||
Backgrounds.erase(
|
||||
std::remove_if(Backgrounds.begin(), Backgrounds.end(), stars_background_empty),
|
||||
Backgrounds.end());
|
||||
size_t remove_count = 0;
|
||||
|
||||
// remove all empty backgrounds, with a caveat:
|
||||
// in FRED, make sure we always have at least one background
|
||||
if (Fred_running && Backgrounds.empty())
|
||||
stars_add_blank_background(true);
|
||||
// (note: older code removed all blank backgrounds and re-added one if necessary; but that method caused flag changes to be lost)
|
||||
Backgrounds.erase(
|
||||
std::remove_if(Backgrounds.begin(), Backgrounds.end(), [&](const background_t& bg) {
|
||||
if (stars_background_empty(bg)) {
|
||||
if (Fred_running && ++remove_count == Backgrounds.size())
|
||||
return false; // cancel the last removal if FRED is running and if the last removal would result in all backgrounds being removed (i.e. all were blank)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}), Backgrounds.end());
|
||||
}
|
||||
|
||||
static void render_environment(int i, vec3d *eye_pos, matrix *new_orient, fov_t new_zoom)
|
||||
|
||||
Loaded 100 of 129 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user