mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 18:31:26 -10:00
Compare commits
180
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05f2db381a | ||
|
|
6038076bf0 | ||
|
|
40c8cbbb25 | ||
|
|
bd7429c353 | ||
|
|
faf130adb3 | ||
|
|
f7fef072df | ||
|
|
0da6a4a64c | ||
|
|
f542fea96e | ||
|
|
742326e42e | ||
|
|
e25a6517fc | ||
|
|
be0c78dc72 | ||
|
|
ef681affbf | ||
|
|
3a2ac5ab5f | ||
|
|
435676a67d | ||
|
|
4fbe3b7131 | ||
|
|
87a4ae1e41 | ||
|
|
c738941ccf | ||
|
|
5c25bb9bcb | ||
|
|
e0bc6d0ed7 | ||
|
|
ec706a6a87 | ||
|
|
5d0127a764 | ||
|
|
91c15e6f48 | ||
|
|
a9fc7bab8a | ||
|
|
042c85d213 | ||
|
|
bb3d59ecbe | ||
|
|
d1c57391cf | ||
|
|
5986b7143f | ||
|
|
5d447951b4 | ||
|
|
f149c36b44 | ||
|
|
34b6cf74ab | ||
|
|
bc33f90e32 | ||
|
|
bb47531c55 | ||
|
|
aed90493ec | ||
|
|
d54c3e51e3 | ||
|
|
a215bea0d0 | ||
|
|
ec23f6bd0e | ||
|
|
d93d56e1c9 | ||
|
|
d2265325e9 | ||
|
|
2bb22a2153 | ||
|
|
018c22eee1 | ||
|
|
6ef60c67ca | ||
|
|
982e8d7f85 | ||
|
|
8affd53cf6 | ||
|
|
eeaf894b15 | ||
|
|
b546d897ae | ||
|
|
d8aea4ad30 | ||
|
|
829692b7bd | ||
|
|
855935d4eb | ||
|
|
f83efb54c0 | ||
|
|
3ca26587eb | ||
|
|
3e2bb36d4b | ||
|
|
02bd62ff3c | ||
|
|
e1e0239914 | ||
|
|
e621dbe997 | ||
|
|
ea5c328c13 | ||
|
|
8c0bc25303 | ||
|
|
6b0a3b7606 | ||
|
|
9afe76b5d2 | ||
|
|
ad27664ebc | ||
|
|
2fe182a4b1 | ||
|
|
60c2718b91 | ||
|
|
15d9b9b3db | ||
|
|
d00003e199 | ||
|
|
991d0ee2d6 | ||
|
|
3eee74a31c | ||
|
|
941d5f7ec3 | ||
|
|
0cde26dd6e | ||
|
|
7804f7fff5 | ||
|
|
832cec27ad | ||
|
|
31acb115c2 | ||
|
|
f9591b3a92 | ||
|
|
21f92194f1 | ||
|
|
c605451460 | ||
|
|
2acdc65875 | ||
|
|
b7de2fd644 | ||
|
|
a226a81d80 | ||
|
|
eb39532f7c | ||
|
|
1478ace3e0 | ||
|
|
7edc5bf842 | ||
|
|
b8dc7d643d | ||
|
|
883ed32796 | ||
|
|
f3dfc85c0f | ||
|
|
e32ea7b694 | ||
|
|
7ef70f6d4d | ||
|
|
1b1afbf8d7 | ||
|
|
bfdf05469b | ||
|
|
aee48373ab | ||
|
|
a2f1638a99 | ||
|
|
762cf4cb88 | ||
|
|
705287c8d4 | ||
|
|
e2aac31912 | ||
|
|
a9f5a11813 | ||
|
|
b8728ed828 | ||
|
|
de1110650f | ||
|
|
b3295e5a2d | ||
|
|
a6c1b1b04a | ||
|
|
b5fdf52e8c | ||
|
|
c43f5bdd58 | ||
|
|
dc7fc774b8 | ||
|
|
dad16f76c4 | ||
|
|
d10c59f6cc | ||
|
|
3bd2fc9a56 | ||
|
|
fabff58d09 | ||
|
|
2fd3bf091d | ||
|
|
b4442d3423 | ||
|
|
cf4cae7264 | ||
|
|
ebea1b1240 | ||
|
|
54341acb9b | ||
|
|
07fd188064 | ||
|
|
0cbe06884b | ||
|
|
c1d3e5a2ad | ||
|
|
2bcedc34cc | ||
|
|
16892c3e46 | ||
|
|
5c88b75b94 | ||
|
|
987c705bc9 | ||
|
|
b89cbbd530 | ||
|
|
d3383d9d87 | ||
|
|
4f6d9c36a8 | ||
|
|
a36157f582 | ||
|
|
3837455004 | ||
|
|
808f7a88c6 | ||
|
|
79702273d5 | ||
|
|
d06018bcad | ||
|
|
ac87cde80d | ||
|
|
06d9e02c34 | ||
|
|
40233ae05f | ||
|
|
57192065d6 | ||
|
|
d2031a476a | ||
|
|
c60ea2d4a7 | ||
|
|
6843d48358 | ||
|
|
066b251052 | ||
|
|
4596600627 | ||
|
|
ea262f90c0 | ||
|
|
02e84f212a | ||
|
|
a1d92afebf | ||
|
|
a20f3ca030 | ||
|
|
e132fcf74c | ||
|
|
7a4df25fc5 | ||
|
|
08dfcc8b74 | ||
|
|
0def45b381 | ||
|
|
be6a2b9196 | ||
|
|
f7413be1d8 | ||
|
|
02233fc439 | ||
|
|
febd8cd2ad | ||
|
|
bf7125724d | ||
|
|
efce98db47 | ||
|
|
45abdefc07 | ||
|
|
73c612034b | ||
|
|
f98806b034 | ||
|
|
dcfea6f141 | ||
|
|
5688ba8637 | ||
|
|
1ce9d46822 | ||
|
|
f7b9896294 | ||
|
|
14a98e1470 | ||
|
|
cb5bf05424 | ||
|
|
15db3b17bc | ||
|
|
ba2c37a1fe | ||
|
|
aa997dd9ed | ||
|
|
a0a523223c | ||
|
|
8fbf22a055 | ||
|
|
0811c7037b | ||
|
|
f13a5b3736 | ||
|
|
04a5778235 | ||
|
|
5a941c1d59 | ||
|
|
9586f21780 | ||
|
|
ed5a5861f7 | ||
|
|
89b33ebbc5 | ||
|
|
53e6edf8bb | ||
|
|
8b8daece46 | ||
|
|
344e231058 | ||
|
|
210a9a8309 | ||
|
|
6b3e50dade | ||
|
|
9a7500de36 | ||
|
|
e71dba4207 | ||
|
|
3b42ee42ca | ||
|
|
bb6b010487 | ||
|
|
c80f787d34 | ||
|
|
15daaf2633 | ||
|
|
17d36156cb | ||
|
|
99450fa643 |
No files matched your search
@@ -92,6 +92,7 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -145,6 +146,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v2
|
||||
@@ -191,6 +193,7 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -285,7 +288,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
@@ -357,6 +360,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
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
|
||||
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
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
coverity_email: [email protected]
|
||||
coverity_token: ${{ secrets.COVERITY_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
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
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
run: |
|
||||
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
|
||||
mkdir cov-scan
|
||||
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
|
||||
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
|
||||
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
|
||||
|
||||
- name: 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
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
- name: Build FSO with Coverity Wrapper
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
run: cov-build --dir cov-int ninja -k 20 all
|
||||
|
||||
- name: Compress Results
|
||||
working-directory: ./build
|
||||
run: tar zcf cov-scan.tgz cov-int
|
||||
|
||||
#Comment this out when testing to keep from running into upload limits
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
@@ -250,6 +250,7 @@ documentation/doxygen/*
|
||||
projects/*
|
||||
/.vs
|
||||
CMakeSettings.json
|
||||
CMakePresets.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
# HLP_API:
|
||||
# HLP_KEY:
|
||||
|
||||
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
|
||||
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
|
||||
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
|
||||
|
||||
import sys
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 23)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
|
||||
+9
-18
@@ -56,12 +56,6 @@ extern const int Num_ai_flag_names;
|
||||
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
|
||||
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
|
||||
|
||||
// Flags to ai_turn_towards_vector().
|
||||
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
|
||||
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
|
||||
@@ -93,7 +87,7 @@ extern const int Num_ai_flag_names;
|
||||
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
|
||||
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
|
||||
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
|
||||
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
|
||||
#define AIM_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
|
||||
#define AIM_LUA 22 // Generic Lua-based AI mode
|
||||
|
||||
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
|
||||
@@ -186,6 +180,12 @@ typedef struct ai_class {
|
||||
#define AIS_UNDOCK_3 33
|
||||
#define AIS_UNDOCK_4 34
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
|
||||
|
||||
// Submodes for Guard behavior
|
||||
#define AIS_GUARD_PATROL 101
|
||||
#define AIS_GUARD_ATTACK 102
|
||||
@@ -240,7 +240,6 @@ typedef struct ai_info {
|
||||
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
|
||||
int shipnum; // Ship using this slot, -1 means none.
|
||||
|
||||
int behavior; // AI behavior; vestigial field from early development of FS1
|
||||
int mode;
|
||||
int previous_mode;
|
||||
int mode_time; // timestamp at which current mode elapses.
|
||||
@@ -308,6 +307,7 @@ typedef struct ai_info {
|
||||
fix submode_start_time; // time at which we entered the current submode
|
||||
int submode_parm0; // parameter specific to current submode
|
||||
int submode_parm1; // SUSHI: Another optional parameter
|
||||
float submode_float0; // Goober5000: a float parameter
|
||||
fix next_predict_pos_time; // Next time to predict position.
|
||||
|
||||
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
|
||||
@@ -373,11 +373,6 @@ typedef struct ai_info {
|
||||
float ai_turret_max_aim_update_delay;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
|
||||
|
||||
union {
|
||||
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
|
||||
};
|
||||
|
||||
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
|
||||
ship_subsys* last_subsys_target; // last known subsystem target
|
||||
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
|
||||
@@ -565,7 +560,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
|
||||
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
|
||||
@@ -625,10 +620,6 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
// added by kazan
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum);
|
||||
void ai_fly_to_ship();
|
||||
|
||||
//Moved declaration here for player ship -WMC
|
||||
void ai_process_subobjects(int objnum);
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ namespace AI {
|
||||
Whackable_debris,
|
||||
Whackable_asteroids,
|
||||
Dynamic_goals_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
@@ -552,7 +552,9 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
profile->flags.set(AI::Profile_Flags::All_nonshielded_ships_can_manage_ets, temp);
|
||||
}
|
||||
|
||||
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
|
||||
// ----------
|
||||
|
||||
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
|
||||
|
||||
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
|
||||
|
||||
@@ -623,6 +625,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
@@ -812,4 +816,7 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(23, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
}
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -914,13 +914,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
|
||||
+94
-153
@@ -1316,7 +1316,7 @@ void ai_turn_towards_vector(vec3d* dest, object* objp, vec3d* slide_vec, vec3d*
|
||||
// Don't allow a ship to turn if it has no engine strength.
|
||||
// AL 3-12-98: objp may not always be a ship!
|
||||
if ( (objp->type == OBJ_SHIP) && !(flags & AITTV_VIA_SEXP) ) {
|
||||
if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
if (!Ships[objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3462,36 +3462,6 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cause a ship to fly toward a ship.
|
||||
*/
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics] && AutoPilotEngaged)
|
||||
{
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
else
|
||||
{
|
||||
aip->ai_flags.set(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
|
||||
aip->mode = AIM_FLY_TO_SHIP;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
aip->target_objnum = Ships[shipnum].objnum;
|
||||
// clear targeted subsystem
|
||||
set_targeted_subsys(aip, nullptr, -1);
|
||||
|
||||
Assert(aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC);
|
||||
}
|
||||
|
||||
|
||||
// Cause a ship to fly its waypoints.
|
||||
// flags tells:
|
||||
// WPF_REPEAT Set -> repeat waypoints.
|
||||
@@ -3533,7 +3503,7 @@ void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags)
|
||||
/**
|
||||
* Make *objp stay within dist units of *other_objp
|
||||
*/
|
||||
void ai_do_stay_near(object *objp, object *other_objp, float dist)
|
||||
void ai_do_stay_near(object *objp, object *other_objp, float dist, int additional_data)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -3546,7 +3516,8 @@ void ai_do_stay_near(object *objp, object *other_objp, float dist)
|
||||
aip->mode = AIM_STAY_NEAR;
|
||||
aip->submode = -1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
aip->stay_near_distance = dist;
|
||||
aip->submode_float0 = dist;
|
||||
aip->submode_parm0 = additional_data;
|
||||
aip->goal_objnum = OBJ_INDEX(other_objp);
|
||||
aip->goal_signature = other_objp->signature;
|
||||
}
|
||||
@@ -4922,84 +4893,6 @@ void ai_waypoints()
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// make Pl_objp fly toward a ship
|
||||
void ai_fly_to_ship()
|
||||
{
|
||||
ai_info *aip;
|
||||
object* target_p = NULL;
|
||||
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
if ( aip->mode != AIM_FLY_TO_SHIP ) {
|
||||
Warning(LOCATION,
|
||||
"ai_fly_to_ship called for '%s' when ai_info.mode not equal to AIM_FLY_TO_SHIP. Is actually '%d'",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->mode);
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
if ( aip->active_goal < 0 || aip->active_goal >= MAX_AI_GOALS ) {
|
||||
Warning(LOCATION,
|
||||
"'%s' is trying to fly-to a ship without an active AI_GOAL\n\n"
|
||||
"Active ai mode is '%d'",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->active_goal);
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
Assert( aip->goals[aip->active_goal].target_name != NULL );
|
||||
if ( aip->goals[aip->active_goal].target_name[0] == '\0' ) {
|
||||
Warning(LOCATION, "'%s' is trying to fly-to-ship without a name for the ship", Ships[Pl_objp->instance].ship_name);
|
||||
aip->mode = AIM_NONE;
|
||||
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < MAX_SHIPS; j++)
|
||||
{
|
||||
if (Ships[j].objnum != -1 && !stricmp(aip->goals[aip->active_goal].target_name, Ships[j].ship_name))
|
||||
{
|
||||
target_p = &Objects[Ships[j].objnum];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( target_p == NULL ) {
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < MAX_AI_GOALS; i++)
|
||||
{
|
||||
if (aip->mode == AIM_FLY_TO_SHIP || aip->goals[i].ai_mode == AI_GOAL_FLY_TO_SHIP)
|
||||
{
|
||||
mprintf(("Ship '%s' told to fly to target ship '%s'\n",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->goals[i].target_name));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Warning(LOCATION, "Ship '%s' told to fly to a ship but none of the ships it was told to fly to exist.\n"
|
||||
"See log before this message for list of ships set as fly-to tagets",
|
||||
Ships[Pl_objp->instance].ship_name);
|
||||
aip->mode = AIM_NONE;
|
||||
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
|
||||
return;
|
||||
} else {
|
||||
bool done, treat_as_ship;
|
||||
ai_fly_to_target_position(&(target_p->pos), &done, &treat_as_ship);
|
||||
|
||||
if ( done ) {
|
||||
// remove the goal from the AI goals of the ship pr wing, respectively.
|
||||
// Wether or not we should treat this as a ship or a wing is determined by
|
||||
// ai_fly_to_target when it marks the AI directive as complete
|
||||
if ( treat_as_ship ) {
|
||||
ai_mission_goal_complete( aip ); // this call should reset the AI mode
|
||||
} else {
|
||||
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make Pl_objp avoid En_objp
|
||||
// Not like evading. This is for avoiding a collision!
|
||||
// Note, use sliding if available.
|
||||
@@ -5671,7 +5564,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < ship_info_size());
|
||||
|
||||
//made it so it only selects puncture weapons if the active goal is to disable something -Bobboau
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISABLE_SHIP)))
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL)))
|
||||
{
|
||||
if (swp->current_primary_bank >= 0)
|
||||
{
|
||||
@@ -5896,7 +5789,7 @@ void set_primary_weapon_linkage(object *objp)
|
||||
// puncture weapons
|
||||
if ( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
{
|
||||
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISARM_SHIP) )
|
||||
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISABLE_SHIP_TACTICAL|AI_GOAL_DISARM_SHIP|AI_GOAL_DISARM_SHIP_TACTICAL) )
|
||||
{
|
||||
// only continue if both primaries are puncture weapons
|
||||
if ( swp->num_primary_banks == 2 ) {
|
||||
@@ -9486,9 +9379,15 @@ void ai_chase()
|
||||
firing_range = MIN((swip->max_speed * swip->lifetime * 0.75f), swip->weapon_range);
|
||||
else
|
||||
{
|
||||
float secondary_range_mult = (aip->ai_secondary_range_mult == FLT_MIN)
|
||||
? (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS
|
||||
: aip->ai_secondary_range_mult;
|
||||
float secondary_range_mult;
|
||||
|
||||
// Cyborg: need to check for division by zero, coverity 1523419
|
||||
if (aip->ai_secondary_range_mult == FLT_MIN && (ai_maybe_autoscale(Num_ai_classes) > 1))
|
||||
secondary_range_mult = (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS;
|
||||
else if (aip->ai_secondary_range_mult == FLT_MIN)
|
||||
secondary_range_mult = (float)(Game_skill_level + 2)/NUM_SKILL_LEVELS; // default to using the default retail class Captain out of the seven there are total when we don't have enough autoscale classes or just one regular class. (This simplifies to 2 + Game_skill_level / Num of skill levels)
|
||||
else
|
||||
secondary_range_mult = aip->ai_secondary_range_mult;
|
||||
|
||||
firing_range = MIN((swip->max_speed * swip->lifetime * secondary_range_mult), swip->weapon_range);
|
||||
}
|
||||
@@ -9791,7 +9690,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
|
||||
|
||||
// Goober5000 - moved out here to save calculations
|
||||
if (dock_mode != DOA_DOCK_STAY)
|
||||
if (ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
if (!Ships[docker_objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
return 9999.9f;
|
||||
|
||||
// If dockee has moved much, then path will be recreated.
|
||||
@@ -11357,24 +11256,52 @@ void ai_still()
|
||||
// Make *Pl_objp stay near another ship.
|
||||
void ai_stay_near()
|
||||
{
|
||||
ai_info *aip;
|
||||
int goal_objnum;
|
||||
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
goal_objnum = aip->goal_objnum;
|
||||
auto aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
int goal_objnum = aip->goal_objnum;
|
||||
|
||||
if ((goal_objnum < 0) || (Objects[goal_objnum].type != OBJ_SHIP) || (Objects[goal_objnum].signature != aip->goal_signature)) {
|
||||
aip->mode = AIM_NONE;
|
||||
} else {
|
||||
float dist, max_dist, scale;
|
||||
vec3d rand_vec, goal_pos, vec_to_goal;
|
||||
object *goal_objp;
|
||||
}
|
||||
// "escort" behavior
|
||||
else if (aip->submode_parm0 != 0) {
|
||||
vec3d rand_vec, center_to_goal, center_to_objp;
|
||||
auto goal_objp = &Objects[goal_objnum];
|
||||
float max_dist = aip->submode_float0;
|
||||
|
||||
goal_objp = &Objects[goal_objnum];
|
||||
// Figure out a goal point to fly to
|
||||
// Make not all ships pursue same point.
|
||||
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
|
||||
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
|
||||
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
|
||||
|
||||
// Make sure point is on the near side of goal_objp (relative to Pl_objp's position).
|
||||
center_to_goal = aip->goal_point - goal_objp->pos;
|
||||
center_to_objp = Pl_objp->pos - goal_objp->pos;
|
||||
if (vm_vec_dot(¢er_to_goal, ¢er_to_objp) < 0.0f) {
|
||||
vm_vec_negate(&rand_vec);
|
||||
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
|
||||
}
|
||||
|
||||
// Fly to the point
|
||||
auto dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
if (dist > max_dist) {
|
||||
turn_towards_point(Pl_objp, &aip->goal_point, nullptr, 0.0f);
|
||||
accelerate_ship(aip, dist / max_dist - 0.8f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &aip->goal_point);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
}
|
||||
// standard behavior
|
||||
else {
|
||||
vec3d rand_vec, goal_pos, vec_to_goal;
|
||||
auto goal_objp = &Objects[goal_objnum];
|
||||
float max_dist = aip->submode_float0;
|
||||
|
||||
// Make not all ships pursue same point.
|
||||
static_randvec(OBJ_INDEX(Pl_objp), &rand_vec);
|
||||
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
|
||||
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
|
||||
|
||||
// Make sure point is in front hemisphere (relative to Pl_objp's position.
|
||||
vm_vec_sub(&vec_to_goal, &goal_objp->pos, &Pl_objp->pos);
|
||||
@@ -11383,28 +11310,22 @@ void ai_stay_near()
|
||||
}
|
||||
|
||||
// Scale the random vector by an amount proportional to the distance from Pl_objp to the true goal.
|
||||
dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
max_dist = aip->stay_near_distance;
|
||||
scale = dist - max_dist/2;
|
||||
float dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
float scale = dist - max_dist/2;
|
||||
if (scale < 0.0f)
|
||||
scale = 0.0f;
|
||||
|
||||
vm_vec_scale_add(&goal_pos, &goal_objp->pos, &rand_vec, scale);
|
||||
|
||||
if (max_dist < Pl_objp->radius + goal_objp->radius + 25.0f)
|
||||
max_dist = Pl_objp->radius + goal_objp->radius + 25.0f;
|
||||
|
||||
// Fly to the point
|
||||
if (dist > max_dist) {
|
||||
turn_towards_point(Pl_objp, &goal_pos, NULL, 0.0f);
|
||||
turn_towards_point(Pl_objp, &goal_pos, nullptr, 0.0f);
|
||||
accelerate_ship(aip, dist / max_dist - 0.8f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &goal_pos);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Warn player if dock path is obstructed.
|
||||
@@ -12156,7 +12077,7 @@ object *get_wing_leader(int wingnum)
|
||||
|
||||
// If this ship is disabled, try another ship in the wing.
|
||||
int n = 0;
|
||||
while (ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
|
||||
while (!Ships[ship_num].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
|
||||
n++;
|
||||
|
||||
if (n >= wingp->current_count) {
|
||||
@@ -12499,7 +12420,7 @@ int ai_formation()
|
||||
} else { // Formation flying in waypoint mode.
|
||||
Assert(aip->ai_flags[AI::AI_Flags::Formation_wing]);
|
||||
|
||||
if ( (aip->mode != AIM_WAYPOINTS) && (aip->mode != AIM_FLY_TO_SHIP) ) {
|
||||
if ( aip->mode != AIM_WAYPOINTS ) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
return 1;
|
||||
}
|
||||
@@ -13129,10 +13050,25 @@ void ai_manage_shield(object *objp, ai_info *aip)
|
||||
// Scale between 1x and 3x based on ai_class (SUSHI: only if autoscale is on)
|
||||
if (aip->ai_class_autoscale)
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
delay = delay + delay * (float)(3 * (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) / (ai_get_autoscale_index(Num_ai_classes) - 1));
|
||||
else
|
||||
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
|
||||
int number_of_as_classes = ai_get_autoscale_index(Num_ai_classes);
|
||||
|
||||
// Cyborg: Make sure that autoscale index is greater than one before dividing, coverity 1523548
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale] && number_of_as_classes > 1)
|
||||
delay = delay + delay * (float)(3 * (number_of_as_classes - ai_get_autoscale_index(aip->ai_class) - 1) / (number_of_as_classes - 1));
|
||||
else {
|
||||
static bool autoscale_checked = false;
|
||||
|
||||
// warn if there's only one autoscale ai class
|
||||
if (number_of_as_classes == 1 && !autoscale_checked) {
|
||||
mprintf(("Warning! Having only 1 autoscale ai class will disable autoscale features that rely on division."));
|
||||
autoscale_checked = true;
|
||||
}
|
||||
|
||||
// Only adjust if we have more than one ai class to avoid div by 0
|
||||
if (Num_ai_classes > 1){
|
||||
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set timestamp
|
||||
@@ -13502,8 +13438,14 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
|
||||
}
|
||||
}
|
||||
|
||||
// cycle through the allowed paths
|
||||
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
|
||||
// Cyborg: to avoid divide by zero and avoid a logic path that should not exist check for 0 allowed paths -- Coverity 1523287
|
||||
if (num_allowed_paths == 0) {
|
||||
bay_path = Ai_last_arrive_path % bay->num_paths;
|
||||
UNREACHABLE("Parent_shipp in ai_acquire_emerge_path somehow does not have any allowed bay paths!");
|
||||
} else {
|
||||
// cycle through the allowed paths
|
||||
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
|
||||
}
|
||||
}
|
||||
// choose from among all paths
|
||||
else
|
||||
@@ -13921,6 +13863,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_STILL:
|
||||
ai_still();
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP: // same code as stay-near
|
||||
case AIM_STAY_NEAR:
|
||||
ai_stay_near();
|
||||
break;
|
||||
@@ -13930,9 +13873,6 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_WAYPOINTS:
|
||||
ai_waypoints();
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP:
|
||||
ai_fly_to_ship();
|
||||
break;
|
||||
case AIM_DOCK:
|
||||
ai_dock();
|
||||
break;
|
||||
@@ -14899,7 +14839,7 @@ void ai_frame(int objnum)
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_started);
|
||||
}
|
||||
|
||||
// moved call to ai_do_repair frame here from below because of the subsequent if statment returning
|
||||
// moved call to ai_do_repair frame here from below because of the subsequent if statement returning
|
||||
// if the ship is getting repaired
|
||||
// If waiting to be repaired, just stop and sit.
|
||||
ai_do_repair_frame(Pl_objp, aip, flFrametime);
|
||||
@@ -15021,9 +14961,9 @@ void ai_frame(int objnum)
|
||||
if ( aip->targeted_subsys->current_hits <= 0.0f ) {
|
||||
int subsys_type;
|
||||
|
||||
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP ) {
|
||||
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL ) {
|
||||
subsys_type = SUBSYSTEM_ENGINE;
|
||||
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP ) {
|
||||
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL ) {
|
||||
subsys_type = SUBSYSTEM_TURRET;
|
||||
} else {
|
||||
subsys_type = -1;
|
||||
@@ -15279,6 +15219,7 @@ void init_ai_object(int objnum)
|
||||
aip->submode_start_time = 0;
|
||||
aip->submode_parm0 = 0;
|
||||
aip->submode_parm1 = 0;
|
||||
aip->submode_float0 = 0.0f;
|
||||
aip->active_goal = -1;
|
||||
aip->goal_check_time = timestamp(0);
|
||||
aip->last_predicted_enemy_pos = near_vec;
|
||||
|
||||
+133
-124
@@ -51,6 +51,8 @@ struct ship_registry_entry;
|
||||
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
|
||||
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
|
||||
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
|
||||
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
|
||||
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
|
||||
#define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
|
||||
#define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
|
||||
|
||||
@@ -75,7 +77,9 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
@@ -120,8 +124,10 @@ const char *Ai_goal_text(int goal, int submode)
|
||||
case AI_GOAL_GUARD_WING:
|
||||
return XSTR( "guard ", 480);
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
return XSTR( "disable ", 481);
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
return XSTR( "disarm ", 482);
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
return XSTR( "evade ", 483);
|
||||
@@ -528,11 +534,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// ignore goals should get rid of any kind of attack goal
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
break;
|
||||
|
||||
// disarm/disable goals should remove attacks from certain ships types
|
||||
// (but not tactical disarm/disable)
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
|
||||
@@ -549,12 +556,17 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
}
|
||||
|
||||
// grab the ship type of the ship that is being disarmed/disabled
|
||||
ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
|
||||
int crippled_ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
|
||||
|
||||
// work through all the ship types which to see if the class matching our ai ship must ignore the ship
|
||||
if (ai_ship_type < 0 || crippled_ship_type < 0)
|
||||
break;
|
||||
|
||||
ship_type_info *crippled_ship_type_info = &Ship_types[crippled_ship_type];
|
||||
|
||||
// work through all the ship types to see if the class matching our ai ship must ignore the ship
|
||||
// being disarmed/disabled
|
||||
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
for ( j=0 ; j < (int)crippled_ship_type_info->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ship_type_info->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
}
|
||||
}
|
||||
@@ -931,14 +943,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
break;
|
||||
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_ENGINE;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DISARM_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISARM_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_TURRET;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
@@ -1022,17 +1036,30 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
{
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDDR(node)) );
|
||||
|
||||
// distance from ship
|
||||
if ( CDDDR(node) < 0 )
|
||||
aigp->float_data = 300.0f;
|
||||
else
|
||||
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
|
||||
// (the CDDDDR argument is whether to afterburn, and is handled at the end of the function, so don't handle it here)
|
||||
|
||||
// whether to "escort" the ship
|
||||
if ( CDDDDDR(node) >= 0 )
|
||||
aigp->int_data = is_sexp_true(CDDDDDR(node)) ? 1 : 0;
|
||||
|
||||
if (op == OP_AI_FLY_TO_SHIP)
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
else
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1050,7 +1077,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
case OP_AI_EVADE_SHIP:
|
||||
case OP_AI_IGNORE:
|
||||
case OP_AI_IGNORE_NEW:
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
@@ -1077,14 +1103,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_CHASE_WING;
|
||||
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
} else if ( op == OP_AI_IGNORE ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE;
|
||||
} else if ( op == OP_AI_IGNORE_NEW ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
|
||||
} else if ( op == OP_AI_FLY_TO_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
} else
|
||||
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
|
||||
|
||||
@@ -1121,7 +1143,8 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
}
|
||||
|
||||
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|
||||
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
@@ -1138,8 +1161,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
if (op == OP_AI_GUARD ||
|
||||
op == OP_AI_GUARD_WING ||
|
||||
op == OP_AI_WAYPOINTS ||
|
||||
op == OP_AI_WAYPOINTS_ONCE ||
|
||||
op == OP_AI_FLY_TO_SHIP) {
|
||||
op == OP_AI_WAYPOINTS_ONCE) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
@@ -1147,8 +1169,11 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
op == OP_AI_CHASE_WING ||
|
||||
op == OP_AI_CHASE_SHIP_CLASS ||
|
||||
op == OP_AI_DISABLE_SHIP ||
|
||||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
|
||||
op == OP_AI_DISARM_SHIP ||
|
||||
op == OP_AI_STAY_NEAR_SHIP) {
|
||||
op == OP_AI_DISARM_SHIP_TACTICAL ||
|
||||
op == OP_AI_STAY_NEAR_SHIP ||
|
||||
op == OP_AI_FLY_TO_SHIP) {
|
||||
if (is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
@@ -1223,11 +1248,13 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISARM_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WARP_OUT:
|
||||
@@ -1257,11 +1284,8 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD:
|
||||
goalmode = AI_GOAL_PLAY_DEAD;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
@@ -1303,12 +1327,9 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
goalmode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
case OP_AI_IGNORE:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE;
|
||||
break;
|
||||
case OP_AI_IGNORE_NEW:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE_NEW;
|
||||
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
|
||||
break;
|
||||
case OP_AI_FORM_ON_WING:
|
||||
priority = 99;
|
||||
@@ -1530,13 +1551,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
{
|
||||
int status;
|
||||
ai_achievability return_val;
|
||||
ai_info *aip;
|
||||
int index = -1, sindex = -1;
|
||||
int modelnum = -1;
|
||||
|
||||
auto objp = &Objects[objnum];
|
||||
Assert( objp->instance != -1 );
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
// these orders are always achievable.
|
||||
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|
||||
@@ -1547,11 +1566,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
if (aigp->ai_mode == AI_GOAL_LUA)
|
||||
return ai_lua_is_achievable(aigp, objnum);
|
||||
|
||||
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
|
||||
|
||||
// warp (depart) only achievable if there's somewhere to depart to
|
||||
if (aigp->ai_mode == AI_GOAL_WARP)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
|
||||
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
|
||||
if ( ship_can_warp_full_check(shipp) )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
@@ -1570,9 +1589,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if the wing target is valid then be sure to set the override bit so that it always
|
||||
// gets executed next
|
||||
if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (!target_ship_entry || !target_ship_entry->shipp)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
@@ -1629,11 +1646,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
// or we haven't found a valid subsystem index yet
|
||||
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
if ( !target_ship_entry || !target_ship_entry->shipp || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1642,46 +1658,46 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
|
||||
// for this goal to be valid).
|
||||
Assert ( aigp->ai_submode >= 0 );
|
||||
ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
|
||||
ssp = ship_get_indexed_subsys( target_ship_entry->shipp, aigp->ai_submode );
|
||||
if (ssp != NULL) {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (ssp->current_hits <= 0.0f) ? 1 : 0;
|
||||
} else {
|
||||
// not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, target_ship_entry->shipp->ship_name));
|
||||
status = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1700,22 +1716,23 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// MWA -- 4/22/98. Check for the ship actually being in the mission before
|
||||
// checking departure and destroyed. In multiplayer, since ships can respawn,
|
||||
// they get log entries for being destroyed even though they have respawned.
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
if ( sindex < 0 ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if ( status )
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
// Goober5000 - update this to use ship registry status with similar logic
|
||||
if (target_ship_entry && target_ship_entry->status == ShipStatus::EXITED) {
|
||||
status = 1;
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
|
||||
// fly-to-ship can potentially be determined
|
||||
if (aigp->ai_mode == AI_GOAL_FLY_TO_SHIP && target_ship_entry && target_ship_entry->objp) {
|
||||
auto dist = vm_vec_dist(&target_ship_entry->objp->pos, &objp->pos);
|
||||
if (dist < aigp->float_data) {
|
||||
return_val = ai_achievability::SATISFIED;
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1768,12 +1785,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// the if statement.
|
||||
if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
|
||||
{
|
||||
sindex = wing_name_lookup( aigp->target_name );
|
||||
int wingnum = wing_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (wingnum < 0)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
wing *wingp = &Wings[sindex];
|
||||
wing *wingp = &Wings[wingnum];
|
||||
|
||||
if ( wingp->flags[Ship::Wing_Flags::Gone] )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
@@ -1790,24 +1807,22 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
|
||||
if (!ship_entry)
|
||||
if (!target_ship_entry)
|
||||
{
|
||||
status = SHIP_STATUS_UNKNOWN;
|
||||
}
|
||||
// goal ship is currently in mission
|
||||
else if (ship_entry->status == ShipStatus::PRESENT || ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
else if (target_ship_entry->status == ShipStatus::PRESENT || target_ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
{
|
||||
status = SHIP_STATUS_ARRIVED;
|
||||
}
|
||||
// goal ship is still on the arrival list
|
||||
else if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
else if (target_ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
{
|
||||
status = SHIP_STATUS_NOT_ARRIVED;
|
||||
}
|
||||
// goal ship has left the area
|
||||
else if (ship_entry->status == ShipStatus::EXITED)
|
||||
else if (target_ship_entry->status == ShipStatus::EXITED)
|
||||
{
|
||||
status = SHIP_STATUS_GONE;
|
||||
}
|
||||
@@ -1818,18 +1833,16 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
if (status == SHIP_STATUS_UNKNOWN)
|
||||
{
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", shipp->ship_name, aigp->target_name));
|
||||
}
|
||||
}
|
||||
|
||||
// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
|
||||
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
|
||||
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
|
||||
{
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
if (target_ship_entry && target_ship_entry->shipp) {
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
if (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
@@ -1856,40 +1869,36 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// this goal will get removed.
|
||||
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
|
||||
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
int modelnum = Ship_info[shipp->ship_info_index].model_num;
|
||||
Assert( modelnum >= 0 );
|
||||
index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->docker.index = index;
|
||||
aigp->docker.index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
|
||||
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
if ( sindex != -1 ) {
|
||||
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
|
||||
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->dockee.index = index;
|
||||
if (target_ship_entry && target_ship_entry->shipp) {
|
||||
int modelnum = Ship_info[target_ship_entry->shipp->ship_info_index].model_num;
|
||||
aigp->dockee.index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
|
||||
} else
|
||||
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
|
||||
}
|
||||
|
||||
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
|
||||
Warning(LOCATION, "Cannot determine docking information for %s!", Ships[objp->instance].ship_name); // for now, allender wants to know about these things!!!!
|
||||
Warning(LOCATION, "Cannot determine docking information for %s!", shipp->ship_name); // for now, allender wants to know about these things!!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if ship is disabled, don't know if it can dock or not
|
||||
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Disabled] )
|
||||
if ( shipp->flags[Ship::Ship_Flags::Disabled] )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
// we must also determine if we're prevented from docking for any reason
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
object *goal_objp = &Objects[Ships[sindex].objnum];
|
||||
auto goal_objp = target_ship_entry->objp;
|
||||
|
||||
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
|
||||
// [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
|
||||
@@ -1938,11 +1947,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
|
||||
if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
|
||||
{
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
if ( target_ship_entry && target_ship_entry->shipp ) {
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != Ships[sindex].objnum)
|
||||
if (aip->goal_objnum != target_ship_entry->shipp->objnum)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
@@ -1955,10 +1962,8 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
|
||||
// the ship's subsystem list
|
||||
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex != -1 ) {
|
||||
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
|
||||
if ( target_ship_entry && target_ship_entry->shipp ) {
|
||||
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp, aigp->docker.name );
|
||||
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
@@ -1966,15 +1971,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
}
|
||||
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
object *ignored;
|
||||
|
||||
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
ignored = &Objects[Ships[sindex].objnum];
|
||||
auto ignored = target_ship_entry->objp;
|
||||
|
||||
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
|
||||
|
||||
@@ -1990,7 +1992,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_GUARD_WING:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
@@ -2007,7 +2011,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
else if ( status == SHIP_STATUS_UNKNOWN )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, Ships[objp->instance].ship_name); // get allender -- bad logic
|
||||
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, shipp->ship_name); // get allender -- bad logic
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2019,30 +2023,29 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
|
||||
// we mark the goal as not achievable.
|
||||
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
|
||||
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", Ships[objp->instance].ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
if ( status == SHIP_STATUS_GONE )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
if ( sindex < 0 ) {
|
||||
if ( !target_ship_entry || !target_ship_entry->shipp ) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if desitnation currently being repaired, then goal is stil active
|
||||
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
// if destination currently being repaired, then goal is still active
|
||||
if ( Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
// if the destination ship is dying or departing (but not completed yet), the mark goal as
|
||||
// not achievable.
|
||||
if ( Ships[sindex].is_dying_or_departing())
|
||||
if ( target_ship_entry->shipp->is_dying_or_departing())
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// if the destination object is no longer awaiting repair, then remove the item
|
||||
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
if ( !(Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// not repairing anything means that he can do this goal!!!
|
||||
@@ -2057,7 +2060,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if he is repairing something, he can satisfy his repair goal (his goal_objnum)
|
||||
// return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
|
||||
// satisfied.
|
||||
if ( aip->goal_objnum != Ships[sindex].objnum )
|
||||
if ( aip->goal_objnum != target_ship_entry->shipp->objnum )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
@@ -2338,12 +2341,6 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
ai_start_fly_to_ship(objp, shipnum);
|
||||
break;
|
||||
|
||||
case AI_GOAL_DOCK: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
@@ -2418,22 +2415,27 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP: {
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_attack_object( objp, other_obj);
|
||||
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
|
||||
|
||||
// don't protect-ship for tactical goals
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
|
||||
if (aip->target_objnum != -1) {
|
||||
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
|
||||
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
|
||||
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
|
||||
}
|
||||
} else // Just in case this ship had been protected, unprotect it.
|
||||
@@ -2511,14 +2513,17 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// labels for support ship commands
|
||||
|
||||
case AI_GOAL_STAY_NEAR_SHIP: {
|
||||
case AI_GOAL_STAY_NEAR_SHIP:
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
{
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
|
||||
ai_do_stay_near(objp, other_obj, dist);
|
||||
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
|
||||
ai_do_stay_near(objp, other_obj, dist, additional_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
||||
// todo MK: hook to keep support ship at a safe distance
|
||||
@@ -2566,7 +2571,9 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
@@ -2640,7 +2647,9 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
|
||||
+5
-3
@@ -73,15 +73,17 @@ struct ai_info;
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x04000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
|
||||
+162
-5
@@ -18,9 +18,9 @@ void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
|
||||
}
|
||||
|
||||
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
|
||||
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
|
||||
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
|
||||
Player_orders.back().localize();
|
||||
|
||||
|
||||
Lua_player_orders.emplace(sexp_op, std::move(order));
|
||||
|
||||
return true;
|
||||
@@ -48,6 +48,134 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
|
||||
return &aiLuaOrder->second;
|
||||
}
|
||||
|
||||
int ai_lua_get_num_general_orders() {
|
||||
int count = 0;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
const SCP_string &cat = order.second.category;
|
||||
|
||||
// If it's not a general order then move on
|
||||
if (!order.second.generalOrder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the order is not enabled then move on
|
||||
if (enabled_only && !order.second.cur_enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
|
||||
|
||||
for (size_t i = 0; i <= list.size(); i++) {
|
||||
|
||||
// reached the end of the list, so add it
|
||||
if (i == list.size()) {
|
||||
list.push_back(cat);
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's already in the list then don't add it
|
||||
if (cat == list[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (auto order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
bool add = false;
|
||||
|
||||
// Only enabled orders
|
||||
if (onlyEnabled && order.second.cur_enabled) {
|
||||
add = true;
|
||||
|
||||
// Only valid orders
|
||||
} else if (onlyValid && order.second.cur_valid) {
|
||||
add = true;
|
||||
|
||||
// Only orders that match the category requested
|
||||
} else if ((!category.empty()) && (order.second.category == category)) {
|
||||
add = true;
|
||||
|
||||
// All general orders
|
||||
} else {
|
||||
add = true;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
list.push_back(order.second.parseText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int ai_lua_find_general_order_id(const SCP_string& name) {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.parseText == name) {
|
||||
return order.first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_enabled = enable;
|
||||
}
|
||||
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity)
|
||||
{
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_valid = validity;
|
||||
}
|
||||
|
||||
void ai_lua_reset_general_orders() {
|
||||
for (auto order : Lua_player_orders) {
|
||||
ai_lua_enable_general_order(order.first, false);
|
||||
ai_lua_validate_general_order(order.first, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ai_lua_is_general_order(int sexp_op) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return false;
|
||||
|
||||
return aiLuaOrder->second.generalOrder;
|
||||
}
|
||||
|
||||
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
|
||||
if (!action.isValid()) {
|
||||
Error(LOCATION,
|
||||
@@ -56,7 +184,11 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
}
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
if (aip->shipnum >= 0){
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
} else {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
|
||||
}
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
|
||||
}
|
||||
@@ -67,8 +199,13 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
if (retVals[0].getValue<bool>())
|
||||
ai_mission_goal_complete(aip);
|
||||
if (retVals[0].getValue<bool>()) {
|
||||
|
||||
// If we don't have a ship then it's a general order and we have nothing else to do
|
||||
if (aip->shipnum >= 0) {
|
||||
ai_mission_goal_complete(aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +240,26 @@ void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
// For sending general orders that don't run on a ship.
|
||||
// Essentially just runs arbitrary lua script when the command is called
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
|
||||
{
|
||||
//Create a dummy aip to pass the target data
|
||||
ai_info aip;
|
||||
aip.shipnum = -1;
|
||||
|
||||
if (target_objnum >= 0) {
|
||||
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
|
||||
}
|
||||
|
||||
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai->sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, *lua_ai, &aip);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
|
||||
ship* target = &Ships[Objects[target_objnum].instance];
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ struct player_order_lua {
|
||||
int ai_message = MESSAGE_YESSIR;
|
||||
SCP_string parseText = "";
|
||||
SCP_string displayText = "";
|
||||
bool generalOrder = false;
|
||||
SCP_string category = "";
|
||||
bool cur_enabled = false;
|
||||
bool cur_valid = false;
|
||||
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
|
||||
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
|
||||
};
|
||||
@@ -29,8 +33,17 @@ bool ai_lua_add_order(int sexp_op, player_order_lua order);
|
||||
bool ai_lua_has_mode(int sexp_op);
|
||||
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
|
||||
int ai_lua_get_num_general_orders();
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
|
||||
int ai_lua_find_general_order_id(const SCP_string& name);
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable);
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity);
|
||||
void ai_lua_reset_general_orders();
|
||||
bool ai_lua_is_general_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
|
||||
@@ -1104,7 +1104,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
|
||||
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
|
||||
|
||||
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
if ((sip->class_type >= 0) && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
int target_objnum = aip->target_objnum;
|
||||
|
||||
if (Objects[target_objnum].signature == aip->target_signature) {
|
||||
|
||||
@@ -670,7 +670,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if sucess, NULL if failure.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
|
||||
@@ -1030,7 +1030,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
float dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
|
||||
|
||||
// if asteroid is within view or far enough away then wrap
|
||||
if (dot > cos(Proj_fov)) {
|
||||
if (dot > cos(g3_get_hfov(Proj_fov))) {
|
||||
if (range_override) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -598,7 +598,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
|
||||
// make sure that we have valid data
|
||||
if (data == nullptr) {
|
||||
UNREACHABLE("No valid data recieved for 3D Bitmap creation!");
|
||||
UNREACHABLE("No valid data received for 3D Bitmap creation!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+53
-21
@@ -14,8 +14,8 @@
|
||||
#include "ship/ship.h" //compute_slew_matrix
|
||||
|
||||
//*************************IMPORTANT GLOBALS*************************
|
||||
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
float COCKPIT_ZOOM_DEFAULT = 0.75f;
|
||||
fov_t VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
fov_t COCKPIT_ZOOM_DEFAULT = 0.75f;
|
||||
float Sexp_fov = 0.0f;
|
||||
warp_camera Warp_camera;
|
||||
|
||||
@@ -27,6 +27,33 @@ SCP_vector<camera*> Cameras;
|
||||
camid Current_camera;
|
||||
camid Main_camera;
|
||||
|
||||
asymmetric_fov operator* (const asymmetric_fov& left, const float& right) {
|
||||
return asymmetric_fov{ left.left * right, left.right * right, left.up * right, left.down * right };
|
||||
}
|
||||
asymmetric_fov operator+ (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left - right * 0.5f, left.right + right * 0.5f, left.up + right * 0.5f * ar, left.down - right * 0.5f * ar };
|
||||
}
|
||||
asymmetric_fov operator- (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left + right * 0.5f, left.right - right * 0.5f, left.up - right * 0.5f * ar, left.down + right * 0.5f * ar };
|
||||
}
|
||||
|
||||
#define APPLY_TO_FOV_T(op, name) \
|
||||
struct apply_##name##_to_fov { \
|
||||
float r; \
|
||||
template<typename T> \
|
||||
fov_t operator()(const T& l) { \
|
||||
return fov_t(l op r); \
|
||||
} \
|
||||
}; \
|
||||
fov_t operator op (const fov_t& zoom, const float& scale) { \
|
||||
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
}
|
||||
APPLY_TO_FOV_T(*, mul)
|
||||
APPLY_TO_FOV_T(+, add)
|
||||
APPLY_TO_FOV_T(-, sub)
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
auto degrees = fl_degrees(val);
|
||||
@@ -34,15 +61,20 @@ static SCP_string fov_display(float val)
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.bind_to(&VIEWER_ZOOM_DEFAULT)
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
std::pair<const char*, int>{"Field Of View", 1703},
|
||||
std::pair<const char*, int>{"The vertical field of view", 1704})
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.change_listener([](const float& val, bool) {
|
||||
VIEWER_ZOOM_DEFAULT = val;
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
//This is where the camera class begins! :D
|
||||
@@ -85,7 +117,7 @@ void camera::reset()
|
||||
func_custom_orientation = NULL;
|
||||
|
||||
fov.clear();
|
||||
fov.set(VIEWER_ZOOM_DEFAULT);
|
||||
fov.set(g3_get_hfov(VIEWER_ZOOM_DEFAULT));
|
||||
|
||||
pos_x.clear();
|
||||
pos_y.clear();
|
||||
@@ -104,7 +136,7 @@ void camera::set_name(const char *in_name)
|
||||
strncpy(name, in_name, NAME_LENGTH-1);
|
||||
}
|
||||
|
||||
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
{
|
||||
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
|
||||
{
|
||||
@@ -114,26 +146,23 @@ void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_
|
||||
}
|
||||
|
||||
flags &= ~CAM_STATIONARY_FOV;
|
||||
if(in_fov <= 0.0f)
|
||||
if(g3_get_hfov(in_fov) <= 0.0f)
|
||||
{
|
||||
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
fov.setAVD(g3_get_hfov(in_fov), in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
void camera::set_object_host(object *objp, int n_object_host_submodel)
|
||||
{
|
||||
if(objp == NULL)
|
||||
object_host = object_h();
|
||||
|
||||
object_host = object_h(objp);
|
||||
object_host_submodel = n_object_host_submodel;
|
||||
set_custom_position_function(NULL);
|
||||
set_custom_orientation_function(NULL);
|
||||
if(n_object_host_submodel > 0)
|
||||
{
|
||||
if(objp->type == OBJ_SHIP)
|
||||
if(objp != nullptr && objp->type == OBJ_SHIP)
|
||||
{
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
|
||||
@@ -319,11 +348,14 @@ int camera::get_object_target_submodel()
|
||||
return object_target_submodel;
|
||||
}
|
||||
|
||||
float camera::get_fov()
|
||||
fov_t camera::get_fov()
|
||||
{
|
||||
if(!(flags & CAM_STATIONARY_FOV))
|
||||
{
|
||||
fov.get(&c_fov, NULL);
|
||||
float fov_now;
|
||||
fov.get(&fov_now, nullptr);
|
||||
return fov_now;
|
||||
//TODO enable moving asymmetric fov
|
||||
}
|
||||
|
||||
return c_fov;
|
||||
|
||||
+18
-5
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
#define CAM_STATIONARY_FOV (1<<0)
|
||||
#define CAM_STATIONARY_ORI (1<<1)
|
||||
#define CAM_STATIONARY_POS (1<<2)
|
||||
@@ -18,6 +20,17 @@
|
||||
#define EXTERN_CAM_BBOX_CONSTANT_PADDING 5.0f
|
||||
#define EXTERN_CAM_BBOX_MULTIPLIER_PADDING 1.5f
|
||||
|
||||
struct asymmetric_fov {
|
||||
float left, right, up, down;
|
||||
friend asymmetric_fov operator* (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
|
||||
};
|
||||
using fov_t = mpark::variant<float, asymmetric_fov>;
|
||||
fov_t operator* (const fov_t&, const float&);
|
||||
fov_t operator+ (const fov_t&, const float&);
|
||||
fov_t operator- (const fov_t&, const float&);
|
||||
|
||||
class camera
|
||||
{
|
||||
protected:
|
||||
@@ -41,7 +54,7 @@ protected:
|
||||
avd_movement ori[9];
|
||||
|
||||
//Cache stuff
|
||||
float c_fov;
|
||||
fov_t c_fov;
|
||||
vec3d c_pos;
|
||||
matrix c_ori;
|
||||
public:
|
||||
@@ -59,7 +72,7 @@ public:
|
||||
void set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *pos));
|
||||
void set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *ori));
|
||||
|
||||
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
void set_fov(fov_t in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
|
||||
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
|
||||
|
||||
@@ -74,7 +87,7 @@ public:
|
||||
int get_object_host_submodel();
|
||||
object *get_object_target();
|
||||
int get_object_target_submodel();
|
||||
float get_fov();
|
||||
fov_t get_fov();
|
||||
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
|
||||
|
||||
//Is
|
||||
@@ -155,8 +168,8 @@ public:
|
||||
|
||||
//Some global stuff
|
||||
extern SCP_vector<subtitle> Subtitles;
|
||||
extern float VIEWER_ZOOM_DEFAULT;
|
||||
extern float COCKPIT_ZOOM_DEFAULT;
|
||||
extern fov_t VIEWER_ZOOM_DEFAULT;
|
||||
extern fov_t COCKPIT_ZOOM_DEFAULT;
|
||||
extern float Sexp_fov;
|
||||
|
||||
//Helpful functions
|
||||
|
||||
@@ -438,7 +438,7 @@ int cfile_flush_dir(int dir_type)
|
||||
// filename = name of filename or filepath to process
|
||||
// ext = extension to add. Must start with the period
|
||||
// Returns: new filename or filepath with extension.
|
||||
char *cf_add_ext(const char *filename, const char *ext)
|
||||
const char *cf_add_ext(const char *filename, const char *ext)
|
||||
{
|
||||
static char path[MAX_PATH_LEN];
|
||||
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
void cfile_close();
|
||||
|
||||
// add an extension to a filename if it doesn't already have it
|
||||
char *cf_add_ext(const char *filename, const char *ext);
|
||||
const char *cf_add_ext(const char *filename, const char *ext);
|
||||
|
||||
// return filename of a CFILE you called cfopen() successfully on.
|
||||
const char *cf_get_filename(const CFILE *cfile);
|
||||
|
||||
@@ -188,6 +188,7 @@ Flag exe_params[] =
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
|
||||
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
|
||||
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
@@ -406,6 +407,7 @@ cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3
|
||||
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
|
||||
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
|
||||
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
|
||||
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
|
||||
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
|
||||
cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
@@ -414,6 +416,7 @@ int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
int Cmdline_deadzone = -1;
|
||||
|
||||
@@ -1646,7 +1649,7 @@ bool SetCmdlineParams()
|
||||
|
||||
// be sure that this string fits in our limits
|
||||
if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d characters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1871,6 +1874,10 @@ bool SetCmdlineParams()
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
|
||||
if ( capture_mouse.found() ) {
|
||||
Cmdline_capture_mouse = true;
|
||||
}
|
||||
// new lighting lines
|
||||
if ( ambient_power_arg.found() )
|
||||
Cmdline_ambient_power = ambient_power_arg.get_float();
|
||||
|
||||
@@ -86,6 +86,7 @@ extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_no_screenshake;
|
||||
extern int Cmdline_deadzone;
|
||||
|
||||
|
||||
@@ -1359,9 +1359,6 @@ bool control_config_accept(bool API_Access)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
@@ -1630,7 +1627,7 @@ void control_config_close(bool API_Access)
|
||||
Ui_window.destroy();
|
||||
common_free_interface_palette(); // restore game palette
|
||||
}
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
game_flush();
|
||||
|
||||
if (Game_mode & GM_MULTIPLAYER) {
|
||||
@@ -2536,6 +2533,10 @@ void control_config_do_frame(float frametime)
|
||||
if (List_buttons[i].pressed()) {
|
||||
// Select the pressed line
|
||||
Selected_line = i + Scroll_offset;
|
||||
|
||||
// Cyborg - Quick assertion for Coverity 1093701. Not likely to happen, but we check for a negative Selected Line later.
|
||||
Assertion(Selected_line > -1, "control_config_do_frame() has somehow managed to get a negative Selected_line index of %d. Please get an SCP member.", Selected_line);
|
||||
|
||||
Selected_item = selItem::None;
|
||||
List_buttons[i].get_mouse_pos(&x, &y);
|
||||
|
||||
|
||||
@@ -45,27 +45,29 @@ int Failed_key_index;
|
||||
// Joystick configuration
|
||||
int Joy_dead_zone_size = 10;
|
||||
|
||||
auto DeadZoneOption =
|
||||
options::OptionBuilder<int>("Input.JoystickDeadZone", "Deadzone", "The deadzone of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.finish();
|
||||
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
|
||||
std::pair<const char*, int>{"Deadzone", 1377},
|
||||
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
|
||||
.category("Input")
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.finish();
|
||||
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
auto SensitivityOption =
|
||||
options::OptionBuilder<int>("Input.JoystickSensitivity", "Sensitivity", "The sentitivity of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.finish();
|
||||
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
|
||||
std::pair<const char*, int>{"Sensitivity", 1745},
|
||||
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.finish();
|
||||
|
||||
//! arrays which hold the key mappings. The array index represents a key-independent action.
|
||||
//! please use SPACES for aligning the fields of this array
|
||||
@@ -158,8 +160,8 @@ void control_config_common_init_bindings() {
|
||||
// flight controls (flight modes)
|
||||
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 0, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 0, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
|
||||
// flight controls (axes)
|
||||
(JOY_HEADING_AXIS, JOY_X_AXIS, MOUSE_X_AXIS, SHIP_TAB, 1016, "Turn (Yaw) Axis", CC_TYPE_AXIS_REL)
|
||||
@@ -173,7 +175,7 @@ void control_config_common_init_bindings() {
|
||||
(FIRE_SECONDARY, KEY_SPACEBAR, 1, WEAPON_TAB, 1, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS)
|
||||
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 0, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
|
||||
@@ -209,8 +211,8 @@ void control_config_common_init_bindings() {
|
||||
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 0, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 0, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
|
||||
(RADAR_RANGE_CYCLE, KEY_RAPOSTRO, -1, COMPUTER_TAB, 1, "Cycle Radar Range", CC_TYPE_TRIGGER)
|
||||
(SQUADMSG_MENU, KEY_C, -1, COMPUTER_TAB, 1, "Communications Menu", CC_TYPE_TRIGGER)
|
||||
@@ -235,8 +237,8 @@ void control_config_common_init_bindings() {
|
||||
|
||||
// Navigation and Autopilot
|
||||
(SHOW_NAVMAP, -1, -1, NO_TAB, 1, "Show Nav Map", CC_TYPE_TRIGGER, true)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 0, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 0, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 1779, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 1780, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
|
||||
// Escort
|
||||
(ADD_REMOVE_ESCORT, KEY_ALTED | KEY_E, -1, COMPUTER_TAB, 1, "Add or Remove Escort", CC_TYPE_TRIGGER)
|
||||
@@ -258,7 +260,7 @@ void control_config_common_init_bindings() {
|
||||
// HUD
|
||||
(TOGGLE_HUD, KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, 1, "Toggle HUD", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 0, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
|
||||
|
||||
// Custom Controls
|
||||
|
||||
@@ -108,7 +108,7 @@ class Decoder {
|
||||
* @note A implementation should initialize the datastructures required for decoding here.
|
||||
*
|
||||
* @param fileName The name of the file that should be opened
|
||||
* @return @c true if the initialization was successfull, @c false otherwise
|
||||
* @return @c true if the initialization was successful, @c false otherwise
|
||||
*/
|
||||
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
* half-rate linear filtering on GCN.
|
||||
*
|
||||
* If SMAA is applied to 64-bit color buffers, switching to point filtering
|
||||
* when accesing them will increase the performance. Search for
|
||||
* when accessing them will increase the performance. Search for
|
||||
* 'SMAASamplePoint' to see which textures may benefit from point
|
||||
* filtering, and where (which is basically the color input in the edge
|
||||
* detection and resolve passes).
|
||||
|
||||
@@ -24,6 +24,8 @@ layout (std140) uniform globalDeferredData {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
|
||||
float nearPlane;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
@@ -79,7 +81,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float dist = length(lightDirOut);
|
||||
|
||||
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// this chunk is unnecessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// given a sphere of radius sourceRadius centered at lightDirOut,
|
||||
// move lightDirOut towards the ray defined by reflectDir
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
@@ -122,7 +124,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
// should figure out how to optimise these calcs - qaz
|
||||
|
||||
|
||||
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// this chunk is unnecessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// Same principle as in LT_POINT, treat chosen location as a spherelight.
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
float dist = length(lightDirOut);
|
||||
@@ -168,7 +170,7 @@ void main()
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
|
||||
vec3 position = texture(PositionBuffer, screenPos).xyz;
|
||||
|
||||
if(abs(dot(position, position)) < 0.1)
|
||||
if(abs(dot(position, position)) < nearPlane * nearPlane)
|
||||
discard;
|
||||
|
||||
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
|
||||
|
||||
@@ -11,7 +11,7 @@ in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
|
||||
const vec3 points[128] = vec3[128](
|
||||
vec3(-0.2268, 0.6185, 0.7523),
|
||||
vec3( 0.9958, -0.0871, -0.0277),
|
||||
|
||||
@@ -33,7 +33,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
|
||||
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
|
||||
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
|
||||
// Distribution Term - Trowbridge-Reitz GGX
|
||||
|
||||
@@ -49,7 +49,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
// Smith's method:
|
||||
// Microsurfaces block light rays coming in from the light
|
||||
// AND block light rays reflecting to the camera.
|
||||
// Hence, model both seperately and multiply.
|
||||
// Hence, model both separately and multiply.
|
||||
float g1vNL = GeometrySchlickGGX(dotNL, k);
|
||||
float g1vNV = GeometrySchlickGGX(dotNV, k);
|
||||
float geometry = g1vNL * g1vNV;
|
||||
|
||||
@@ -0,0 +1,714 @@
|
||||
-- Module options:
|
||||
local always_try_using_lpeg = true
|
||||
local register_global_module_table = false
|
||||
local global_module_name = 'json'
|
||||
|
||||
--[==[
|
||||
|
||||
David Kolf's JSON module for Lua 5.1/5.2
|
||||
|
||||
Version 2.5
|
||||
|
||||
|
||||
For the documentation see the corresponding readme.txt or visit
|
||||
<http://dkolf.de/src/dkjson-lua.fsl/>.
|
||||
|
||||
You can contact the author by sending an e-mail to 'david' at the
|
||||
domain 'dkolf.de'.
|
||||
|
||||
|
||||
Copyright (C) 2010-2014 David Heiko Kolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--]==]
|
||||
|
||||
-- global dependencies:
|
||||
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
|
||||
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
|
||||
local error, require, pcall, select = error, require, pcall, select
|
||||
local floor, huge = math.floor, math.huge
|
||||
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
|
||||
string.rep, string.gsub, string.sub, string.byte, string.char,
|
||||
string.find, string.len, string.format
|
||||
local strmatch = string.match
|
||||
local concat = table.concat
|
||||
|
||||
local json = { version = "dkjson 2.5" }
|
||||
|
||||
if register_global_module_table then
|
||||
_G[global_module_name] = json
|
||||
end
|
||||
|
||||
local _ENV = nil -- blocking globals in Lua 5.2
|
||||
|
||||
pcall (function()
|
||||
-- Enable access to blocked metatables.
|
||||
-- Don't worry, this module doesn't change anything in them.
|
||||
local debmeta = require "debug".getmetatable
|
||||
if debmeta then getmetatable = debmeta end
|
||||
end)
|
||||
|
||||
json.null = setmetatable ({}, {
|
||||
__tojson = function () return "null" end
|
||||
})
|
||||
|
||||
local function isarray (tbl)
|
||||
local max, n, arraylen = 0, 0, 0
|
||||
for k,v in pairs (tbl) do
|
||||
if k == 'n' and type(v) == 'number' then
|
||||
arraylen = v
|
||||
if v > max then
|
||||
max = v
|
||||
end
|
||||
else
|
||||
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
|
||||
return false
|
||||
end
|
||||
if k > max then
|
||||
max = k
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
if max > 10 and max > arraylen and max > n * 2 then
|
||||
return false -- don't create an array with too many holes
|
||||
end
|
||||
return true, max
|
||||
end
|
||||
|
||||
local escapecodes = {
|
||||
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
|
||||
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
|
||||
}
|
||||
|
||||
local function escapeutf8 (uchar)
|
||||
local value = escapecodes[uchar]
|
||||
if value then
|
||||
return value
|
||||
end
|
||||
local a, b, c, d = strbyte (uchar, 1, 4)
|
||||
a, b, c, d = a or 0, b or 0, c or 0, d or 0
|
||||
if a <= 0x7f then
|
||||
value = a
|
||||
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
|
||||
value = (a - 0xc0) * 0x40 + b - 0x80
|
||||
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
|
||||
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
|
||||
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
|
||||
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
|
||||
else
|
||||
return ""
|
||||
end
|
||||
if value <= 0xffff then
|
||||
return strformat ("\\u%.4x", value)
|
||||
elseif value <= 0x10ffff then
|
||||
-- encode as UTF-16 surrogate pair
|
||||
value = value - 0x10000
|
||||
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
|
||||
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
local function fsub (str, pattern, repl)
|
||||
-- gsub always builds a new string in a buffer, even when no match
|
||||
-- exists. First using find should be more efficient when most strings
|
||||
-- don't contain the pattern.
|
||||
if strfind (str, pattern) then
|
||||
return gsub (str, pattern, repl)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
local function quotestring (value)
|
||||
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
|
||||
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
|
||||
if strfind (value, "[\194\216\220\225\226\239]") then
|
||||
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
|
||||
value = fsub (value, "\216[\128-\132]", escapeutf8)
|
||||
value = fsub (value, "\220\143", escapeutf8)
|
||||
value = fsub (value, "\225\158[\180\181]", escapeutf8)
|
||||
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
|
||||
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
|
||||
value = fsub (value, "\239\187\191", escapeutf8)
|
||||
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
|
||||
end
|
||||
return "\"" .. value .. "\""
|
||||
end
|
||||
json.quotestring = quotestring
|
||||
|
||||
local function replace(str, o, n)
|
||||
local i, j = strfind (str, o, 1, true)
|
||||
if i then
|
||||
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
-- locale independent num2str and str2num functions
|
||||
local decpoint, numfilter
|
||||
|
||||
local function updatedecpoint ()
|
||||
decpoint = strmatch(tostring(0.5), "([^05+])")
|
||||
-- build a filter that can be used to remove group separators
|
||||
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
|
||||
end
|
||||
|
||||
updatedecpoint()
|
||||
|
||||
local function num2str (num)
|
||||
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
|
||||
end
|
||||
|
||||
local function str2num (str)
|
||||
local num = tonumber(replace(str, ".", decpoint))
|
||||
if not num then
|
||||
updatedecpoint()
|
||||
num = tonumber(replace(str, ".", decpoint))
|
||||
end
|
||||
return num
|
||||
end
|
||||
|
||||
local function addnewline2 (level, buffer, buflen)
|
||||
buffer[buflen+1] = "\n"
|
||||
buffer[buflen+2] = strrep (" ", level)
|
||||
buflen = buflen + 2
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.addnewline (state)
|
||||
if state.indent then
|
||||
state.bufferlen = addnewline2 (state.level or 0,
|
||||
state.buffer, state.bufferlen or #(state.buffer))
|
||||
end
|
||||
end
|
||||
|
||||
local encode2 -- forward declaration
|
||||
|
||||
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local kt = type (key)
|
||||
if kt ~= 'string' and kt ~= 'number' then
|
||||
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
|
||||
end
|
||||
if prev then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level, buffer, buflen)
|
||||
end
|
||||
buffer[buflen+1] = quotestring (key)
|
||||
buffer[buflen+2] = ":"
|
||||
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
|
||||
end
|
||||
|
||||
local function appendcustom(res, buffer, state)
|
||||
local buflen = state.bufferlen
|
||||
if type (res) == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = res
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
local function exception(reason, value, state, buffer, buflen, defaultmessage)
|
||||
defaultmessage = defaultmessage or reason
|
||||
local handler = state.exception
|
||||
if not handler then
|
||||
return nil, defaultmessage
|
||||
else
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = handler (reason, value, state, defaultmessage)
|
||||
if not ret then return nil, msg or defaultmessage end
|
||||
return appendcustom(ret, buffer, state)
|
||||
end
|
||||
end
|
||||
|
||||
function json.encodeexception(reason, value, state, defaultmessage)
|
||||
return quotestring("<" .. defaultmessage .. ">")
|
||||
end
|
||||
|
||||
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local valtype = type (value)
|
||||
local valmeta = getmetatable (value)
|
||||
valmeta = type (valmeta) == 'table' and valmeta -- only tables
|
||||
local valtojson = valmeta and valmeta.__tojson
|
||||
if valtojson then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = valtojson (value, state)
|
||||
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
|
||||
tables[value] = nil
|
||||
buflen = appendcustom(ret, buffer, state)
|
||||
elseif value == nil then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "null"
|
||||
elseif valtype == 'number' then
|
||||
local s
|
||||
if value ~= value or value >= huge or -value >= huge then
|
||||
-- This is the behaviour of the original JSON implementation.
|
||||
s = "null"
|
||||
else
|
||||
s = num2str (value)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = s
|
||||
elseif valtype == 'boolean' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = value and "true" or "false"
|
||||
elseif valtype == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = quotestring (value)
|
||||
elseif valtype == 'table' then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
level = level + 1
|
||||
local isa, n = isarray (value)
|
||||
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
|
||||
isa = false
|
||||
end
|
||||
local msg
|
||||
if isa then -- JSON array
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "["
|
||||
for i = 1, n do
|
||||
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
if i < n then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "]"
|
||||
else -- JSON object
|
||||
local prev = false
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "{"
|
||||
local order = valmeta and valmeta.__jsonorder or globalorder
|
||||
if order then
|
||||
local used = {}
|
||||
n = #order
|
||||
for i = 1, n do
|
||||
local k = order[i]
|
||||
local v = value[k]
|
||||
if v then
|
||||
used[k] = true
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
for k,v in pairs (value) do
|
||||
if not used[k] then
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
else -- unordered
|
||||
for k,v in pairs (value) do
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level - 1, buffer, buflen)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "}"
|
||||
end
|
||||
tables[value] = nil
|
||||
else
|
||||
return exception ('unsupported type', value, state, buffer, buflen,
|
||||
"type '" .. valtype .. "' is not supported by JSON.")
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.encode (value, state)
|
||||
state = state or {}
|
||||
local oldbuffer = state.buffer
|
||||
local buffer = oldbuffer or {}
|
||||
state.buffer = buffer
|
||||
updatedecpoint()
|
||||
local ret, msg = encode2 (value, state.indent, state.level or 0,
|
||||
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
|
||||
if not ret then
|
||||
error (msg, 2)
|
||||
elseif oldbuffer == buffer then
|
||||
state.bufferlen = ret
|
||||
return true
|
||||
else
|
||||
state.bufferlen = nil
|
||||
state.buffer = nil
|
||||
return concat (buffer)
|
||||
end
|
||||
end
|
||||
|
||||
local function loc (str, where)
|
||||
local line, pos, linepos = 1, 1, 0
|
||||
while true do
|
||||
pos = strfind (str, "\n", pos, true)
|
||||
if pos and pos < where then
|
||||
line = line + 1
|
||||
linepos = pos
|
||||
pos = pos + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return "line " .. line .. ", column " .. (where - linepos)
|
||||
end
|
||||
|
||||
local function unterminated (str, what, where)
|
||||
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
|
||||
end
|
||||
|
||||
local function scanwhite (str, pos)
|
||||
while true do
|
||||
pos = strfind (str, "%S", pos)
|
||||
if not pos then return nil end
|
||||
local sub2 = strsub (str, pos, pos + 1)
|
||||
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
|
||||
-- UTF-8 Byte Order Mark
|
||||
pos = pos + 3
|
||||
elseif sub2 == "//" then
|
||||
pos = strfind (str, "[\n\r]", pos + 2)
|
||||
if not pos then return nil end
|
||||
elseif sub2 == "/*" then
|
||||
pos = strfind (str, "*/", pos + 2)
|
||||
if not pos then return nil end
|
||||
pos = pos + 2
|
||||
else
|
||||
return pos
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local escapechars = {
|
||||
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
|
||||
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
|
||||
}
|
||||
|
||||
local function unichar (value)
|
||||
if value < 0 then
|
||||
return nil
|
||||
elseif value <= 0x007f then
|
||||
return strchar (value)
|
||||
elseif value <= 0x07ff then
|
||||
return strchar (0xc0 + floor(value/0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0xffff then
|
||||
return strchar (0xe0 + floor(value/0x1000),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0x10ffff then
|
||||
return strchar (0xf0 + floor(value/0x40000),
|
||||
0x80 + (floor(value/0x1000) % 0x40),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function scanstring (str, pos)
|
||||
local lastpos = pos + 1
|
||||
local buffer, n = {}, 0
|
||||
while true do
|
||||
local nextpos = strfind (str, "[\"\\]", lastpos)
|
||||
if not nextpos then
|
||||
return unterminated (str, "string", pos)
|
||||
end
|
||||
if nextpos > lastpos then
|
||||
n = n + 1
|
||||
buffer[n] = strsub (str, lastpos, nextpos - 1)
|
||||
end
|
||||
if strsub (str, nextpos, nextpos) == "\"" then
|
||||
lastpos = nextpos + 1
|
||||
break
|
||||
else
|
||||
local escchar = strsub (str, nextpos + 1, nextpos + 1)
|
||||
local value
|
||||
if escchar == "u" then
|
||||
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
|
||||
if value then
|
||||
local value2
|
||||
if 0xD800 <= value and value <= 0xDBff then
|
||||
-- we have the high surrogate of UTF-16. Check if there is a
|
||||
-- low surrogate escaped nearby to combine them.
|
||||
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
|
||||
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
|
||||
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
|
||||
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
|
||||
else
|
||||
value2 = nil -- in case it was out of range for a low surrogate
|
||||
end
|
||||
end
|
||||
end
|
||||
value = value and unichar (value)
|
||||
if value then
|
||||
if value2 then
|
||||
lastpos = nextpos + 12
|
||||
else
|
||||
lastpos = nextpos + 6
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not value then
|
||||
value = escapechars[escchar] or escchar
|
||||
lastpos = nextpos + 2
|
||||
end
|
||||
n = n + 1
|
||||
buffer[n] = value
|
||||
end
|
||||
end
|
||||
if n == 1 then
|
||||
return buffer[1], lastpos
|
||||
elseif n > 1 then
|
||||
return concat (buffer), lastpos
|
||||
else
|
||||
return "", lastpos
|
||||
end
|
||||
end
|
||||
|
||||
local scanvalue -- forward declaration
|
||||
|
||||
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
|
||||
local len = strlen (str)
|
||||
local tbl, n = {}, 0
|
||||
local pos = startpos + 1
|
||||
if what == 'object' then
|
||||
setmetatable (tbl, objectmeta)
|
||||
else
|
||||
setmetatable (tbl, arraymeta)
|
||||
end
|
||||
while true do
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == closechar then
|
||||
return tbl, pos + 1
|
||||
end
|
||||
local val1, err
|
||||
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
if char == ":" then
|
||||
if val1 == nil then
|
||||
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
|
||||
end
|
||||
pos = scanwhite (str, pos + 1)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local val2
|
||||
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
tbl[val1] = val2
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
else
|
||||
n = n + 1
|
||||
tbl[n] = val1
|
||||
end
|
||||
if char == "," then
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
|
||||
pos = pos or 1
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then
|
||||
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
|
||||
end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == "{" then
|
||||
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "[" then
|
||||
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "\"" then
|
||||
return scanstring (str, pos)
|
||||
else
|
||||
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
|
||||
if pstart then
|
||||
local number = str2num (strsub (str, pstart, pend))
|
||||
if number then
|
||||
return number, pend + 1
|
||||
end
|
||||
end
|
||||
pstart, pend = strfind (str, "^%a%w*", pos)
|
||||
if pstart then
|
||||
local name = strsub (str, pstart, pend)
|
||||
if name == "true" then
|
||||
return true, pend + 1
|
||||
elseif name == "false" then
|
||||
return false, pend + 1
|
||||
elseif name == "null" then
|
||||
return nullval, pend + 1
|
||||
end
|
||||
end
|
||||
return nil, pos, "no valid JSON value at " .. loc (str, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function optionalmetatables(...)
|
||||
if select("#", ...) > 0 then
|
||||
return ...
|
||||
else
|
||||
return {__jsontype = 'object'}, {__jsontype = 'array'}
|
||||
end
|
||||
end
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local objectmeta, arraymeta = optionalmetatables(...)
|
||||
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
end
|
||||
|
||||
function json.use_lpeg ()
|
||||
local g = require ("lpeg")
|
||||
|
||||
if g.version() == "0.11" then
|
||||
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
|
||||
end
|
||||
|
||||
local pegmatch = g.match
|
||||
local P, S, R = g.P, g.S, g.R
|
||||
|
||||
local function ErrorCall (str, pos, msg, state)
|
||||
if not state.msg then
|
||||
state.msg = msg .. " at " .. loc (str, pos)
|
||||
state.pos = pos
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function Err (msg)
|
||||
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
|
||||
end
|
||||
|
||||
local SingleLineComment = P"//" * (1 - S"\n\r")^0
|
||||
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
|
||||
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
|
||||
|
||||
local PlainChar = 1 - S"\"\\\n\r"
|
||||
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
|
||||
local HexDigit = R("09", "af", "AF")
|
||||
local function UTF16Surrogate (match, pos, high, low)
|
||||
high, low = tonumber (high, 16), tonumber (low, 16)
|
||||
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
|
||||
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
local function UTF16BMP (hex)
|
||||
return unichar (tonumber (hex, 16))
|
||||
end
|
||||
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
|
||||
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
|
||||
local Char = UnicodeEscape + EscapeSequence + PlainChar
|
||||
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
|
||||
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
|
||||
local Fractal = P"." * R"09"^0
|
||||
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
|
||||
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
|
||||
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
|
||||
local SimpleValue = Number + String + Constant
|
||||
local ArrayContent, ObjectContent
|
||||
|
||||
-- The functions parsearray and parseobject parse only a single value/pair
|
||||
-- at a time and store them directly to avoid hitting the LPeg limits.
|
||||
local function parsearray (str, pos, nullval, state)
|
||||
local obj, cont
|
||||
local npos
|
||||
local t, nt = {}, 0
|
||||
repeat
|
||||
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
nt = nt + 1
|
||||
t[nt] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.arraymeta)
|
||||
end
|
||||
|
||||
local function parseobject (str, pos, nullval, state)
|
||||
local obj, key, cont
|
||||
local npos
|
||||
local t = {}
|
||||
repeat
|
||||
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
t[key] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.objectmeta)
|
||||
end
|
||||
|
||||
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
|
||||
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
|
||||
local Value = Space * (Array + Object + SimpleValue)
|
||||
local ExpectedValue = Value + Space * Err "value expected"
|
||||
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
|
||||
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local DecodeValue = ExpectedValue * g.Cp ()
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local state = {}
|
||||
state.objectmeta, state.arraymeta = optionalmetatables(...)
|
||||
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
|
||||
if state.msg then
|
||||
return nil, state.pos, state.msg
|
||||
else
|
||||
return obj, retpos
|
||||
end
|
||||
end
|
||||
|
||||
-- use this function only once:
|
||||
json.use_lpeg = function () return json end
|
||||
|
||||
json.using_lpeg = true
|
||||
|
||||
return json -- so you can get the module using json = require "dkjson".use_lpeg()
|
||||
end
|
||||
|
||||
if always_try_using_lpeg then
|
||||
pcall (json.use_lpeg)
|
||||
end
|
||||
|
||||
return json
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
#Ship types
|
||||
#Ship types
|
||||
|
||||
$Name: Navbuoy
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 1.0
|
||||
@@ -12,6 +12,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Sentry Gun
|
||||
$Counts for Alone: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -32,6 +33,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Escape Pod
|
||||
$Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -50,6 +52,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
$Scannable: YES
|
||||
$Max Debris Speed: 200
|
||||
@@ -63,6 +66,7 @@ $Fog:
|
||||
$AI:
|
||||
+Passive docks: ( "cargo" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Support
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -89,6 +93,7 @@ $AI:
|
||||
+Active docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
;;WMC - Stealth ships always have another type, so this isn't used
|
||||
$Name: Stealth
|
||||
$Counts for Alone: YES
|
||||
@@ -114,6 +119,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Fighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -141,6 +147,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -168,7 +175,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
$Name: Fighter/bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -195,6 +203,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Transport
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -204,6 +213,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 2.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -223,6 +233,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Freighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -233,6 +244,7 @@ $Scannable: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.75
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -253,6 +265,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: AWACS
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -262,6 +275,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.8
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -281,6 +295,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Gas Miner
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -290,6 +305,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -309,6 +325,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Cruiser
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -318,6 +335,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.9
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -337,6 +355,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Corvette
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -346,6 +365,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.3333
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -365,6 +385,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Capital
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -394,6 +415,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Super Cap
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -421,6 +443,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Drydock
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -446,6 +469,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Knossos Device
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -469,4 +493,5 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
#End
|
||||
|
||||
#End
|
||||
@@ -311,7 +311,7 @@ static char* GetFilePart(char *source)
|
||||
SCP_string safe_string;
|
||||
|
||||
// Entry point into the main exception handling routine. This routine is put into an except()
|
||||
// statment at the beginning of a thread and is called anytime that there is a program exception
|
||||
// statement at the beginning of a thread and is called anytime that there is a program exception
|
||||
// The data is stored in a file called ErrorLog.txt in the data directory.
|
||||
//
|
||||
// data: pointer to the exception data
|
||||
|
||||
+36
-29
@@ -48,44 +48,51 @@ bool fireballs_parsed = false;
|
||||
|
||||
bool Fireball_use_3d_warp = false;
|
||||
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp",
|
||||
std::pair<const char*, int>{"3D Warp", 1770},
|
||||
std::pair<const char*, int>{"Use a 3D model for warp effects", 1771})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
/**
|
||||
* Play warp in sound for warp effect
|
||||
*/
|
||||
void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
float range_multiplier = 1.0f;
|
||||
object *fireball_objp;
|
||||
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
if(fb->warp_open_sound_index.isValid()) {
|
||||
if (fb->warp_open_sound_index.isValid()) {
|
||||
sound_index = fb->warp_open_sound_index;
|
||||
} else if ((ship_class >= 0) && (ship_class < ship_info_size())) {
|
||||
if ( Ship_info[ship_class].is_huge_ship() ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_IN);
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if ( Ship_info[ship_class].is_big_ship() ) {
|
||||
range_multiplier = 6.0f;
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
|
||||
if (ship_class >= 0 && ship_class < ship_info_size()) {
|
||||
if (Ship_info[ship_class].is_huge_ship()) {
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if (Ship_info[ship_class].is_big_ship()) {
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
|
||||
// originally 6.0 for SIF_BIG_SHIP and 1.0 for everything else
|
||||
if (Ship_info[ship_class].class_type >= 0)
|
||||
fb->warp_sound_range_multiplier = Ship_types[Ship_info[ship_class].class_type].warp_sound_range_multiplier;
|
||||
else
|
||||
fb->warp_sound_range_multiplier = 1.0f;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,15 +100,14 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
*/
|
||||
void fireball_play_warphole_close_sound(fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
object *fireball_objp;
|
||||
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
if ( fb->warp_close_sound_index.isValid() ) {
|
||||
if (fb->warp_close_sound_index.isValid()) {
|
||||
sound_index = fb->warp_close_sound_index;
|
||||
} else if ( fb->flags & FBF_WARP_CAPITAL_SIZE ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_OUT);
|
||||
@@ -109,7 +115,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
|
||||
return;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0F, SND_PRIORITY_SINGLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
|
||||
@@ -845,6 +851,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
|
||||
new_fireball->warp_close_sound_index = warp_close_sound;
|
||||
new_fireball->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
|
||||
new_fireball->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
|
||||
new_fireball->warp_sound_range_multiplier = 1.0f;
|
||||
|
||||
matrix orient;
|
||||
if(orient_override != NULL){
|
||||
|
||||
@@ -92,6 +92,9 @@ typedef struct fireball {
|
||||
gamesnd_id warp_close_sound_index;
|
||||
float warp_open_duration;
|
||||
float warp_close_duration;
|
||||
|
||||
// the sound multiplier is based on the ship class, but we lose that while the warp is closing
|
||||
float warp_sound_range_multiplier;
|
||||
} fireball;
|
||||
// end move
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash", "Warp Flash", "Show flash upon warp open or close")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash",
|
||||
std::pair<const char*, int>{"Warp Flash", 1768},
|
||||
std::pair<const char*, int>{"Show flash upon warp open or close", 1769})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "io/key.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "missionui/missionscreencommon.h"
|
||||
#include "sound/audiostr.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -516,6 +517,7 @@ void gameplay_help_leave()
|
||||
// unpause all game sounds
|
||||
weapon_unpause_sounds();
|
||||
audiostream_unpause_all();
|
||||
message_resume_all();
|
||||
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
game_flush();
|
||||
@@ -631,6 +633,7 @@ void gameplay_help_do_frame(float /*frametime*/)
|
||||
// make sure game sounds are paused
|
||||
weapon_pause_sounds();
|
||||
audiostream_pause_all();
|
||||
message_pause_all();
|
||||
|
||||
k = Ui_window.process() & ~KEY_DEBUGGED;
|
||||
gameplay_help_process_key(k);
|
||||
|
||||
@@ -45,13 +45,15 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music", "Music", "Volume used for playing music")
|
||||
.category("Audio")
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.finish();
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music",
|
||||
std::pair<const char*, int>{"Music", 1371},
|
||||
std::pair<const char*, int>{"Volume used for playing music", 1760})
|
||||
.category("Audio")
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.finish();
|
||||
|
||||
typedef struct tagSNDPATTERN {
|
||||
int default_next_pattern; // Needed so the next_pattern member can be reset
|
||||
@@ -604,7 +606,10 @@ void event_music_level_start(int force_soundtrack)
|
||||
|
||||
// Check that soundtrack index is in range, except that < 0 means no soundtrack
|
||||
if (Current_soundtrack_num < 0)
|
||||
{
|
||||
Pattern_timer_id = TIMESTAMP::never(); // update the timestamp as if a soundtrack did start
|
||||
return;
|
||||
}
|
||||
Assert(Current_soundtrack_num < (int)Soundtracks.size());
|
||||
if (Current_soundtrack_num >= (int)Soundtracks.size())
|
||||
return;
|
||||
|
||||
@@ -245,57 +245,89 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
|
||||
// Global used to access detail levels in game and libs
|
||||
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto ModelDetailOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
|
||||
std::pair<const char*, int>{"Model Detail", 1739},
|
||||
std::pair<const char*, int>{"Detail level of models", 1740})
|
||||
.importance(8)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
|
||||
"3D Hardware Textures",
|
||||
"Level of detail of textures").importance(6).category("Graphics").values(
|
||||
DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"3D Hardware Textures", 1362},
|
||||
std::pair<const char*, int>{"Level of detail of textures", 1720})
|
||||
.importance(6)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
|
||||
"Particles",
|
||||
"Level of detail for particles").importance(5).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Particles", 1363},
|
||||
std::pair<const char*, int>{"Level of detail for particles", 1717})
|
||||
.importance(5)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto SmallDebrisOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
|
||||
bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto SmallDebrisOption __UNUSED = options::OptionBuilder<int>("Graphics.SmallDebris",
|
||||
std::pair<const char*, int>{"Impact Effects", 1364},
|
||||
std::pair<const char*, int>{"Level of detail of impact effects", 1743})
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.importance(4)
|
||||
.change_listener([](int val,bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
"Shield Hit Effects",
|
||||
"Level of detail of shield impacts").importance(3).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Shield Hit Effects", 1718},
|
||||
std::pair<const char*, int>{"Level of detail of shield impacts", 1719})
|
||||
.importance(3)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto StarsOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto StarsOption __UNUSED = options::OptionBuilder<int>("Graphics.Stars",
|
||||
std::pair<const char*, int>{"Stars", 1366},
|
||||
std::pair<const char*, int>{"Number of stars in the mission", 1698})
|
||||
.importance(2)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
// Call this with:
|
||||
// 0 - lowest
|
||||
|
||||
+48
-32
@@ -53,41 +53,10 @@ version parse_version() {
|
||||
return v;
|
||||
}
|
||||
version parse_version_inline() {
|
||||
version v;
|
||||
|
||||
SCP_string input;
|
||||
stuff_string(input, F_RAW);
|
||||
|
||||
size_t start_pos = 0;
|
||||
size_t end_pos = input.find('.');
|
||||
|
||||
v.major = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.minor = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.build = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.revision = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
return v;
|
||||
return version(std::move(input), 0);
|
||||
}
|
||||
version get_executable_version() {
|
||||
version v;
|
||||
@@ -102,6 +71,53 @@ version get_executable_version() {
|
||||
version::version(int major_in, int minor_in, int build_in, int revision_in) :
|
||||
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
|
||||
}
|
||||
|
||||
version::version(const SCP_string& semver, int missing) : major(missing), minor(missing), build(missing), revision(missing) {
|
||||
int i = 0;
|
||||
auto str = semver;
|
||||
int has_fields = 0;
|
||||
while (i <= 4) {
|
||||
size_t pos = str.find_first_of('.');
|
||||
SCP_string ver;
|
||||
if (pos != SCP_string::npos) {
|
||||
ver = str.substr(0, pos);
|
||||
str.erase(0, pos + 1);
|
||||
}
|
||||
else {
|
||||
ver = str;
|
||||
str.clear();
|
||||
}
|
||||
|
||||
if (!ver.empty() && std::find_if(ver.begin(), ver.end(), [](char c) { return !std::isdigit(c, SCP_default_locale); }) == ver.end()) {
|
||||
switch (has_fields) {
|
||||
case 0:
|
||||
major = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 1:
|
||||
minor = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 2:
|
||||
build = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 3:
|
||||
revision = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Version parsing broken, get a coder!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break; //Break out of the loop if the first string is not a digit.
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool version::isValid() const { return major != 0 || minor != 0 || build != 0 || revision != 0; }
|
||||
bool version::operator<(const version& v) const {
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ struct version {
|
||||
|
||||
version(int major, int minor = 0, int build = 0, int revision = 0);
|
||||
|
||||
version(const SCP_string& semver, int missing = -1);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
bool operator<(const version& other) const;
|
||||
|
||||
+138
-128
@@ -112,35 +112,38 @@ static bool gamma_change_listener(float new_val, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto GammaOption __UNUSED =
|
||||
options::OptionBuilder<float>("Graphics.Gamma", "Brightness", "The brighness value used for the game window")
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.finish();
|
||||
static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma",
|
||||
std::pair<const char*, int>{"Brightness", 1375},
|
||||
std::pair<const char*, int>{"The brightness value used for the game window", 1738})
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.finish();
|
||||
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
|
||||
std::pair<const char*, int>{"Lighting", 1367},
|
||||
std::pair<const char*, int>{"Level of detail of the lighting", 1715})
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
os::ViewportState Gr_configured_window_state = os::ViewportState::Windowed;
|
||||
|
||||
@@ -162,17 +165,18 @@ static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
|
||||
"Controls how the game window is created.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, "Fullscreen"},
|
||||
{os::ViewportState::Borderless, "Borderless"},
|
||||
{os::ViewportState::Windowed, "Windowed"}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode",
|
||||
std::pair<const char*, int>{"Window Mode", 1772},
|
||||
std::pair<const char*, int>{"Controls how the game window is created", 1773})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, {"Fullscreen", 1679}},
|
||||
{os::ViewportState::Borderless, {"Borderless", 1675}},
|
||||
{os::ViewportState::Windowed, {"Windowed", 1676}}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
|
||||
@@ -188,6 +192,7 @@ int gr_stencil_mode = 0;
|
||||
// Default clipping distances
|
||||
const float Default_min_draw_distance = 1.0f;
|
||||
const float Default_max_draw_distance = 1e10;
|
||||
float Min_draw_distance_cockpit = 0.02f;
|
||||
float Min_draw_distance = Default_min_draw_distance;
|
||||
float Max_draw_distance = Default_max_draw_distance;
|
||||
|
||||
@@ -251,18 +256,19 @@ static bool videodisplay_change(int display, bool initial)
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
|
||||
return true;
|
||||
}
|
||||
static auto VideoDisplayOption =
|
||||
options::OptionBuilder<int>("Graphics.Display", "Primary display", "The display used for rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
static auto VideoDisplayOption = options::OptionBuilder<int>("Graphics.Display",
|
||||
std::pair<const char*, int>{"Primary display", 1741},
|
||||
std::pair<const char*, int>{"The display used for rendering", 1742})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
|
||||
struct ResolutionInfo {
|
||||
uint32_t width = 0;
|
||||
@@ -359,80 +365,83 @@ static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
}
|
||||
*/
|
||||
}
|
||||
static auto ResolutionOption =
|
||||
options::OptionBuilder<ResolutionInfo>("Graphics.Resolution", "Resolution", "The rendering resolution.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.Resolution",
|
||||
std::pair<const char*, int>{"Resolution", 1748},
|
||||
std::pair<const char*, int>{"The rendering resolution", 1749})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_soft_particles = false;
|
||||
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
|
||||
"Enable or disable soft particle rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles",
|
||||
std::pair<const char*, int>{"Soft Particles", 1761},
|
||||
std::pair<const char*, int>{"Enable or disable soft particle rendering", 1762})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects;
|
||||
|
||||
static auto FramebufferEffectsOption __UNUSED =
|
||||
options::OptionBuilder<flagset<FramebufferEffects>>(
|
||||
"Graphics.FramebufferEffects", "Framebuffer effects",
|
||||
"Controls which framebuffer effects will be applied to the scene.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, "None"},
|
||||
{{FramebufferEffects::Shockwaves}, "Shockwaves"},
|
||||
{{FramebufferEffects::Thrusters}, "Thrusters"},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, "All"}})
|
||||
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<FramebufferEffects>>("Graphics.FramebufferEffects",
|
||||
std::pair<const char*, int>{"Framebuffer effects", 1732},
|
||||
std::pair<const char*, int>{"Controls which framebuffer effects will be applied to the scene", 1733})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, {"None", 211}},
|
||||
{{FramebufferEffects::Shockwaves}, {"Shockwaves", 1688}},
|
||||
{{FramebufferEffects::Thrusters}, {"Thrusters", 1689}},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, {"All", 1690}}})
|
||||
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
|
||||
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
|
||||
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
|
||||
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
|
||||
"Controls the anti aliasing mode of the engine.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, "None"},
|
||||
{AntiAliasMode::FXAA_Low, "FXAA Low"},
|
||||
{AntiAliasMode::FXAA_Medium, "FXAA Medium"},
|
||||
{AntiAliasMode::FXAA_High, "FXAA High"},
|
||||
{AntiAliasMode::SMAA_Low, "SMAA Low"},
|
||||
{AntiAliasMode::SMAA_Medium, "SMAA Medium"},
|
||||
{AntiAliasMode::SMAA_High, "SMAA High"},
|
||||
{AntiAliasMode::SMAA_Ultra, "SMAA Ultra"}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
|
||||
std::pair<const char*, int>{"Anti Aliasing", 1752},
|
||||
std::pair<const char*, int>{"Controls the anti aliasing mode of the engine.", 1753})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, {"None", 211}},
|
||||
{AntiAliasMode::FXAA_Low, {"FXAA Low", 1681}},
|
||||
{AntiAliasMode::FXAA_Medium, {"FXAA Medium", 1682}},
|
||||
{AntiAliasMode::FXAA_High, {"FXAA High", 1683}},
|
||||
{AntiAliasMode::SMAA_Low, {"SMAA Low", 1684}},
|
||||
{AntiAliasMode::SMAA_Medium, {"SMAA Medium", 1685}},
|
||||
{AntiAliasMode::SMAA_High, {"SMAA High", 1686}},
|
||||
{AntiAliasMode::SMAA_Ultra, {"SMAA Ultra", 1687}}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
|
||||
extern int Cmdline_msaa_enabled;
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples", "Multisample Anti Aliasing",
|
||||
"Controls whether multisample anti aliasing is enabled, and with how many samples.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, "Off"},
|
||||
{4, "4 Samples"},
|
||||
{8, "8 Samples"},
|
||||
{16, "16 Samples"}})
|
||||
.default_val(0)
|
||||
.bind_to(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples",
|
||||
std::pair<const char*, int>{"Multisample Anti Aliasing", 1758},
|
||||
std::pair<const char*, int>{"Controls whether multisample anti asliasing is enabled, and with how many samples", 1759})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, {"Off", 1693}},
|
||||
{4, {"4 Samples", 1694}},
|
||||
{8, {"8 Samples", 1695}},
|
||||
{16, {"16 Samples", 1696}}})
|
||||
.default_val(0)
|
||||
.bind_to_once(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
bool gr_is_fxaa_mode(AntiAliasMode mode)
|
||||
{
|
||||
@@ -444,26 +453,27 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
|
||||
"Controls whether post processing is enabled in the engine")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.PostProcessing",
|
||||
std::pair<const char*, int>{"Post processing", 1726},
|
||||
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
"Controls how the engine does vertical synchronization")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync",
|
||||
std::pair<const char*, int>{"Vertical Sync", 1766},
|
||||
std::pair<const char*, int>{"Controls how the engine does vertical synchronization", 1767})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
|
||||
|
||||
|
||||
+4
-3
@@ -36,6 +36,7 @@ class OverridableHook;
|
||||
|
||||
extern const float Default_min_draw_distance;
|
||||
extern const float Default_max_draw_distance;
|
||||
extern float Min_draw_distance_cockpit;
|
||||
extern float Min_draw_distance;
|
||||
extern float Max_draw_distance;
|
||||
extern int Gr_inited;
|
||||
@@ -102,7 +103,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
matrix4 &get_transform()
|
||||
const matrix4 &get_transform() const
|
||||
{
|
||||
return Current_transform;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
void push_and_replace(matrix4 new_transform)
|
||||
void push_and_replace(const matrix4 &new_transform)
|
||||
{
|
||||
Current_transform = new_transform;
|
||||
Stack.push_back(Current_transform);
|
||||
@@ -300,7 +301,7 @@ public:
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
|
||||
|
||||
size_t get_vertex_stride() { return Vertex_stride; }
|
||||
size_t get_vertex_stride() const { return Vertex_stride; }
|
||||
|
||||
bool operator==(const vertex_layout& other) const;
|
||||
|
||||
|
||||
@@ -734,6 +734,43 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
|
||||
}
|
||||
}
|
||||
|
||||
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu, const generic_extras* ge)
|
||||
{
|
||||
if ((ge != nullptr) && (ga->use_hud_color == true)) {
|
||||
Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)");
|
||||
return;
|
||||
}
|
||||
|
||||
float a = 1.0f;
|
||||
if (ge != nullptr) {
|
||||
a = ge->alpha;
|
||||
}
|
||||
if (ga->type == BM_TYPE_PNG) {
|
||||
generic_anim_render_variable_frame_delay(ga, frametime, a);
|
||||
}
|
||||
else {
|
||||
generic_anim_render_fixed_frame_delay(ga, frametime, a);
|
||||
}
|
||||
|
||||
if (ga->num_frames > 0) {
|
||||
ga->previous_frame = ga->current_frame;
|
||||
|
||||
if (ga->use_hud_color) {
|
||||
gr_aabitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else {
|
||||
if (ge == nullptr) {
|
||||
gr_bitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else if (ge->draw == true) {
|
||||
// currently only for lua streaminganim objects
|
||||
// and don't draw them unless requested...
|
||||
gr_bitmap_uv(x, y, w, h, ge->u0, ge->v0, ge->u1, ge->v1, ge->resize_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief reset an animation back to the start
|
||||
*
|
||||
|
||||
@@ -91,5 +91,6 @@ int generic_anim_stream(generic_anim *ga, const bool cache = true);
|
||||
int generic_bitmap_load(generic_bitmap *gb);
|
||||
void generic_anim_unload(generic_anim *ga);
|
||||
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr);
|
||||
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu = false, const generic_extras* ge = nullptr);
|
||||
void generic_anim_reset(generic_anim *ga);
|
||||
#endif
|
||||
@@ -441,7 +441,7 @@ void material::set_color(int r, int g, int b, int a)
|
||||
Clr.xyzw.w = i2fl(a) / 255.0f;
|
||||
}
|
||||
|
||||
void material::set_color(color &clr_in)
|
||||
void material::set_color(const color &clr_in)
|
||||
{
|
||||
if ( clr_in.is_alphacolor ) {
|
||||
Clr.xyzw.x = i2fl(clr_in.red) / 255.0f;
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
|
||||
void set_color(float red, float green, float blue, float alpha);
|
||||
void set_color(int r, int g, int b, int a);
|
||||
void set_color(color &clr_in);
|
||||
void set_color(const color &clr_in);
|
||||
const vec4& get_color() const;
|
||||
|
||||
void set_color_scale(float scale);
|
||||
|
||||
+27
-10
@@ -16,6 +16,8 @@ matrix4 gr_texture_matrix;
|
||||
|
||||
matrix4 gr_env_texture_matrix;
|
||||
|
||||
float gr_near_plane;
|
||||
|
||||
bool gr_htl_projection_matrix_set = false;
|
||||
|
||||
static int modelview_matrix_depth = 1;
|
||||
@@ -116,28 +118,43 @@ void gr_end_instance_matrix()
|
||||
}
|
||||
|
||||
// the projection matrix; fov, aspect ratio, near, far
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far) {
|
||||
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far) {
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
gr_set_viewport(gr_screen.offset_x, gr_screen.offset_y, gr_screen.clip_width, gr_screen.clip_height);
|
||||
} else {
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
}
|
||||
|
||||
float clip_width, clip_height;
|
||||
|
||||
clip_height = tan( fov * 0.5f ) * z_near;
|
||||
clip_width = clip_height * aspect;
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
|
||||
} else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
|
||||
|
||||
if (mpark::holds_alternative<float>(fov)) {
|
||||
float clip_width, clip_height;
|
||||
clip_height = tan(mpark::get<float>(fov) * 0.5f) * z_near;
|
||||
clip_width = clip_height * aspect;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
|
||||
} else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const auto& afov = mpark::get<asymmetric_fov>(fov);
|
||||
float clip_l = tanf(afov.left) * z_near;
|
||||
float clip_r = tanf(afov.right) * z_near;
|
||||
float clip_u = tanf(afov.up) * z_near;
|
||||
float clip_d = tanf(afov.down) * z_near;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_u, clip_d, z_near, z_far);
|
||||
}
|
||||
else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_d, clip_u, z_near, z_far);
|
||||
}
|
||||
}
|
||||
|
||||
gr_htl_projection_matrix_set = true;
|
||||
|
||||
matrix_uniform_up_to_date = false;
|
||||
gr_near_plane = z_near;
|
||||
}
|
||||
|
||||
void gr_end_proj_matrix() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/2d.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
extern transform_stack gr_model_matrix_stack;
|
||||
extern matrix4 gr_view_matrix;
|
||||
@@ -8,6 +9,7 @@ extern matrix4 gr_model_view_matrix;
|
||||
extern matrix4 gr_projection_matrix;
|
||||
extern matrix4 gr_last_projection_matrix;
|
||||
extern matrix4 gr_env_texture_matrix;
|
||||
extern float gr_near_plane;
|
||||
|
||||
void gr_matrix_on_frame();
|
||||
|
||||
@@ -15,7 +17,7 @@ void gr_start_instance_matrix(const vec3d* offset, const matrix* rotation);
|
||||
void gr_start_angles_instance_matrix(const vec3d* pos, const angles* rotation);
|
||||
void gr_end_instance_matrix();
|
||||
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far);
|
||||
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far);
|
||||
void gr_end_proj_matrix();
|
||||
|
||||
void gr_set_view_matrix(const vec3d* pos, const matrix* orient);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "libs/renderdoc/renderdoc.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "math/floating.h"
|
||||
#include "model/model.h"
|
||||
#include "options/Option.h"
|
||||
@@ -861,6 +862,9 @@ int opengl_init_display_device()
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_capture_mouse)
|
||||
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
|
||||
|
||||
auto viewport = gr_opengl_create_viewport(attrs);
|
||||
if (!viewport) {
|
||||
return 1;
|
||||
@@ -1177,7 +1181,7 @@ static void init_extensions() {
|
||||
|
||||
// we require a minimum GLSL version
|
||||
if (GLSL_version < MIN_REQUIRED_GLSL_VERSION) {
|
||||
Error(LOCATION, "Current GL Shading Langauge Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
|
||||
Error(LOCATION, "Current GL Shading Language Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
|
||||
}
|
||||
|
||||
GLint max_texture_units;
|
||||
@@ -1399,7 +1403,7 @@ bool gr_opengl_is_capable(gr_capability capability)
|
||||
case CAPABILITY_POST_PROCESSING:
|
||||
return Gr_post_processing_enabled && !Cmdline_no_fbo;
|
||||
case CAPABILITY_DEFERRED_LIGHTING:
|
||||
return !Cmdline_no_fbo && !Cmdline_no_deferred_lighting;
|
||||
return !Cmdline_no_fbo && light_deferred_enabled();
|
||||
case CAPABILITY_SHADOWS:
|
||||
case CAPABILITY_THICK_OUTLINE:
|
||||
return !Cmdline_no_geo_sdr_effects;
|
||||
|
||||
@@ -57,7 +57,7 @@ void opengl_clear_deferred_buffers()
|
||||
|
||||
void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs)
|
||||
{
|
||||
if ( Cmdline_no_deferred_lighting)
|
||||
if (!light_deferred_enabled())
|
||||
return;
|
||||
|
||||
static const float black[] = {0, 0, 0, 1.0f};
|
||||
@@ -149,7 +149,7 @@ void gr_opengl_deferred_lighting_msaa()
|
||||
opengl_set_generic_uniform_data<graphics::generic_data::msaa_data>(
|
||||
[&](graphics::generic_data::msaa_data* data) {
|
||||
data->samples = Cmdline_msaa_enabled;
|
||||
data->fov = Proj_fov;
|
||||
data->fov = g3_get_hfov(Proj_fov);
|
||||
});
|
||||
GL_state.SetAlphaBlendMode(gr_alpha_blend::ALPHA_BLEND_NONE);
|
||||
GL_state.SetZbufferType(ZBUFFER_TYPE_WRITE);
|
||||
@@ -181,7 +181,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
GR_DEBUG_SCOPE("Deferred lighting finish");
|
||||
TRACE_SCOPE(tracing::ApplyLights);
|
||||
|
||||
if (Cmdline_no_deferred_lighting) {
|
||||
if (!light_deferred_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
|
||||
header->invScreenWidth = 1.0f / gr_screen.max_w;
|
||||
header->invScreenHeight = 1.0f / gr_screen.max_h;
|
||||
header->nearPlane = gr_near_plane;
|
||||
|
||||
// Only the first directional light uses shaders so we need to know when we already saw that light
|
||||
bool first_directional = true;
|
||||
@@ -480,7 +481,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
data->noiseColorScale2 = std::get<1>(neb.getNoiseColorScale());
|
||||
data->noiseColorIntensity = neb.getNoiseColorIntensity();
|
||||
data->aspect = gr_screen.clip_aspect;
|
||||
data->fov = Proj_fov;
|
||||
data->fov = g3_get_hfov(Proj_fov);
|
||||
});
|
||||
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "render/3d.h"
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
@@ -673,7 +674,7 @@ void gr_opengl_scene_texture_begin()
|
||||
Scene_texture_v_scale = 1.0f;
|
||||
}
|
||||
|
||||
if ( Cmdline_no_deferred_lighting ) {
|
||||
if (!light_deferred_enabled()) {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
|
||||
@@ -398,7 +398,7 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote charaters.",
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote characters.",
|
||||
filename.c_str(),
|
||||
line_num);
|
||||
}
|
||||
|
||||
@@ -47,17 +47,19 @@ extern int GLOWMAP;
|
||||
extern int SPECMAP;
|
||||
extern int ENVMAP;
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> TextureFilteringValues = {{ 0, "Bilinear" },
|
||||
{ 1, "Trilinear" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> TextureFilteringValues = {{0, {"Bilinear", 1677}},
|
||||
{ 1, {"Trilinear", 1678}}};
|
||||
|
||||
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter", "Texture Filtering", "Texture filtering option")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(TextureFilteringValues)
|
||||
.default_val(0)
|
||||
.bind_to_once(&GL_mipmap_filter)
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.finish();
|
||||
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter",
|
||||
std::pair<const char*, int>{"Texture Filtering", 1763},
|
||||
std::pair<const char*, int>{"Texture filtering option", 1764})
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(TextureFilteringValues)
|
||||
.default_val(0)
|
||||
.bind_to_once(&GL_mipmap_filter)
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.finish();
|
||||
|
||||
static SCP_vector<float> anisotropic_value_enumerator()
|
||||
{
|
||||
@@ -100,16 +102,16 @@ static float anisotropic_default()
|
||||
return max;
|
||||
}
|
||||
|
||||
static auto AnisotropyOption =
|
||||
options::OptionBuilder<float>("Graphics.Anisotropy", "Anisotropic filtering",
|
||||
"Controls the amount of anisotropic filtering of the textures.")
|
||||
.enumerator(anisotropic_value_enumerator)
|
||||
.category("Graphics")
|
||||
.display(anisotropic_display)
|
||||
.default_func(anisotropic_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(78)
|
||||
.finish();
|
||||
static auto AnisotropyOption = options::OptionBuilder<float>("Graphics.Anisotropy",
|
||||
std::pair<const char*, int>{"Anistropic filtering", 1736},
|
||||
std::pair<const char*, int>{"Controls the amount of anistropic filtering of the textures", 1737})
|
||||
.enumerator(anisotropic_value_enumerator)
|
||||
.category("Graphics")
|
||||
.display(anisotropic_display)
|
||||
.default_func(anisotropic_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
// forward declarations
|
||||
int opengl_free_texture(tcache_slot_opengl *t);
|
||||
|
||||
@@ -974,7 +974,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
|
||||
data->srgb = High_dynamic_range ? 1 : 0;
|
||||
data->blend_alpha = material_info->get_blend_mode() != ALPHA_BLEND_ADDITIVE;
|
||||
|
||||
if (Cmdline_no_deferred_lighting) {
|
||||
if (!light_deferred_enabled()) {
|
||||
data->linear_depth = 0;
|
||||
} else {
|
||||
data->linear_depth = 1;
|
||||
@@ -984,7 +984,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
|
||||
Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
|
||||
Current_shader->program->Uniforms.setTextureUniform("depthMap", 1);
|
||||
|
||||
if (!Cmdline_no_deferred_lighting) {
|
||||
if (light_deferred_enabled()) {
|
||||
Assert(Scene_position_texture != 0);
|
||||
|
||||
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_position_texture);
|
||||
|
||||
@@ -40,27 +40,28 @@ PostEffectUniformType mapUniformNameToType(const SCP_string& uniform_name)
|
||||
// used by In-Game Options menu
|
||||
bool Post_processing_enable_lightshafts = true;
|
||||
|
||||
auto LightshaftsOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.Lightshafts", "Lightshafts", "Enable lightshafts (requires post-processing)")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Post_processing_enable_lightshafts)
|
||||
.importance(60)
|
||||
.finish();
|
||||
static auto LightshaftsOption __UNUSED = options::OptionBuilder<bool>("Graphics.Lightshafts",
|
||||
std::pair<const char*, int>{"Lightshafts", 1724},
|
||||
std::pair<const char*, int>{"Enables or disables lightshafts (requires post-processing)", 1725})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Post_processing_enable_lightshafts)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
int Post_processing_bloom_intensity = 25; // using default value of Cmdline_bloom_intensity
|
||||
|
||||
auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
|
||||
"Bloom intensity",
|
||||
"Set bloom intensity (requires post-processing)")
|
||||
.category("Graphics")
|
||||
.range(0, 200)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(25)
|
||||
.bind_to(&Post_processing_bloom_intensity)
|
||||
.importance(55)
|
||||
.finish();
|
||||
static auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
|
||||
std::pair<const char*, int>{"Bloom intensity", 1701},
|
||||
std::pair<const char*, int>{"Sets the bloom intensity (requires post-processing)", 1702})
|
||||
.category("Graphics")
|
||||
.range(0, 200)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(25)
|
||||
.bind_to(&Post_processing_bloom_intensity)
|
||||
.importance(55)
|
||||
.finish();
|
||||
} // namespace
|
||||
|
||||
bool PostProcessingManager::parse_table()
|
||||
@@ -223,7 +224,7 @@ bool gr_lightshafts_enabled()
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
return graphics::Post_processing_enable_lightshafts;
|
||||
return graphics::LightshaftsOption->getValue();
|
||||
} else {
|
||||
return !Cmdline_force_lightshaft_off;
|
||||
}
|
||||
@@ -240,7 +241,7 @@ int gr_bloom_intensity()
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
return graphics::Post_processing_bloom_intensity;
|
||||
return graphics::BloomIntensityOption->getValue();
|
||||
} else {
|
||||
return Cmdline_bloom_intensity;
|
||||
}
|
||||
|
||||
+57
-41
@@ -34,24 +34,20 @@ ShadowQuality Shadow_quality = ShadowQuality::Disabled;
|
||||
|
||||
bool Shadow_quality_uses_mod_option = false;
|
||||
|
||||
auto ShadowQualityOption =
|
||||
options::OptionBuilder<ShadowQuality>("Graphics.Shadows", "Shadow Quality", "The quality of the shadows")
|
||||
.values({{ShadowQuality::Disabled, "Disabled"},
|
||||
{ShadowQuality::Low, "Low"},
|
||||
{ShadowQuality::Medium, "Medium"},
|
||||
{ShadowQuality::High, "High"},
|
||||
{ShadowQuality::Ultra, "Ultra"}})
|
||||
.change_listener([](ShadowQuality val, bool initial) {
|
||||
if (initial) {
|
||||
Shadow_quality = val;
|
||||
}
|
||||
return initial; // No dynamic changes implemented
|
||||
})
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.category("Graphics")
|
||||
.default_val(ShadowQuality::Disabled)
|
||||
.importance(80)
|
||||
.finish();
|
||||
auto ShadowQualityOption = options::OptionBuilder<ShadowQuality>("Graphics.Shadows",
|
||||
std::pair<const char*, int>{"Shadow Quality", 1750},
|
||||
std::pair<const char*, int>{"The quality of the shadows", 1751})
|
||||
.values({{ShadowQuality::Disabled, {"Disabled", 1779}},
|
||||
{ShadowQuality::Low, {"Low", 1160}},
|
||||
{ShadowQuality::Medium, {"Medium", 1161}},
|
||||
{ShadowQuality::High, {"High", 1162}},
|
||||
{ShadowQuality::Ultra, {"Ultra", 1721}}})
|
||||
.change_listener([](ShadowQuality val, bool initial) {if (initial) {Shadow_quality = val;}return initial;})
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.category("Graphics")
|
||||
.default_val(ShadowQuality::Disabled)
|
||||
.importance(80)
|
||||
.finish();
|
||||
|
||||
bool shadows_obj_in_frustum(object *objp, matrix *light_orient, vec3d *min, vec3d *max)
|
||||
{
|
||||
@@ -222,14 +218,34 @@ void shadows_debug_show_frustum(matrix* orient, vec3d *pos, float fov, float asp
|
||||
g3_render_line_3d(true, &far_bottom_left, &far_top_left);
|
||||
}
|
||||
|
||||
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, float fov, float aspect, float z_near, float z_far)
|
||||
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, fov_t fov, float aspect, float z_near, float z_far)
|
||||
{
|
||||
// find the widths and heights of the near plane and far plane to determine the points of this frustum
|
||||
float near_height = tanf(fov * 0.5f) * z_near;
|
||||
float near_width = near_height * aspect;
|
||||
float near_l, near_r, near_u, near_d;
|
||||
float far_l, far_r, far_u, far_d;
|
||||
if (mpark::holds_alternative<float>(fov)) {
|
||||
near_d = tanf(mpark::get<float>(fov) * 0.5f) * z_near;
|
||||
near_u = -near_d;
|
||||
near_r = near_d * aspect;
|
||||
near_l = -near_r;
|
||||
|
||||
float far_height = tanf(fov * 0.5f) * z_far;
|
||||
float far_width = far_height * aspect;
|
||||
far_d = tanf(mpark::get<float>(fov) * 0.5f) * z_far;
|
||||
far_u = -far_d;
|
||||
far_r = far_d * aspect;
|
||||
far_l = -far_r;
|
||||
}
|
||||
else {
|
||||
const auto& afov = mpark::get<asymmetric_fov>(fov);
|
||||
near_d = tanf(-afov.down) * z_near;
|
||||
near_u = -tanf(afov.up) * z_near;
|
||||
near_r = tanf(-afov.left) * z_near;
|
||||
near_l = -tanf(afov.right) * z_near;
|
||||
|
||||
far_d = tanf(-afov.down) * z_far;
|
||||
far_u = -tanf(afov.up) * z_far;
|
||||
far_r = tanf(-afov.left) * z_far;
|
||||
far_l = -tanf(afov.right) * z_far;
|
||||
}
|
||||
|
||||
vec3d up_scale = ZERO_VECTOR;
|
||||
vec3d right_scale = ZERO_VECTOR;
|
||||
@@ -247,40 +263,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
|
||||
// near top left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -near_height);
|
||||
vm_vec_scale(&up_scale, near_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -near_width);
|
||||
vm_vec_scale(&right_scale, near_l);
|
||||
|
||||
vm_vec_add(&near_top_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_top_left, &forward_scale_near);
|
||||
|
||||
// near top right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -near_height);
|
||||
vm_vec_scale(&up_scale, near_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, near_width);
|
||||
vm_vec_scale(&right_scale, near_r);
|
||||
|
||||
vm_vec_add(&near_top_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_top_right, &forward_scale_near);
|
||||
|
||||
// near bottom left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, near_height);
|
||||
vm_vec_scale(&up_scale, near_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -near_width);
|
||||
vm_vec_scale(&right_scale, near_l);
|
||||
|
||||
vm_vec_add(&near_bottom_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_bottom_left, &forward_scale_near);
|
||||
|
||||
// near bottom right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, near_height);
|
||||
vm_vec_scale(&up_scale, near_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, near_width);
|
||||
vm_vec_scale(&right_scale, near_r);
|
||||
|
||||
vm_vec_add(&near_bottom_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_bottom_right, &forward_scale_near);
|
||||
@@ -292,40 +308,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
|
||||
// far top left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -far_height);
|
||||
vm_vec_scale(&up_scale, far_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -far_width);
|
||||
vm_vec_scale(&right_scale, far_l);
|
||||
|
||||
vm_vec_add(&far_top_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_top_left, &forward_scale_far);
|
||||
|
||||
// far top right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -far_height);
|
||||
vm_vec_scale(&up_scale, far_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, far_width);
|
||||
vm_vec_scale(&right_scale, far_r);
|
||||
|
||||
vm_vec_add(&far_top_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_top_right, &forward_scale_far);
|
||||
|
||||
// far bottom left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, far_height);
|
||||
vm_vec_scale(&up_scale, far_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -far_width);
|
||||
vm_vec_scale(&right_scale, far_l);
|
||||
|
||||
vm_vec_add(&far_bottom_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_bottom_left, &forward_scale_far);
|
||||
|
||||
// far bottom right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, far_height);
|
||||
vm_vec_scale(&up_scale, far_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, far_width);
|
||||
vm_vec_scale(&right_scale, far_r);
|
||||
|
||||
vm_vec_add(&far_bottom_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_bottom_right, &forward_scale_far);
|
||||
@@ -381,7 +397,7 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
shadows_construct_light_proj(shadow_data);
|
||||
}
|
||||
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
|
||||
{
|
||||
if(Static_light.empty())
|
||||
return vmd_identity_matrix;
|
||||
@@ -419,7 +435,7 @@ void shadows_end_render()
|
||||
gr_shadow_map_end();
|
||||
}
|
||||
|
||||
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
|
||||
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "object/object.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
#define MAX_SHADOW_CASCADES 4
|
||||
|
||||
@@ -38,11 +39,11 @@ extern bool Shadow_quality_uses_mod_option;
|
||||
extern matrix4 Shadow_proj_matrix[MAX_SHADOW_CASCADES];
|
||||
extern float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
|
||||
|
||||
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, float fov, float aspect, float z_near, float z_far);
|
||||
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, fov_t fov, float aspect, float z_near, float z_far);
|
||||
bool shadows_obj_in_frustum(object *objp, vec3d *min, vec3d *max, matrix *light_orient);
|
||||
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos);
|
||||
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos);
|
||||
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
|
||||
void shadows_end_render();
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace font
|
||||
{
|
||||
if (string[i] >= Lcl_special_chars || string[i] < 0)
|
||||
{
|
||||
// Special character needs to be handled seperately
|
||||
// Special character needs to be handled separately
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ struct deferred_global_data {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
float nearPlane;
|
||||
|
||||
float pad[2];
|
||||
float pad;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -321,6 +321,9 @@ bool VulkanRenderer::initDisplayDevice() const
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_capture_mouse)
|
||||
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
|
||||
|
||||
auto viewPort = m_graphicsOps->createViewport(attrs);
|
||||
if (!viewPort) {
|
||||
return false;
|
||||
|
||||
+29
-66
@@ -71,7 +71,7 @@ SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
|
||||
#define HUD_NEW_ALPHA_BRIGHT_HI 255
|
||||
|
||||
// Externals not related to the HUD code itself
|
||||
extern float View_zoom;
|
||||
extern fov_t View_zoom;
|
||||
|
||||
// globals that will control the color of the HUD gauges
|
||||
int HUD_color_red = 0;
|
||||
@@ -91,10 +91,6 @@ color HUD_color_debug; // grey debug text shown on HUD
|
||||
|
||||
static sound_handle Player_engine_snd_loop = sound_handle::invalid();
|
||||
|
||||
// HUD render frame offsets
|
||||
float HUD_offset_x = 0.0f;
|
||||
float HUD_offset_y = 0.0f;
|
||||
|
||||
// the offset of the player's view vector and the ship forward vector in pixels (Swifty)
|
||||
int HUD_nose_x;
|
||||
int HUD_nose_y;
|
||||
@@ -1033,8 +1029,8 @@ void HudGauge::renderCircle(int x, int y, int diameter, bool filled)
|
||||
|
||||
void HudGauge::setClip(int x, int y, int w, int h)
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
int hx = 0;
|
||||
int hy = 0;
|
||||
|
||||
if ( gr_screen.rendering_to_texture != -1 ) {
|
||||
gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
|
||||
@@ -1051,17 +1047,22 @@ void HudGauge::setClip(int x, int y, int w, int h)
|
||||
|
||||
gr_set_clip(hx, hy, w, h);
|
||||
} else {
|
||||
if ( reticle_follow ) {
|
||||
if (reticle_follow) {
|
||||
hx += HUD_nose_x;
|
||||
hy += HUD_nose_y;
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
gr_unsize_screen_pos(&hx, &hy);
|
||||
}
|
||||
else {
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
}
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
x += hx;
|
||||
y += hy;
|
||||
gr_resize_screen_pos(&x, &y, &w, &h);
|
||||
|
||||
gr_set_clip(hx+x, hy+y, w, h, GR_RESIZE_NONE);
|
||||
gr_set_clip(x, y, w, h, GR_RESIZE_NONE);
|
||||
}
|
||||
|
||||
gr_reset_screen_scale();
|
||||
@@ -1085,9 +1086,6 @@ void HudGauge::resetClip()
|
||||
|
||||
gr_set_clip(hx, hy, w, h);
|
||||
} else {
|
||||
hx = fl2i(HUD_offset_x);
|
||||
hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
|
||||
@@ -1778,8 +1776,8 @@ void HudGaugeMissionTime::render(float /*frametime*/)
|
||||
int minutes=0;
|
||||
int seconds=0;
|
||||
|
||||
mission_time = f2fl(Missiontime); // convert to seconds
|
||||
|
||||
mission_time = f2fl(Missiontime) + (float)The_mission.HUD_timer_padding; // convert to seconds
|
||||
|
||||
minutes=(int)(mission_time/60);
|
||||
seconds=(int)mission_time%60;
|
||||
|
||||
@@ -2021,7 +2019,7 @@ void hud_damage_popup_init()
|
||||
Damage_flash_timer = 1;
|
||||
|
||||
for ( i = 0; i < SUBSYSTEM_MAX; i++ ) {
|
||||
Pl_hud_subsys_info[i].last_str = 1000.0f;
|
||||
Pl_hud_subsys_info[i].last_str = 1.0f;
|
||||
Pl_hud_subsys_info[i].flash_duration_timestamp = 1;
|
||||
Pl_hud_next_flash_timestamp = 1;
|
||||
Pl_hud_is_bright = 0;
|
||||
@@ -2076,6 +2074,11 @@ void HudGaugeDamage::initLineHeight(int h)
|
||||
line_h = h;
|
||||
}
|
||||
|
||||
void HudGaugeDamage::initDisplayValue(bool value)
|
||||
{
|
||||
always_display = value;
|
||||
}
|
||||
|
||||
void HudGaugeDamage::initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom)
|
||||
{
|
||||
damage_top.first_frame = bm_load_animation(fname_top, &damage_top.num_frames);
|
||||
@@ -2136,7 +2139,7 @@ void HudGaugeDamage::render(float /*frametime*/)
|
||||
for ( pss = GET_FIRST(&Player_ship->subsys_list); pss !=END_OF_LIST(&Player_ship->subsys_list); pss = GET_NEXT(pss) ) {
|
||||
psub = pss->system_info;
|
||||
strength = ship_get_subsystem_strength(Player_ship, psub->type);
|
||||
if ( strength < 1 ) {
|
||||
if ( always_display || strength < 1 ) {
|
||||
// display the actual health of this specific subsystem --wookieejedi
|
||||
if (pss->max_hits > 0) {
|
||||
// get percentage if this subsystem has hitpoints to begin with
|
||||
@@ -2273,7 +2276,7 @@ void HudGaugeDamage::render(float /*frametime*/)
|
||||
// Show hull integrity if it's below 100% or if a subsystem is damaged
|
||||
// The second case is just to make the display look complete
|
||||
// The third case is there to make the gauge appear only if needed if the right option is set
|
||||
if ( screen_integrity < 100 || !info_lines.empty() ) {
|
||||
if ( always_display || screen_integrity < 100 || !info_lines.empty() ) {
|
||||
DamageInfo info;
|
||||
|
||||
info.name = XSTR( "Hull Integrity", 220);
|
||||
@@ -3746,42 +3749,8 @@ int hud_objective_notify_active()
|
||||
* @param wiggedy_wack
|
||||
* @param eye_orient
|
||||
*/
|
||||
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient)
|
||||
void HUD_set_offsets()
|
||||
{
|
||||
if ( (viewer_obj == Player_obj) && wiggedy_wack ){
|
||||
vec3d tmp;
|
||||
vertex pt;
|
||||
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
|
||||
vm_vec_scale_add( &tmp, &Eye_position, &eye_orient->vec.fvec, 100.0f );
|
||||
|
||||
(void) g3_rotate_vertex(&pt,&tmp);
|
||||
|
||||
g3_project_vertex(&pt);
|
||||
|
||||
gr_unsize_screen_posf( &pt.screen.xyw.x, &pt.screen.xyw.y );
|
||||
HUD_offset_x -= 0.45f * (i2fl(gr_screen.clip_width_unscaled)*0.5f - pt.screen.xyw.x);
|
||||
HUD_offset_y -= 0.45f * (i2fl(gr_screen.clip_height_unscaled)*0.5f - pt.screen.xyw.y);
|
||||
|
||||
if ( HUD_offset_x > 100.0f ) {
|
||||
HUD_offset_x = 100.0f;
|
||||
} else if ( HUD_offset_x < -100.0f ) {
|
||||
HUD_offset_x += 100.0f;
|
||||
}
|
||||
|
||||
if ( HUD_offset_y > 100.0f ) {
|
||||
HUD_offset_y = 100.0f;
|
||||
} else if ( HUD_offset_y < -100.0f ) {
|
||||
HUD_offset_y += 100.0f;
|
||||
}
|
||||
|
||||
} else {
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
}
|
||||
|
||||
if ( Viewer_mode & ( VM_TOPDOWN | VM_CHASE ) ) {
|
||||
HUD_nose_x = 0;
|
||||
HUD_nose_y = 0;
|
||||
@@ -3845,10 +3814,7 @@ void HUD_get_nose_coordinates(int *x, int *y)
|
||||
*/
|
||||
void HUD_reset_clip()
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_set_clip(hx, hy, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
|
||||
gr_set_clip(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3856,10 +3822,7 @@ void HUD_reset_clip()
|
||||
*/
|
||||
void HUD_set_clip(int x, int y, int w, int h)
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_set_clip(hx+x, hy+y, w, h);
|
||||
gr_set_clip(x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3869,7 +3832,7 @@ void HUD_set_clip(int x, int y, int w, int h)
|
||||
void hud_save_restore_camera_data(int save)
|
||||
{
|
||||
static vec3d save_view_position;
|
||||
static float save_view_zoom;
|
||||
static fov_t save_view_zoom;
|
||||
static matrix save_view_matrix;
|
||||
static matrix save_eye_matrix;
|
||||
static vec3d save_eye_position;
|
||||
@@ -4135,7 +4098,7 @@ void HudGaugeSupernova::render(float /*frametime*/)
|
||||
}
|
||||
|
||||
HudGaugeFlightPath::HudGaugeFlightPath():
|
||||
HudGauge(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+23
-4
@@ -129,7 +129,7 @@ void hud_render_gauges(int cockpit_display_num = -1);
|
||||
void hud_stop_looped_engine_sounds();
|
||||
|
||||
// set the offset values for this render frame
|
||||
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient);
|
||||
void HUD_set_offsets();
|
||||
// returns the offset between the player's view vector and the forward vector of the ship in pixels (Swifty)
|
||||
void HUD_get_nose_coordinates(int *x, int *y);
|
||||
|
||||
@@ -277,7 +277,7 @@ public:
|
||||
void initOriginAndOffset(float originX, float originY, int offsetX, int offsetY);
|
||||
void initCoords(bool use_coords, int coordsX, int coordsY);
|
||||
|
||||
void initSlew(bool slew);
|
||||
virtual void initSlew(bool slew);
|
||||
void initCockpitTarget(const char* display_name, int _target_x, int _target_y, int _target_w, int _target_h, int _canvas_w, int _canvas_h);
|
||||
void initRenderStatus(bool render);
|
||||
|
||||
@@ -362,6 +362,21 @@ public:
|
||||
void resetClip();
|
||||
};
|
||||
|
||||
//Use this instead of HudGauge whenever you have a HudGauge that is anchored in 3D-space (i.e. takes its rendering coordinates from g3_rotate/project_vertex, as these MUST NEVER slew.
|
||||
class HudGauge3DAnchor : public HudGauge {
|
||||
|
||||
public:
|
||||
HudGauge3DAnchor()
|
||||
: HudGauge() { }
|
||||
HudGauge3DAnchor(int _gauge_object, int _gauge_config, bool /*_slew*/, bool _message, int _disabled_views, int r, int g, int b)
|
||||
: HudGauge(_gauge_object, _gauge_config, false, _message, _disabled_views, r, g, b) { }
|
||||
// constructor for custom gauges
|
||||
HudGauge3DAnchor(int _gauge_config, bool /*_slew*/, int r, int g, int b, char* _custom_name, char* _custom_text, char* frame_fname, int txtoffset_x, int txtoffset_y)
|
||||
: HudGauge(_gauge_config, false, r, g, b, _custom_name, _custom_text, frame_fname, txtoffset_x, txtoffset_y) { }
|
||||
|
||||
void initSlew(bool /*slew*/) override {};
|
||||
};
|
||||
|
||||
class HudGaugeMissionTime: public HudGauge // HUD_MISSION_TIME
|
||||
{
|
||||
hud_frames time_gauge;
|
||||
@@ -492,7 +507,10 @@ protected:
|
||||
|
||||
int next_flash;
|
||||
bool flash_status;
|
||||
public:
|
||||
|
||||
bool always_display;
|
||||
|
||||
public:
|
||||
HudGaugeDamage();
|
||||
void initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom);
|
||||
void initHeaderOffsets(int x, int y);
|
||||
@@ -503,6 +521,7 @@ public:
|
||||
void initSubsysIntegValueOffsetX(int x);
|
||||
void initBottomBgOffset(int offset);
|
||||
void initLineHeight(int h);
|
||||
void initDisplayValue(bool value);
|
||||
void render(float frametime) override;
|
||||
void pageIn() override;
|
||||
void initialize() override;
|
||||
@@ -562,7 +581,7 @@ public:
|
||||
void render(float frametime) override;
|
||||
};
|
||||
|
||||
class HudGaugeFlightPath: public HudGauge
|
||||
class HudGaugeFlightPath: public HudGauge3DAnchor
|
||||
{
|
||||
hud_frames Marker;
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsy
|
||||
}
|
||||
|
||||
HudGaugeBrackets::HudGaugeBrackets():
|
||||
HudGauge(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void draw_brackets_diamond_quick(graphics::line_draw_list* draw_list, int x1, in
|
||||
|
||||
int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsys, int min_width, int min_height, bool draw = true, bool set_color = true, int* draw_coords = NULL);
|
||||
|
||||
class HudGaugeBrackets: public HudGauge
|
||||
class HudGaugeBrackets: public HudGauge3DAnchor
|
||||
{
|
||||
protected:
|
||||
int attacking_dot;
|
||||
|
||||
@@ -1266,7 +1266,7 @@ void hud_config_button_do(int n)
|
||||
|
||||
case HCB_SAVE_HCF:
|
||||
int exists;
|
||||
char *out;
|
||||
const char *out;
|
||||
|
||||
// get the text in the input control
|
||||
exists = 0;
|
||||
@@ -1658,10 +1658,6 @@ void hud_config_as_observer(ship *shipp,ai_info *aif)
|
||||
// store the current hud
|
||||
hud_config_backup();
|
||||
|
||||
// bash these values so the HUD is not offset incorrectly
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
|
||||
// initialize the observer HUD
|
||||
hud_observer_init(shipp,aif);
|
||||
}
|
||||
@@ -1708,10 +1704,9 @@ void hud_config_color_load(const char *name)
|
||||
{
|
||||
int idx;
|
||||
char str[1024];
|
||||
char *fname;
|
||||
ubyte r, g, b, a;
|
||||
|
||||
fname = cf_add_ext(name, ".hcf");
|
||||
const char *fname = cf_add_ext(name, ".hcf");
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
+13
-7
@@ -125,19 +125,25 @@ void update_ets(object* objp, float fl_frametime)
|
||||
// This will translate to 71% max speed at 50% engines, and 31% max speed at 10% engines
|
||||
//
|
||||
|
||||
float eng_current_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
|
||||
float engine_aggregate_strength;
|
||||
if (ship_p->flags[Ship::Ship_Flags::Maneuver_despite_engines]) {
|
||||
// Pretend our strength is 100% when this flag is active
|
||||
engine_aggregate_strength = 1.0f;
|
||||
} else {
|
||||
engine_aggregate_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
|
||||
}
|
||||
|
||||
// only update max speed if aggregate engine health has changed
|
||||
// which helps minimze amount of overrides to max speed
|
||||
if (eng_current_strength != ship_p->prev_engine_aggregate_strength) {
|
||||
// only update max speed if engine_aggregate_strength has changed
|
||||
// which helps minimize amount of overrides to max speed
|
||||
if (engine_aggregate_strength != ship_p->prev_engine_aggregate_strength) {
|
||||
ets_update_max_speed(objp);
|
||||
ship_p->prev_engine_aggregate_strength = eng_current_strength;
|
||||
ship_p->prev_engine_aggregate_strength = engine_aggregate_strength;
|
||||
|
||||
// check if newly updated max speed should be reduced due to engine damage
|
||||
// don't let engine strength affect max speed when playing on lowest skill level
|
||||
if ((objp != Player_obj) || (Game_skill_level > 0)) {
|
||||
if (eng_current_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
|
||||
objp->phys_info.max_vel.xyz.z *= fl_sqrt(eng_current_strength);
|
||||
if (engine_aggregate_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
|
||||
objp->phys_info.max_vel.xyz.z *= fl_sqrt(engine_aggregate_strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ void hud_init_missile_lock()
|
||||
}
|
||||
|
||||
HudGaugeLock::HudGaugeLock():
|
||||
HudGauge(HUD_OBJECT_LOCK, HUD_LEAD_INDICATOR, false, false, VM_DEAD_VIEW, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_LOCK, HUD_LEAD_INDICATOR, false, false, VM_DEAD_VIEW, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ void hud_do_lock_indicators(float frametime);
|
||||
void hud_stop_looped_locking_sounds();
|
||||
void hud_lock_reset(float lock_time_scale=1.0f);
|
||||
|
||||
class HudGaugeLock: public HudGauge
|
||||
class HudGaugeLock: public HudGauge3DAnchor
|
||||
{
|
||||
protected:
|
||||
hud_anim Lock_gauge;
|
||||
|
||||
+36
-6
@@ -444,6 +444,10 @@ void HudGaugeMessages::render(float /*frametime*/)
|
||||
// dependant on max_width, max_lines, and line_height
|
||||
setClip(position[0], position[1], Window_width, Window_height+2);
|
||||
|
||||
//Since setClip already sets makes drawing local, further renderings mustn't additionally slew
|
||||
bool doSlew = reticle_follow;
|
||||
reticle_follow = false;
|
||||
|
||||
for ( SCP_vector<Hud_display_info>::iterator m = active_messages.begin(); m != active_messages.end(); ++m) {
|
||||
if ( !timestamp_elapsed(m->total_life) ) {
|
||||
if ( !(Player->flags & PLAYER_FLAGS_MSG_MODE) || !Hidden_by_comms_menu) {
|
||||
@@ -459,6 +463,8 @@ void HudGaugeMessages::render(float /*frametime*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reticle_follow = doSlew;
|
||||
}
|
||||
|
||||
// Similar to HUD printf, but shows only one message at a time, at a fixed location.
|
||||
@@ -874,6 +880,7 @@ void hud_scrollback_init()
|
||||
// pause all game sounds
|
||||
weapon_pause_sounds();
|
||||
audiostream_pause_all();
|
||||
message_pause_all();
|
||||
|
||||
hud_initialize_scrollback_lines();
|
||||
|
||||
@@ -934,6 +941,7 @@ void hud_scrollback_close()
|
||||
// unpause all game sounds
|
||||
weapon_unpause_sounds();
|
||||
audiostream_unpause_all();
|
||||
message_resume_all();
|
||||
|
||||
}
|
||||
|
||||
@@ -1180,19 +1188,41 @@ void HudGaugeTalkingHead::render(float frametime)
|
||||
// hud_set_default_color();
|
||||
setGaugeColor();
|
||||
|
||||
int tablePosX = position[0];
|
||||
int tablePosY = position[1];
|
||||
if (reticle_follow && gr_screen.rendering_to_texture == -1) {
|
||||
int nx = HUD_nose_x;
|
||||
int ny = HUD_nose_y;
|
||||
|
||||
gr_resize_screen_pos(&nx, &ny);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
gr_unsize_screen_pos(&nx, &ny);
|
||||
gr_reset_screen_scale();
|
||||
|
||||
tablePosX += nx;
|
||||
tablePosY += ny;
|
||||
}
|
||||
|
||||
// clear
|
||||
setClip(position[0] + Anim_offsets[0], position[1] + Anim_offsets[1], Anim_size[0], Anim_size[1]);
|
||||
gr_clear();
|
||||
resetClip();
|
||||
|
||||
//renderBitmap is slew corrected, so use uncorrected position
|
||||
renderBitmap(Head_frame.first_frame, position[0], position[1]); // head ani border
|
||||
float scale_x = i2fl(Anim_size[0]) / i2fl(head_anim->width);
|
||||
float scale_y = i2fl(Anim_size[1]) / i2fl(head_anim->height);
|
||||
gr_set_screen_scale(fl2ir(base_w / scale_x), fl2ir(base_h / scale_y));
|
||||
setGaugeColor();
|
||||
generic_anim_render(head_anim,frametime, fl2ir((position[0] + Anim_offsets[0] + HUD_offset_x) / scale_x), fl2ir((position[1] + Anim_offsets[1] + HUD_offset_y) / scale_y));
|
||||
|
||||
int hx = tablePosX + Anim_offsets[0];
|
||||
int hy = tablePosY + Anim_offsets[1];
|
||||
|
||||
if (gr_screen.rendering_to_texture != -1)
|
||||
gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
|
||||
else
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
|
||||
generic_anim_render_ex(head_anim,frametime, hx, hy, Anim_size[0], Anim_size[1]);
|
||||
gr_reset_screen_scale();
|
||||
|
||||
// draw title
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
renderString(position[0] + Header_offsets[0], position[1] + Header_offsets[1], XSTR("message", 217));
|
||||
} else {
|
||||
for (int j = 0; j < Num_messages_playing; ++j) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#define MAX_HUD_LINE_LEN 256 // maximum number of characters for a HUD message
|
||||
|
||||
// If these are changed, the lua 'addMessageToScrollback' method in mission.cpp should be updated.
|
||||
#define HUD_SOURCE_COMPUTER 0
|
||||
#define HUD_SOURCE_TRAINING 1
|
||||
#define HUD_SOURCE_HIDDEN 2
|
||||
|
||||
@@ -4143,6 +4143,7 @@ void load_gauge_damage(gauge_settings* settings)
|
||||
char fname_top[MAX_FILENAME_LEN] = "damage1";
|
||||
char fname_middle[MAX_FILENAME_LEN] = "damage2";
|
||||
char fname_bottom[MAX_FILENAME_LEN] = "damage3";
|
||||
bool always_display = false;
|
||||
|
||||
settings->origin[0] = 0.5f;
|
||||
settings->origin[1] = 0.0f;
|
||||
@@ -4200,6 +4201,9 @@ void load_gauge_damage(gauge_settings* settings)
|
||||
if(optional_string("Bottom Background Offset:")) {
|
||||
stuff_int(&bottom_bg_offset);
|
||||
}
|
||||
if(optional_string("Always Display:")) {
|
||||
stuff_boolean(&always_display);
|
||||
}
|
||||
|
||||
hud_gauge->initBitmaps(fname_top, fname_middle, fname_bottom);
|
||||
hud_gauge->initHullIntegOffsets(hull_integ_offsets[0], hull_integ_offsets[1]);
|
||||
@@ -4210,6 +4214,7 @@ void load_gauge_damage(gauge_settings* settings)
|
||||
hud_gauge->initSubsysIntegValueOffsetX(subsys_integ_val_offset_x);
|
||||
hud_gauge->initBottomBgOffset(bottom_bg_offset);
|
||||
hud_gauge->initHeaderOffsets(header_offsets[0], header_offsets[1]);
|
||||
hud_gauge->initDisplayValue(always_display);
|
||||
|
||||
gauge_assign_common(settings, std::move(hud_gauge));
|
||||
}
|
||||
|
||||
+7
-10
@@ -365,8 +365,8 @@ void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_off
|
||||
if (!Shield_mini_loaded)
|
||||
return;
|
||||
|
||||
sx = (x_force == -1) ? Shield_mini_coords[gr_screen.res][0]+fl2i(HUD_offset_x) : x_force;
|
||||
sy = (y_force == -1) ? Shield_mini_coords[gr_screen.res][1]+fl2i(HUD_offset_y) : y_force;
|
||||
sx = (x_force == -1) ? Shield_mini_coords[gr_screen.res][0] : x_force;
|
||||
sy = (y_force == -1) ? Shield_mini_coords[gr_screen.res][1] : y_force;
|
||||
|
||||
// draw the ship first
|
||||
hud_shield_maybe_flash(HUD_TARGET_MINI_ICON, SHIELD_HIT_TARGET, Shield_hit_data[SHIELD_HIT_TARGET].hull_hit_index);
|
||||
@@ -596,9 +596,6 @@ void HudGaugeShield::showShields(object *objp, int mode)
|
||||
sx = position[0];
|
||||
sy = position[1];
|
||||
|
||||
sx += fl2i(HUD_offset_x);
|
||||
sy += fl2i(HUD_offset_y);
|
||||
|
||||
// draw the ship first
|
||||
maybeFlashShield(SHIELD_HIT_PLAYER, Shield_hit_data[SHIELD_HIT_PLAYER].hull_hit_index);
|
||||
|
||||
@@ -635,7 +632,7 @@ void HudGaugeShield::showShields(object *objp, int mode)
|
||||
g3_set_view_matrix( &finger_vec, &vmd_identity_matrix, 1.0f);
|
||||
}*/
|
||||
|
||||
gr_set_proj_matrix(0.5f*Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
|
||||
gr_set_proj_matrix(Proj_fov * 0.5f, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
|
||||
gr_set_view_matrix(&Eye_position, &Eye_matrix);
|
||||
|
||||
//We're ready to show stuff
|
||||
@@ -971,8 +968,8 @@ void HudGaugeShieldMini::showMiniShields(object *objp)
|
||||
|
||||
setGaugeColor();
|
||||
|
||||
sx = position[0]+fl2i(HUD_offset_x);
|
||||
sy = position[1]+fl2i(HUD_offset_y);
|
||||
sx = position[0];
|
||||
sy = position[1];
|
||||
|
||||
// draw the ship first
|
||||
maybeFlashShield(SHIELD_HIT_TARGET, Shield_hit_data[SHIELD_HIT_TARGET].hull_hit_index);
|
||||
@@ -1061,8 +1058,8 @@ void HudGaugeShieldMini::showIntegrity(float p_target_integrity)
|
||||
}
|
||||
}
|
||||
|
||||
final_pos[0] += fl2i( HUD_offset_x ) + position[0];
|
||||
final_pos[1] += fl2i( HUD_offset_y ) + position[1];
|
||||
final_pos[0] += position[0];
|
||||
final_pos[1] += position[1];
|
||||
|
||||
sprintf(text_integrity, "%d", numeric_integrity);
|
||||
if ( numeric_integrity < 100 ) {
|
||||
|
||||
+91
-100
@@ -105,32 +105,15 @@ typedef struct mmode_item {
|
||||
SCP_string text; // text to display on the menu
|
||||
} mmode_item;
|
||||
|
||||
#define MAX_MENU_ITEMS 50 // max number of items in the menu
|
||||
#define MAX_MENU_DISPLAY 10 // max number that can be displayed
|
||||
|
||||
char Squad_msg_title[256] = "";
|
||||
mmode_item MsgItems[MAX_MENU_ITEMS];
|
||||
int Num_menu_items = -1; // number of items for a message menu
|
||||
int First_menu_item= -1; // index of first item in the menu
|
||||
|
||||
// -----------
|
||||
// following set of vars/defines are used to store/restore key bindings for keys that
|
||||
// are used in messaging mode
|
||||
|
||||
// array to temporarily store key bindings that will be in use for the messaging
|
||||
// system
|
||||
typedef struct key_store {
|
||||
int option_num; // which element in the Control_config array is this
|
||||
int id; // which id (1 or 2) is this key.
|
||||
int key_value; // which key value to put there.
|
||||
} key_store;
|
||||
SCP_string Lua_sqd_msg_cat;
|
||||
|
||||
#define MAX_KEYS_NO_SCROLL 10
|
||||
#define MAX_KEYS_USED 12 // maximum number of keys used for the messaging system
|
||||
|
||||
key_store key_save[MAX_KEYS_USED]; // array to save the key information during messaging mode
|
||||
int num_keys_saved = 0; // number of keys that are saved.
|
||||
|
||||
// next array is the array of MAX_KEYS_USED size which are the keys to use for messaging mode
|
||||
|
||||
int keys_used[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
|
||||
@@ -139,17 +122,6 @@ int keys_used[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_
|
||||
#define ID1 1
|
||||
#define ID2 2
|
||||
|
||||
// following are defines and character strings that are used as part of messaging mode
|
||||
|
||||
#define NUM_COMM_ORDER_TYPES 6
|
||||
|
||||
#define TYPE_SHIP_ITEM 0
|
||||
#define TYPE_WING_ITEM 1
|
||||
#define TYPE_ALL_FIGHTERS_ITEM 2
|
||||
#define TYPE_REINFORCEMENT_ITEM 3
|
||||
#define TYPE_REPAIR_REARM_ITEM 4
|
||||
#define TYPE_REPAIR_REARM_ABORT_ITEM 5
|
||||
|
||||
|
||||
SCP_string Comm_order_types[NUM_COMM_ORDER_TYPES];
|
||||
|
||||
@@ -242,18 +214,8 @@ void hud_squadmsg_start()
|
||||
}
|
||||
}
|
||||
|
||||
// int i;
|
||||
|
||||
//if ( num_keys_saved < 0 ) // save the keys if they haven't been saved yet
|
||||
hud_squadmsg_save_keys();
|
||||
|
||||
Msg_key = -1;
|
||||
|
||||
/*
|
||||
for (i=0; i<num_keys_saved; i++)
|
||||
clear_key_binding ( (short) key_save[i].key_value ); // removes all mention of this key from Control_config
|
||||
*/
|
||||
|
||||
Num_menu_items = -1; // reset the menu items
|
||||
First_menu_item = 0;
|
||||
Squad_msg_mode = SM_MODE_TYPE_SELECT; // start off at the base state
|
||||
@@ -274,7 +236,7 @@ void hud_squadmsg_start()
|
||||
}
|
||||
}
|
||||
|
||||
// functions which will restore all of the key binding stuff when messaging mode is done
|
||||
// function which will clean things up when messaging mode is done
|
||||
void hud_squadmsg_end()
|
||||
{
|
||||
if (scripting::hooks::OnHudCommMenuClosed->isActive())
|
||||
@@ -287,17 +249,6 @@ void hud_squadmsg_end()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
int i;
|
||||
key_store *ksp;
|
||||
|
||||
// move through all keys saved and restore their orignal values.
|
||||
for ( i=0; i<num_keys_saved; i++ ) {
|
||||
ksp = &key_save[i];
|
||||
Control_config[ksp->option_num].key_id = (short) ksp->key_value;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( message_is_playing() == FALSE )
|
||||
snd_play( gamesnd_get_game_sound(GameSounds::SQUADMSGING_OFF) );
|
||||
|
||||
@@ -426,10 +377,6 @@ int hud_squadmsg_count_ships(int add_to_menu)
|
||||
}
|
||||
}
|
||||
|
||||
// if adding to the menu and we have > 10 items, then don't allow page up and page down to be used.
|
||||
if ( add_to_menu && (Num_menu_items > MAX_MENU_DISPLAY) )
|
||||
hud_squadmsg_save_keys(1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -616,7 +563,7 @@ int hud_squadmsg_get_key()
|
||||
|
||||
// use a timestamp to prevent top level key code from possibly reprocessing this key
|
||||
Msg_eat_key_timestamp = timestamp(MSG_KEY_EAT_TIME);
|
||||
if ( k == KEY_PAGEDOWN ) { // pageup and pagedown scroll the menu -- deal with these seperately!!
|
||||
if ( k == KEY_PAGEDOWN ) { // pageup and pagedown scroll the menu -- deal with these separately!!
|
||||
hud_squadmsg_page_down();
|
||||
return -1;
|
||||
} else if ( k == KEY_PAGEUP ) {
|
||||
@@ -1147,7 +1094,7 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
|
||||
Objects[ainfo->target_objnum].flags.remove(Object::Object_Flags::Protected);
|
||||
}
|
||||
|
||||
ai_mode = AI_GOAL_DISABLE_SHIP;
|
||||
ai_mode = (The_mission.ai_profile->flags[AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable]) ? AI_GOAL_DISABLE_SHIP_TACTICAL : AI_GOAL_DISABLE_SHIP;
|
||||
ai_submode = -SUBSYSTEM_ENGINE;
|
||||
message = MESSAGE_DISABLE_TARGET;
|
||||
break;
|
||||
@@ -1161,7 +1108,7 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
|
||||
Objects[ainfo->target_objnum].flags.remove(Object::Object_Flags::Protected);
|
||||
}
|
||||
|
||||
ai_mode = AI_GOAL_DISARM_SHIP;
|
||||
ai_mode = (The_mission.ai_profile->flags[AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable]) ? AI_GOAL_DISARM_SHIP_TACTICAL : AI_GOAL_DISARM_SHIP;
|
||||
ai_submode = -SUBSYSTEM_TURRET;
|
||||
message = MESSAGE_DISARM_TARGET;
|
||||
break;
|
||||
@@ -1433,7 +1380,7 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
|
||||
Assert(target_shipname);
|
||||
Assert(wing_team != target_team);
|
||||
|
||||
ai_mode = AI_GOAL_DISABLE_SHIP;
|
||||
ai_mode = (The_mission.ai_profile->flags[AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable]) ? AI_GOAL_DISABLE_SHIP_TACTICAL : AI_GOAL_DISABLE_SHIP;
|
||||
ai_submode = -SUBSYSTEM_ENGINE;
|
||||
message = MESSAGE_DISABLE_TARGET;
|
||||
break;
|
||||
@@ -1442,7 +1389,7 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
|
||||
Assert(target_shipname);
|
||||
Assert(wing_team != target_team);
|
||||
|
||||
ai_mode = AI_GOAL_DISARM_SHIP;
|
||||
ai_mode = (The_mission.ai_profile->flags[AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable]) ? AI_GOAL_DISARM_SHIP_TACTICAL : AI_GOAL_DISARM_SHIP;
|
||||
ai_submode = -SUBSYSTEM_TURRET;
|
||||
message = MESSAGE_DISARM_TARGET;
|
||||
break;
|
||||
@@ -1630,13 +1577,26 @@ void hud_squadmsg_type_select( )
|
||||
{
|
||||
int k, i;
|
||||
|
||||
int num_order_types = NUM_COMM_ORDER_TYPES;
|
||||
|
||||
int lua_order_count = 0;
|
||||
|
||||
// Now get a list of all lua categories to add. Meow.
|
||||
SCP_vector<SCP_string> lua_cat_list = ai_lua_get_general_order_categories();
|
||||
|
||||
num_order_types += (int)lua_cat_list.size();
|
||||
|
||||
// Add the items
|
||||
for (i = 0; i < NUM_COMM_ORDER_TYPES; i++)
|
||||
for (i = 0; i < num_order_types; i++)
|
||||
{
|
||||
MsgItems[i].text = Comm_order_types[i];
|
||||
if (i < NUM_COMM_ORDER_TYPES) {
|
||||
MsgItems[i].text = Comm_order_types[i];
|
||||
} else {
|
||||
MsgItems[i].text = lua_cat_list[i - NUM_COMM_ORDER_TYPES];
|
||||
}
|
||||
MsgItems[i].active = 1; // assume active
|
||||
}
|
||||
Num_menu_items = NUM_COMM_ORDER_TYPES;
|
||||
Num_menu_items = num_order_types;
|
||||
|
||||
|
||||
// check to see if the player is a traitor. If so, then he will not
|
||||
@@ -1667,6 +1627,13 @@ void hud_squadmsg_type_select( )
|
||||
MsgItems[TYPE_REPAIR_REARM_ITEM].active = 1; // this item will always be available (I think)
|
||||
MsgItems[TYPE_REPAIR_REARM_ABORT_ITEM].active = 0;
|
||||
|
||||
for(const auto& cat : lua_cat_list){
|
||||
if (ai_lua_get_general_orders(false, false, cat).size() == 0) {
|
||||
MsgItems[NUM_COMM_ORDER_TYPES + lua_order_count].active = 0;
|
||||
}
|
||||
lua_order_count++;
|
||||
}
|
||||
|
||||
// AL: 10/13/97
|
||||
// If the player ship communications are severely damaged, then the player
|
||||
// will only be able to call for repair/rearm ships
|
||||
@@ -1734,6 +1701,9 @@ do_main_menu:
|
||||
hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM );
|
||||
} else if ( k == TYPE_REPAIR_REARM_ABORT_ITEM ) {
|
||||
hud_squadmsg_do_mode( SM_MODE_REPAIR_REARM_ABORT );
|
||||
} else if (k >= NUM_COMM_ORDER_TYPES) {
|
||||
Lua_sqd_msg_cat = lua_cat_list[k - NUM_COMM_ORDER_TYPES];
|
||||
hud_squadmsg_do_mode( SM_MODE_GENERAL );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2078,6 +2048,60 @@ void hud_squadmsg_ship_command()
|
||||
}
|
||||
}
|
||||
|
||||
void hud_squadmsg_msg_general()
|
||||
{
|
||||
int k;
|
||||
|
||||
Num_menu_items = 0;
|
||||
for (size_t order_id = 0; order_id < Player_orders.size(); order_id++) {
|
||||
Assert(Num_menu_items < MAX_MENU_ITEMS);
|
||||
|
||||
if (Player_orders[order_id].lua_id <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto lua_porder = ai_lua_find_player_order(Player_orders[order_id].lua_id);
|
||||
|
||||
//If it's not a general order then do not add it.
|
||||
if (!lua_porder->generalOrder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//If it's not part of the selected category then do not add it.
|
||||
if (lua_porder->category != Lua_sqd_msg_cat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Only add it if it is enabled for the mission
|
||||
if (lua_porder->cur_enabled) {
|
||||
|
||||
MsgItems[Num_menu_items].text = Player_orders[order_id].localized_name;
|
||||
MsgItems[Num_menu_items].instance = Player_orders[order_id].lua_id;
|
||||
MsgItems[Num_menu_items].active = (int)lua_porder->cur_valid;
|
||||
|
||||
// do some other checks to possibly gray out other items.
|
||||
// if no target, remove any items which are associated with the players target
|
||||
if (!hud_squadmsg_is_target_order_valid(order_id, nullptr))
|
||||
MsgItems[Num_menu_items].active = 0;
|
||||
|
||||
Num_menu_items++;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy_s(Squad_msg_title, XSTR("What Command", 321));
|
||||
k = hud_squadmsg_get_key();
|
||||
|
||||
// when we get a valid goal, we must add the goal to the ai ship's goal list
|
||||
|
||||
if (k != -1) {
|
||||
Assert(k < Num_menu_items);
|
||||
|
||||
ai_lua_start_general(MsgItems[k].instance, Player_ai->target_objnum);
|
||||
|
||||
hud_squadmsg_toggle();
|
||||
}
|
||||
}
|
||||
|
||||
// function to display list of command for a wing
|
||||
void hud_squadmsg_wing_command()
|
||||
{
|
||||
@@ -2163,43 +2187,6 @@ void hud_squadmsg_wing_command()
|
||||
//----------------------------------------------------------
|
||||
// external entry points below!!!!
|
||||
|
||||
// when starting messaging mode, we must remove old bindings from the
|
||||
// keys that are used for messaging mode (which will get restored when
|
||||
// messaging mode is done).
|
||||
|
||||
// this code below will get called only the key config changes (from ControlsConfig.cpp)
|
||||
// or if the bindings haven't been saved yet. This code doesn't remove the bindings
|
||||
// but just sets up the array so that the bindings can be removed when messaging
|
||||
// mode is entered.
|
||||
//
|
||||
// do_scroll indicates whether we should save the page up and page down keys
|
||||
void hud_squadmsg_save_keys( int /*do_scroll*/ )
|
||||
{
|
||||
// int i, j;
|
||||
|
||||
num_keys_saved = 0;
|
||||
|
||||
/*
|
||||
for ( j=0; j<MAX_KEYS_USED; j++ ) {
|
||||
for ( i=0; Control_config[i].text[0]; i++ ) { // the text field in this structure is empty at the end of the config list
|
||||
if ( Control_config[i].key_id == keys_used[j] ) { // this is true if we have a match
|
||||
|
||||
// if we are not saving scrolling keys and we are trying to match page up and page down
|
||||
// then skip them.
|
||||
if ( !do_scroll && ((keys_used[j] == KEY_PAGEDOWN) || (keys_used[j] == KEY_PAGEUP)) )
|
||||
continue;
|
||||
|
||||
Assert( num_keys_saved < MAX_KEYS_USED );
|
||||
key_save[num_keys_saved].option_num = i;
|
||||
key_save[num_keys_saved].key_value = keys_used[j];
|
||||
num_keys_saved++;
|
||||
break; // done with this key -- move to next.
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// function is called once per mission start. Initializes those values
|
||||
// which only need to be inited once per mission.
|
||||
void hud_init_squadmsg( void )
|
||||
@@ -2414,6 +2401,10 @@ int hud_squadmsg_do_frame( )
|
||||
hud_squadmsg_msg_all_fighters();
|
||||
break;
|
||||
|
||||
case SM_MODE_GENERAL:
|
||||
hud_squadmsg_msg_general();
|
||||
break;
|
||||
|
||||
default:
|
||||
Int3(); // get allender -- invalid mode in messaging system
|
||||
break;
|
||||
|
||||
+15
-1
@@ -24,6 +24,7 @@
|
||||
#define SM_MODE_REPAIR_REARM 7 //repair/rearm player ship
|
||||
#define SM_MODE_REPAIR_REARM_ABORT 8 //abort repair/rearm of player ship
|
||||
#define SM_MODE_ALL_FIGHTERS 9 //message all fighters/bombers
|
||||
#define SM_MODE_GENERAL 10 //general orders, usually luaAI
|
||||
|
||||
// define for trapping messages send to "all fighters"
|
||||
#define MESSAGE_ALL_FIGHTERS -999
|
||||
@@ -60,6 +61,20 @@ class object;
|
||||
// used for Message box gauge
|
||||
#define NUM_MBOX_FRAMES 3
|
||||
|
||||
#define MAX_MENU_ITEMS 50 // max number of items in the menu
|
||||
#define MAX_MENU_DISPLAY 10 // max number that can be displayed
|
||||
|
||||
// following are defines and character strings that are used as part of messaging mode
|
||||
|
||||
#define NUM_COMM_ORDER_TYPES 6
|
||||
|
||||
#define TYPE_SHIP_ITEM 0
|
||||
#define TYPE_WING_ITEM 1
|
||||
#define TYPE_ALL_FIGHTERS_ITEM 2
|
||||
#define TYPE_REINFORCEMENT_ITEM 3
|
||||
#define TYPE_REPAIR_REARM_ITEM 4
|
||||
#define TYPE_REPAIR_REARM_ABORT_ITEM 5
|
||||
|
||||
typedef struct player_order {
|
||||
private:
|
||||
//Needed, because legacy order-id's were not assigned in order
|
||||
@@ -140,7 +155,6 @@ extern void hud_init_comm_orders();
|
||||
extern void hud_squadmsg_toggle(); // toggles the state of messaging mode
|
||||
extern void hud_squadmsg_shortcut( int command ); // use of a shortcut key
|
||||
extern int hud_squadmsg_hotkey_select( int k ); // a hotkey was hit -- maybe send a message to those ship(s)
|
||||
extern void hud_squadmsg_save_keys( int do_scroll = 0 ); // saves into local area keys which need to be saved/restored when in messaging mode
|
||||
extern int hud_squadmsg_do_frame();
|
||||
extern int hud_query_order_issued(const char *to, const char *order_name, const char *target = nullptr, int timestamp = 0, const char *from = nullptr, const char *special_index = nullptr);
|
||||
extern int hud_squadmsg_read_key( int k ); // called from high level keyboard code
|
||||
|
||||
+61
-36
@@ -2073,7 +2073,7 @@ bool evaluate_ship_as_closest_target(esct *esct_p)
|
||||
}
|
||||
|
||||
// bail if harmless
|
||||
if ( Ship_info[esct_p->shipp->ship_info_index].class_type > -1 && !(Ship_types[Ship_info[esct_p->shipp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::Target_as_threat])) {
|
||||
if ( Ship_info[esct_p->shipp->ship_info_index].class_type < 0 || !(Ship_types[Ship_info[esct_p->shipp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::Target_as_threat])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2758,18 +2758,12 @@ void HudGaugeOrientationTee::renderOrientation(object *from_objp, object *to_obj
|
||||
y1 += position[1];
|
||||
x1 += position[0];
|
||||
|
||||
x1 += HUD_offset_x;
|
||||
y1 += HUD_offset_y;
|
||||
|
||||
y2 = sinf(dot_product) * (Radius - T_OFFSET_FROM_CIRCLE - T_LENGTH);
|
||||
x2 = cosf(dot_product) * (Radius - T_OFFSET_FROM_CIRCLE - T_LENGTH);
|
||||
|
||||
y2 += position[1];
|
||||
x2 += position[0];
|
||||
|
||||
x2 += HUD_offset_x;
|
||||
y2 += HUD_offset_y;
|
||||
|
||||
x3 = x1 - T_BASE_LENGTH * sinf(dot_product);
|
||||
y3 = y1 + T_BASE_LENGTH * cosf(dot_product);
|
||||
x4 = x1 + T_BASE_LENGTH * sinf(dot_product);
|
||||
@@ -2983,6 +2977,7 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
|
||||
float ang;
|
||||
float xpos,ypos,cur_dist,sin_ang,cos_ang;
|
||||
int draw_inside=0;
|
||||
int tablePosX, tablePosY;
|
||||
|
||||
// determine if the given object is within the targeting reticle
|
||||
// (which means the triangle is not drawn)
|
||||
@@ -2992,6 +2987,24 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
|
||||
g3_rotate_vertex(&hostile_vertex, hostile_pos);
|
||||
g3_project_vertex(&hostile_vertex);
|
||||
|
||||
if (reticle_follow) {
|
||||
int nx = HUD_nose_x;
|
||||
int ny = HUD_nose_y;
|
||||
|
||||
gr_resize_screen_pos(&nx, &ny);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
gr_unsize_screen_pos(&nx, &ny);
|
||||
gr_reset_screen_scale();
|
||||
|
||||
tablePosX = position[0] + nx;
|
||||
tablePosY = position[1] + ny;
|
||||
}
|
||||
else {
|
||||
//Technically not non-slewing, but keeps old behaviour
|
||||
tablePosX = position[0] + fl2i(HUD_nose_x);
|
||||
tablePosY = position[1] + fl2i(HUD_nose_y);
|
||||
}
|
||||
|
||||
if (hostile_vertex.codes == 0) { // on screen
|
||||
int projected_x, projected_y;
|
||||
|
||||
@@ -3003,8 +3016,8 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
|
||||
|
||||
unsize(&projected_x, &projected_y);
|
||||
|
||||
mag_squared = (projected_x - position[0]) * (projected_x - position[0]) +
|
||||
(projected_y - position[1]) * (projected_y - position[1]);
|
||||
mag_squared = (projected_x - tablePosX) * (projected_x - tablePosX) +
|
||||
(projected_y - tablePosY) * (projected_y - tablePosY);
|
||||
|
||||
if ( mag_squared < Radius*Radius ) {
|
||||
if ( show_interior ) {
|
||||
@@ -3016,28 +3029,21 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
|
||||
}
|
||||
}
|
||||
|
||||
int HUD_nose_scaled_x = HUD_nose_x;
|
||||
int HUD_nose_scaled_y = HUD_nose_y;
|
||||
// even if the screen position overflowed, it will still be pointing in the correct direction
|
||||
unsize( &hostile_vertex.screen.xyw.x, &hostile_vertex.screen.xyw.y );
|
||||
|
||||
gr_resize_screen_pos(&HUD_nose_scaled_x, &HUD_nose_scaled_y);
|
||||
|
||||
unsize( &hostile_vertex.world.xyz.x, &hostile_vertex.world.xyz.y );
|
||||
|
||||
ang = atan2_safe(hostile_vertex.world.xyz.y,hostile_vertex.world.xyz.x);
|
||||
ang = atan2_safe(-(hostile_vertex.screen.xyw.y - tablePosY), hostile_vertex.screen.xyw.x - tablePosX);
|
||||
sin_ang=sinf(ang);
|
||||
cos_ang=cosf(ang);
|
||||
|
||||
if ( draw_inside ) {
|
||||
xpos = position[0] + cos_ang*(Radius-7);
|
||||
ypos = position[1] - sin_ang*(Radius-7);
|
||||
xpos = tablePosX + cos_ang*(Radius-7);
|
||||
ypos = tablePosY - sin_ang*(Radius-7);
|
||||
} else {
|
||||
xpos = position[0] + cos_ang*(Radius+4);
|
||||
ypos = position[1] - sin_ang*(Radius+4);
|
||||
xpos = tablePosX + cos_ang*(Radius+4);
|
||||
ypos = tablePosY - sin_ang*(Radius+4);
|
||||
}
|
||||
|
||||
xpos += HUD_offset_x + HUD_nose_x;
|
||||
ypos += HUD_offset_y + HUD_nose_y;
|
||||
|
||||
if ( split_tri ) {
|
||||
// renderTriangleMissileSplit(ang, xpos, ypos, cur_dist, aspect_flag, draw_inside);
|
||||
renderTriangleMissileTail(ang, xpos, ypos, cur_dist, aspect_flag, draw_inside);
|
||||
@@ -3577,8 +3583,8 @@ void hud_show_hostile_triangle()
|
||||
continue;
|
||||
}
|
||||
|
||||
// always ignore cargo containers and navbuoys
|
||||
if ( Ship_info[sp->ship_info_index].class_type > -1 && !(Ship_types[Ship_info[sp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::Show_attack_direction]) ) {
|
||||
// always ignore cargo containers, navbouys, etc, and non-ships
|
||||
if ( Ship_info[sp->ship_info_index].class_type < 0 || !(Ship_types[Ship_info[sp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::Show_attack_direction]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3818,7 +3824,7 @@ void polish_predicted_target_pos(weapon_info *wip, object *targetp, vec3d *enemy
|
||||
}
|
||||
|
||||
HudGaugeLeadIndicator::HudGaugeLeadIndicator():
|
||||
HudGauge(HUD_OBJECT_LEAD, HUD_LEAD_INDICATOR, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_OTHER_SHIP, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_LEAD, HUD_LEAD_INDICATOR, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_OTHER_SHIP, 255, 255, 255)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -4249,11 +4255,32 @@ void HudGaugeLeadSight::renderSight(int frame_offset, vec3d *target_pos, vec3d *
|
||||
float reticle_target_sx = target_sx - Lead_sight_half[0] - target_lead_sx;
|
||||
float reticle_target_sy = target_sy - Lead_sight_half[1] - target_lead_sy;
|
||||
|
||||
reticle_target_sx += position[0] + 0.5f;
|
||||
reticle_target_sy += position[1] + 0.5f;
|
||||
int tablePosX = position[0];
|
||||
int tablePosY = position[1];
|
||||
|
||||
bool do_slew = reticle_follow;
|
||||
if (do_slew) {
|
||||
int nx = HUD_nose_x;
|
||||
int ny = HUD_nose_y;
|
||||
|
||||
gr_resize_screen_pos(&nx, &ny);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
gr_unsize_screen_pos(&nx, &ny);
|
||||
gr_reset_screen_scale();
|
||||
|
||||
tablePosX += nx;
|
||||
tablePosY += ny;
|
||||
}
|
||||
|
||||
reticle_target_sx += tablePosX + 0.5f;
|
||||
reticle_target_sy += tablePosY + 0.5f;
|
||||
|
||||
setGaugeColor();
|
||||
renderBitmap(Lead_sight.first_frame + frame_offset, fl2i(reticle_target_sx) + fl2i(HUD_offset_x), fl2i(reticle_target_sy) + fl2i(HUD_offset_y));
|
||||
|
||||
//We need to do slewing manually only on the non-3D-dependant part of the hud, so make the rendering function believe that we don't slew
|
||||
reticle_follow = false;
|
||||
renderBitmap(Lead_sight.first_frame + frame_offset, fl2i(reticle_target_sx), fl2i(reticle_target_sy));
|
||||
reticle_follow = do_slew;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6364,7 +6391,7 @@ void hud_target_clear_display_list()
|
||||
}
|
||||
|
||||
HudGaugeOffscreen::HudGaugeOffscreen():
|
||||
HudGauge(HUD_OBJECT_OFFSCREEN, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW | VM_OTHER_SHIP, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_OFFSCREEN, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW | VM_OTHER_SHIP, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6495,11 +6522,9 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
|
||||
codes_or = (ubyte)(target_point->codes | eye_vertex->codes);
|
||||
clip_line(&target_point,&eye_vertex,codes_or,0);
|
||||
|
||||
if (!(target_point->flags&PF_PROJECTED))
|
||||
g3_project_vertex(target_point);
|
||||
g3_project_vertex(target_point);
|
||||
|
||||
if (!(eye_vertex->flags&PF_PROJECTED))
|
||||
g3_project_vertex(eye_vertex);
|
||||
g3_project_vertex(eye_vertex);
|
||||
|
||||
if (eye_vertex->flags&PF_OVERFLOW) {
|
||||
Int3(); // This is unlikely to happen, but can if a clip goes through the player's eye.
|
||||
@@ -7416,8 +7441,8 @@ void HudGaugeHardpoints::render(float /*frametime*/)
|
||||
|
||||
//unsize(&xc, &yc);
|
||||
//unsize(&draw_point.screen.xyw.x, &draw_point.screen.xyw.y);
|
||||
|
||||
renderCircle((int)draw_point.screen.xyw.x + position[0], (int)draw_point.screen.xyw.y + position[1], 10);
|
||||
if (!(draw_point.flags & PF_OVERFLOW))
|
||||
renderCircle((int)draw_point.screen.xyw.x + position[0], (int)draw_point.screen.xyw.y + position[1], 10);
|
||||
//renderCircle(xc, yc, 25);
|
||||
} else {
|
||||
model_render_params weapon_render_info;
|
||||
|
||||
@@ -543,7 +543,7 @@ public:
|
||||
void render(float frametime) override;
|
||||
};
|
||||
|
||||
class HudGaugeOffscreen: public HudGauge
|
||||
class HudGaugeOffscreen: public HudGauge3DAnchor
|
||||
{
|
||||
protected:
|
||||
float Max_offscreen_tri_seperation;
|
||||
@@ -562,7 +562,7 @@ public:
|
||||
void pageIn() override;
|
||||
};
|
||||
|
||||
class HudGaugeLeadIndicator: public HudGauge
|
||||
class HudGaugeLeadIndicator: public HudGauge3DAnchor
|
||||
{
|
||||
protected:
|
||||
hud_frames Lead_indicator_gauge;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
extern float View_zoom;
|
||||
extern fov_t View_zoom;
|
||||
|
||||
int Target_window_coords[GR_NUM_RESOLUTIONS][4] =
|
||||
{
|
||||
@@ -524,7 +524,7 @@ void HudGaugeTargetBox::renderTargetIntegrity(int disabled,int force_obj_num)
|
||||
}
|
||||
}
|
||||
|
||||
void HudGaugeTargetBox::renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, float zoom)
|
||||
void HudGaugeTargetBox::renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, fov_t zoom)
|
||||
{
|
||||
// JAS: g3_start_frame uses clip_width and clip_height to determine the
|
||||
// size to render to. Normally, you would set this by using gr_set_clip,
|
||||
@@ -943,7 +943,7 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
vm_vec_sub(&obj_pos, &viewed_obj->pos, &viewer_obj->pos);
|
||||
}
|
||||
|
||||
renderTargetSetup(&camera_eye, &camera_orient, View_zoom/3);
|
||||
renderTargetSetup(&camera_eye, &camera_orient, View_zoom * (1.0f/3.0f));
|
||||
model_clear_instance(viewed_model_num);
|
||||
|
||||
model_render_params render_info;
|
||||
@@ -1269,7 +1269,7 @@ void HudGaugeTargetBox::renderTargetJumpNode(object *target_objp)
|
||||
matrix camera_orient = IDENTITY_MATRIX;
|
||||
vec3d orient_vec, up_vector;
|
||||
float factor, dist;
|
||||
int hx, hy, w, h;
|
||||
int hx = 0, hy = 0, w, h;
|
||||
SCP_list<CJumpNode>::iterator jnp;
|
||||
|
||||
for (jnp = Jump_nodes.begin(); jnp != Jump_nodes.end(); ++jnp) {
|
||||
@@ -1329,10 +1329,6 @@ void HudGaugeTargetBox::renderTargetJumpNode(object *target_objp)
|
||||
dist = dist * Hud_unit_multiplier;
|
||||
}
|
||||
|
||||
// account for hud shaking
|
||||
hx = fl2i(HUD_offset_x);
|
||||
hy = fl2i(HUD_offset_y);
|
||||
|
||||
sprintf(outstr,XSTR( "d: %.0f", 340), dist);
|
||||
hud_num_make_mono(outstr, font_num);
|
||||
gr_get_string_size(&w,&h,outstr);
|
||||
@@ -2111,19 +2107,13 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
break;
|
||||
}
|
||||
|
||||
int hx, hy;
|
||||
|
||||
// Account for HUD shaking
|
||||
hx = fl2i(HUD_offset_x);
|
||||
hy = fl2i(HUD_offset_y);
|
||||
|
||||
// print out the target distance and speed
|
||||
sprintf(outstr,XSTR( "d: %.0f%s", 350), displayed_target_distance, modifiers[Player_ai->current_target_dist_trend]);
|
||||
|
||||
hud_num_make_mono(outstr, font_num);
|
||||
gr_get_string_size(&w,&h,outstr);
|
||||
|
||||
renderString(position[0] + Dist_offsets[0]+hx, position[1] + Dist_offsets[1]+hy, EG_TBOX_DIST, outstr);
|
||||
renderString(position[0] + Dist_offsets[0], position[1] + Dist_offsets[1], EG_TBOX_DIST, outstr);
|
||||
|
||||
#if 0
|
||||
current_target_speed = vm_vec_dist(&target_objp->pos, &target_objp->last_pos) / frametime;
|
||||
@@ -2151,7 +2141,7 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
sprintf(outstr, XSTR( "s: %.0f%s", 351), displayed_target_speed, (displayed_target_speed>1)?modifiers[Player_ai->current_target_speed_trend]:"");
|
||||
hud_num_make_mono(outstr, font_num);
|
||||
|
||||
renderString(position[0] + Speed_offsets[0]+hx, position[1] + Speed_offsets[1]+hy, EG_TBOX_SPEED, outstr);
|
||||
renderString(position[0] + Speed_offsets[0], position[1] + Speed_offsets[1], EG_TBOX_SPEED, outstr);
|
||||
|
||||
//
|
||||
// output target info for debug purposes only, this will be removed later
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
void renderTargetDebris(object *target_objp);
|
||||
void renderTargetAsteroid(object *target_objp);
|
||||
void renderTargetJumpNode(object *target_objp);
|
||||
void renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, float zoom);
|
||||
void renderTargetSetup(vec3d *camera_eye, matrix *camera_orient, fov_t zoom);
|
||||
void renderTargetClose();
|
||||
void renderTargetForeground();
|
||||
void renderTargetIntegrity(int disabled, int force_obj_num = -1);
|
||||
|
||||
+52
-44
@@ -238,53 +238,61 @@ SCP_vector<Joystick*> joystick_enumerator()
|
||||
* Joystick options for the new menu system
|
||||
* These should be displayed as a dropdown box type widget
|
||||
*/
|
||||
auto JoystickOption = options::OptionBuilder<Joystick*>("Input.Joystick", "Joystick", "The current joystick 0.")
|
||||
.category("Input") // Category this option shows up in the scripting heirachy
|
||||
.deserializer(joystick_deserialize) // callback for json to C++
|
||||
.serializer(joystick_serializer) // callback for C++ to json
|
||||
.display(joystick_display) // callback for constructing the display label
|
||||
.enumerator(joystick_enumerator) // callback for enumerating/constructing the values this option may take
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr) // initial/default value for this option
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.importance(3)
|
||||
.finish();
|
||||
auto JoystickOption = options::OptionBuilder<Joystick*>("Input.Joystick",
|
||||
std::pair<const char*, int>{"Joystick 0", 1705},
|
||||
std::pair<const char*, int>{"The current joystick 0", 1706})
|
||||
.category("Input") // Category this option shows up in the scripting heirachy
|
||||
.deserializer(joystick_deserialize) // callback for json to C++
|
||||
.serializer(joystick_serializer) // callback for C++ to json
|
||||
.display(joystick_display) // callback for constructing the display label
|
||||
.enumerator(joystick_enumerator) // callback for enumerating/constructing the values this option may take
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr) // initial/default value for this option
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.importance(3)
|
||||
.finish();
|
||||
|
||||
auto JoystickOption1 = options::OptionBuilder<Joystick*>("Input.Joystick1", "Joystick1", "The current joystick 1.")
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
auto JoystickOption1 = options::OptionBuilder<Joystick*>("Input.Joystick1",
|
||||
std::pair<const char*, int>{"Joystick 1", 1707},
|
||||
std::pair<const char*, int>{"The current joystick 1", 1708})
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
|
||||
auto JoystickOption2 = options::OptionBuilder<Joystick*>("Input.Joystick2", "Joystick2", "The current joystick 2.")
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
auto JoystickOption2 = options::OptionBuilder<Joystick*>("Input.Joystick2",
|
||||
std::pair<const char*, int>{"Joystick 2", 1709},
|
||||
std::pair<const char*, int>{"The current joystick 2", 1710})
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
|
||||
auto JoystickOption3 = options::OptionBuilder<Joystick*>("Input.Joystick3", "Joystick3", "The current joystick 3.")
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
auto JoystickOption3 = options::OptionBuilder<Joystick*>("Input.Joystick3",
|
||||
std::pair<const char*, int>{"Joystick 3", 1711},
|
||||
std::pair<const char*, int>{"The current joystick 3", 1712})
|
||||
.category("Input")
|
||||
.deserializer(joystick_deserialize)
|
||||
.serializer(joystick_serializer)
|
||||
.display(joystick_display)
|
||||
.enumerator(joystick_enumerator)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(nullptr)
|
||||
.flags({ options::OptionFlags::ForceMultiValueSelection })
|
||||
.importance(3)
|
||||
.finish();
|
||||
|
||||
HatPosition convertSDLHat(int val)
|
||||
{
|
||||
|
||||
+22
-19
@@ -46,27 +46,30 @@ static haptic_effect_t pDeathroll1;
|
||||
static haptic_effect_t pDeathroll2;
|
||||
static haptic_effect_t pExplode;
|
||||
|
||||
static auto ForceFeedbackOption =
|
||||
options::OptionBuilder<bool>("Input.ForceFeedback", "Force Feedback", "Enable or disable force feedback.")
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.finish();
|
||||
static auto ForceFeedbackOption = options::OptionBuilder<bool>("Input.ForceFeedback",
|
||||
std::pair<const char*, int>{"Force Feedback", 1728},
|
||||
std::pair<const char*, int>{"Enable or disable force feedback", 1729})
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.finish();
|
||||
|
||||
static auto HitEffectOption =
|
||||
options::OptionBuilder<bool>("Input.HitEffect", "Directional Hit", "Enable or disable the directional hit effect.")
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.finish();
|
||||
static auto HitEffectOption = options::OptionBuilder<bool>("Input.HitEffect",
|
||||
std::pair<const char*, int>{"Directional Hit", 1730},
|
||||
std::pair<const char*, int>{"Enable or disable the directional hit effect", 1731})
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.finish();
|
||||
|
||||
static auto ForceFeedbackStrength = options::OptionBuilder<float>("Input.FFStrength", "Force Feedback Strength",
|
||||
"The relative strength of Force Feedback effects.")
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.range(0, 100)
|
||||
.default_val(100)
|
||||
.finish();
|
||||
static auto ForceFeedbackStrength = options::OptionBuilder<float>("Input.FFStrength",
|
||||
std::pair<const char*, int>{"Force Feedback Strength", 1756},
|
||||
std::pair<const char*, int>{"The realtive strength of Force Feedback effects", 1757})
|
||||
.category("Input")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.range(0, 100)
|
||||
.default_val(100)
|
||||
.finish();
|
||||
|
||||
static int joy_ff_create_effects();
|
||||
static int joy_ff_has_valid_effects();
|
||||
|
||||
+20
-11
@@ -166,6 +166,8 @@ void factor_table::resize(size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
// Cyborg -- You may see a linter or coverity complain about this function, since it basically discards a lot of the result of the float division.
|
||||
// But using modulo division instead is actually about 60% slower based on some quick testing I did, and it gives the same results.
|
||||
bool factor_table::isNaturalNumberFactor(size_t factor, size_t n)
|
||||
{
|
||||
return ((float)n / (float)factor) == n / factor;
|
||||
@@ -641,7 +643,7 @@ extern int Framerate_delay;
|
||||
|
||||
extern vec3d Eye_position;
|
||||
extern matrix Eye_matrix;
|
||||
extern void g3_set_view_matrix(const vec3d *view_pos, const matrix *view_matrix, float zoom);
|
||||
extern void g3_set_view_matrix(const vec3d *view_pos, const matrix *view_matrix, fov_t zoom);
|
||||
|
||||
extern int Show_cpu;
|
||||
|
||||
@@ -873,13 +875,17 @@ void process_debug_keys(int k)
|
||||
|
||||
do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, Player_ai->targeted_subsys->system_info->subobj_num, (float) -Player_ai->targeted_subsys->system_info->type, NULL); //100.0f);
|
||||
|
||||
if ( sp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f ) {
|
||||
mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
|
||||
sp->flags.set(Ship::Ship_Flags::Disabled); // add the disabled flag
|
||||
if ( Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_ENGINE ) {
|
||||
if ( sp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f ) {
|
||||
mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
|
||||
sp->flags.set(Ship::Ship_Flags::Disabled); // add the disabled flag
|
||||
}
|
||||
}
|
||||
|
||||
if ( sp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f ) {
|
||||
mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
|
||||
if ( Player_ai->targeted_subsys->system_info->type == SUBSYSTEM_TURRET ) {
|
||||
if ( sp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f ) {
|
||||
mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1320,7 +1326,7 @@ void process_debug_keys(int k)
|
||||
break;
|
||||
}
|
||||
cam->set_fov(cam->get_fov() + 0.1f);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov raised to %0.2f" , cam->get_fov());
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov raised to %0.2f" , g3_get_hfov(cam->get_fov()));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1334,7 +1340,7 @@ void process_debug_keys(int k)
|
||||
break;
|
||||
}
|
||||
cam->set_fov(cam->get_fov() - 0.1f);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov lowered to %0.2f" , cam->get_fov());
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Camera fov lowered to %0.2f" , g3_get_hfov(cam->get_fov()));
|
||||
}
|
||||
break;
|
||||
case KEY_DEBUGGED + KEY_Z:
|
||||
@@ -1511,7 +1517,8 @@ void game_do_end_mission_popup()
|
||||
game_stop_time();
|
||||
game_stop_looped_sounds();
|
||||
audiostream_pause_all();
|
||||
snd_stop_all();
|
||||
weapon_pause_sounds();
|
||||
message_pause_all();
|
||||
|
||||
pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
|
||||
choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
|
||||
@@ -1532,6 +1539,8 @@ void game_do_end_mission_popup()
|
||||
game_start_subspace_ambient_sound();
|
||||
}
|
||||
audiostream_unpause_all();
|
||||
weapon_unpause_sounds();
|
||||
message_resume_all();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1831,7 +1840,7 @@ int button_function_critical(int n, net_player *p = NULL)
|
||||
}
|
||||
|
||||
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
|
||||
if (ship_select_next_primary(objp, CYCLE_PRIMARY_NEXT)) {
|
||||
if (ship_select_next_primary(objp, CycleDirection::NEXT)) {
|
||||
ship* shipp = &Ships[objp->instance];
|
||||
if ( timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank]) ) {
|
||||
shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(BANK_SWITCH_DELAY); // 1/4 second delay until can fire
|
||||
@@ -1852,7 +1861,7 @@ int button_function_critical(int n, net_player *p = NULL)
|
||||
}
|
||||
|
||||
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
|
||||
if (ship_select_next_primary(objp, CYCLE_PRIMARY_PREV)) {
|
||||
if (ship_select_next_primary(objp, CycleDirection::PREV)) {
|
||||
ship* shipp = &Ships[objp->instance];
|
||||
if ( timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank]) ) {
|
||||
shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(BANK_SWITCH_DELAY); // 1/4 second delay until can fire
|
||||
|
||||
+21
-18
@@ -56,28 +56,31 @@ int Mouse_dz = 0;
|
||||
|
||||
int Mouse_sensitivity = 4;
|
||||
|
||||
static auto MouseSensitivityOption __UNUSED =
|
||||
options::OptionBuilder<int>("Input.MouseSensitivity", "Sensitivity", "The sentitivity of the mouse input.")
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(4)
|
||||
.bind_to(&Mouse_sensitivity)
|
||||
.importance(0)
|
||||
.finish();
|
||||
static auto MouseSensitivityOption __UNUSED = options::OptionBuilder<int>("Input.MouseSensitivity",
|
||||
std::pair<const char*, int>{"Sensitivity", 1374},
|
||||
std::pair<const char*, int>{"The sensitivity of the mouse input", 1747})
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(4)
|
||||
.bind_to(&Mouse_sensitivity)
|
||||
.importance(0)
|
||||
.finish();
|
||||
|
||||
bool Use_mouse_to_fly = false;
|
||||
|
||||
static SCP_string mouse_mode_display(bool mode) { return mode ? "Joy-0" : "Mouse"; }
|
||||
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", "Mouse", "Use the mouse for flying")
|
||||
.category("Input")
|
||||
.display(mouse_mode_display)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.bind_to(&Use_mouse_to_fly)
|
||||
.importance(1)
|
||||
.finish();
|
||||
static auto UseMouseOption __UNUSED = options::OptionBuilder<bool>("Input.UseMouse",
|
||||
std::pair<const char*, int>{"Mouse", 1376},
|
||||
std::pair<const char*, int>{"Whether or not to use the mouse for flying", 1765})
|
||||
.category("Input")
|
||||
.display(mouse_mode_display)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(false)
|
||||
.bind_to(&Use_mouse_to_fly)
|
||||
.importance(1)
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::Hook<>> OnMouseWheelHook = scripting::Hook<>::Factory(
|
||||
"On Mouse Wheel", "Called when the mouse wheel is moved in any direction.",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "math/vecmat.h"
|
||||
#include "model/modelrender.h"
|
||||
#include "render/3d.h"
|
||||
#include "options/Option.h"
|
||||
|
||||
|
||||
SCP_vector<light> Lights;
|
||||
@@ -100,6 +101,29 @@ DCF(light,"Changes lighting parameters")
|
||||
}
|
||||
}
|
||||
|
||||
// used by In-Game Options menu
|
||||
static bool DeferredLightingEnabled = true;
|
||||
|
||||
static auto DeferredLightingOption = options::OptionBuilder<bool>("Graphics.DeferredLighting",
|
||||
std::pair<const char*, int>{"Deferred Lighting", 1782},
|
||||
std::pair<const char*, int>{"Enables or disables deferred lighting", 1783})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&DeferredLightingEnabled)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
|
||||
bool light_deferred_enabled()
|
||||
{
|
||||
if (Using_in_game_options) {
|
||||
return DeferredLightingOption->getValue();
|
||||
} else {
|
||||
return !Cmdline_no_deferred_lighting;
|
||||
}
|
||||
}
|
||||
|
||||
void light_reset()
|
||||
{
|
||||
Static_light.clear();
|
||||
|
||||
@@ -114,4 +114,6 @@ extern int light_get_global_count();
|
||||
extern int light_get_global_dir(vec3d *pos, int n);
|
||||
|
||||
bool light_compare_by_type(const light &a, const light &b);
|
||||
|
||||
bool light_deferred_enabled();
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "playerman/player.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
#include <tl/optional.hpp>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// LOCALIZE DEFINES/VARS
|
||||
@@ -62,7 +63,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 1675
|
||||
// #define XSTR_SIZE 1784 // This is the next available ID
|
||||
|
||||
|
||||
// struct to allow for strings.tbl-determined x offset
|
||||
@@ -481,6 +482,35 @@ void parse_tstringstbl(const char *filename)
|
||||
parse_stringstbl_common(filename, true);
|
||||
}
|
||||
|
||||
struct xstr_delayed_order {
|
||||
SCP_string& toFill;
|
||||
const char* name;
|
||||
int xstr;
|
||||
};
|
||||
|
||||
static void lcl_delayed_xstr_internal(tl::optional<xstr_delayed_order> to_init) {
|
||||
static SCP_vector<xstr_delayed_order> delayed_init;
|
||||
|
||||
if (to_init) {
|
||||
if (Xstr_inited)
|
||||
to_init->toFill = XSTR(to_init->name, to_init->xstr);
|
||||
else
|
||||
delayed_init.emplace_back(std::move(*to_init));
|
||||
}
|
||||
else {
|
||||
Assertion(Xstr_inited, "Tried to resolve delayed XSTR before XSTR init!");
|
||||
|
||||
for (const auto& delayed : delayed_init)
|
||||
delayed.toFill = XSTR(delayed.name, delayed.xstr);
|
||||
|
||||
delayed_init.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void lcl_delayed_xstr(SCP_string& str, const char* name, int xstr) {
|
||||
lcl_delayed_xstr_internal(xstr_delayed_order{ str, name, xstr });
|
||||
}
|
||||
|
||||
// initialize the xstr table
|
||||
void lcl_xstr_init()
|
||||
{
|
||||
@@ -549,6 +579,8 @@ void lcl_xstr_init()
|
||||
|
||||
|
||||
Xstr_inited = true;
|
||||
|
||||
lcl_delayed_xstr_internal(tl::nullopt);
|
||||
}
|
||||
|
||||
|
||||
@@ -1183,6 +1215,7 @@ const char *XSTR(const char *str, int index, bool force_lookup)
|
||||
{
|
||||
if(!Xstr_inited)
|
||||
{
|
||||
//If you're here then you should use lcl_delayed_xstr instead!
|
||||
Int3();
|
||||
return str;
|
||||
}
|
||||
@@ -1735,4 +1768,4 @@ void lcl_translate_medal_name_pl(char *name)
|
||||
} else if (!strcmp(name, "SOC Unit Crest")) {
|
||||
strcpy(name, "Tarcza S\xB3u\xBF\x62 Specjalnych");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,4 +135,6 @@ void lcl_translate_targetbox_name_pl(char *name);
|
||||
void lcl_translate_medal_name_gr(char *name);
|
||||
void lcl_translate_medal_name_pl(char *name);
|
||||
|
||||
void lcl_delayed_xstr(SCP_string& str, const char* name, int xstr);
|
||||
|
||||
#endif // defined __FREESPACE2_LOCALIZATION_UTILITIES_HEADER_FILE
|
||||
@@ -2811,7 +2811,7 @@ void vm_matrix4_get_orientation(matrix *out, const matrix4 *m)
|
||||
out->a2d[2][2] = m->a2d[2][2];
|
||||
}
|
||||
|
||||
void vm_matrix4_get_offset(vec3d *out, matrix4 *m)
|
||||
void vm_matrix4_get_offset(vec3d *out, const matrix4 *m)
|
||||
{
|
||||
out->xyz.x = m->vec.pos.xyzw.x;
|
||||
out->xyz.y = m->vec.pos.xyzw.y;
|
||||
|
||||
+7
-1
@@ -565,7 +565,7 @@ void vm_matrix4_set_transform(matrix4 *out, matrix *m, vec3d *v);
|
||||
|
||||
void vm_matrix4_get_orientation(matrix *out, const matrix4 *m);
|
||||
|
||||
void vm_matrix4_get_offset(vec3d *out, matrix4 *m);
|
||||
void vm_matrix4_get_offset(vec3d *out, const matrix4 *m);
|
||||
|
||||
void vm_vec_transform(vec4 *dest, const vec4 *src, const matrix4 *m);
|
||||
void vm_vec_transform(vec3d *dest, const vec3d *src, const matrix4 *m, bool pos = true);
|
||||
@@ -669,6 +669,12 @@ inline vec3d operator*(const vec3d& left, float right)
|
||||
vm_vec_copy_scale(&out, &left, right);
|
||||
return out;
|
||||
}
|
||||
inline vec3d operator*(float left, const vec3d& right)
|
||||
{
|
||||
vec3d out;
|
||||
vm_vec_copy_scale(&out, &right, left);
|
||||
return out;
|
||||
}
|
||||
inline vec3d& operator*=(vec3d& left, float right)
|
||||
{
|
||||
vm_vec_scale(&left, right);
|
||||
|
||||
@@ -114,6 +114,7 @@ const char *fs2_open_credit_text =
|
||||
"libpcp - Copyright (c) 2013 by Cisco Systems, Inc.\n"
|
||||
"This software uses libraries from the FFmpeg project under the LGPLv2.1\n"
|
||||
"Dear ImGui by Omar Cornut and contributors\n"
|
||||
"dkjson.lua - Copyright (C) 2010-2014 David Heiko Kolf"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
@@ -2610,7 +2610,7 @@ void parse_one_main_hall(bool replace, int num_resolutions, int &hall_idx, int &
|
||||
err_msg += Main_hall_region_map[i].name;
|
||||
}
|
||||
|
||||
Error(LOCATION, "Unkown Door Region '%s'! Expected one of: %s", temp_scp_string.c_str(), err_msg.c_str());
|
||||
Error(LOCATION, "Unknown Door Region '%s'! Expected one of: %s", temp_scp_string.c_str(), err_msg.c_str());
|
||||
}
|
||||
|
||||
m->regions[idx].action = action;
|
||||
@@ -2717,3 +2717,11 @@ void main_hall_unpause()
|
||||
|
||||
main_hall_start_ambient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the help overlay
|
||||
*/
|
||||
void main_hall_toggle_help(bool enable)
|
||||
{
|
||||
help_overlay_set_state(Main_hall_overlay_id, main_hall_get_overlay_resolution_index(), (int)enable);
|
||||
}
|
||||
@@ -216,4 +216,6 @@ void main_hall_vasudan_funny();
|
||||
void main_hall_pause();
|
||||
void main_hall_unpause();
|
||||
|
||||
void main_hall_toggle_help(bool enable);
|
||||
|
||||
#endif
|
||||
@@ -1804,7 +1804,7 @@ void options_multi_vox_do()
|
||||
}
|
||||
|
||||
// if the currently selected player is muted
|
||||
if((Om_vox_player_select != NULL) && !Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)]){
|
||||
if((Om_vox_player_select != NULL) && options_multi_vox_plist_get(Om_vox_player_select) > -1 && !Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)]){
|
||||
Om_vox_buttons[gr_screen.res][OM_VOX_VOICE_MUTE].button.draw_forced(2);
|
||||
}
|
||||
|
||||
@@ -1910,7 +1910,15 @@ void options_multi_vox_button_pressed(int n)
|
||||
// mute/unmute button
|
||||
case OM_VOX_VOICE_MUTE:
|
||||
if(Om_vox_player_select != NULL){
|
||||
Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)] = !Om_vox_player_flags[options_multi_vox_plist_get(Om_vox_player_select)];
|
||||
int index = options_multi_vox_plist_get(Om_vox_player_select);
|
||||
|
||||
// there's already an assertion for this in options_multi_vox_plist_get, just ignore in release
|
||||
if (index < 0){
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
break;
|
||||
}
|
||||
|
||||
Om_vox_player_flags[index] = !Om_vox_player_flags[index];
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
} else {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
@@ -2105,13 +2113,17 @@ int options_multi_vox_plist_get(net_player *pl)
|
||||
|
||||
for(idx=0;idx<Om_vox_num_players;idx++){
|
||||
if(pl == Om_vox_players[idx]){
|
||||
return idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// should neve get here. hmmm.
|
||||
Int3();
|
||||
return -1;
|
||||
// Should never get a bad value here, but the places where this is called can now handle the negative return value, as it's not catastrophic.
|
||||
// Still Assert to assist with bug tracking in debug.
|
||||
Assertion(idx < Om_vox_num_players, "options_multi_vox_plist_get() could not find the correct net player. Please report to an SCP member!");
|
||||
if (idx >= Om_vox_num_players)
|
||||
return -1;
|
||||
else
|
||||
return idx;
|
||||
}
|
||||
|
||||
// scroll the player list down
|
||||
|
||||
@@ -402,7 +402,7 @@ void player_select_do()
|
||||
// Goober5000 - display a popup warning about problems in the mod
|
||||
if ((Global_warning_count > 10 || Global_error_count > 0) && !Startup_warning_dialog_displayed) {
|
||||
char text[512];
|
||||
sprintf(text, XSTR ("Warning!\n\nThe currently active mod has generated %d warnings and/or errors during program startup. These could have been caused by anything from incorrectly formated table files to corrupt models.\n\nWhile FreeSpace Open will attempt to compensate for these issues, it cannot guarantee a trouble-free gameplay experience.\n\nPlease contact the authors of the mod for assistance.", 1640), Global_warning_count + Global_error_count);
|
||||
sprintf(text, XSTR ("Warning!\n\nThe currently active mod has generated %d warnings and/or errors during program startup. These could have been caused by anything from incorrectly formatted table files to corrupt models.\n\nWhile FreeSpace Open will attempt to compensate for these issues, it cannot guarantee a trouble-free gameplay experience.\n\nPlease contact the authors of the mod for assistance.", 1640), Global_warning_count + Global_error_count);
|
||||
popup(PF_TITLE_BIG | PF_TITLE_RED | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, text);
|
||||
Startup_warning_dialog_displayed = true;
|
||||
}
|
||||
|
||||
+26
-104
@@ -191,8 +191,8 @@ int Sim_room_slider_coords[GR_NUM_RESOLUTIONS][4] = {
|
||||
#define READYROOM_FLAG_FROM_VOLITION (1<<0) // volition made
|
||||
static struct {
|
||||
int type; // see READYROOM_LINE_* defines above
|
||||
char *name;
|
||||
char *filename;
|
||||
const char *name;
|
||||
const char *filename;
|
||||
int x; // X coordinate of line
|
||||
int y; // Y coordinate of line
|
||||
int flags; // special flags, see READYROOM_FLAG_* defines above
|
||||
@@ -238,7 +238,7 @@ static UI_SLIDER2 Sim_room_slider;
|
||||
|
||||
typedef struct hash_node {
|
||||
hash_node *next;
|
||||
char *filename;
|
||||
const char *filename;
|
||||
} hash_node;
|
||||
|
||||
static hash_node *Campaign_mission_hash_table[CAMPAIGN_MISSION_HASH_SIZE];
|
||||
@@ -294,7 +294,7 @@ int hash_filename(const char *filename) {
|
||||
// insert filename into Campaign_mission_hash_table
|
||||
//
|
||||
// returns 1 if successful, 0 if could not allocate memory
|
||||
int hash_insert(char *filename) {
|
||||
int hash_insert(const char *filename) {
|
||||
int hash_val = hash_filename(filename);
|
||||
hash_node *cur_node;
|
||||
|
||||
@@ -403,7 +403,7 @@ void campaign_mission_hash_table_delete()
|
||||
|
||||
|
||||
// add a line of sim_room smuck to end of list
|
||||
int sim_room_line_add(int type, char *name, char *filename, int x, int y, int flags)
|
||||
int sim_room_line_add(int type, const char *name, const char *filename, int x, int y, int flags)
|
||||
{
|
||||
if (Num_lines >= MAX_LINES)
|
||||
return 0;
|
||||
@@ -458,8 +458,7 @@ int sim_room_standalone_mission_filter(const char *filename)
|
||||
int build_standalone_mission_list_do_frame(bool API_Access)
|
||||
{
|
||||
int font_height = gr_get_font_height();
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
char str[256];
|
||||
SCP_string popup_str;
|
||||
bool lcl_weirdness = false;
|
||||
|
||||
// When no standalone missions in data directory
|
||||
@@ -474,15 +473,12 @@ int build_standalone_mission_list_do_frame(bool API_Access)
|
||||
|
||||
if (Num_standalone_missions > 0) { // sanity check
|
||||
if (strlen(Mission_filenames[Num_standalone_missions_with_info]) < MAX_FILENAME_LEN - 4) { // sanity check?
|
||||
strcpy_s(filename, Mission_filenames[Num_standalone_missions_with_info]);
|
||||
|
||||
// update popup
|
||||
memset(str, 0, 256);
|
||||
sprintf(str, XSTR("Single Mission\n\n%s",989), filename);
|
||||
popup_change_text(str);
|
||||
|
||||
// tack on an extension
|
||||
strcat_s(filename, FS_MISSION_FILE_EXT);
|
||||
auto filename = cf_add_ext(Mission_filenames[Num_standalone_missions_with_info], FS_MISSION_FILE_EXT);
|
||||
|
||||
// update popup
|
||||
sprintf(popup_str, XSTR("Single Mission\n\n%s", 989), filename);
|
||||
popup_change_text(popup_str.c_str());
|
||||
|
||||
// activate tstrings check
|
||||
Lcl_unexpected_tstring_check = &lcl_weirdness;
|
||||
@@ -516,7 +512,7 @@ int build_standalone_mission_list_do_frame(bool API_Access)
|
||||
|
||||
// determine some extra information
|
||||
int flags = 0;
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(filename);
|
||||
auto fb = game_find_builtin_mission(filename);
|
||||
if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
|
||||
flags |= READYROOM_FLAG_FROM_VOLITION;
|
||||
}
|
||||
@@ -545,8 +541,7 @@ int build_standalone_mission_list_do_frame(bool API_Access)
|
||||
int build_campaign_mission_list_do_frame(bool API_Access)
|
||||
{
|
||||
int font_height = gr_get_font_height();
|
||||
char str[256];
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
SCP_string popup_str;
|
||||
static int valid_missions_with_info = 0; // we use this to avoid blank entries in the mission list
|
||||
|
||||
// When no campaign files in data directory
|
||||
@@ -556,9 +551,8 @@ int build_campaign_mission_list_do_frame(bool API_Access)
|
||||
}
|
||||
|
||||
// change popup
|
||||
memset(str, 0, 256);
|
||||
sprintf(str, XSTR("Campaign Mission\n\n%s",990), Campaign.missions[Num_campaign_missions_with_info].name);
|
||||
popup_change_text(str);
|
||||
sprintf(popup_str, XSTR("Campaign Mission\n\n%s", 990), Campaign.missions[Num_campaign_missions_with_info].name);
|
||||
popup_change_text(popup_str.c_str());
|
||||
|
||||
// Set global variable so we we'll have list available next time
|
||||
Campaign_mission_names[Num_campaign_missions_with_info] = NULL;
|
||||
@@ -569,7 +563,7 @@ int build_campaign_mission_list_do_frame(bool API_Access)
|
||||
{
|
||||
if (!get_mission_info(Campaign.missions[Num_campaign_missions_with_info].name))
|
||||
{
|
||||
strcpy_s(filename, Campaign.missions[Num_campaign_missions_with_info].name);
|
||||
auto filename = Campaign.missions[Num_campaign_missions_with_info].name;
|
||||
|
||||
// add to list
|
||||
Campaign_mission_names[Num_campaign_missions_with_info] = vm_strdup(The_mission.name);
|
||||
@@ -590,7 +584,7 @@ int build_campaign_mission_list_do_frame(bool API_Access)
|
||||
|
||||
// determine some extra information
|
||||
int flags = 0;
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(Campaign.missions[Num_campaign_missions_with_info].name);
|
||||
auto fb = game_find_builtin_mission(Campaign.missions[Num_campaign_missions_with_info].name);
|
||||
if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION))
|
||||
{
|
||||
flags |= READYROOM_FLAG_FROM_VOLITION;
|
||||
@@ -618,7 +612,6 @@ void sim_room_build_listing()
|
||||
{
|
||||
int i, y, max_num_entries_viewable;
|
||||
int font_height = gr_get_font_height();
|
||||
char full_filename[256];
|
||||
|
||||
Num_lines = y = 0;
|
||||
list_y = Mission_list_coords[gr_screen.res][1];
|
||||
@@ -637,9 +630,8 @@ void sim_room_build_listing()
|
||||
if (Standalone_mission_names[i]) {
|
||||
// determine some extra information
|
||||
int flags = 0;
|
||||
memset(full_filename, 0, 256);
|
||||
strcpy_s(full_filename, cf_add_ext(Mission_filenames[i], FS_MISSION_FILE_EXT));
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
|
||||
auto full_filename = cf_add_ext(Mission_filenames[i], FS_MISSION_FILE_EXT);
|
||||
auto fb = game_find_builtin_mission(full_filename);
|
||||
if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
|
||||
flags |= READYROOM_FLAG_FROM_VOLITION;
|
||||
}
|
||||
@@ -665,9 +657,8 @@ void sim_room_build_listing()
|
||||
if (Campaign_mission_names[i]) {
|
||||
// determine some extra information
|
||||
int flags = 0;
|
||||
memset(full_filename, 0, 256);
|
||||
strcpy_s(full_filename, cf_add_ext(Campaign.missions[i].name, FS_MISSION_FILE_EXT));
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(full_filename);
|
||||
auto full_filename = cf_add_ext(Campaign.missions[i].name, FS_MISSION_FILE_EXT);
|
||||
auto fb = game_find_builtin_mission(full_filename);
|
||||
if((fb != NULL) && (fb->flags & FSB_FROM_VOLITION)){
|
||||
flags |= READYROOM_FLAG_FROM_VOLITION;
|
||||
}
|
||||
@@ -837,70 +828,6 @@ int sim_room_can_resume_savegame(char * /*savegame_filename*/)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Decide wether to resume a save game or not
|
||||
// exit: 1 => savegame has been restored
|
||||
// 0 => no restore, proceed to briefing
|
||||
// -1 => don't start mission at all
|
||||
int sim_room_maybe_resume_savegame()
|
||||
{
|
||||
// MWA -- 3/26/98 -- removed all savegame references in game
|
||||
return 0;
|
||||
|
||||
/*
|
||||
char savegame_filename[_MAX_FNAME];
|
||||
int popup_rval = -1, resume_savegame = 0;
|
||||
|
||||
// Generate the save-game filename for this campaign
|
||||
memset(savegame_filename, 0, _MAX_FNAME);
|
||||
mission_campaign_savefile_generate_root(savegame_filename);
|
||||
strcat_s(savegame_filename, NOX("svg"));
|
||||
|
||||
// Decide if we should offer choice to resume this savegame
|
||||
if ( sim_room_can_resume_savegame(savegame_filename) ) {
|
||||
popup_rval = popup(0, 3, XSTR("&Cancel",-1), XSTR("&Overwrite",-1), XSTR("&Resume",-1), XSTR("A save game for this mission exists.", -1));
|
||||
switch ( popup_rval ) {
|
||||
case 0:
|
||||
case -1:
|
||||
resume_savegame = -1;
|
||||
break;
|
||||
case 1:
|
||||
resume_savegame = 0;
|
||||
break;
|
||||
case 2:
|
||||
resume_savegame = 1;
|
||||
break;
|
||||
default:
|
||||
Int3();
|
||||
resume_savegame = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
resume_savegame = 0;
|
||||
}
|
||||
|
||||
if (resume_savegame == 1) {
|
||||
if ( state_restore_all(savegame_filename) == -1 ) {
|
||||
popup_rval = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR("Error\nSaved misison could not be loaded.\nDo you wish to start this mission from the beginning?", -1));
|
||||
if (popup_rval == 1) {
|
||||
resume_savegame = 0;
|
||||
} else {
|
||||
resume_savegame = -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
resume_savegame = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are resuming this savegame, then delete the file
|
||||
if (resume_savegame == 1) {
|
||||
cf_delete(savegame_filename);
|
||||
}
|
||||
|
||||
return resume_savegame;
|
||||
*/
|
||||
}
|
||||
|
||||
int readyroom_continue_campaign()
|
||||
{
|
||||
// check for possible mission loop, need to do this before calling mission_campaign_next_mission()!
|
||||
@@ -1052,7 +979,7 @@ void sim_room_init()
|
||||
{
|
||||
int i;
|
||||
sim_room_buttons *b;
|
||||
char wild_card[256];
|
||||
char wild_card[8];
|
||||
|
||||
list_x1 = Mission_list_coords[gr_screen.res][0];
|
||||
list_x2 = Campaign_list_coords[gr_screen.res][0];
|
||||
@@ -1150,7 +1077,6 @@ void sim_room_init()
|
||||
gr_flip();
|
||||
|
||||
Get_file_list_filter = sim_room_standalone_mission_filter;
|
||||
memset(wild_card, 0, 256);
|
||||
strcpy_s(wild_card, NOX("*"));
|
||||
strcat_s(wild_card, FS_MISSION_FILE_EXT);
|
||||
|
||||
@@ -1239,7 +1165,7 @@ void sim_room_close()
|
||||
//functionality without a complete refactor.
|
||||
void api_sim_room_build_mission_list(bool API_Access)
|
||||
{
|
||||
char wild_card[256];
|
||||
char wild_card[8];
|
||||
|
||||
Num_campaign_missions = 0;
|
||||
Get_file_list_filter = sim_room_campaign_mission_filter;
|
||||
@@ -1252,7 +1178,6 @@ void api_sim_room_build_mission_list(bool API_Access)
|
||||
}
|
||||
|
||||
Get_file_list_filter = sim_room_standalone_mission_filter;
|
||||
memset(wild_card, 0, 256);
|
||||
strcpy_s(wild_card, NOX("*"));
|
||||
strcat_s(wild_card, FS_MISSION_FILE_EXT);
|
||||
|
||||
@@ -1440,10 +1365,8 @@ void sim_room_do_frame(float /*frametime*/)
|
||||
gr_printf_menu(list_x2, Mission_list_coords[gr_screen.res][1], "%s", buf);
|
||||
|
||||
// blit the proper icons if necessary
|
||||
char full_name[CF_MAX_PATHNAME_LENGTH + 4];
|
||||
memset(full_name, 0, CF_MAX_PATHNAME_LENGTH + 4);
|
||||
strcpy_s(full_name, cf_add_ext(Campaign.filename,FS_CAMPAIGN_FILE_EXT));
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(full_name);
|
||||
auto full_name = cf_add_ext(Campaign.filename,FS_CAMPAIGN_FILE_EXT);
|
||||
auto fb = game_find_builtin_mission(full_name);
|
||||
if(fb != NULL){
|
||||
// sim_room_blit_icons(0, Mission_list_coords[gr_screen.res][1], fb, 0);
|
||||
}
|
||||
@@ -1605,8 +1528,7 @@ void campaign_room_build_listing()
|
||||
if (Campaign_names[i] != NULL) {
|
||||
// determine some extra information
|
||||
int flags = 0;
|
||||
fs_builtin_mission *fb = game_find_builtin_mission(Campaign_file_names[i]);
|
||||
|
||||
auto fb = game_find_builtin_mission(Campaign_file_names[i]);
|
||||
if (fb != NULL) {
|
||||
if (fb->flags & FSB_FROM_VOLITION) {
|
||||
flags |= READYROOM_FLAG_FROM_VOLITION;
|
||||
|
||||
@@ -1082,6 +1082,7 @@ static void intel_info_init(intel_data* inteli)
|
||||
inteli->desc = "";
|
||||
inteli->anim_filename[0] = '\0';
|
||||
inteli->flags = IIF_DEFAULT_VALUE;
|
||||
inteli->custom_data = {};
|
||||
}
|
||||
|
||||
void parse_intel_table(const char* filename)
|
||||
@@ -1156,6 +1157,10 @@ void parse_intel_table(const char* filename)
|
||||
stuff_string(intel_p->desc, F_MULTITEXT);
|
||||
}
|
||||
|
||||
if (optional_string("$Custom data:")) {
|
||||
parse_string_map(intel_p->custom_data, "$end_custom_data", "+Val:");
|
||||
}
|
||||
|
||||
//retail table doesn't have #end so we have to check for the start of the next entry
|
||||
//or for the end of the file instead. I have also Added #end compatibility here to
|
||||
//bring the table in line with other tables for absent minded modders - Mjn
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct intel_data {
|
||||
char name[NAME_LENGTH];
|
||||
SCP_string desc;
|
||||
char anim_filename[NAME_LENGTH];
|
||||
int flags;
|
||||
SCP_map<SCP_string, SCP_string> custom_data;
|
||||
} intel_data;
|
||||
|
||||
// flags by Goober5000
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Mission {
|
||||
Toggle_start_chase_view, // Toggles (versus the default) whether the player starts the mission in chase view - Goober5000
|
||||
Neb2_fog_color_override, // Whether to use explicit fog colors instead of checking the palette - Goober5000
|
||||
Fullneb_background_bitmaps, // Show background bitmaps despite fullneb
|
||||
Preload_subspace, // Preload the subspace tunnel for both the sexp and specs checkbox (for scripts) - MjnMixael
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
@@ -127,14 +127,15 @@ debriefing *Debriefing; // pointer to correct debriefing
|
||||
|
||||
bool Briefing_voice_enabled = true; // flag which turn on/off voice playback of briefings/debriefings
|
||||
|
||||
static auto BriefingVoiceOption __UNUSED = options::OptionBuilder<bool>("Audio.BriefingVoice", "Briefing voice",
|
||||
"Enable or disable voice playback in the briefing.")
|
||||
.category("Audio")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(true)
|
||||
.bind_to(&Briefing_voice_enabled)
|
||||
.importance(4)
|
||||
.finish();
|
||||
static auto BriefingVoiceOption __UNUSED = options::OptionBuilder<bool>("Audio.BriefingVoice",
|
||||
std::pair<const char*, int>{"Briefing voice", 1368},
|
||||
std::pair<const char*, int>{"Enable or disable voice playback in the briefing", 1716})
|
||||
.category("Audio")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(true)
|
||||
.bind_to(&Briefing_voice_enabled)
|
||||
.importance(4)
|
||||
.finish();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Module global data
|
||||
|
||||
Loaded 100 of 258 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user