Compare commits

..
Author SHA1 Message Date
JohnAFernandez 0feab10244 Upgrade velocity compression in OO packet
Previously, the velocity could be off by up to 1 m/s.  This gives that packing function one more byte to work with, so that we have a lot more accuracy to work with.
2021-03-20 06:49:11 -04:00
JohnAFernandez b342ec50eb Properly Set net_signatures for wing ships
Previously wing ships were being given a net signature that was one too large.
2021-03-20 06:49:11 -04:00
Goober5000 61ef36b238 allow two SEXPs to be used in multiplayer that previously couldn't be
1) The ship-vanish SEXP (and script function) was already multiplayer-ready
2) The is-ship-visible SEXP was enhanced to add a second argument, which defaults to the player's ship in single-player mode
2021-03-20 06:49:11 -04:00
JohnAFernandez fe84d11025 Hopefully Temporary Disable Support ship in TvT
Support ship is not fully support per-team.  Logic for TvT has to be added otherwise players can "steal" each othere's support ships during the mission.
2021-03-20 06:49:11 -04:00
JohnAFernandez 735e00d839 Fix Missile Syncing Between Server and Client 2021-03-20 06:49:11 -04:00
JohnAFernandez 8bbe4733fb Fix implementation of multi_pack_unpack_desired_vel_and_desired_rotvel 2021-03-19 23:34:15 -04:00
JohnAFernandez 56f7dc2f8c Multi Version bump for 21_2
since many of the fixes and features require a multi bump.
2021-03-19 23:33:50 -04:00
345 changed files with 5456 additions and 22690 deletions

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
steps:
- name: Cache Qt
id: cache-qt-lin
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
name: Linux
needs: create_release
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
steps:
- name: Cache Qt
id: cache-qt-lin
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
steps:
- name: Cache Qt
id: cache-qt-lin
-62
View File
@@ -1,62 +0,0 @@
name: Build caches for master
on:
push:
branches:
- master
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-5, gcc-10]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
+1 -6
View File
@@ -22,7 +22,7 @@ jobs:
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -44,11 +44,6 @@ jobs:
with:
submodules: true
fetch-depth: 0
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
+12
View File
@@ -1,3 +1,15 @@
include(WriteCompilerDetectionHeader)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
set(CMAKE_CXX_STANDARD 11)
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
write_compiler_detection_header(
FILE "${GENERATED_SOURCE_DIR}/scp_compiler_detection.h"
PREFIX SCP
COMPILERS AppleClang Clang GNU MSVC
FEATURES ${CMAKE_CXX_KNOWN_FEATURES}
VERSION 3.2
)
+2
View File
@@ -21,6 +21,8 @@ endif()
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
+2
View File
@@ -8,6 +8,8 @@
#cmakedefine SCP_HAVE_MAX_ALIGN_T
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
#cmakedefine01 HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine01 IS_64BIT
#cmakedefine01 SCP_HAVE_STRCASECMP
+1 -1
View File
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 21)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
-1
View File
@@ -26,7 +26,6 @@ TARGET_LINK_LIBRARIES(code PUBLIC openal)
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC lz4)
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
-3
View File
@@ -491,9 +491,6 @@ typedef struct ai_info {
int ai_override_rot_timestamp; // mark for when to end the current rotational maneuver override
int form_obj_slotnum; // for flying in formation object mode, the position in the formation
int multilock_check_timestamp; // when to check for multilock next
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
} ai_info;
// Goober5000
+1 -4
View File
@@ -5,7 +5,7 @@
namespace AI {
FLAG_LIST(AI_Flags) {
Formation_wing, // Fly in formation as part of wing. Also used when flying waypoints.
Formation_wing, // Fly in formation as part of wing.
Awaiting_repair, // Awaiting a repair ship.
Being_repaired, // Currently docked with repair ship.
Repairing, // Repairing a ship (or going to repair a ship)
@@ -137,9 +137,6 @@ namespace AI {
Improved_missile_avoidance,
Friendlies_use_countermeasure_firechance,
Improved_subsystem_attack_pathing,
Fixed_ship_weapon_collision,
No_shield_damage_from_ship_collisions,
Reset_last_hit_target_time_for_player_hits,
NUM_VALUES
};
+7 -52
View File
@@ -58,26 +58,6 @@ int ai_path_type_match(char *p)
return -1;
}
const char* AI_secondary_range_aware_select_modes[] = {
"retail",
"aware",
};
int Num_ai_secondary_range_aware_select_modes = sizeof(AI_secondary_range_aware_select_modes) / sizeof(char*);
int ai_secondary_range_select_mode_match(char* p)
{
int i;
for (i = 0; i < Num_ai_secondary_range_aware_select_modes; i++)
{
if (!stricmp(AI_secondary_range_aware_select_modes[i], p))
return i;
}
return -1;
}
void parse_ai_profiles_tbl(const char *filename)
{
int i;
@@ -468,6 +448,7 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -500,12 +481,14 @@ void parse_ai_profiles_tbl(const char *filename)
if (path_radii >= Minimum_subsystem_path_pt_dist) {
profile->subsystem_path_radii = path_radii;
} else {
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used.\n", Minimum_subsystem_path_pt_dist, path_radii));
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used. ", Minimum_subsystem_path_pt_dist, path_radii));
}
}
set_flag(profile, "$use POF radius for subsystem path points:", AI::Profile_Flags::Use_subsystem_path_point_radii);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive speed multiplier:")) {
stuff_float(&profile->bay_arrive_speed_mult);
}
@@ -561,26 +544,6 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$improved subsystem attack pathing:", AI::Profile_Flags::Improved_subsystem_attack_pathing);
set_flag(profile, "$fixed ship-weapon collisions:", AI::Profile_Flags::Fixed_ship_weapon_collision);
//Intention is to expand this feature to include a preference for close or long range weapons
//hence using something besides a simple flag.
if (optional_string("$AI secondary range awareness:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
int j = ai_secondary_range_select_mode_match(buf);
if (j >= 0) {
profile->ai_range_aware_secondary_select_mode = j;
}
else {
Warning(LOCATION, "Invalid ai secondary range awareness mode '%s' specified", buf);
}
}
set_flag(profile, "$no shield damage from ship collisions:", AI::Profile_Flags::No_shield_damage_from_ship_collisions);
set_flag(profile, "$reset last_hit_target_time for player hits:", AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
@@ -652,12 +615,11 @@ void ai_profile_t::reset()
flags.reset();
ai_path_mode = AI_PATH_MODE_NORMAL;
ai_path_mode = 0;
subsystem_path_radii = 0;
bay_arrive_speed_mult = 1.0f;
bay_depart_speed_mult = 1.0f;
bay_arrive_speed_mult = 0;
bay_depart_speed_mult = 0;
second_order_lead_predict_factor = 0;
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
@@ -735,11 +697,4 @@ void ai_profile_t::reset()
if (mod_supports_version(3, 7, 2)) {
flags.set(AI::Profile_Flags::Fix_ramming_stationary_targets_bug);
}
// and this flag has been enabled ever since 3.6.10
if (mod_supports_version(3, 6, 10)) {
flags.set(AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
}
if (mod_supports_version(21, 4, 0)) {
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
}
}
-6
View File
@@ -17,9 +17,6 @@
// AI Path types
#define AI_PATH_MODE_NORMAL 0
#define AI_PATH_MODE_ALT1 1
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
#define MAX_AI_PROFILES 5
@@ -110,9 +107,6 @@ public:
// How much 0-1 of a second-order lead prediction factor to add to lead indicators. Affects only the HUD indicator, and autoaim.
float second_order_lead_predict_factor;
//Controls if the AI is dumb enough to keep trying to use out-of-range secondaries.
int ai_range_aware_secondary_select_mode;
void reset();
};
+12 -26
View File
@@ -17,12 +17,12 @@
#include "io/timer.h"
#include "math/staticrand.h"
#include "mission/missionparse.h"
#include "object/objcollide.h"
#include "object/object.h"
#include "ship/afterburner.h"
#include "ship/ship.h"
#include "utils/Random.h"
#include "weapon/weapon.h"
#include "object/objcollide.h"
#ifdef _MSC_VER
#pragma optimize("", off)
@@ -777,25 +777,11 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
ai_turn_towards_vector(enemy_pos, Pl_objp, nullptr, rel_pos, 0.0f, 0, rvec);
// set an optimal range if applicable
float optimal_range = 0.0f;
ship_weapon* weapons = &Ships[Pl_objp->instance].weapons;
weapon_info* wip = nullptr;
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0) {
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0) {
wip = &Weapon_info[weapons->secondary_bank_weapons[weapons->current_secondary_bank]];
}
if (wip != nullptr && wip->optimum_range > 0)
optimal_range = wip->optimum_range;
// calc range of primary weapon
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
if ( aip->targeted_subsys != NULL ) {
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist-20))) {
if (dist_to_enemy > (weapon_travel_dist-20)) {
accelerate_ship(aip, 1.0f);
ship *shipp = &Ships[Pl_objp->instance];
@@ -823,7 +809,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
} else if (dot_to_enemy < 0.75f) {
accel = 0.75f;
} else {
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist/2.0f))) {
if (dist_to_enemy > weapon_travel_dist/2.0f) {
accel = 1.0f;
} else {
accel = 1.0f - dot_to_enemy;
@@ -928,7 +914,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
}
}
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank]) && weapon_target_satisfies_lock_restrictions(swip, En_objp)) {
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
float firing_range;
if (swip->wi_flags[Weapon::Info_Flags::Local_ssm])
firing_range=swip->lssm_lock_range;
@@ -958,11 +944,11 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
} else {
t = swip->fire_wait;
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
swp->burst_seed[current_bank_adjusted] = rand32();
}
} else {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
@@ -971,11 +957,11 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
} else {
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
swp->burst_seed[current_bank_adjusted] = rand32();
}
}
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
@@ -1462,7 +1448,7 @@ void ai_big_strafe_attack()
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if (ai_big_maybe_follow_subsys_path(0))
return;
return
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(&target_pos) )
@@ -1485,7 +1471,7 @@ void ai_big_strafe_attack()
if ( t > 0.0f && t < 1.5f ) {
// set up goal_point for avoid path to turn towards
aip->goal_point = Pl_objp->pos;
switch(Random::next(4)) {
switch(rand()%4) {
case 0:
vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, 2.0f);
break;
@@ -1717,7 +1703,7 @@ void ai_big_strafe_retreat1()
if (Missiontime - aip->submode_start_time > fl2f(1.50f)) {
// set up goal_point for avoid path to turn towards
aip->prev_goal_point = Pl_objp->pos;
switch(Random::next(4)) {
switch(rand()%4) {
case 0:
vm_vec_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec);
break;
+77 -249
View File
@@ -68,7 +68,6 @@
#include "ship/shipfx.h"
#include "ship/shiphit.h"
#include "ship/subsysdamage.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/flak.h"
#include "weapon/swarm.h"
@@ -1078,8 +1077,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
float old_dot, new_dot;
object *old_weapon_objp = NULL;
// any object number less than 0 is invalid
if ((attacked_objnum < 0) || (weapon_objnum < 0)) {
if ((attacked_objnum == -1) || (weapon_objnum == -1)) {
return;
}
@@ -2289,7 +2287,7 @@ int num_turrets_attacking(object *turret_parent, int target_objnum)
*/
int get_enemy_timestamp()
{
return (NUM_SKILL_LEVELS - Game_skill_level) * Random::next(500, 999);
return (NUM_SKILL_LEVELS - Game_skill_level) * ( (myrand() % 500) + 500);
}
/**
@@ -2350,9 +2348,8 @@ void ai_set_goal_abort_support_call(object *objp, ai_info *aip)
object *repair_obj;
if (aip->support_ship_objnum == -1) {
repair_obj = nullptr;
repair_obj = NULL;
} else {
Assertion(aip->support_ship_objnum >= 0, "%s has a nonsense support_ship_objnum of %d, please report!", Ships[aip->shipnum].ship_name, aip->support_ship_objnum);
repair_obj = &Objects[aip->support_ship_objnum];
}
ai_do_objects_repairing_stuff( objp, repair_obj, REPAIR_INFO_ABORT );
@@ -2379,7 +2376,7 @@ void ai_attack_object(object* attacker, object* attacked, int ship_info_index)
ai_info* aip;
Assert(attacker != nullptr);
Assert(attacker->instance >= 0);
Assert(attacker->instance != -1);
Assert(Ships[attacker->instance].ai_index != -1);
// Bogus! Who tried to get me to attack myself!
if (attacker == attacked) {
@@ -4420,13 +4417,6 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
bool carry_flag = ((shipp->flags[Ship::Ship_Flags::Navpoint_carry]) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags[Ship::Wing_Flags::Nav_carry])));
float waypoint_turnrate = 1 / (3.0f * scale);
// for retail compatability reasons, have to take into account rotdamp so that ships with less than 1 rotdamp have increased waypoint turnrate
// please see PR #2740 and #3494 for more information
if (Pl_objp->phys_info.rotdamp < 1.0f )
// start increasing the turnrate to 2x at 0.5 rotdamp and 3x at 0
waypoint_turnrate *= (3 - 2 * Pl_objp->phys_info.rotdamp);
vec3d turnrate_mod;
vm_vec_make(&turnrate_mod, waypoint_turnrate, waypoint_turnrate, waypoint_turnrate);
@@ -4707,13 +4697,11 @@ void ai_waypoints()
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
}
// adds scripting hook for 'On Waypoints Done' --wookieejedi
if (Script_system.IsActiveAction(CHA_ONWAYPOINTSDONE)) {
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
Script_system.SetHookVar("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)));
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
Script_system.RemHookVars({"Ship", "Wing", "Waypointlist"});
}
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
Script_system.SetHookVar("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)));
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
Script_system.RemHookVars({"Ship", "Wing", "Waypointlist"});
}
}
}
@@ -5297,7 +5285,7 @@ void evade_ship()
}
} else {
evade_ship_l1: ;
if (aip->ai_evasion > Random::next()*Random::INV_F_MAX_VALUE*100.0f) {
if (aip->ai_evasion > myrand()*100.0f/32767.0f) {
int temp;
float scale;
float psrandval; // some value close to zero to choose whether to turn right or left.
@@ -5767,140 +5755,6 @@ void set_primary_weapon_linkage(object *objp)
}
}
const int MULTILOCK_CHECK_INTERVAL = 250; // every quarter of a second
// This function returns if the ship could theoretically have fully locked all available targets
// given the current time it's been locking on its primary target
// If so, it cheats a little bit and assumes that's what it has done, and fills
// the ai's missile_locks_firing vector, and to be fired at those targets
bool ai_do_multilock(ai_info* aip, weapon_info* wip) {
if (!timestamp_elapsed(aip->multilock_check_timestamp))
return false;
object* primary_target = &Objects[aip->target_objnum];
struct multilock_target {
object* objp;
ship_subsys* subsys;
float dot;
};
// First we accrue all available targets into this vector which we will later sort by dot
SCP_vector<multilock_target> multilock_targets;
if (wip->target_restrict == LR_CURRENT_TARGET)
multilock_targets.push_back(multilock_target{ primary_target, aip->targeted_subsys, 1.0f });
else if (wip->target_restrict == LR_CURRENT_TARGET_SUBSYS) {
if (primary_target->type != OBJ_SHIP)
multilock_targets.push_back(multilock_target{ primary_target, nullptr, 1.0f });
else {
ship* sp = &Ships[primary_target->instance];
ship_subsys* ss;
if (Ship_info[sp->ship_info_index].is_big_or_huge()) {
for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss)) {
float dot;
if (!weapon_multilock_can_lock_on_subsys(Pl_objp, primary_target, ss, wip, &dot))
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (aip->targeted_subsys == ss)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ primary_target, ss, dot });
}
} else
multilock_targets.push_back(multilock_target{ primary_target, nullptr, 1.0f });
}
} else { // any target
for (ship_obj* so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so)) {
object* target_objp = &Objects[so->objnum];
ship* target_ship = &Ships[target_objp->instance];
float dot;
if (!weapon_multilock_can_lock_on_target(Pl_objp, target_objp, wip, &dot))
continue;
if (Ship_info[target_ship->ship_info_index].is_big_or_huge()) {
// add ALL the valid subsystems as possible targets
// dont check range or lock fov, the sub function will do that for subsystems
ship_subsys* ss;
for (ss = GET_FIRST(&target_ship->subsys_list); ss != END_OF_LIST(&target_ship->subsys_list); ss = GET_NEXT(ss)) {
if (!weapon_multilock_can_lock_on_subsys(Pl_objp, target_objp, ss, wip, &dot))
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (aip->targeted_subsys == ss)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ target_objp, ss, dot });
}
} else {
// just a small target, now we check range and fov
if (!weapon_secondary_world_pos_in_range(Player_obj, wip, &target_objp->pos))
continue;
if (dot < wip->lock_fov)
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (primary_target == target_objp)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ target_objp, nullptr, dot });
}
}
}
// before any sorting let's first determine if we're maximally locked
int allocatable_missiles = MIN(weapon_get_max_missile_seekers(wip), (int)multilock_targets.size() * wip->max_seekers_per_target);
float missiles_allocated = wip->max_seeking * (aip->aspect_locked_time / wip->min_lock_time);
// we could still lock more missiles! wait for it (or couldn't find any targets??)
if (missiles_allocated < allocatable_missiles || allocatable_missiles == 0) {
aip->multilock_check_timestamp = timestamp(MULTILOCK_CHECK_INTERVAL);
return false;
}
// we're fully locked! sort by dot and let them fly!
std::sort(multilock_targets.begin(), multilock_targets.end(), [](multilock_target &a, multilock_target &b)
{ return a.dot < b.dot; });
aip->ai_missile_locks_firing.clear();
int missiles = weapon_get_max_missile_seekers(wip);
int remaining_seekers_per_target = wip->max_seekers_per_target;
for (size_t i = multilock_targets.size() - 1;; i--) {
std::pair<int, ship_subsys*> lock;
lock.first = OBJ_INDEX(multilock_targets.at(i).objp);
lock.second = multilock_targets.at(i).subsys;
aip->ai_missile_locks_firing.push_back(lock);
missiles--;
// out of missiles, we're done
if (missiles == 0)
break;
// still more missiles, but exhausted our targets, time to loop over them all again
// and start double-locking triple-locking etc
if (i == 0) {
remaining_seekers_per_target--;
// exhausted our seekers per target, we're done
if (remaining_seekers_per_target == 0)
break;
// reset i and go through the whole list again
i = multilock_targets.size();
}
}
return true;
}
// --------------------------------------------------------------------------
// Fire the current primary weapon.
// *objp is the object to fire from.
@@ -6542,18 +6396,9 @@ int ai_fire_secondary_weapon(object *objp)
// Note, maybe don't fire if firing at player and any homers yet fired.
// Decreasing chance to fire the more homers are incoming on player.
if (check_ok_to_fire(OBJ_INDEX(objp), aip->target_objnum, wip, current_bank, nullptr)) {
if (wip->multi_lock && !ai_do_multilock(aip, wip))
return rval;
if (ship_fire_secondary(objp)) {
rval = 1;
swp->next_secondary_fire_stamp[current_bank] = timestamp(500);
if (wip->multi_lock && wip->launch_reset_locks) {
aip->aspect_locked_time = 0.0f;
aip->current_target_is_locked = 0;
}
}
} else {
@@ -6761,8 +6606,6 @@ float ai_get_weapon_dist(ship_weapon *swp)
return 1000.0f;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return MIN((Weapon_info[weapon_num].max_speed * Weapon_info[weapon_num].lifetime), Weapon_info[weapon_num].weapon_range);
}
@@ -6780,8 +6623,6 @@ float ai_get_weapon_speed(ship_weapon *swp)
return 100.0f;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return Weapon_info[weapon_num].max_speed;
}
@@ -6791,16 +6632,14 @@ weapon_info* ai_get_weapon(ship_weapon *swp)
bank_num = swp->current_primary_bank;
if (bank_num < 0)
return nullptr;
return NULL;
weapon_num = swp->primary_bank_weapons[bank_num];
if (weapon_num == -1) {
return nullptr;
return NULL;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return &Weapon_info[weapon_num];
}
@@ -7055,8 +6894,6 @@ float ai_endangered_by_weapon(ai_info *aip)
return -1.0f;
}
Assertion(aip->danger_weapon_objnum >= 0, "%s has a nonsense danger_weapon_objnum of %d. Please report!", Ships[aip->shipnum].ship_name, aip->danger_weapon_objnum);\
weapon_objp = &Objects[aip->danger_weapon_objnum];
if (weapon_objp->signature != aip->danger_weapon_signature) {
@@ -7098,8 +6935,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip)
AI_ci.sideways = side_vec.x;
AI_ci.vertical = side_vec.y;
}
const float AI_DEFAULT_ATTACK_APPROACH_DIST = 200.0f;
/**
* Set acceleration while in attack mode.
@@ -7152,24 +6987,10 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
return;
}
// assume the original retail value of a 200m range
float optimal_range = AI_DEFAULT_ATTACK_APPROACH_DIST;
ship_weapon* weapons = &Ships[Pl_objp->instance].weapons;
weapon_info* wip = nullptr;
// see if we can get a better one
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0) {
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0) {
wip = &Weapon_info[weapons->secondary_bank_weapons[weapons->current_secondary_bank]];
}
if (wip != nullptr && wip->optimum_range > 0)
optimal_range = wip->optimum_range;
if (dist_to_enemy > optimal_range + vm_vec_mag_quick(&En_objp->phys_info.vel) * dot_from_enemy + Pl_objp->phys_info.speed * speed_ratio) {
if (dist_to_enemy > 200.0f + vm_vec_mag_quick(&En_objp->phys_info.vel) * dot_from_enemy + Pl_objp->phys_info.speed * speed_ratio) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
if (dist_to_enemy > optimal_range + 600.0f) {
if (dist_to_enemy > 800.0f) {
if (!( Pl_objp->phys_info.flags & PF_AFTERBURNER_ON )) {
float percent_left;
ship *shipp;
@@ -7722,7 +7543,7 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
vec3d new_pos;
start_bank = Ships[aip->shipnum].weapons.current_primary_bank;
if (po->n_guns && start_bank != -1 && !(The_mission.ai_profile->flags[AI::Profile_Flags::Ai_aims_from_ship_center])) {
if (po->n_guns && start_bank != -1 ) {
rel_pos = &po->gun_banks[start_bank].pnt[0];
} else
rel_pos = NULL;
@@ -7856,8 +7677,6 @@ int ai_set_attack_subsystem(object *objp, int subnum)
if ( aip->target_objnum == -1 )
return 0;
Assertion(aip->target_objnum >= 0, "The target_objnum for %s has become a nonsense value of %d. Please report!",attacker_shipp->ship_name ,aip->target_objnum);
attacked_objp = &Objects[aip->target_objnum];
shipp = &Ships[attacked_objp->instance]; // need to get our target's ship pointer!!!
@@ -8072,13 +7891,11 @@ void update_aspect_lock_information(ai_info *aip, vec3d *vec_to_enemy, float dis
(tshpp == NULL ||
ship_get_closest_subsys_in_sight(tshpp, SUBSYSTEM_ENGINE, &aiobjp->pos))))) {
aip->aspect_locked_time += flFrametime;
if (aip->aspect_locked_time >= wip->min_lock_time) {
if (aip->aspect_locked_time >= wip->min_lock_time) {
aip->aspect_locked_time = wip->min_lock_time;
aip->current_target_is_locked = 1;
}
} else {
if (aip->aspect_locked_time > wip->min_lock_time)
aip->aspect_locked_time = wip->min_lock_time;
aip->aspect_locked_time -= flFrametime*2;
if (aip->aspect_locked_time < 0.0f)
aip->aspect_locked_time = 0.0f;
@@ -8115,8 +7932,6 @@ void ai_chase_fly_away(object *objp, ai_info *aip)
} else {
vec3d v2e;
float dot;
Assertion(aip->target_objnum >= 0, "This ship's target objnum is nonsense. It is %d instead of a positive number or -1.", aip->target_objnum);
vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, &objp->pos);
@@ -8961,7 +8776,7 @@ void ai_chase()
if (frand() > 0.5f) {
aip->submode = SM_CONTINUOUS_TURN;
aip->submode_start_time = Missiontime;
aip->submode_parm0 = Random::next() & 0x0f;
aip->submode_parm0 = myrand() & 0x0f;
} else {
aip->submode = SM_EVADE;
aip->submode_start_time = Missiontime;
@@ -9044,7 +8859,7 @@ void ai_chase()
? (float)(aip->ai_class + Game_skill_level)/(Num_ai_classes + NUM_SKILL_LEVELS)
: aip->ai_get_away_chance;
switch (Random::next(5)) {
switch (myrand() % 5) {
case 0:
aip->submode = SM_CONTINUOUS_TURN;
aip->submode_start_time = Missiontime;
@@ -9249,7 +9064,7 @@ void ai_chase()
float range_max = pwip->max_speed * (1.0f + scale);
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
range_max = std::min({range_max, pwip->max_speed * pwip->lifetime, pwip->weapon_range});
range_min = pwip->weapon_min_range;
range_min = pwip->WeaponMinRange;
}
if ((dist_to_enemy < range_max) && (dist_to_enemy >= range_min)) {
if(ai_fire_primary_weapon(Pl_objp) == 1){
@@ -9333,11 +9148,11 @@ void ai_chase()
} else {
t = swip->fire_wait;
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
swp->burst_seed[current_bank_adjusted] = rand32();
}
} else {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
@@ -9346,11 +9161,11 @@ void ai_chase()
} else {
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
swp->burst_seed[current_bank_adjusted] = rand32();
}
}
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
@@ -9941,7 +9756,7 @@ void remove_farthest_attacker(int objnum)
aip->ignore_objnum = aip->target_objnum;
aip->ignore_signature = Objects[aip->target_objnum].signature;
aip->ai_flags.set(AI::AI_Flags::Temporary_ignore);
aip->ignore_expire_timestamp = timestamp(Random::next(20, 29) * 1000); // OK to attack again in 20 to 29 seconds.
aip->ignore_expire_timestamp = timestamp(((myrand() % 10) + 20) * 1000); // OK to attack again in 20 to 24 seconds.
}
aip->target_objnum = -1;
ai_do_default_behavior(farthest_objp);
@@ -11648,6 +11463,9 @@ void process_subobjects(int objnum)
ai_info *aip = &Ai_info[shipp->ai_index];
ship_info *sip = &Ship_info[shipp->ship_info_index];
//Look for enemies. If none are present, we don't have to move turrets
int enemies_present = -1;
model_subsystem *psub;
for ( pss = GET_FIRST(&shipp->subsys_list); pss !=END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
psub = pss->system_info;
@@ -11667,7 +11485,34 @@ void process_subobjects(int objnum)
if ( psub->turret_num_firing_points > 0 )
{
ai_turret_execute_behavior(shipp, pss);
if(enemies_present == -1)
{
enemies_present = 0;
for(unsigned int i = 0; i < MAX_OBJECTS; i++)
{
objp = &Objects[i];
switch(objp->type)
{
case OBJ_SHIP:
case OBJ_DEBRIS:
case OBJ_WEAPON:
if(obj_team(objp) != shipp->team)
enemies_present = 1;
break;
case OBJ_ASTEROID:
enemies_present = 1;
break;
}
if(enemies_present==1)
break;
}
//Reset objp
objp = &Objects[objnum];
}
//Only move turrets if enemies are present
if(enemies_present == 1 || pss->turret_enemy_objnum >= 0)
ai_fire_from_turret(shipp, pss);
} else {
Warning( LOCATION, "Turret %s on ship %s has no firing points assigned to it.\nThis needs to be fixed in the model.\n", psub->name, shipp->ship_name );
}
@@ -12449,8 +12294,6 @@ void ai_do_repair_frame(object *objp, ai_info *aip, float frametime)
if (support_objnum == -1)
return;
Assertion(support_objnum >= 0, "The support ship objnum is nonsense. It is %d instead of a positive number or -1.", support_objnum);
// Curious -- object numbers match, but signatures do not.
// Must mean original repair ship died and was replaced by current ship.
Assert(Objects[support_objnum].signature == aip->support_ship_signature);
@@ -13050,9 +12893,7 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
pnode *pnp;
vec3d *next_point;
Assertion(pl_objp->instance >= 0, "Arriving ship does not have a valid ship number. Has %d instead. Please report!", pl_objp->instance);
ship *shipp = &Ships[pl_objp->instance];
Assertion(shipp->ai_index >= 0, "Arriving ship does not have a valid ai index. Has %d instead. Please report!", shipp->ai_index);
ai_info *aip = &Ai_info[shipp->ai_index];
if ( parent_objnum == -1 ) {
@@ -13060,7 +12901,6 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
return -1;
}
Assertion(parent_objnum >= 0, "Arriving ship does not have a parent object number. Has %d instead. Please report!", parent_objnum);
object *parent_objp = &Objects[parent_objnum];
ship *parent_shipp = &Ships[parent_objp->instance];
@@ -13769,7 +13609,7 @@ void ai_maybe_depart(object *objp)
if (sip->is_fighter_bomber()) {
if (aip->warp_out_timestamp == 0) {
//if (ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS) == 0.0f) {
// aip->warp_out_timestamp = timestamp(Random::next(10, 19) * 1000);
// aip->warp_out_timestamp = timestamp(((myrand() % 10) + 10) * 1000);
//}
} else if (timestamp_elapsed(aip->warp_out_timestamp)) {
mission_do_departure(objp);
@@ -14256,7 +14096,7 @@ void ai_maybe_self_destruct(object *objp, ai_info *aip)
}
if (timestamp_elapsed(aip->self_destruct_timestamp)) {
ship_apply_local_damage( objp, objp, &objp->pos, objp->hull_strength*flFrametime + 1.0f, -1, MISS_SHIELDS);
ship_apply_local_damage( objp, objp, &objp->pos, objp->hull_strength*flFrametime + 1.0f, MISS_SHIELDS);
}
}
}
@@ -14925,9 +14765,6 @@ void init_ai_object(int objnum)
memset(&aip->ai_override_ci,0,sizeof(control_info));
aip->form_obj_slotnum = -1;
aip->multilock_check_timestamp = timestamp(1);
aip->ai_missile_locks_firing.clear();
}
void init_ai_system()
@@ -15388,7 +15225,7 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
{
int hitter_objnum = -2;
object *objp_hitter = nullptr;
object *objp_hitter = NULL;
ship *shipp;
ai_info *aip, *hitter_aip;
@@ -15396,29 +15233,25 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
aip = &Ai_info[shipp->ai_index];
if (objp_ship->flags[Object::Object_Flags::Player_ship]) {
if (The_mission.ai_profile->flags[AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits]) {
//SUSHI: So that hitting a player ship actually resets the last_hit_target_time counter for whoever hit the player.
//This is all copypasted from code below
// Added OBJ_BEAM for traitor detection - FUBAR
if ((hit_objp->type == OBJ_WEAPON) || (hit_objp->type == OBJ_BEAM)) {
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum < MAX_OBJECTS));
if (hitter_objnum == -1) {
return; // Possible SSM, bail while we still can.
}
objp_hitter = &Objects[hitter_objnum];
} else if (hit_objp->type == OBJ_SHIP) {
objp_hitter = hit_objp;
} else {
UNREACHABLE("Should never happen.");
return;
//SUSHI: So that hitting a player ship actually resets the last_hit_target_time counter for whoever hit the player.
//This is all copypasted from code below
// Added OBJ_BEAM for traitor detection - FUBAR
if ((hit_objp->type == OBJ_WEAPON) || (hit_objp->type == OBJ_BEAM)) {
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum < MAX_OBJECTS));
if (hitter_objnum == -1) {
return; // Possible SSM, bail while we still can.
}
Assert(objp_hitter != nullptr);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
aip->last_hit_time = Missiontime;
objp_hitter = &Objects[hitter_objnum];
} else if (hit_objp->type == OBJ_SHIP) {
objp_hitter = hit_objp;
} else {
Int3(); // Should never happen.
return;
}
Assert(objp_hitter != NULL);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
return;
}
@@ -15444,11 +15277,6 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
if ( hit_objp->parent_sig != Objects[hit_objp->parent].signature ){
return;
}
weapon_info* wip = hit_objp->type == OBJ_WEAPON ? &Weapon_info[Weapons[hit_objp->instance].weapon_info_index] :
&Weapon_info[Beams[hit_objp->instance].weapon_info_index];
if (wip->wi_flags[Weapon::Info_Flags::Heals])
return;
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum >= 0) && (hitter_objnum < MAX_OBJECTS));
@@ -15504,7 +15332,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
if (hit_objp->flags[Object::Object_Flags::Protected])
return;
Assert(objp_hitter != nullptr);
Assert(objp_hitter != NULL);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
+3 -5
View File
@@ -293,11 +293,9 @@ void ai_clear_ship_goals( ai_info *aip )
}
// add scripting hook for 'On Goals Cleared' --wookieejedi
if (Script_system.IsActiveAction(CHA_ONGOALSCLEARED)) {
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
Script_system.RunCondition(CHA_ONGOALSCLEARED);
Script_system.RemHookVars({"Ship"});
}
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
Script_system.RunCondition(CHA_ONGOALSCLEARED);
Script_system.RemHookVars({"Ship"});
}
void ai_clear_wing_goals( wing *wingp )
+1 -1
View File
@@ -32,6 +32,6 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int second
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret);
//Does all the stuff needed to aim and fire a turret.
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss);
void ai_fire_from_turret(ship *shipp, ship_subsys *ss);
#endif
+163 -117
View File
@@ -18,7 +18,6 @@
#include "render/3d.h"
#include "ship/ship.h"
#include "ship/shipfx.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/flak.h"
#include "weapon/muzzleflash.h"
@@ -88,18 +87,6 @@ typedef struct eval_enemy_obj_struct {
int nearest_objnum;
} eval_enemy_obj_struct;
// the current world orientation of the turret matrix, corresponding to its fvec and uvec defined in the model
// is NOT affected by the turret's current aiming
void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num, int submodel_num, const matrix* objorient)
{
auto pmi = model_get_instance(model_instance_num);
auto pm = model_get(pmi->model_num);
vec3d fvec, uvec;
model_instance_find_world_dir(&fvec, &pm->submodel[submodel_num].frame_of_reference.vec.fvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
model_instance_find_world_dir(&uvec, &pm->submodel[submodel_num].frame_of_reference.vec.uvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
vm_vector_2_matrix_norm(out_mat, &fvec, &uvec);
}
/**
* Is object in turret field of view?
*
@@ -111,53 +98,124 @@ void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num,
*
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
*/
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
int object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
{
vec3d v2e;
float size_mod;
bool in_fov = false;
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
int model_num;
switch (objp->type) {
case OBJ_SHIP:
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
break;
case OBJ_ASTEROID:
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
break;
default:
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
size_mod = objp->radius / (dist + objp->radius);
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
return in_fov;
}
auto pm = model_get(model_num);
for (int i = 0; i < 8; i++) {
vec3d bbox_point;
vm_vec_unrotate(&bbox_point, &pm->bounding_box[i], &objp->orient);
bbox_point += objp->pos;
vm_vec_normalized_dir(&v2e, &bbox_point, tpos);
in_fov = turret_fov_test(ss, tvec, &v2e, -0.2f);
if (in_fov)
return true;
}
}
// if the bbox points method didn't work (or fov_edge_checks isn't on)
// try the normal method
bool in_fov;
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
size_mod = objp->radius / (dist + objp->radius);
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
if ( in_fov ) {
return 1;
}
return in_fov;
return 0;
}
bool is_object_radius_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, vec3d *v2e, vec3d *predicted_pos, float distance)
{
float target_dist = distance;
if (distance == 0.0f)
target_dist = vm_vec_dist(predicted_pos,tpos);
if (object_in_turret_fov(objp, ss, tvec, tpos, target_dist + objp->radius)) {
// so the targeted spot in not in fov but the enemy + radius is
// lets align the darn gun and try shooting there
vec3d temp_vec;
float multiplier = 0;
model_subsystem *tp = ss->system_info;
// project v2e_from_turret to turret normal
// substract resultant vector from the temp_vec (v2e_from_turret)
// adjust z component as necessary
// calculate multiplier for the resultant vector
// use multiplier and the z component and compose a new vector
float dot = vm_vec_dot(v2e, tvec);
vm_vec_scale_add(&temp_vec, v2e, tvec, -dot);
if (IS_VEC_NULL_SQ_SAFE(&temp_vec)) {
// return false, target is perfectly aligned over or below the turret
// safe bet is to allow turret to reacquire better target
return false;
}
// normalize the vec, it needs to be done regardless
vm_vec_normalize(&temp_vec);
bool fix_elevation = false;
bool fix_base_rot = false;
if (dot < tp->turret_fov) {
dot = tp->turret_fov;
fix_elevation = true;
}
if (dot > tp->turret_max_fov) {
dot = tp->turret_max_fov;
fix_elevation = true;
}
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
vec3d turret_norm;
matrix turret_matrix, world_to_turret_matrix;
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
vec3d temp_vec2;
vm_vec_rotate(&temp_vec2, &temp_vec, &world_to_turret_matrix);
// now in turrets frame of reference
// check if math is actually possible
if (!((temp_vec2.xyz.x == 0) && (temp_vec2.xyz.y == 0))) {
float temp_z = temp_vec2.xyz.z;
temp_vec2.xyz.z = 0.0f;
// make sure null vecs wont happen
if (!IS_VEC_NULL_SQ_SAFE(&temp_vec2)) {
vm_vec_normalize(&temp_vec2);
// only do this if it actually is required
if (-temp_vec2.xyz.y < tp->turret_y_fov) {
float check_pos = 1;
fix_base_rot = true;
temp_vec2.xyz.y = -tp->turret_y_fov;
if (temp_vec2.xyz.x < 0)
check_pos = -1;
temp_vec2.xyz.x = check_pos * sqrtf(1 - (temp_vec2.xyz.y*temp_vec2.xyz.y));
// restore z component
float scaler = sqrtf(1 - (temp_z*temp_z));
vm_vec_scale(&temp_vec2,scaler);
temp_vec2.xyz.z = temp_z;
// back to world frame
vm_vec_unrotate(&temp_vec, &temp_vec2, &world_to_turret_matrix);
}
}
}
}
if (fix_elevation || fix_base_rot) {
if (fix_elevation) {
multiplier = sqrtf(1 - (dot*dot));
// keep the temp_vec scaled with the tweaked vector
vm_vec_scale(&temp_vec, multiplier);
}
vm_vec_scale_add(v2e, &temp_vec, tvec, dot);
// and we are done with v2e...
vm_vec_scale_add(predicted_pos, tpos, v2e, target_dist);
// and we are done with predicted position
return true;
} else {
mprintf(("Warning: Function 'is_object_radius_in_turret_fov' was called\nwithout need to fix turret alignments\n"));
return false;
}
}
// outside of the expanded radii, unable to align, return false
return false;
}
/**
@@ -1138,11 +1196,17 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
if ( tagged_only_flag && ship_is_tagged(&Objects[aip->target_objnum]) ) {
// select new target if aip->target_objnum is out of field of view
vec3d v2e;
float dist;
bool in_fov;
vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
dist = vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
in_fov = turret_fov_test(turret_subsys, tvec, &v2e);
if (turret_subsys->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
if (in_fov == false)
if (object_in_turret_fov(&Objects[aip->target_objnum], turret_subsys, tvec, tpos, dist + Objects[aip->target_objnum].radius))
in_fov = true;
}
// MODIFY FOR ATTACKING BIG SHIP
// dot += (0.5f * Objects[aip->target_objnum].radius / dist);
if (in_fov) {
@@ -1192,7 +1256,7 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
if (gpos)
model_instance_find_world_point(gpos, &vmd_zero_vector, model_instance_num, tp->subobj_num, &objp->orient, &objp->pos);
if (gvec)
model_instance_find_world_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
model_instance_find_world_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient);
}
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
@@ -1253,7 +1317,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
} else {
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
// the turret norm here is from the perspective of the base submodel, not the gun submodel
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, pm, pmi, tp->subobj_num, &objp->orient);
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
}
else {
@@ -1384,13 +1448,18 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
in_fov = turret_fov_test(ss, gvec, &v2e);
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
if (in_fov == false)
in_fov = is_object_radius_in_turret_fov(&Objects[ss->turret_enemy_objnum], ss, gvec, &gun_pos, &v2e, predicted_enemy_pos, 0.0f);
}
if (in_fov) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos);
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos, true);
}
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
ret_val = model_rotate_gun(objp, pm, pmi, ss->system_info, predicted_enemy_pos, true);
}
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
@@ -1422,7 +1491,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
vec3d turret_norm;
model_instance_find_world_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
model_instance_find_world_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient);
float dot_return = vm_vec_dot(&turret_norm, &vector_out);
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
@@ -1605,10 +1674,8 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
float wait = 1000.0f;
// should subtract 1 from firepoints to match behavior of wip->burst_shots
int burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points - 1 : wip->burst_shots);
if (burst_shots > turret->weapons.burst_counter[weapon_num]) {
if (wip->burst_shots > turret->weapons.burst_counter[weapon_num]) {
wait *= wip->burst_delay;
turret->weapons.burst_counter[weapon_num]++;
} else {
@@ -1618,12 +1685,12 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
} else {
wait *= wip->fire_wait;
}
if ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
turret->weapons.burst_counter[weapon_num] = Random::next(burst_shots);
turret->weapons.burst_seed[weapon_num] = Random::next();
if ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
turret->weapons.burst_counter[weapon_num] = (myrand() % wip->burst_shots);
turret->weapons.burst_seed[weapon_num] = rand32();
} else {
turret->weapons.burst_counter[weapon_num] = 0;
turret->weapons.burst_seed[weapon_num] = Random::next();
turret->weapons.burst_seed[weapon_num] = rand32();
}
}
@@ -1634,7 +1701,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
fs_dest = &turret->weapons.next_secondary_fire_stamp[weapon_num - MAX_SHIP_PRIMARY_BANKS];
//Check for the new cooldown flag
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
{
// make side even for team vs. team
@@ -1790,19 +1857,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
vm_vector_2_matrix(&turret_orient, firing_vec, nullptr, nullptr);
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
int old_burst_seed = swp->burst_seed[weapon_num];
int old_burst_counter = swp->burst_counter[weapon_num];
// only used by type 5 beams
if (turret->weapons.burst_counter[weapon_num] == 0) {
swp->per_burst_rot += wip->b_info.t5info.per_burst_rot;
if (swp->per_burst_rot > PI2)
swp->per_burst_rot -= PI2;
else if (swp->per_burst_rot < -PI2)
swp->per_burst_rot += PI2;
}
// set next fire timestamp for the turret
int old_burst_seed = swp->burst_seed[weapon_num];
if (last_shot_in_salvo)
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
@@ -1828,8 +1884,6 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = old_burst_counter;
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
@@ -1840,11 +1894,9 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
@@ -1974,11 +2026,9 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
// AL 1-6-97: Store pointer to turret subsystem
wp->turret_subsys = turret;
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
// if the gun is a flak gun
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
@@ -2092,11 +2142,9 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
Ships[Objects[tsi->parent_objnum].instance].last_fired_turret = tsi->turret;
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
// muzzle flash?
if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
@@ -2127,15 +2175,13 @@ int Num_find_turret_enemy = 0;
int Num_turrets_fired = 0;
/**
* Previously called ai_fire_from_turret()
* Given a ship and a turret subsystem, handle all its behavior, mostly targeting and shooting but also
* all turret movement and resetting when idle
* Given a turret tp and its parent parent_objnum, fire from the turret at its enemy.
*/
extern int Nebula_sec_range;
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
{
float weapon_firing_range;
float weapon_min_range; // *Weapon minimum firing range -Et1
float WeaponMinRange; // *Weapon minimum firing range -Et1
vec3d v2e;
object *lep; // Last enemy pointer
model_subsystem *tp = ss->system_info;
@@ -2310,12 +2356,12 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
{
weapon_firing_range = wip->lssm_lock_range;
weapon_min_range = 0.0f;
WeaponMinRange = 0.0f;
}
else
{
weapon_firing_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
weapon_min_range = wip->weapon_min_range;
WeaponMinRange = wip->WeaponMinRange;
}
// if beam weapon in nebula and target not tagged, decrease firing range
@@ -2328,7 +2374,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
}
// Don't try to fire beyond weapon_limit_range (or within min range)
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
if (dist_to_enemy < WeaponMinRange || dist_to_enemy > weapon_firing_range) {
// it's possible another weapon is in range, but if not,
// we will end up selecting a new target
continue;
@@ -2395,11 +2441,6 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
tentative_return = true;
continue;
}
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
tentative_return = true;
continue;
}
}
else {
// check tagged-only for bombs only if the flag is set; see Mantis #3114
@@ -2771,20 +2812,25 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
model_subsystem *tp = ss->system_info;
float dot = vm_vec_dot(v2e, gvec);
if (((dot + size_mod) >= tp->turret_fov) && ((dot - size_mod) <= tp->turret_max_fov)) {
object* objp = &Objects[ss->parent_objnum];
matrix turret_matrix;
turret_instance_find_world_orient(&turret_matrix, Ships[objp->instance].model_instance_num, tp->subobj_num, &objp->orient);
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
object *objp = &Objects[ss->parent_objnum];
vec3d turret_norm;
matrix turret_matrix, world_to_turret_matrix;
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
vec3d of_dst;
vm_vec_rotate(&of_dst, v2e, &turret_matrix);
if ((of_dst.xyz.x == 0) && (of_dst.xyz.z == 0))
return true;
else {
of_dst.xyz.y = 0;
vm_vec_rotate( &of_dst, v2e, &world_to_turret_matrix );
if ((of_dst.xyz.x == 0) && (of_dst.xyz.y == 0)) {
return true;
} else {
of_dst.xyz.z = 0;
if (!IS_VEC_NULL_SQ_SAFE(&of_dst)) {
vm_vec_normalize(&of_dst);
// now we have 2d vector with lenght of 1 that points at the targets direction after being rotated to turrets FOR
if ((of_dst.xyz.z + size_mod) >= tp->turret_base_fov)
if ((-of_dst.xyz.y + size_mod) >= tp->turret_y_fov)
return true;
}
}
@@ -2795,7 +2841,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
bool in_fov = false;
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_restricted_fov])
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_alt_math])
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
else
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
+10 -17
View File
@@ -324,7 +324,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asteroid_default_flagset += Object::Object_Flags::Physics;
asteroid_default_flagset += Object::Object_Flags::Collides;
objnum = obj_create(OBJ_ASTEROID, -1, n, &orient, &pos, radius, asteroid_default_flagset, false);
objnum = obj_create(OBJ_ASTEROID, -1, n, &orient, &pos, radius, asteroid_default_flagset);
if ( (objnum == -1) || (objnum >= MAX_OBJECTS) ) {
mprintf(("Couldn't create asteroid -- out of object slots\n"));
@@ -496,7 +496,7 @@ void asteroid_create_all()
// ship_debris_odds_table keeps track of debris type of the next debris piece
// each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
// choose next type from table ship_debris_odds_table by Random::next()%max_weighted_range,
// choose next type from table ship_debris_odds_table by rand()%max_weighted_range,
// the threshold *below* which the debris type is selected.
struct {
float random_threshold;
@@ -564,7 +564,7 @@ void asteroid_create_all()
// For asteroid, load only large asteroids
// get a valid subtype
int subtype = Random::next(NUM_DEBRIS_POFS);
int subtype = rand() % NUM_DEBRIS_POFS;
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
}
@@ -758,7 +758,7 @@ static void maybe_throw_asteroid(int count)
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
object *A = &Objects[so->objnum];
if (so->objnum == Asteroid_throw_objnum) {
int subtype = Random::next(NUM_DEBRIS_POFS);
int subtype = rand() % NUM_DEBRIS_POFS;
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
}
@@ -1324,7 +1324,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage );
weapon_area_apply_blast(NULL, ship_objp, &asteroid_objp->pos, blast, 0);
} // end for
}
@@ -1432,14 +1432,9 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
if ( timestamp_elapsed(asp->final_death_time) ) {
vec3d relvec, vfh, tvec;
bool skip = false;
bool hooked = Script_system.IsActiveAction(CHA_DEATH);
if (hooked) {
Script_system.SetHookObject("Self", pasteroid_obj);
skip = Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj);
}
if (!skip)
Script_system.SetHookObject("Self", pasteroid_obj);
if(!Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj))
{
pasteroid_obj->flags.set(Object::Object_Flags::Should_be_dead);
@@ -1489,7 +1484,7 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
int num_roids_var = split->max - split->min;
if (num_roids_var > 0)
num_roids += Random::next(num_roids_var);
num_roids += rand() % num_roids_var;
if (num_roids > 0)
for (int i=0; i<num_roids; i++)
@@ -1544,10 +1539,8 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
}
asp->final_death_time = timestamp(-1);
}
if (hooked) {
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
}
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
}
}
+2 -3
View File
@@ -716,7 +716,7 @@ bool StartAutopilot()
vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship
switch (Random::next(24))
switch (myrand()%24)
// 8 different ways of getting perp points
// 4 of which will not be used when capships are present (anything below, or straight above)
{
@@ -795,8 +795,7 @@ bool StartAutopilot()
vm_vec_scale(&perp, Autopilot_flight_leader->radius+radius);
// randomly scale up/down by up to 20%
// jg18 - original comment said [-20,20] but preserving existing behavior
j = Random::next(-19, 20);
j = 20-myrand()%40; // [-20,20]
vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
vm_vec_add(&cameraPos, &pos, &perp);
+3 -5
View File
@@ -866,7 +866,6 @@ static int cfget_cfile_block()
cfile->data = nullptr;
cfile->fp = nullptr;
cfile->type = CFILE_BLOCK_USED;
cf_clear_compression_info(cfile);
return i;
}
}
@@ -922,7 +921,7 @@ int cfclose( CFILE * cfile )
} else {
// VP do nothing
}
cf_clear_compression_info(cfile);
cfile->type = CFILE_BLOCK_UNUSED;
return result;
}
@@ -974,7 +973,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
if(pos == -1L)
pos = 0;
cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)), 0 );
cf_check_compression(cfp);
return cfp;
}
}
@@ -1009,7 +1008,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
cfp->line_num = line;
cf_init_lowlevel_read_code(cfp,offset, size, 0 );
cf_check_compression(cfp);
return cfp;
}
@@ -1053,7 +1052,6 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const ch
cfp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
#if defined _WIN32
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (cfp->hMapFile == NULL) {
+8 -47
View File
@@ -24,7 +24,6 @@
#include "cfile/cfile.h"
#include "cfile/cfilearchive.h"
#include "cfile/cfilecompression.h"
#include "luaconf.h"
#include <sstream>
@@ -34,6 +33,7 @@
#define CHECK_POSITION
// Called once to setup the low-level reading code.
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos )
{
Assert(cfile != nullptr);
@@ -54,33 +54,6 @@ void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size,
}
}
//This function checks the file header to see if the file is compressed, if so it fills the correct compression info.
void cf_check_compression(CFILE* cfile)
{
if (cfile->size <= 16)
return;
int header=cfread_int(cfile);
cfseek(cfile, 0, SEEK_SET);
if (comp_check_header(header) == COMP_HEADER_MATCH)
comp_create_ci(cfile, header);
}
//This function is called to cleanup compression info when the cfile handle is reused.
void cf_clear_compression_info(CFILE* cfile)
{
if (cfile->compression_info.header != 0)
{
free(cfile->compression_info.offsets);
free(cfile->compression_info.decoder_buffer);
cfile->compression_info.offsets = nullptr;
cfile->compression_info.decoder_buffer = nullptr;
cfile->compression_info.header = 0;
cfile->compression_info.block_size = 0;
cfile->compression_info.last_decoded_block_pos = 0;
cfile->compression_info.last_decoded_block_bytes = 0;
cfile->compression_info.num_offsets = 0;
}
}
// cfeof() Tests for end-of-file on a stream
@@ -88,11 +61,11 @@ void cf_clear_compression_info(CFILE* cfile)
// returns a nonzero value after the first read operation that attempts to read
// past the end of the file. It returns 0 if the current position is not end of file.
// There is no error return.
int cfeof(CFILE *cfile)
{
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return comp_feof(cfile);
int result = 0;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
@@ -119,8 +92,6 @@ int cfeof(CFILE *cfile)
int cftell( CFILE * cfile )
{
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return (int)comp_ftell(cfile);
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
@@ -146,9 +117,6 @@ int cfseek( CFILE *cfile, int offset, int where )
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return comp_fseek(cfile, offset, where);
// TODO: seek to offset in memory mapped file
Assert( !cfile->mem_mapped );
@@ -234,31 +202,23 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
} else if (cfile->compression_info.header != 0) {
bytes_read = comp_fread(cfile, reinterpret_cast<char*>(buf),size);
if (bytes_read != size)
{
mprintf(("\nFile: %s decompression error. Result was: %d expected: %d\n", cfile->original_filename.c_str(), (int)bytes_read, (int)size));
Assertion(bytes_read == size, "File decompression error!");
}
} else {
bytes_read = fread(buf, 1, size, cfile->fp);
bytes_read = fread( buf, 1, size, cfile->fp );
}
if ( bytes_read > 0 ) {
cfile->raw_position += bytes_read;
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
//Raw position is not the fp position with compressed files
if (cfile->fp && cfile->compression_info.header == 0) {
if (cfile->fp) {
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
Assert(tmp_offset == cfile->raw_position);
Assert(tmp_offset==cfile->raw_position);
}
#endif
return (int)(bytes_read / elsize);
}
int cfread_lua_number(double *buf, CFILE *cfile)
@@ -306,3 +266,4 @@ int cfread_lua_number(double *buf, CFILE *cfile)
return items_read;
}
+2 -19
View File
@@ -7,6 +7,7 @@
*
*/
#ifndef _CFILEARCHIVE_H
#define _CFILEARCHIVE_H
@@ -22,17 +23,6 @@
#define CFILE_BLOCK_UNUSED 0
#define CFILE_BLOCK_USED 1
struct COMPRESSION_INFO {
int header = 0;
size_t compressed_size = 0;
int block_size = 0;
int num_offsets = 0;
int* offsets = nullptr;
char* decoder_buffer = nullptr;
int last_decoded_block_pos = 0;
int last_decoded_block_bytes = 0;
};
struct CFILE {
int type = CFILE_BLOCK_UNUSED; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
@@ -54,19 +44,12 @@ struct CFILE {
SCP_string original_filename;
const char* source_file;
int line_num;
COMPRESSION_INFO compression_info;
};
#define MAX_CFILE_BLOCKS 64
extern std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
// Called once to setup the low-level reading code.
void cf_init_lowlevel_read_code(CFILE* cfile, size_t lib_offset, size_t size, size_t pos);
// This checks if the file is compressed or not, and creates the proper compression info if so.
void cf_check_compression(CFILE* cfile);
// Used to clear compression info data and free dynamic memory used by compression
void cf_clear_compression_info(CFILE* cfile);
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos );
#endif
-206
View File
@@ -1,206 +0,0 @@
#define _CFILE_INTERNAL
#include <cstdlib>
#include <cstring>
#include <cstdio>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#include <windows.h>
#include <winbase.h>
#endif
#include "lz4.h"
#include "cfilecompression.h"
#include "cfilearchive.h"
/*INTERNAL FUNCTIONS*/
/*LZ41*/
void lz41_load_offsets(CFILE* cf);
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length);
void lz41_create_ci(CFILE* cf, int header);
/*MISC*/
int fso_fseek(CFILE* cfile, int offset, int where);
/*END OF INTERNAL FUNCTIONS*/
int comp_check_header(int header)
{
if (LZ41_FILE_HEADER == header)
return COMP_HEADER_MATCH;
return COMP_HEADER_MISMATCH;
}
void comp_create_ci(CFILE* cf, int header)
{
//mprintf(("(CI)Compressed File Opened: %s \n", cf->original_filename.c_str()));
if (LZ41_FILE_HEADER == header)
lz41_create_ci(cf, header);
//mprintf(("(CI)Uncompressed FileSize: %d \n", cf->size));
//mprintf(("(CI)Compressed FileSize: %d \n", cf->compression_info.compressed_size));
//mprintf(("(CI)Block Size: %d \n", cf->compression_info.block_size));
}
size_t comp_fread(CFILE* cf, char* buffer, size_t length)
{
/* Check the request to be at least 1 byte */
Assertion(length > 0, "Invalid length requested.");
/* Check that we are not requesting to read beyond end of file */
Assertion(cf->raw_position + length <= cf->size, "Invalid length requested.");
if (LZ41_FILE_HEADER == cf->compression_info.header)
return lz41_stream_random_access(cf, buffer, cf->raw_position, length);
return 0;
}
size_t comp_ftell(CFILE* cf)
{
return cf->raw_position;
}
int comp_feof(CFILE* cf)
{
if (cf->raw_position >= cf->size)
return 1;
else
return 0;
}
int comp_fseek(CFILE* cf, int offset, int where)
{
size_t goal_position;
switch (where) {
case SEEK_SET: goal_position = offset; break;
case SEEK_CUR: goal_position = cf->raw_position + offset; break;
case SEEK_END: goal_position = cf->size + offset; break;
default: return 1;
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position,(size_t)0, cf->size);
cf->raw_position = goal_position;
return 0;
}
//Special fseek for compressed files handled by FSO, only SEEK_SET and SEEK_END is supported.
int fso_fseek(CFILE* cfile, int offset, int where)
{
size_t goal_position;
switch (where) {
case SEEK_SET: goal_position = offset + cfile->lib_offset; break;
case SEEK_END: goal_position = cfile->compression_info.compressed_size + offset + cfile->lib_offset; break;
default: return 0;
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position, cfile->lib_offset, cfile->lib_offset + cfile->compression_info.compressed_size);
int result = 0;
if (cfile->fp)
{
result = fseek(cfile->fp, (long)goal_position, SEEK_SET);
Assertion(goal_position >= cfile->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cfile->lib_offset);
}
return result;
}
void lz41_create_ci(CFILE* cf, int header)
{
cf->compression_info.header = header;
cf->compression_info.compressed_size = cf->size;
fso_fseek(cf, (int)sizeof(int)*-3, SEEK_END);
auto fNumoffsets = fread(&cf->compression_info.num_offsets, sizeof(int), 1, cf->fp);
auto fSize = fread(&cf->size, sizeof(int), 1, cf->fp);
auto fBsize = fread(&cf->compression_info.block_size, sizeof(int), 1, cf->fp);
Assertion(cf->compression_info.num_offsets > 0, "Invalid number of offsets, compressed file is possibly in the wrong format or corrupted.");
#if !defined(NDEBUG)
Assertion(cf->size > 4, "Invalid filesize, compressed file is possibly in the wrong format or corrupted.");
Assertion(cf->compression_info.block_size > 16, "Invalid block size, compressed file is possibly in the wrong format or corrupted.");
Assertion(fNumoffsets == 1, "Error while reading the number of offsets, compressed file is possibly in the wrong format or corrupted.");
Assertion(fSize == 1, "Error while reading original filesize, compressed file is possibly in the wrong format or corrupted.");
Assertion(fBsize == 1, "Error while reading block size, compressed file is possibly in the wrong format or corrupted.");
#endif
cf->compression_info.decoder_buffer = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
cf->compression_info.last_decoded_block_pos = 0;
cf->compression_info.last_decoded_block_bytes = 0;
lz41_load_offsets(cf);
}
void lz41_load_offsets(CFILE* cf)
{
cf->compression_info.offsets = (int*)malloc(cf->compression_info.num_offsets * sizeof(int));
int block;
int* offsets_ptr = cf->compression_info.offsets;
/* Seek to the first offset position, remember to consider the trailing ints */
fso_fseek(cf, ( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
for (block = 0; block < cf->compression_info.num_offsets; ++block)
{
auto bytes_read = fread(offsets_ptr++, sizeof(int), 1, cf->fp);
Assertion(bytes_read == 1, "Error reading offset list.");
}
}
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length)
{
LZ4_streamDecode_t lz4_stream_decode_body;
LZ4_streamDecode_t* lz4_stream_decode = &lz4_stream_decode_body;
/* The blocks (current_block to end_block) contain the data we want */
size_t current_block = offset / cf->compression_info.block_size;
size_t end_block = ((offset + length - 1) / cf->compression_info.block_size) + 1;
size_t written_bytes = 0;
if (cf->compression_info.num_offsets <= (int)end_block)
return (size_t)LZ41_OFFSETS_MISMATCH;
/* Seek to the first block to read, if it matches the cached block, search the next one instead */
if (cf->compression_info.last_decoded_block_pos == cf->compression_info.offsets[current_block] && current_block + 1 <= end_block)
fso_fseek(cf, cf->compression_info.offsets[current_block+1], SEEK_SET);
else
fso_fseek(cf, cf->compression_info.offsets[current_block], SEEK_SET);
offset = offset % cf->compression_info.block_size;
char* cmp_buf = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
/* Start decoding */
for (; current_block < end_block; ++current_block)
{
/* Only read and decode if the requested block is not the cached one */
if (cf->compression_info.last_decoded_block_pos != cf->compression_info.offsets[current_block])
{
cf->compression_info.last_decoded_block_pos = cf->compression_info.offsets[current_block];
/* The difference in offsets is the size of the block */
int cmp_bytes = cf->compression_info.offsets[current_block + 1] - cf->compression_info.offsets[current_block];
auto bytes_read = fread(cmp_buf, cmp_bytes, 1, cf->fp);
Assertion(bytes_read == 1, "Error reading from compressed file.");
cf->compression_info.last_decoded_block_bytes = LZ4_decompress_safe_continue(lz4_stream_decode, cmp_buf, cf->compression_info.decoder_buffer, cmp_bytes, cf->compression_info.block_size);
if (cf->compression_info.last_decoded_block_bytes <= 0)
{
free(cmp_buf);
return (size_t)LZ41_DECOMPRESSION_ERROR;
}
}
/* Write out the part of the data we care about from buffer */
size_t block_length = (length < (cf->compression_info.last_decoded_block_bytes - offset) ? length : (cf->compression_info.last_decoded_block_bytes - offset));
memcpy(bytes_out + written_bytes, cf->compression_info.decoder_buffer + offset, (size_t)block_length);
written_bytes += block_length;
offset = 0;
length -= block_length;
}
free(cmp_buf);
return written_bytes;
}
-66
View File
@@ -1,66 +0,0 @@
/*
ShivanSpS - Compressed files support for FSO. Many thanks to ngld, taylor and everyone elsewho helped me in getting this done.
-The file header is a version, this is used to tell FSO how to decompress that file, always use 4 chars to mantain alignment.
-The header ID can be used to add diferent revisions to LZ41 decompression system or to add other compression format supports whiout breaking compatibility.
-The system uses a offset list to record the position of every block in file, this list, along with the number of offsets, original filesize,
and block size, must be written by the compressor app.
-A decoder cache is used to store the last decoded block, this ensures each block is read and decoded only once in sequential reads. This cache
is a little bit bigger than the block size, a higher block size means less overhead added to the file, but it also means a little more ram will
be used during decompression.
-All this dynamic memory is assigned at cfopen() and it is cleared on cfclose().
................................char[4]..........(n ints)...(int)..........(int)..........(int)
-COMPRESSED FILE DATA STUCTURE: HEADER|N BLOCKS|N OFFSETS|NUM_OFFSETS|ORIGINAL_FILESIZE|BLOCK_SIZE
*/
#ifndef _CFILECOMPRESSION_H
#define _CFILECOMPRESSION_H
struct CFILE;
/*LZ41*/
#define LZ41_FILE_HEADER 0x31345A4C // "14ZL" -> "LZ41", inverted
#define LZ41_DECOMPRESSION_ERROR -1
#define LZ41_MAX_BLOCKS_OVERFLOW -2
#define LZ41_HEADER_MISMATCH -3
#define LZ41_OFFSETS_MISMATCH -4
/******/
#define COMP_HEADER_MATCH 1
#define COMP_HEADER_MISMATCH 0
/*
Returns COMP_HEADER_MATCH if header is a valid compressed file header,
returns COMP_HEADER_MISMATCH if it dosent.
*/
int comp_check_header(int header);
/*
This is called to generate the correct compression_info data
after the file has been indentified as a compressed file.
This must be done before calling any other function.
*/
void comp_create_ci(CFILE* cf, int header);
/*
Read X bytes from the uncompressed file starting from X offset.
Returns the amount of bytes read, and 0 or lower to indicate errors.
*/
size_t comp_fread(CFILE* cf, char* buffer, size_t length);
/*
Returns the current uncompressed file position.
*/
size_t comp_ftell(CFILE* cf);
/*
Returns 1 of the uncompressed file has been completely read, otherwise it returns a 0.
*/
int comp_feof(CFILE* cf);
/*
Used to move the uncompressed file current position.
*/
int comp_fseek(CFILE* cf, int offset, int where);
#endif
+5 -13
View File
@@ -246,7 +246,7 @@ Flag exe_params[] =
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
@@ -479,7 +479,6 @@ cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
@@ -511,7 +510,6 @@ int Cmdline_reparse_mainhall = 0;
bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_benchmark_mode = false;
const char *Cmdline_pilot = nullptr;
bool Cmdline_noninteractive = false;
bool Cmdline_json_profiling = false;
bool Cmdline_frame_profile = false;
@@ -1619,7 +1617,7 @@ bool SetCmdlineParams()
Cmdline_game_name = gamename_arg.str();
// be sure that this string fits in our limits
if ( strlen(Cmdline_game_name) >= MAX_GAMENAME_LEN ) {
if ( strlen(Cmdline_game_name) > MAX_GAMENAME_LEN ) {
Cmdline_game_name[MAX_GAMENAME_LEN-1] = '\0';
}
}
@@ -1629,9 +1627,8 @@ bool SetCmdlineParams()
Cmdline_game_password = gamepassword_arg.str();
// 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);
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
if ( strlen(Cmdline_game_name) > MAX_PASSWD_LEN ) {
Cmdline_game_name[MAX_PASSWD_LEN-1] = '\0';
}
}
@@ -1716,7 +1713,7 @@ bool SetCmdlineParams()
sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
} else {
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res));
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".", Cmdline_res));
}
}
if(center_res_arg.found()){
@@ -2126,11 +2123,6 @@ bool SetCmdlineParams()
Cmdline_benchmark_mode = true;
}
if (pilot_arg.found())
{
Cmdline_pilot = pilot_arg.str();
}
if (noninteractive_arg.found())
{
Cmdline_noninteractive = true;
-1
View File
@@ -143,7 +143,6 @@ extern int Cmdline_reparse_mainhall;
extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_benchmark_mode;
extern const char *Cmdline_pilot;
extern bool Cmdline_noninteractive;
extern bool Cmdline_json_profiling;
extern bool Cmdline_frame_profile;
+9 -13
View File
@@ -115,10 +115,10 @@ int Conflict_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
// conflict warning anim coords
int Conflict_warning_coords[GR_NUM_RESOLUTIONS][2] = {
{
320, 420 // GR_640
-1, 420 // GR_640
},
{
512, 669 // GR_1024
-1, 669 // GR_1024
}
};
@@ -1288,7 +1288,7 @@ void control_config_cancel_exit()
{
// Restore all bindings with the backup
std::move(Control_config_backup.begin(), Control_config_backup.end(), Control_config.begin());
std::move(Axis_map_to_backup, Axis_map_to_backup + NUM_JOY_AXIS_ACTIONS, Axis_map_to);
std::move(Axis_map_to_backup, Axis_map_to_backup + JOY_NUM_AXES, Axis_map_to);
std::move(Invert_axis_backup, Invert_axis_backup + JOY_NUM_AXES, Invert_axis);
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
@@ -1934,7 +1934,7 @@ void control_config_do_frame(float frametime)
for (i=0; i<MOUSE_NUM_BUTTONS; i++) {
if (mouse_down(1 << i)) {
Assert(!(z & JOY_AXIS));
control_config_bind_btn(z, CC_bind(CID_JOY0, static_cast<short>(i)), 1);
control_config_bind_btn(z, CC_bind(CID_MOUSE, static_cast<short>(i)), 1);
strcpy_s(bound_string, Joy_button_text[i]);
done = true;
@@ -2295,9 +2295,7 @@ void control_config_do_frame(float frametime)
int sw, sh;
gr_get_string_size(&sw, &sh, conflict_str);
x = Conflict_warning_coords[gr_screen.res][CONTROL_X_COORD] - (sw / 2);
y = Conflict_warning_coords[gr_screen.res][CONTROL_Y_COORD];
gr_printf_menu(x, y, "%s", conflict_str);
gr_string((gr_screen.max_w / 2) - (sw / 2), Conflict_warning_coords[gr_screen.res][1], conflict_str, GR_RESIZE_MENU);
font::set_font(font::FONT1);
} else {
@@ -2552,11 +2550,9 @@ int check_control(int id, int key)
// If we reach this point, then it means this is a continuous control
// which has just been released
if (Script_system.IsActiveAction(CHA_ONACTIONSTOPPED)) {
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RemHookVar("Action");
}
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RemHookVar("Action");
Control_config[id].continuous_ongoing = false;
}
@@ -2651,4 +2647,4 @@ void control_config_clear()
for (auto &item : Control_config) {
item.clear();
}
}
}
+2 -2
View File
@@ -1516,9 +1516,9 @@ void control_config_common_read_section(int s, bool first_override) {
// Assign the various attributes to this control
int iTemp;
short key = 0;
auto item = &Control_config[item_id];
auto& new_binding = new_preset.bindings[item_id];
short key = new_binding.get_btn(CID_KEYBOARD);
// Key assignment and modifiers
if (optional_string("$Key Default:")) {
@@ -1987,7 +1987,7 @@ CCI_builder& CCI_builder::operator()(IoActionId action_id, short key_default, sh
item.type = type;
if (tab == NO_TAB) {
mprintf(("Control item defined without a valid tab. Disabling: %s\n", item.text.c_str()));
mprintf(("Control item defined without a valid tab. Disabling: %s", item.text.c_str()));
}
// Assign disabled state
+3 -2
View File
@@ -93,12 +93,13 @@ class Decoder {
bool m_decoding;
size_t m_queueSize = 0;
Decoder(const Decoder&) SCP_DELETED_FUNCTION;
Decoder& operator=(const Decoder&) SCP_DELETED_FUNCTION;
protected:
Decoder();
public:
Decoder(const Decoder&) = delete;
Decoder& operator=(const Decoder&) = delete;
virtual ~Decoder();
+1 -1
View File
@@ -613,7 +613,7 @@ void cutscenes_screen_do_frame()
if (src)
{
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines,
Cutscene_max_text_lines[gr_screen.res], MAX_TEXT_LINE_LEN);
Cutscene_max_text_lines[gr_screen.res]);
Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
}
}
+6 -4
View File
@@ -45,8 +45,10 @@ struct DecoderStatus {
~DecoderStatus();
DecoderStatus(const DecoderStatus&) = delete;
DecoderStatus& operator=(const DecoderStatus&) = delete;
private:
DecoderStatus(const DecoderStatus&) SCP_DELETED_FUNCTION;
DecoderStatus& operator=(const DecoderStatus&) SCP_DELETED_FUNCTION;
};
template<typename Frame>
@@ -65,8 +67,8 @@ class FFMPEGStreamDecoder {
explicit FFMPEGStreamDecoder(DecoderStatus* status);
virtual ~FFMPEGStreamDecoder();
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) = delete;
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) = delete;
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
virtual void decodePacket(AVPacket* packet) = 0;
+67 -30
View File
@@ -30,9 +30,8 @@
#include "ship/ship.h"
#include "ship/shipfx.h"
#include "species_defs/species_defs.h"
#include "tracing/Monitor.h"
#include "utils/Random.h"
#include "weapon/weapon.h"
#include "tracing/Monitor.h"
#define MIN_RADIUS_FOR_PERSISTANT_DEBRIS 50 // ship radius at which debris from it becomes persistant
#define DEBRIS_SOUND_DELAY 2000 // time to start debris sound after created
@@ -52,6 +51,8 @@ int Debris_model = -1;
int Debris_vaporize_model = -1;
int Debris_num_submodels = 0;
#define MAX_DEBRIS_DIST 10000.0f // Debris goes away if it's this far away.
#define DEBRIS_DISTANCE_CHECK_TIME (10*1000) // Check every 10 seconds.
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
const auto OnDebrisCreatedHook = scripting::Hook::Factory(
@@ -74,7 +75,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]);
if(fireball_type < 0) {
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
}
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
@@ -195,6 +196,34 @@ void debris_delete( object * obj )
db->objnum = -1;
}
/**
* If debris piece *db is far away from all players, make it go away very soon.
* In single player game, delete if MAX_DEBRIS_DIST from player.
* In multiplayer game, delete if MAX_DEBRIS_DIST from all players.
*/
void maybe_delete_debris(debris *db)
{
object *objp;
if (Player_obj != nullptr && timestamp_elapsed(db->next_distance_check) && timestamp_elapsed(db->must_survive_until)) {
if (!(Game_mode & GM_MULTIPLAYER)) { // In single player game, just check against player.
if (vm_vec_dist_quick(&Player_obj->pos, &Objects[db->objnum].pos) > MAX_DEBRIS_DIST)
db->lifeleft = 0.1f;
else
db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME);
} else {
for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
if (objp->flags[Object::Object_Flags::Player_ship]) {
if (vm_vec_dist_quick(&objp->pos, &Objects[db->objnum].pos) < MAX_DEBRIS_DIST) {
db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME);
return;
}
}
}
db->lifeleft = 0.1f;
}
}
}
/**
* Do various updates to debris: check if time to die, start fireballs
@@ -217,7 +246,7 @@ void debris_process_post(object * obj, float frame_time)
radar_plot_object( obj );
if ( timestamp_elapsed(db->sound_delay) ) {
obj_snd_assign(objnum, db->ambient_sound, &vmd_zero_vector);
obj_snd_assign(objnum, db->ambient_sound, &vmd_zero_vector, 0);
db->sound_delay = 0;
}
}
@@ -231,6 +260,8 @@ void debris_process_post(object * obj, float frame_time)
}
}
maybe_delete_debris(db); // Make this debris go away if it's very far away.
// ================== DO THE ELECTRIC ARCING STUFF =====================
if ( db->arc_frequency <= 0 ) {
return; // If arc_frequency <= 0, this piece has no arcs on it
@@ -243,7 +274,7 @@ void debris_process_post(object * obj, float frame_time)
if (db->is_hull) {
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
int n, n_arcs = ((rand()>>5) % 3)+1; // Create 1-3 sparks
vec3d v1, v2, v3, v4;
@@ -252,7 +283,8 @@ void debris_process_post(object * obj, float frame_time)
n = 0;
int lifetime = Random::next(100, 1000);
int a = 100, b = 1000;
int lifetime = (myrand()%((b)-(a)+1))+(a);
// Create the spark effects
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
@@ -319,8 +351,8 @@ void debris_process_post(object * obj, float frame_time)
db->arc_timestamp[i] = timestamp(-1);
} else {
// Maybe move a vertex.... 20% of the time maybe?
int mr = Random::next();
if ( mr < Random::MAX_VALUE/5 ) {
int mr = myrand();
if ( mr < RAND_MAX/5 ) {
vec3d v1, v2;
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
@@ -392,6 +424,17 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
sip = &Ship_info[shipp->ship_info_index];
vaporize = (shipp->flags[Ship::Ship_Flags::Vaporize]);
if ( !hull_flag ) {
// Make vaporize debris seen from farther away
float dist = vm_vec_dist_quick( pos, &Eye_position );
if (vaporize) {
dist /= 2.0f;
}
if ( dist > source_obj->radius * 20.0f ) {
return NULL;
}
}
// try to maintain our soft limit
if (hull_flag && (Num_hull_pieces >= SOFT_LIMIT_DEBRIS_PIECES)) {
// cause oldest hull debris chunk to blow up
@@ -417,15 +460,15 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
if (!hull_flag) {
if (model_num >= 0) {
db->model_num = model_num;
db->submodel_num = Random::next(sip->generic_debris_num_submodels);
db->submodel_num = (myrand() >> 4) % sip->generic_debris_num_submodels;
}
else if (vaporize) {
db->model_num = Debris_vaporize_model;
db->submodel_num = Random::next(Debris_num_submodels);
db->submodel_num = (myrand() >> 4) % Debris_num_submodels;
}
else {
db->model_num = Debris_model;
db->submodel_num = Random::next(Debris_num_submodels);
db->submodel_num = (myrand() >> 4) % Debris_num_submodels;
}
}
else {
@@ -437,17 +480,8 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
float radius = submodel_get_radius(db->model_num, db->submodel_num);
// if its generic, maybe cull it if its too small and far
if (!hull_flag) {
float dist = vm_vec_dist_quick(pos, &Eye_position);
// Make vaporize debris seen from farther away
if (vaporize) {
dist /= 2.0f;
}
if (dist > radius * 200.0f) {
return nullptr;
}
}
//WMC - We must survive until now, at least.
db->must_survive_until = timestamp();
if(hull_flag && sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
{
@@ -457,7 +491,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
{
// Create Debris piece n!
if ( hull_flag ) {
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
if (rand() < RAND_MAX/6) // Make some pieces blow up shortly after explosion.
db->lifeleft = 2.0f * (frand()) + 0.5f;
else {
db->flags.set(Debris_Flags::DoNotExpire);
@@ -475,10 +509,12 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
{
if(sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
{
db->must_survive_until = timestamp(fl2i(sip->debris_min_lifetime * 1000.0f));
db->lifeleft = (( sip->debris_max_lifetime - sip->debris_min_lifetime ) * frand()) + sip->debris_min_lifetime;
}
else if(sip->debris_min_lifetime >= 0.0f)
{
db->must_survive_until = timestamp(fl2i(sip->debris_min_lifetime * 1000.0f));
if(db->lifeleft < sip->debris_min_lifetime)
db->lifeleft = sip->debris_min_lifetime;
}
@@ -503,6 +539,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
db->fire_timeout = 0; // if not changed, timestamp_elapsed() will return false
db->time_started = Missiontime;
db->species = Ship_info[shipp->ship_info_index].species;
db->next_distance_check = (myrand() % 2000) + 4*DEBRIS_DISTANCE_CHECK_TIME;
db->parent_alt_name = shipp->alt_type_index;
db->damage_mult = 1.0f;
@@ -523,7 +560,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
db->next_fireball = timestamp_rand(500,2000); //start one 1/2 - 2 secs later
if ( pos == nullptr )
if ( pos == NULL )
pos = &source_obj->pos;
flagset<Object::Object_Flags> default_flags;
@@ -539,10 +576,10 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
vm_vector_2_matrix(&orient, &rand);
}
objnum = obj_create(OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags, false);
objnum = obj_create( OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags);
if ( objnum == -1 ) {
mprintf(("Couldn't create debris object -- out of object slots\n"));
return nullptr;
return NULL;
}
db->objnum = objnum;
@@ -592,7 +629,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
if ( hull_flag ) {
float t;
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from location of blast center
scale = exp_force * i2fl((myrand()%20) + 10); // for radial_vel away from location of blast center
db->sound_delay = timestamp(DEBRIS_SOUND_DELAY);
// set up physics mass and I_inv for hull debris pieces
@@ -604,7 +641,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
// limit the amount of time that fireballs appear
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
t = 1000*Objects[db->source_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[db->source_objnum].radius));
t = 1000*Objects[db->source_objnum].radius/3 + myrand()%(fl2i(1000*3*Objects[db->source_objnum].radius));
db->fire_timeout = timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
if ( Objects[db->source_objnum].radius < MIN_RADIUS_FOR_PERSISTANT_DEBRIS ) {
@@ -615,7 +652,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
}
}
else {
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from blast center (non-hull)
scale = exp_force * i2fl((myrand()%20) + 10); // for radial_vel away from blast center (non-hull)
}
if ( vm_vec_mag_squared( &to_center ) < 0.1f ) {
@@ -642,7 +679,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
radius = 1.0f;
}
scale = (6.0f + i2fl(Random::next(4))) / radius;
scale = ( 6.0f + i2fl(myrand()%4) ) / radius;
vm_vec_rand_vec_quick(&rotvel);
vm_vec_scale(&rotvel, scale);
+2
View File
@@ -40,6 +40,7 @@ typedef struct debris {
gamesnd_id ambient_sound; // Ambient looping sound
int objnum = -1; // What object this is linked to
float lifeleft; // When 0 or less object dies
int must_survive_until; //WMC - timestamp of earliest point that it can be murthered.
int model_num; // What model this uses
int model_instance_num; // What model instance this uses - needed for arcs
int submodel_num; // What submodel this uses
@@ -49,6 +50,7 @@ typedef struct debris {
int fire_timeout; // timestamp that holds time for fireballs to stop appearing
int sound_delay; // timestamp to signal when sound should start
fix time_started; // time when debris was created
int next_distance_check; // timestamp to determine whether to delete this piece of debris.
vec3d arc_pts[MAX_DEBRIS_ARCS][2]; // The endpoints of each arc
int arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. -1 is not used
+4 -2
View File
@@ -12,7 +12,7 @@ layout (std140) uniform genericData {
vec3 fog_color;
float fog_start;
float fog_density;
float fog_scale;
float zNear;
float zFar;
};
@@ -31,7 +31,9 @@ void main()
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
float fog_dist = clamp(1 - pow(fog_density, view_depth - fog_start) , 0.0, 1.0);
// This is the same formula that is also used by the main shader
float fog_dist = clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
+1 -9
View File
@@ -429,15 +429,7 @@ void main()
fragOut0 = baseColor;
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
// basically make surfaces rougher if local normals change too fast in screenspace
vec2 normDx = dFdx(normal.xy);
vec2 normDy = dFdy(normal.xy);
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
fragOut2 = vec4(normal, min(glossData, glossGeo));
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
#endif
+8 -21
View File
@@ -14,7 +14,6 @@
#include "graphics/tmapper.h"
#include "localization/localize.h"
#include "model/model.h"
#include "nebula/neb.h"
#include "object/object.h"
#include "options/Option.h"
#include "parse/parselo.h"
@@ -287,13 +286,11 @@ static void parse_fireball_tbl(const char *table_filename)
}
}
bool first_time;
// now select our entry accordingly...
// are we using a previous entry?
if (existing_idx >= 0)
{
fi = &Fireball_info[existing_idx];
first_time = false;
}
// we are creating a new entry, so set some defaults
else
@@ -317,7 +314,6 @@ static void parse_fireball_tbl(const char *table_filename)
fireball_set_default_warp_attributes(Num_fireball_types);
Num_fireball_types++;
first_time = true;
}
// copy over what we already parsed
@@ -325,7 +321,6 @@ static void parse_fireball_tbl(const char *table_filename)
strcpy_s(fi->unique_id, unique_id);
strcpy_s(fi->lod[0].filename, fireball_filename);
// Do we have a LOD num?
if (optional_string("$LOD:"))
{
@@ -333,9 +328,6 @@ static void parse_fireball_tbl(const char *table_filename)
if (fi->lod_count > MAX_FIREBALL_LOD)
fi->lod_count = MAX_FIREBALL_LOD;
} else if (first_time) {
//assume a LOD of at least 1
fi->lod_count = 1;
}
// check for particular lighting color
@@ -838,7 +830,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
flagset<Object::Object_Flags> default_flags;
default_flags.set(Object::Object_Flags::Renders);
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags, false);
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags);
obj = &Objects[objnum];
@@ -851,11 +843,11 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
switch( new_fireball->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION:
new_fireball->orient = Random::next() & 7; // 0 - 7
new_fireball->orient = (myrand()>>8) & 7; // 0 - 7
break;
case FIREBALL_LARGE_EXPLOSION:
new_fireball->orient = Random::next(360); // 0 - 359
new_fireball->orient = (myrand()>>8) % 360; // 0 - 359
break;
case FIREBALL_WARP_EFFECT:
@@ -986,9 +978,9 @@ int fireball_ship_explosion_type(ship_info *sip)
}
if(ship_fireballs > 0){
index = sip->explosion_bitmap_anims[Random::next(ship_fireballs)];
index = sip->explosion_bitmap_anims[rand()%ship_fireballs];
} else if(objecttype_fireballs > 0){
index = Ship_types[sip->class_type].explosion_bitmap_anims[Random::next(objecttype_fireballs)];
index = Ship_types[sip->class_type].explosion_bitmap_anims[rand()%objecttype_fireballs];
}
return index;
@@ -1005,7 +997,7 @@ int fireball_asteroid_explosion_type(asteroid_info *aip)
int roid_fireballs = (int)aip->explosion_bitmap_anims.size();
if (roid_fireballs > 0) {
index = aip->explosion_bitmap_anims[Random::next(roid_fireballs)];
index = aip->explosion_bitmap_anims[rand()%roid_fireballs];
}
return index;
@@ -1045,24 +1037,19 @@ void fireball_render(object* obj, model_draw_list *scene)
if ( fb->current_bitmap < 0 )
return;
float alpha = 1.0f;
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_fireballs)
alpha *= neb2_get_fog_visibility(&obj->pos, NEB_FOG_VISIBILITY_MULT_FIREBALL(obj->radius));
g3_transfer_vertex(&p, &obj->pos);
switch ( fb->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION: {
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius, alpha);
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius);
}
break;
case FIREBALL_LARGE_EXPLOSION: {
// Make the big explosions rotate with the viewer.
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius, alpha);
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius);
}
break;
+1 -1
View File
@@ -91,7 +91,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
g3_transfer_vertex( &verts[4], &vecs[4] );
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(&obj->pos, 1.0f) : 1.0f;
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f;
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
+1 -4
View File
@@ -239,10 +239,7 @@ bool GameState_Stack_Valid()
// returns one of the GS_STATE_ macros
int gameseq_get_state(int depth)
{
if (!GameState_Stack_Valid())
return GS_STATE_INVALID;
{
Assert(depth <= gs_current_stack);
return gs[gs_current_stack - depth].current_state;
+20 -20
View File
@@ -526,7 +526,7 @@ void parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& desti
//if we're using the old format, double check the size)
if(!scp_list && (destination.size() != (unsigned)check))
{
mprintf(("%s in '%s' has " SIZE_T_ARG " entries. This does not match entered size of %i.\n", tag, object_name, destination.size(), check));
mprintf(("%s in '%s' has " SIZE_T_ARG " entries. This does not match entered size of %i.", tag, object_name, destination.size(), check));
}
}
}
@@ -544,12 +544,12 @@ void gamesnd_preload_common_sounds()
return;
Assert( Snds.size() <= INT_MAX );
for (auto& gs: Snds) {
if ( gs.preload ) {
for (auto& entry : gs.sound_entries) {
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( gs->preload ) {
for (auto& entry : gs->sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, &gs.flags);
entry.id = snd_load(&entry, gs->flags);
}
}
}
@@ -565,12 +565,12 @@ void gamesnd_load_gameplay_sounds()
return;
Assert( Snds.size() <= INT_MAX );
for (auto& gs: Snds) {
if ( !gs.preload ) { // don't try to load anything that's already preloaded
for (auto& entry : gs.sound_entries) {
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( !gs->preload ) { // don't try to load anything that's already preloaded
for (auto& entry : gs->sound_entries) {
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0) {
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, &gs.flags);
entry.id = snd_load(&entry, gs->flags);
}
}
}
@@ -583,8 +583,8 @@ void gamesnd_load_gameplay_sounds()
void gamesnd_unload_gameplay_sounds()
{
Assert( Snds.size() <= INT_MAX );
for (auto& gs: Snds) {
for (auto& entry : gs.sound_entries) {
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
for (auto& entry : gs->sound_entries) {
if (entry.id.isValid()) {
snd_unload(entry.id);
entry.id = sound_load_id::invalid();
@@ -602,10 +602,10 @@ void gamesnd_load_interface_sounds()
return;
Assert( Snds_iface.size() < INT_MAX );
for (auto& gs: Snds) {
for (auto& entry : gs.sound_entries) {
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
for (auto& entry : si->sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
entry.id = snd_load(&entry, &gs.flags);
entry.id = snd_load(&entry, si->flags);
}
}
}
@@ -751,14 +751,14 @@ bool required_string_no_create(const char* token, bool no_create)
static GameSoundCycleType parse_cycle_type() {
if (optional_string("Sequential")) {
return GameSoundCycleType::SequentialCycle;
return GameSoundCycleType::Sequential;
} else if (optional_string("Random")) {
return GameSoundCycleType::RandomCycle;
return GameSoundCycleType::Random;
} else {
error_display(0, "Failed to parse sound cycle type. Expected 'sequential' or 'random'. Got [%.32s]", next_tokens());
// Ignore everything until the end of the line. That should hopefully skip the bad token.
advance_to_eoln(nullptr);
return GameSoundCycleType::SequentialCycle;
return GameSoundCycleType::Sequential;
}
}
@@ -1349,7 +1349,7 @@ float gamesnd_get_max_duration(game_snd* gs) {
for (auto& entry : gs->sound_entries) {
if (!entry.id.isValid()) {
// Lazily load unloaded sound entries when required
entry.id = snd_load(&entry, &gs->flags);
entry.id = snd_load(&entry, gs->flags);
}
max_length = std::max(max_length, snd_get_duration(entry.id));
@@ -1362,14 +1362,14 @@ game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
size_t index = 0;
switch(gs->cycle_type) {
case GameSoundCycleType::RandomCycle:
case GameSoundCycleType::Random:
if (gs->sound_entries.size() == 1) {
index = 0;
} else {
index = util::UniformRange<size_t>(0, gs->sound_entries.size() - 1).next();
}
break;
case GameSoundCycleType::SequentialCycle:
case GameSoundCycleType::Sequential:
if (gs->last_entry_index == std::numeric_limits<size_t>::max()) {
// If this is the first time we must return the first sound to keep everything consistent
index = 0;
+13 -4
View File
@@ -113,8 +113,6 @@ typedef struct vec2d {
float x, y;
} vec2d;
// Euler angles for a rotation: h=heading, b=bank and p=pitch; angles are around the y, z and x axes
// respectively and are performed in that order.
typedef struct angles {
float p, b, h;
} angles_t;
@@ -130,7 +128,6 @@ typedef struct matrix {
};
} matrix;
// You might think this is also row-major. You fool! It is actually column-major.
typedef struct matrix4 {
union {
struct {
@@ -306,6 +303,8 @@ constexpr bool LoggingEnabled = false;
const float PI2 = (PI*2.0f);
// half values
const float PI_2 = (PI/2.0f);
const int RAND_MAX_2 = (RAND_MAX/2);
const float RAND_MAX_1f = (1.0f / RAND_MAX);
extern int Fred_running; // Is Fred running, or FreeSpace?
@@ -351,6 +350,14 @@ const size_t INVALID_SIZE = static_cast<size_t>(-1);
#define TRUE 1
#define FALSE 0
int myrand();
// Returns a random number between 0 and 0x7fffffff
int rand32();
// Returns a random integer from low to high, inclusive
int rand32(int low, int high);
// lod checker for (modular) table parsing
typedef struct lod_checker {
@@ -456,6 +463,7 @@ SCP_string dump_stacktrace();
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
// This is disabled for VS2013 and lower since that doesn't support the necessary features
#if !defined(NDEBUG) && !defined(USING_THIRD_PARTY_LIBS) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
#if SCP_COMPILER_CXX_AUTO_TYPE && SCP_COMPILER_CXX_STATIC_ASSERT && HAVE_STD_IS_TRIVIALLY_COPYABLE
// feature support seems to be: gcc clang msvc
// auto 4.4 2.9 2010
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
@@ -555,6 +563,7 @@ using std::memcpy_if_trivial_else_error;
using std::memmove_if_trivial_else_error;
using std::memset_if_trivial_else_error;
#endif // HAVE_CXX11
#endif // NDEBUG
#endif // _PSTYPES_H
#endif // PS_TYPES_H
+2
View File
@@ -3,6 +3,8 @@
#define SCP_DEFINES_H
#pragma once
#include "scp_compiler_detection.h"
#define SCP_TOKEN_CONCAT1(x, y) x ## y
#define SCP_TOKEN_CONCAT(x, y) SCP_TOKEN_CONCAT1(x, y)
+45
View File
@@ -57,6 +57,7 @@ vci Viewer_chase_info; // View chase camera information
vec3d leaning_position;
int Is_standalone;
int Rand_count;
int Interface_last_tick = -1; // last timer tick on flip
@@ -108,6 +109,47 @@ float Noise[NOISE_NUM_FRAMES] = {
0.000000f
};
int myrand()
{
int rval;
rval = rand();
Rand_count++;
// nprintf(("Alan","RAND: %d\n", rval));
return rval;
}
// returns a random number between 0 and 0x7fffffff, or something close to it.
int rand32()
{
if (RAND_MAX == 0x7fff) {
int random32;
// this gets two random 16 bit numbers and stuffs them into a 32 bit number
random32 = (rand() << 16) | rand();
//since rand() returns between 0 and 0x7fff, there needs to be a thing to randomly generate the 16th bit
random32 |= ((rand() & 1) << 15);
return random32;
}
else {
return rand();
}
}
int rand32(int low, int high)
{
int diff;
// get diff - don't allow negative or zero
diff = high - low;
if (diff < 0)
diff = 0;
// To get a range of values between min and max, inclusive:
// random value = min + random number % (max - min + 1)
return (low + rand32() % (diff + 1));
}
// Variables for the loading callback hooks
static int cf_timestamp = -1;
static void (*cf_callback)(int count) = NULL;
@@ -328,6 +370,9 @@ void detail_level_set(int level)
Assert( level < NUM_DEFAULT_DETAIL_LEVELS );
Detail = Detail_defaults[level];
// reset nebula stuff
neb2_set_detail_level(level);
}
// Returns the current detail level or -1 if custom.
+1
View File
@@ -94,6 +94,7 @@ extern int Game_mode;
#define SINGLEPLAYER !(Game_mode & GM_MULTIPLAYER)
extern int Viewer_mode;
extern int Rand_count;
extern int Game_restoring; // If set, this means we are restoring data from disk
+1 -1
View File
@@ -67,7 +67,7 @@
#define USED_VARIABLE __attribute__((used))
#if __GNUC__ >= 7
#if SCP_COMPILER_VERSION_MAJOR >= 7
#define FALLTHROUGH [[fallthrough]]
#else
#define FALLTHROUGH
+1 -1
View File
@@ -64,7 +64,7 @@
#define USED_VARIABLE __attribute__((used))
#if __GNUC__ >= 7
#if SCP_COMPILER_VERSION_MAJOR >= 7
#define FALLTHROUGH __attribute__((fallthrough))
#else
#define FALLTHROUGH
+1 -3
View File
@@ -41,7 +41,6 @@
#include "scripting/scripting.h"
#include "tracing/tracing.h"
#include "utils/boost/hash_combine.h"
#include "gamesequence/gamesequence.h"
#ifdef WITH_OPENGL
#include "graphics/opengl/gropengl.h"
@@ -2548,8 +2547,7 @@ void gr_flip(bool execute_scripting)
executor::OnFrameExecutor->process();
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
// Cyborg - A similar bug will occur when a mission is restarted so check for that, too.
if (execute_scripting && !popup_active() && !((gameseq_get_state() == GS_STATE_GAME_PLAY) && !(Game_mode & GM_IN_MISSION))) {
if (execute_scripting && !popup_active()) {
TRACE_SCOPE(tracing::LuaOnFrame);
// WMC - Do conditional hooks. Yippee!
+1 -1
View File
@@ -808,7 +808,7 @@ typedef struct screen {
std::function<void(int bitmap_handle, int bpp, const ubyte* data, int width, int height)> gf_update_texture;
std::function<void(void* data_out, int bitmap_num)> gf_get_bitmap_from_texture;
std::function<void(matrix4* shadow_view_matrix, const matrix* light_matrix, vec3d* eye_pos)> gf_shadow_map_start;
std::function<void(matrix4* shadow_view_matrix, const matrix* light_matrix)> gf_shadow_map_start;
std::function<void()> gf_shadow_map_end;
std::function<void()> gf_start_decal_pass;
+2 -16
View File
@@ -630,7 +630,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime,
else {
// playing forwards
ga->anim_time += frametime;
if(ga->anim_time >= ga->total_time && ga->png.anim->current_frame >= ga->png.anim->nframes) {
if(ga->anim_time >= ga->total_time && ga->png.anim->current_frame >= ga->png.anim->nframes-1) {
if(ga->direction & GENERIC_ANIM_DIRECTION_NOLOOP) {
ga->anim_time = ga->total_time; // stop on last frame when playing
}
@@ -660,7 +660,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime,
}
else {
if (ga->anim_time >= ga->png.previous_frame_time + ga->png.anim->frame.delay &&
ga->png.anim->current_frame < ga->png.anim->nframes) {
ga->png.anim->current_frame < ga->png.anim->nframes-1) {
ga->png.previous_frame_time += ga->png.anim->frame.delay;
ga->current_frame++;
}
@@ -725,17 +725,3 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
}
}
}
/*
* @brief reset an animation back to the start
*
* @param [in] *ga animation data
*/
void generic_anim_reset(generic_anim *ga) {
ga->anim_time = 0.0f;
ga->current_frame = 0;
if (ga->type == BM_TYPE_PNG) {
ga->png.previous_frame_time = 0.0f;
ga->png.anim->goto_start();
}
}
+1 -1
View File
@@ -89,5 +89,5 @@ 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_reset(generic_anim *ga);
#endif
+1 -1
View File
@@ -285,7 +285,7 @@ int gr_stub_maybe_create_shader(shader_type /*shader_t*/, unsigned int /*flags
return -1;
}
void gr_stub_shadow_map_start(matrix4 * /*shadow_view_matrix*/, const matrix* /*light_matrix*/, vec3d* /*eye_pos*/)
void gr_stub_shadow_map_start(matrix4 * /*shadow_view_matrix*/, const matrix* /*light_matrix*/)
{
}
+2 -2
View File
@@ -55,8 +55,8 @@ class ShaderProgram {
ShaderUniforms Uniforms;
ShaderProgram(const ShaderProgram&) = delete;
ShaderProgram& operator=(const ShaderProgram&) = delete;
ShaderProgram(const ShaderProgram&) SCP_DELETED_FUNCTION;
ShaderProgram& operator=(const ShaderProgram&) SCP_DELETED_FUNCTION;
ShaderProgram(ShaderProgram&& other) noexcept;
ShaderProgram& operator=(ShaderProgram&& other) noexcept;
+3 -3
View File
@@ -301,8 +301,8 @@ void gr_opengl_deferred_lighting_finish()
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_emissive_texture);
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture);
float fog_near, fog_far, fog_density;
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density);
float fog_near, fog_far;
neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr);
unsigned char r, g, b;
neb2_get_fog_color(&r, &g, &b);
@@ -311,7 +311,7 @@ void gr_opengl_deferred_lighting_finish()
opengl_set_generic_uniform_data<graphics::generic_data::fog_data>([&](graphics::generic_data::fog_data* data) {
data->fog_start = fog_near;
data->fog_density = fog_density;
data->fog_scale = 1.0f / (fog_far - fog_near);
data->fog_color.xyz.x = r / 255.f;
data->fog_color.xyz.y = g / 255.f;
data->fog_color.xyz.z = b / 255.f;
+2 -2
View File
@@ -706,8 +706,8 @@ void gr_opengl_update_distortion()
for(int i = 0; i < 33; i++)
{
distortion_verts[i].r = (ubyte)Random::next(256);
distortion_verts[i].g = (ubyte)Random::next(256);
distortion_verts[i].r = (ubyte)rand() % 256;
distortion_verts[i].g = (ubyte)rand() % 256;
distortion_verts[i].b = 255;
distortion_verts[i].a = 255;
+1 -1
View File
@@ -34,7 +34,7 @@ void gr_opengl_update_distortion();
void gr_opengl_sphere(material *material_def, float rad);
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient, vec3d* eye_pos);
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient);
void gr_opengl_shadow_map_end();
void gr_opengl_render_shield_impact(shield_material* material_info,
@@ -170,7 +170,7 @@ void opengl_post_pass_bloom()
opengl_set_generic_uniform_data<graphics::generic_data::bloom_composition_data>(
[](graphics::generic_data::bloom_composition_data* data) {
data->levels = MAX_MIP_BLUR_LEVELS;
data->bloom_intensity = gr_bloom_intensity() / 100.0f;
data->bloom_intensity = Cmdline_bloom_intensity / 100.0f;
});
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Bloom_textures[0]);
@@ -442,9 +442,9 @@ void opengl_post_lightshafts()
float dot;
if ( (dot = vm_vec_dot(&light_dir, &Eye_matrix.vec.fvec)) > 0.7f ) {
x = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI * 1.5f +
x = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI * 1.5f +
0.5f; // cant get the coordinates right but this works for the limited glare fov
y = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI * 1.5f * gr_screen.clip_aspect + 0.5f;
y = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI * 1.5f * gr_screen.clip_aspect + 0.5f;
opengl_set_generic_uniform_data<graphics::generic_data::lightshaft_data>(
[&](graphics::generic_data::lightshaft_data* data) {
@@ -871,7 +871,7 @@ bool opengl_post_init_shaders()
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_VERTICAL) < 0 ||
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLOOM_COMP, 0) < 0) {
// disable bloom if we don't have those shaders available
graphics::Post_processing_manager->setBloomShadersOk(false);
Cmdline_bloom_intensity = 0;
}
if (gr_is_fxaa_mode(Gr_aa_mode))
+2 -3
View File
@@ -679,7 +679,7 @@ bool Glowpoint_override_save;
extern bool gr_htl_projection_matrix_set;
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient, vec3d* eye_pos)
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient)
{
if (Shadow_quality == ShadowQuality::Disabled)
return;
@@ -701,8 +701,7 @@ void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light
Glowpoint_override = true;
gr_htl_projection_matrix_set = true;
gr_set_view_matrix(eye_pos, light_orient);
gr_set_view_matrix(&Eye_position, light_orient);
*shadow_view_matrix = gr_view_matrix;
+1 -67
View File
@@ -2,7 +2,6 @@
#include "post_processing.h"
#include "graphics/grinternal.h"
#include "options/Option.h"
#include "parse/parselo.h"
#include "ship/ship.h"
@@ -35,31 +34,6 @@ PostEffectUniformType mapUniformNameToType(const SCP_string& uniform_name)
}
}
// used by In-Game Options menu
bool Post_processing_enable_lightshafts = true;
auto LightshaftsOption =
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();
int Post_processing_bloom_intensity = 25; // using default value of Cmdline_bloom_intensity
auto BloomIntensityOption = 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();
} // namespace
bool PostProcessingManager::parse_table()
@@ -195,49 +169,9 @@ SCP_vector<graphics::post_effect_t>& PostProcessingManager::getPostEffects() { r
const lightshaft_parameters& PostProcessingManager::getLightshaftParams() const { return m_lightshaftParams; }
lightshaft_parameters& PostProcessingManager::getLightshaftParams() { return m_lightshaftParams; }
bool PostProcessingManager::bloomShadersOk() const
{
return m_bloomShadersOk;
}
void PostProcessingManager::setBloomShadersOk(bool ok)
{
m_bloomShadersOk = ok;
}
} // namespace graphics
bool gr_lightshafts_enabled()
{
if (!graphics::Post_processing_manager->getLightshaftParams().on) {
return false;
}
if (Using_in_game_options) {
return graphics::Post_processing_enable_lightshafts;
} else {
return !Cmdline_force_lightshaft_off;
}
}
int gr_bloom_intensity()
{
if (graphics::Post_processing_manager == nullptr || !graphics::Post_processing_manager->bloomShadersOk()) {
return 0;
}
if (Using_in_game_options) {
return graphics::Post_processing_bloom_intensity;
} else {
return Cmdline_bloom_intensity;
}
}
void gr_set_bloom_intensity(int intensity)
{
if (Using_in_game_options) {
graphics::Post_processing_bloom_intensity = intensity;
} else {
Cmdline_bloom_intensity = intensity;
}
return graphics::Post_processing_manager->getLightshaftParams().on && !Cmdline_force_lightshaft_off;
}
+1 -8
View File
@@ -35,7 +35,7 @@ struct post_effect_t {
};
struct lightshaft_parameters {
bool on = true; // enabled by default
bool on = false;
float density = 0.5f;
float weight = 0.02f;
float falloff = 1.0f;
@@ -56,19 +56,12 @@ class PostProcessingManager {
const lightshaft_parameters& getLightshaftParams() const;
lightshaft_parameters& getLightshaftParams();
bool bloomShadersOk() const;
void setBloomShadersOk(bool ok);
private:
SCP_vector<post_effect_t> m_postEffects;
lightshaft_parameters m_lightshaftParams;
bool m_bloomShadersOk = true;
};
} // namespace graphics
bool gr_lightshafts_enabled();
int gr_bloom_intensity();
// used by lab
void gr_set_bloom_intensity(int intensity);
+3 -4
View File
@@ -14,7 +14,6 @@
#include "graphics/matrix.h"
#include "lighting/lighting.h"
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
#include "model/model.h"
#include "model/modelrender.h"
#include "options/Option.h"
@@ -406,7 +405,7 @@ matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float
Shadow_proj_matrix[2] = Shadow_frustums[2].proj_matrix;
Shadow_proj_matrix[3] = Shadow_frustums[3].proj_matrix;
gr_shadow_map_start(&Shadow_view_matrix, &light_matrix, eye_pos);
gr_shadow_map_start(&Shadow_view_matrix, &light_matrix);
return light_matrix;
}
@@ -434,9 +433,9 @@ void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
gr_end_proj_matrix();
gr_end_view_matrix();
// the default cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.
// these cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.
// maybe we could use a more programmatic algorithim?
matrix light_matrix = shadows_start_render(eye_orient, eye_pos, fov, gr_screen.clip_aspect, std::get<0>(Shadow_distances), std::get<1>(Shadow_distances), std::get<2>(Shadow_distances), std::get<3>(Shadow_distances));
matrix light_matrix = shadows_start_render(eye_orient, eye_pos, fov, gr_screen.clip_aspect, 200.0f, 600.0f, 2500.0f, 8000.0f);
model_draw_list scene;
object *objp = Objects;
+6 -6
View File
@@ -120,14 +120,14 @@ namespace font
CFILE* fp = cfopen(typeface.c_str(), "rb", CFILE_NORMAL, CF_TYPE_ANY, localize);
if (fp == NULL)
{
mprintf(("Unable to find font file \"%s\"\n", typeface.c_str()));
mprintf(("Unable to find font file \"%s\".", typeface.c_str()));
return NULL;
}
std::unique_ptr<font> fnt(new font());
if (!fnt)
{
mprintf(("Unable to allocate memory for \"%s\"\n", typeface.c_str()));
mprintf(("Unable to allocate memory for \"%s\"", typeface.c_str()));
return NULL;
}
@@ -283,7 +283,7 @@ namespace font
if (fontFile == NULL)
{
mprintf(("Couldn't open font file \"%s\"\n", fileName.c_str()));
mprintf(("Couldn't open font file \"%s\"", fileName.c_str()));
return NULL;
}
@@ -293,14 +293,14 @@ namespace font
if (!fontData)
{
mprintf(("Couldn't allocate " SIZE_T_ARG " bytes for reading font file \"%s\"!\n", size, fileName.c_str()));
mprintf(("Couldn't allocate " SIZE_T_ARG " bytes for reading font file \"%s\"!", size, fileName.c_str()));
cfclose(fontFile);
return NULL;
}
if (!cfread(fontData.get(), (int)size, 1, fontFile))
{
mprintf(("Error while reading font data from \"%s\"\n", fileName.c_str()));
mprintf(("Error while reading font data from \"%s\"", fileName.c_str()));
cfclose(fontFile);
return NULL;
}
@@ -323,7 +323,7 @@ namespace font
if (handle < 0)
{
mprintf(("Couldn't couldn't create font for file \"%s\"\n", fileName.c_str()));
mprintf(("Couldn't couldn't create font for file \"%s\"", fileName.c_str()));
return NULL;
}
+4 -2
View File
@@ -33,8 +33,10 @@ namespace font {
return *this;
}
TrueTypeFontData(const TrueTypeFontData &) = delete;
TrueTypeFontData &operator=(const TrueTypeFontData &) = delete;
private:
TrueTypeFontData(const TrueTypeFontData &) SCP_DELETED_FUNCTION;
TrueTypeFontData &operator=(const TrueTypeFontData &) SCP_DELETED_FUNCTION;
};
// Forward declarations
+8
View File
@@ -40,7 +40,9 @@ class UniformAligner {
{
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(addElement());
}
@@ -48,7 +50,9 @@ class UniformAligner {
template<typename THeader>
THeader* getHeader() {
Assertion(sizeof(THeader) == _headerSize, "Header size does not match requested header type!");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<THeader>::value, "Header type must be trivially copyable!");
#endif
return reinterpret_cast<THeader*>(_buffer);
}
@@ -59,7 +63,9 @@ class UniformAligner {
T* getTypedElement(size_t index) {
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(getElement(index));
}
@@ -76,7 +82,9 @@ class UniformAligner {
T* nextTypedElement(T* currentEl) {
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(nextElement(reinterpret_cast<void*>(currentEl)));
}
+1 -1
View File
@@ -284,7 +284,7 @@ struct fog_data {
vec3d fog_color;
float fog_start;
float fog_density;
float fog_scale;
float zNear;
float zFar;
+1 -1
View File
@@ -121,7 +121,7 @@ bool stub_bm_data(int /*n*/, bitmap* /*bm*/) { return true; }
int stub_maybe_create_shader(shader_type /*shader_t*/, unsigned int /*flags*/) { return -1; }
void stub_shadow_map_start(matrix4* /*shadow_view_matrix*/, const matrix* /*light_matrix*/, vec3d* /*eye_pos*/) {}
void stub_shadow_map_start(matrix4* /*shadow_view_matrix*/, const matrix* /*light_matrix*/) {}
void stub_shadow_map_end() {}
Regular → Executable
+24 -35
View File
@@ -23,7 +23,6 @@
#include "object/object.h"
#include "parse/parselo.h"
#include "sound/sound.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/weapon.h"
@@ -303,7 +302,7 @@ void ssm_create(object *target, vec3d *start, size_t ssm_index, ssm_firing_info
count = Ssm_info[ssm_index].count;
if (Ssm_info[ssm_index].max_count != -1) {
count += Random::next(count, Ssm_info[ssm_index].max_count);
count += rand32(count, Ssm_info[ssm_index].max_count);
}
// override in multiplayer
@@ -400,45 +399,35 @@ void ssm_process()
if(moveup->fireballs[idx] >= 0){
if ((1.0f - fireball_lifeleft_percent(&Objects[moveup->fireballs[idx]])) >= moveup->sinfo.duration) {
weapon_info *wip = &Weapon_info[si->weapon_info_index];
// get an orientation
vec3d temp;
matrix orient;
vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
vm_vec_normalize(&temp);
vm_vector_2_matrix(&orient, &temp, nullptr, nullptr);
// are we a beam? -MageKing17
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
int num_beams = wip->b_info.beam_type == 5 && (int)wip->b_info.t5info.burst_rot_pattern.size() > 1 ?
(int)wip->b_info.t5info.burst_rot_pattern.size() : 1;
for (int i = 0; i < num_beams; i++) {
beam_fire_info fire_info;
memset(&fire_info, 0, sizeof(beam_fire_info));
beam_fire_info fire_info;
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 0.000001f; // this will guarantee a hit
fire_info.shooter = nullptr;
fire_info.turret = nullptr;
fire_info.target = moveup->sinfo.target;
fire_info.target_subsys = nullptr;
fire_info.bfi_flags |= BFIF_FLOATING_BEAM;
fire_info.starting_pos = moveup->sinfo.start_pos[idx];
fire_info.beam_info_index = si->weapon_info_index;
fire_info.team = static_cast<char>(moveup->sinfo.ssm_team);
fire_info.fire_method = BFM_SUBSPACE_STRIKE;
fire_info.burst_index = i;
fire_info.accuracy = 0.000001f; // this will guarantee a hit
fire_info.shooter = NULL;
fire_info.turret = NULL;
fire_info.target = moveup->sinfo.target;
fire_info.target_subsys = NULL;
fire_info.bfi_flags |= BFIF_FLOATING_BEAM;
fire_info.starting_pos = moveup->sinfo.start_pos[idx];
fire_info.beam_info_index = si->weapon_info_index;
fire_info.team = static_cast<char>(moveup->sinfo.ssm_team);
fire_info.fire_method = BFM_SUBSPACE_STRIKE;
// Fill target_pos but DONT turn on BFIF_TARGETING_COORDS
// It would mess up normal beams but type 5s can still make use of this
fire_info.target_pos1 = orient.vec.fvec + fire_info.starting_pos;
// fire the beam
beam_fire(&fire_info);
// fire the beam
beam_fire(&fire_info);
moveup->done_flags[idx] = true;
}
moveup->done_flags[idx] = true;
} else {
// get an orientation
vec3d temp;
matrix orient;
vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
vm_vec_normalize(&temp);
vm_vector_2_matrix(&orient, &temp, NULL, NULL);
// fire the missile and flash the screen
weapon_objnum = weapon_create(&moveup->sinfo.start_pos[idx], &orient, si->weapon_info_index, -1, -1, 1);
+345 -330
View File
@@ -31,7 +31,7 @@
#include "weapon/emp.h"
static int Show_escort_view;
int Show_escort_view;
typedef struct escort_info
{
@@ -45,31 +45,14 @@ typedef struct escort_info
int escort_hit_timer;
int escort_hit_next_flash;
bool escort_show_bright;
escort_info() : objnum(-1), obj_signature(-1), priority(-1), np_id(-1),
escort_hit_timer(0), escort_hit_next_flash(0), escort_show_bright(false) {}
} escort_info;
static SCP_list<escort_info> Escort_ships;
int Max_escort_ships = 3;
escort_info Escort_ships[MAX_COMPLETE_ESCORT_LIST];
int Num_escort_ships;
int Max_escort_ships = 3;
static int Last_target_index; // index into Escort_gauges for last targeted via 'Next Escort Target' key
static SCP_list<escort_info>::iterator get_escort_entry_from_index(int index)
{
int e_idx = 0;
auto it = Escort_ships.begin();
while ( (e_idx != index) && (it != Escort_ships.end()) ) {
++it;
++e_idx;
}
return it;
}
HudGaugeEscort::HudGaugeEscort():
HudGauge(HUD_OBJECT_ESCORT, HUD_ESCORT_VIEW, false, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_OTHER_SHIP), 255, 255, 255)
{
@@ -170,7 +153,6 @@ int HudGaugeEscort::setGaugeColorEscort(int index, int team)
int is_flashing = 0;
int is_bright = 0;
int seen_from_team = (Player_ship != NULL) ? Player_ship->team : -1;
int objnum = -1;
// multiplayer dogfight
if(MULTI_DOGFIGHT)
@@ -178,39 +160,19 @@ int HudGaugeEscort::setGaugeColorEscort(int index, int team)
setGaugeColor();
return 0;
}
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return 0;
}
if ( (Game_mode & GM_MULTIPLAYER) && (eship->np_id >= 0) ) {
int np_index = find_player_index(eship->np_id);
if ( (np_index >= 0) && (Net_players[np_index].m_player != nullptr) ) {
objnum = Net_players[np_index].m_player->objnum;
}
} else {
objnum = eship->objnum;
}
if (objnum < 0) {
return 0;
}
// set flashing color
if (!timestamp_elapsed(eship->escort_hit_timer))
if (!timestamp_elapsed(Escort_ships[index].escort_hit_timer))
{
is_flashing = 1;
if (eship->escort_show_bright)
if (Escort_ships[index].escort_show_bright)
{
is_bright = 1;
}
}
// Goober5000 - now base this on team color
gr_set_color_fast(iff_get_color_by_team_and_object(team, seen_from_team, is_bright, &Objects[objnum]));
gr_set_color_fast(iff_get_color_by_team_and_object(team, seen_from_team, is_bright, &Objects[Escort_ships[index].objnum]));
// Goober5000 - an alternative; same as original but incorporating teams for non-friendlies
@@ -242,7 +204,7 @@ void HudGaugeEscort::render(float /*frametime*/)
return;
}
if ( Escort_ships.empty() ) {
if ( !Num_escort_ships ) {
return;
}
@@ -257,12 +219,12 @@ void HudGaugeEscort::render(float /*frametime*/)
int y = position[1] + list_start_offsets[1];
//This is temporary
int num_escort_ships = std::min(hud_escort_num_ships_on_list(), Max_escort_ships) - 1;
Num_escort_ships--;
i=0;
if(num_escort_ships > 0)
if(Num_escort_ships)
{
for(; i < num_escort_ships; i++)
for(; i < Num_escort_ships; i++)
{
if(i != 0)
{
@@ -280,6 +242,9 @@ void HudGaugeEscort::render(float /*frametime*/)
y += entry_h;
}
//Back to right #
Num_escort_ships++;
//Show the last escort entry
renderBitmap(Escort_gauges[2].first_frame, x, y + bottom_bg_offset);
renderIcon(x, y, i);
@@ -295,32 +260,10 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
}
float shields, integrity;
int screen_integrity, offset, objnum = -1;
int screen_integrity, offset;
char buf[255];
const player *pl = nullptr;
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return;
}
if ( (Game_mode & GM_MULTIPLAYER) && (eship->np_id >= 0) ) {
int np_index = find_player_index(eship->np_id);
if (np_index >= 0) {
pl = Net_players[np_index].m_player;
objnum = pl->objnum;
}
} else {
objnum = eship->objnum;
}
if (objnum < 0) {
return;
}
object *objp = &Objects[objnum];
object *objp = &Objects[Escort_ships[index].objnum];
ship *sp = &Ships[objp->instance];
// determine if its "friendly" or not
@@ -341,20 +284,6 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
// print out ship name
strcpy_s(buf, sp->get_display_name());
// maybe add callsign if multi and player ship
if (pl) {
SCP_string callsign;
callsign.reserve(32);
callsign += " (";
callsign += pl->short_callsign;
callsign += ")";
strcat_s(buf, callsign.c_str());
}
const int w = font::force_fit_string(buf, 255, ship_name_max_width);
if (right_align_names) {
@@ -394,15 +323,8 @@ void HudGaugeEscort::renderIconDogfight(int x, int y, int index)
// always use the standard color to avoid confusion
setGaugeColor();
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return;
}
// netplayer index
np_index = find_player_index(eship->np_id);
np_index = find_player_id(Escort_ships[index].np_id);
if((np_index < 0) || (np_index >= MAX_PLAYERS) || (Net_players[np_index].m_player == NULL)){
return;
}
@@ -438,11 +360,17 @@ void HudGaugeEscort::renderIconDogfight(int x, int y, int index)
void hud_escort_update_list()
{
for (auto &es : Escort_ships) {
if ( !timestamp_elapsed(es.escort_hit_timer) ) {
if (timestamp_elapsed(es.escort_hit_next_flash)) {
es.escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
es.escort_show_bright = !es.escort_show_bright; // toggle between default and bright frames
if(Num_escort_ships)
{
for(int i = 0; i < Num_escort_ships; i++)
{
if (!timestamp_elapsed(Escort_ships[i].escort_hit_timer))
{
if (timestamp_elapsed(Escort_ships[i].escort_hit_next_flash))
{
Escort_ships[i].escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
Escort_ships[i].escort_show_bright = !Escort_ships[i].escort_show_bright; // toggle between default and bright frames
}
}
}
}
@@ -463,75 +391,99 @@ void hud_escort_init()
//
void hud_escort_clear_all(bool clear_flags)
{
if (clear_flags) {
for (auto &es : Escort_ships) {
if ( (es.objnum >= 0) && (Objects[es.objnum].type == OBJ_SHIP) && (Objects[es.objnum].instance >= 0) ) {
Ships[Objects[es.objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
}
}
int i;
Escort_ships.clear();
Num_escort_ships = 0;
for ( i = 0; i < Max_escort_ships; i++ ) {
if(clear_flags && (Escort_ships[i].objnum >= 0) && (Objects[Escort_ships[i].objnum].type == OBJ_SHIP) && (Objects[Escort_ships[i].objnum].instance >= 0)){
Ships[Objects[Escort_ships[i].objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
Escort_ships[i].obj_signature = -99;
Escort_ships[i].np_id = -1;
Escort_ships[i].escort_hit_timer = 0;
Escort_ships[i].escort_hit_next_flash = 0;
Escort_ships[i].escort_show_bright = false;
}
}
// internal helper function for sort.
// sorts first by priority number and then alphabetically
static bool escort_compare(const escort_info &escort1, const escort_info &escort2)
int escort_compare_func(const void *e1, const void *e2)
{
if (MULTI_DOGFIGHT) {
int n1 = find_player_index(escort1.np_id);
int n2 = find_player_index(escort2.np_id);
escort_info *escort1, *escort2;
int diff;
int ret;
if ( (n1 < 0) || (n2 < 0) || (Net_players[n1].m_player == nullptr) || (Net_players[n2].m_player == nullptr) ) {
return false;
}
escort1 = (escort_info*) e1;
escort2 = (escort_info*) e2;
return (Net_players[n1].m_player->stats.m_kill_count_ok >= Net_players[n2].m_player->stats.m_kill_count_ok);
} else {
// in multi, players go to the top
if (Game_mode & GM_MULTIPLAYER) {
if ( (escort1.np_id >= 0) && (escort2.np_id < 0) ) {
return true;
} else if ( (escort1.np_id < 0) && (escort2.np_id >= 0) ) {
return false;
// multiplayer dogfight
if(MULTI_DOGFIGHT){
int n1, n2;
n1 = find_player_id(escort1->np_id);
n2 = find_player_id(escort2->np_id);
if((n1 < 0) || (n2 < 0) || (Net_players[n1].m_player == NULL) || (Net_players[n2].m_player == NULL)){
ret = 0;
} else {
// player 1 is higher than player 2
if(Net_players[n1].m_player->stats.m_kill_count_ok >= Net_players[n2].m_player->stats.m_kill_count_ok){
ret = -1;
} else {
ret = 1;
}
}
} else {
diff = escort2->priority - escort1->priority;
if (escort1.priority != escort2.priority) {
return (escort1.priority > escort2.priority);
} else if ( (escort1.objnum >= 0) && (Objects[escort1.objnum].instance >= 0) &&
(escort2.objnum >= 0) && (Objects[escort2.objnum].instance >= 0) )
{
const char *name1 = Ships[Objects[escort1.objnum].instance].ship_name;
const char *name2 = Ships[Objects[escort2.objnum].instance].ship_name;
if (diff != 0) {
ret = diff;
} else {
char *name1, *name2;
name1 = Ships[Objects[escort1->objnum].instance].ship_name;
name2 = Ships[Objects[escort2->objnum].instance].ship_name;
return (stricmp(name1, name2) > 0);
ret = stricmp(name1, name2);
}
}
return false;
return ret;
}
// create complete priority sorted escort list for all active ships
// escorts - array of escort info
// num_escorts - number of escorts requests in field of active ships
// This will be culled to MAX_ESCORTS, selecting the top set from escorts
void hud_create_complete_escort_list()
void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
{
ship_obj *so;
object *objp;
object *objp;
// start with none on list
*num_escorts = 0;
int idx;
// multiplayer dogfight
if (MULTI_DOGFIGHT) {
for (idx = 0; idx < MAX_PLAYERS; idx++) {
// is this a valid player
if ( MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) ) {
// add the ship
escort_info einfo;
einfo.np_id = Net_players[idx].player_id;
if(MULTI_DOGFIGHT){
for(idx=0; idx<MAX_PLAYERS; idx++){
// break out of the loop when we have reached our max
if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
mprintf(("exceeded max ships in big escort list\n"));
break;
}
Escort_ships.push_back(einfo);
// is this a valid player
if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
// add the ship
escorts[*num_escorts].objnum = -1;
escorts[*num_escorts].obj_signature = -1;
escorts[*num_escorts].priority = -1;
escorts[*num_escorts].np_id = Net_players[idx].player_id;
escorts[*num_escorts].escort_hit_timer = 0;
escorts[*num_escorts].escort_hit_next_flash = 0;
escorts[*num_escorts].escort_show_bright = false;
(*num_escorts)++;
}
}
}
@@ -548,13 +500,19 @@ void hud_create_complete_escort_list()
continue;
}
// break out of the loop when we have reached our max
if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
mprintf(("exceeded max ships in big escort list\n"));
break;
}
// only process ships that might be on the list
if ( !(Ships[objp->instance].flags[Ship::Ship_Flags::Escort]) ) {
if ( !(Ships[objp->instance].flags[Ship::Ship_Flags::Escort]) ){
continue;
}
// only process ships that can be seen by sensors
if ( (Ships[objp->instance].flags[Ship::Ship_Flags::Hidden_from_sensors]) ) {
if ( (Ships[objp->instance].flags[Ship::Ship_Flags::Hidden_from_sensors]) ){
continue;
}
@@ -582,12 +540,14 @@ void hud_create_complete_escort_list()
}
// add the ship
escort_info einfo;
einfo.objnum = so->objnum;
einfo.obj_signature = objp->signature;
einfo.priority = Ships[objp->instance].escort_priority;
Escort_ships.push_back(einfo);
escorts[*num_escorts].objnum = so->objnum;
escorts[*num_escorts].obj_signature = objp->signature;
escorts[*num_escorts].priority = Ships[objp->instance].escort_priority;
escorts[*num_escorts].np_id = -1;
escorts[*num_escorts].escort_hit_timer = 0;
escorts[*num_escorts].escort_hit_next_flash = 0;
escorts[*num_escorts].escort_show_bright = false;
(*num_escorts)++;
}
}
}
@@ -596,26 +556,36 @@ void hud_create_complete_escort_list()
// ----------------------------------------------------------------------
// hud_init_escort_info()
//
// Set up the initial escort list
// Set up the escort list
//
void hud_setup_escort_list(int level)
{
// this should never be called while in a mission
if (Game_mode & GM_IN_MISSION) {
return;
int num_escorts, num_complete_escorts;
escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
hud_escort_clear_all();
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
// set number in escort list
num_escorts = num_complete_escorts;
if (num_escorts > Max_escort_ships) {
num_escorts = Max_escort_ships;
}
Escort_ships.clear();
// build escort list
hud_create_complete_escort_list();
// and sort it by priority
Escort_ships.sort(escort_compare);
// then resize the list to fit max
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
// add ships to escort list
for (Num_escort_ships=0; Num_escort_ships<num_escorts; Num_escort_ships++) {
Escort_ships[Num_escort_ships].obj_signature = complete_escorts[Num_escort_ships].obj_signature;
Escort_ships[Num_escort_ships].priority = complete_escorts[Num_escort_ships].priority;
Escort_ships[Num_escort_ships].objnum = complete_escorts[Num_escort_ships].objnum;
Escort_ships[Num_escort_ships].np_id = complete_escorts[Num_escort_ships].np_id;
Escort_ships[Num_escort_ships].escort_hit_timer = 0;
Escort_ships[Num_escort_ships].escort_hit_next_flash = 0;
Escort_ships[Num_escort_ships].escort_show_bright = false;
}
if(level){
@@ -623,81 +593,151 @@ void hud_setup_escort_list(int level)
}
}
// re-sort the escort list
void hud_resort_escort_list()
// combine complete escort list with Escort_ships, keeping valid hit info
void merge_escort_lists(escort_info *complete_escorts, int num_complete_escorts)
{
Escort_ships.sort(escort_compare);
int i, j, top_complete_escorts;
int valid_hit_info[MAX_COMPLETE_ESCORT_LIST];
// may be > 1 ship change to list (ie, 2 or 3 culled during same frame)
// set Num_escort_ships and cap
Num_escort_ships = num_complete_escorts;
if (Num_escort_ships > Max_escort_ships) {
Num_escort_ships = Max_escort_ships;
}
// nothing to do
if (Num_escort_ships == 0) {
return;
}
// check used as a flag whether top slots in complete_escorts were copied
// this is important re. hit info
for (i=0; i<Max_escort_ships; i++) {
valid_hit_info[i] = 0;
}
// get the top slots in complete escort list that will be copied onto Escort_ships
top_complete_escorts = num_complete_escorts;
if (top_complete_escorts > Max_escort_ships) {
top_complete_escorts = Max_escort_ships;
}
// copy for Escort_ships to complete_escorts to retain hit_info
if(!MULTI_DOGFIGHT) {
for (i=0; i<top_complete_escorts; i++) {
for (j=0; j<Num_escort_ships; j++) {
if (Escort_ships[j].obj_signature == complete_escorts[i].obj_signature) {
complete_escorts[i] = Escort_ships[j];
valid_hit_info[i] = 1;
break;
}
}
}
// copy top slots to Escort_ships
for (i=0; i<top_complete_escorts; i++) {
Escort_ships[i] = complete_escorts[i];
// check all ships are valid
int objnum = Escort_ships[i].objnum;
Assert( objnum >=0 && objnum < MAX_OBJECTS );
if((objnum < 0) || (objnum >= MAX_OBJECTS)){
continue;
}
if ( !valid_hit_info[i] ) {
Escort_ships[i].escort_hit_timer = 0;
Escort_ships[i].escort_hit_next_flash = 0;
Escort_ships[i].escort_show_bright = false;
}
}
}
// reset Num_escort_ships
Num_escort_ships = top_complete_escorts;
}
// ----------------------------------------------------------------------
// hud_remove_ship_from_escort_index()
//
// Take a ship out of the escort list
void hud_remove_ship_from_escort_index(int dead_index, int objnum)
{
int i, count, num_complete_escorts;
escort_info bakup_arr[MAX_COMPLETE_ESCORT_LIST], complete_escorts[MAX_COMPLETE_ESCORT_LIST];
// remove him from escort list
if((objnum >= 0) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0)){
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
count = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( i != dead_index ) {
bakup_arr[count++] = Escort_ships[i];
}
}
for ( i = 0; i < count; i++ ) {
Escort_ships[i] = bakup_arr[i];
}
Num_escort_ships--;
Assert(Num_escort_ships >= 0);
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
// merge list
merge_escort_lists(complete_escorts, num_complete_escorts);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
}
// called once per frame to refresh the escort list if important flags changed
void hud_escort_cull_list()
{
if ( Escort_ships.empty() ) {
return;
}
int i;
int np_index;
auto it = Escort_ships.begin();
// multiplayer dogfight
if(MULTI_DOGFIGHT){
while (it != Escort_ships.end()) {
np_index = find_player_index(it->np_id);
for ( i = 0; i < Num_escort_ships; i++ ) {
np_index = find_player_id(Escort_ships[i].np_id);
// maybe remove him if he left
if (np_index < 0) {
it = Escort_ships.erase(it);
} else {
++it;
if ( np_index < 0 ) {
hud_setup_escort_list(0);
break;
}
}
}
}
// everything else
else {
int objnum;
bool remove;
for ( i = 0; i < Num_escort_ships; i++ ) {
int objnum = Escort_ships[i].objnum;
Assert( objnum >=0 && objnum < MAX_OBJECTS );
while (it != Escort_ships.end()) {
remove = false;
objnum = it->objnum;
// player ships should stay so long as they are valid
if ( (Game_mode & GM_MULTIPLAYER) && (it->np_id >= 0) ) {
np_index = find_player_index(it->np_id);
// maybe remove him if he left
if (np_index < 0) {
remove = true;
}
} else if (Objects[objnum].flags[Object::Object_Flags::Should_be_dead]) {
remove = true;
} else if (Objects[objnum].type == OBJ_SHIP) {
if ( Objects[objnum].flags[Object::Object_Flags::Should_be_dead] ) {
hud_setup_escort_list(0);
break;
} else if ( Objects[objnum].type == OBJ_SHIP ) {
int shipnum = Objects[objnum].instance;
Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
if ( !(Ships[shipnum].flags[Ship::Ship_Flags::Escort]) ) {
remove = true;
} else if (Ships[shipnum].flags[Ship::Ship_Flags::Hidden_from_sensors]) {
remove = true;
} else if (Ships[shipnum].flags[Ship::Ship_Flags::Stealth]) {
if (Ships[shipnum].team != Player_ship->team) {
// friendly stealths are only not seen when explicitly specified
if ( Ships[shipnum].flags[Ship::Ship_Flags::Friendly_stealth_invis]) {
remove = true;
}
}
// non-friendly stealths are never seen
else {
remove = true;
}
if ( (Ships[shipnum].flags[Ship::Ship_Flags::Hidden_from_sensors])
|| ((Ships[shipnum].flags[Ship::Ship_Flags::Stealth]) && ((Ships[shipnum].team != Player_ship->team) || (Ships[shipnum].flags[Ship::Ship_Flags::Friendly_stealth_invis])))
) {
hud_setup_escort_list(0);
break;
}
}
if (remove) {
it = Escort_ships.erase(it);
} else {
++it;
}
}
}
}
@@ -718,68 +758,62 @@ void hud_escort_view_toggle()
// try to add a ship to the escort list, if slot available
void hud_add_ship_to_escort(int objnum, int supress_feedback)
{
// no ships on the escort list in multiplayer dogfight
if (MULTI_DOGFIGHT) {
return;
}
escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
int num_complete_escorts, idx, found;
if (objnum < 0) {
UNREACHABLE("Invalid objnum passed to hud_add_ship_to_escort()!");
return;
}
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
if (Objects[objnum].type != OBJ_SHIP) {
if ( !supress_feedback ) {
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
}
return;
}
// ensure the complete escort list is not full already
if (num_complete_escorts == MAX_COMPLETE_ESCORT_LIST)
{
return;
}
// check if ship is already on complete escort list
bool found = false;
for (auto &es : Escort_ships) {
if (es.obj_signature == Objects[objnum].signature) {
found = true;
found = 0;
for (idx=0; idx<num_complete_escorts; idx++) {
if (complete_escorts[idx].obj_signature == Objects[objnum].signature) {
found = 1;
break;
}
}
// add new ship into complete list
if ( !found ) {
escort_info einfo;
complete_escorts[num_complete_escorts].objnum = objnum;
complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature;
complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority;
complete_escorts[num_complete_escorts].escort_hit_timer = 0;
complete_escorts[num_complete_escorts].escort_hit_next_flash = 0;
complete_escorts[num_complete_escorts].escort_show_bright = false;
einfo.objnum = objnum;
einfo.obj_signature = Objects[objnum].signature;
einfo.priority = Ships[Objects[objnum].instance].escort_priority;
// add him to escort list
Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort);
// add him to escort list and re-sort
Escort_ships.push_back(einfo);
Escort_ships.sort(escort_compare);
Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort);
num_complete_escorts++;
}
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
// maybe do feedback
if ( !supress_feedback ) {
found = false;
// merge list
merge_escort_lists(complete_escorts, num_complete_escorts);
// search thru list for objnum
for (auto &es : Escort_ships) {
if (es.objnum == objnum) {
found = true;
break;
}
// maybe do feedback
if ( (Num_escort_ships == Max_escort_ships) && !supress_feedback) {
found = 0;
// search thru list for objnum
for (idx=0; idx<Num_escort_ships; idx++) {
if (Escort_ships[idx].objnum == objnum) {
found = 1;
break;
}
}
if ( !found ) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), hud_escort_num_ships_on_list());
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
}
if (!found) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships);
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
}
}
@@ -792,6 +826,8 @@ void hud_add_ship_to_escort(int objnum, int supress_feedback)
//
void hud_add_remove_ship_escort(int objnum, int supress_feedback)
{
int in_escort, i;
// no ships on the escort list in multiplayer dogfight
if(MULTI_DOGFIGHT){
return;
@@ -809,27 +845,26 @@ void hud_add_remove_ship_escort(int objnum, int supress_feedback)
return;
}
// if it's in the list already just remove it
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->obj_signature == Objects[objnum].signature) {
if ( (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) ) {
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
Escort_ships.erase(it);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
return;
in_escort = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
in_escort = 1;
break;
}
}
// otherwise add ship to list
if ( in_escort ) {
hud_remove_ship_from_escort_index(i, objnum);
return;
}
hud_add_ship_to_escort(objnum, supress_feedback);
}
void hud_remove_ship_from_escort(int objnum)
{
int in_escort, i;
// no ships on the escort list in multiplayer dogfight
if(MULTI_DOGFIGHT){
return;
@@ -840,19 +875,18 @@ void hud_remove_ship_from_escort(int objnum)
return;
}
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->obj_signature == Objects[objnum].signature) {
if ( (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) ) {
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
Escort_ships.erase(it);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
in_escort = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
in_escort = 1;
break;
}
}
if ( in_escort ) {
hud_remove_ship_from_escort_index(i, objnum);
return;
}
}
/**
@@ -869,14 +903,11 @@ void hud_escort_ship_hit(object *objp, int /*quadrant*/)
return;
}
int objnum = OBJ_INDEX(objp);
for (auto &es : Escort_ships) {
if (es.objnum == objnum) {
for ( int i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].objnum == OBJ_INDEX(objp) ) {
hud_gauge_popup_start(HUD_ESCORT_VIEW);
es.escort_hit_timer = timestamp(SHIELD_HIT_DURATION);
es.escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
break;
Escort_ships[i].escort_hit_timer = timestamp(SHIELD_HIT_DURATION);
Escort_ships[i].escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
}
}
}
@@ -886,24 +917,17 @@ void hud_escort_target_next()
{
int objnum;
if ( Escort_ships.empty() ) {
if ( Num_escort_ships == 0 ) {
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f );
return;
}
Last_target_index++;
if ( Last_target_index >= hud_escort_num_ships_on_list() ) {
if ( Last_target_index >= Num_escort_ships ) {
Last_target_index = 0;
}
auto eship = get_escort_entry_from_index(Last_target_index);
if ( (eship == Escort_ships.end()) || (eship->objnum < 0) ) {
return;
}
objnum = eship->objnum;
objnum = Escort_ships[Last_target_index].objnum;
set_target_objnum( Player_ai, objnum);
hud_restore_subsystem_target(&Ships[Objects[objnum].instance]);
}
@@ -911,33 +935,30 @@ void hud_escort_target_next()
// return the number of ships currently on the escort list
int hud_escort_num_ships_on_list()
{
return static_cast<int>(Escort_ships.size());
return Num_escort_ships;
}
// Return the object number for the ship at index position in the escort list
int hud_escort_return_objnum(int index)
{
int escort_objnum, escort_sig;
if (index < 0) {
if ( index >= Num_escort_ships || index >= MAX_COMPLETE_ESCORT_LIST) {
return -1;
}
auto eship = get_escort_entry_from_index(index);
escort_objnum = Escort_ships[index].objnum;
escort_sig = Escort_ships[index].obj_signature;
if ( (eship == Escort_ships.end()) || (eship->objnum < 0) ) {
if ( escort_objnum < 0 ) {
return -1;
}
escort_objnum = eship->objnum;
escort_sig = eship->obj_signature;
// ensure this is still a valid index
if (Objects[escort_objnum].signature != escort_sig) {
if ( Objects[escort_objnum].signature != escort_sig ) {
return -1;
}
return escort_objnum;
return Escort_ships[index].objnum;
}
void hud_escort_add_player(short id)
@@ -947,24 +968,17 @@ void hud_escort_add_player(short id)
return;
}
int idx;
// just go through and add as long as its not a duplicate
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->np_id == id) {
for(idx=0; idx<Num_escort_ships; idx++){
if(Escort_ships[idx].np_id == id){
return;
}
}
escort_info einfo;
einfo.np_id = id;
Escort_ships.push_back(einfo);
Escort_ships.sort(escort_compare);
// resize the list to fit
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
}
// re-setup the escort list
hud_setup_escort_list(0);
}
void hud_escort_remove_player(short id)
@@ -974,11 +988,12 @@ void hud_escort_remove_player(short id)
return;
}
// find the instance and remove it if possible
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->np_id == id) {
Escort_ships.erase(it);
int idx;
// find the instance and remove it if possible
for(idx=0; idx<Num_escort_ships; idx++){
if(Escort_ships[idx].np_id == id){
hud_remove_ship_from_escort_index(idx, -1);
return;
}
}
-1
View File
@@ -24,7 +24,6 @@ class object;
void hud_escort_update_list();
void hud_escort_init();
void hud_setup_escort_list(int level = 1);
void hud_resort_escort_list();
void hud_add_remove_ship_escort(int objnum, int supress_feedback = 0);
void hud_escort_clear_all(bool clear_flags = false);
void hud_escort_ship_hit(object *objp, int quadrant);
-3
View File
@@ -103,9 +103,6 @@ void update_ets(object* objp, float fl_frametime)
shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy;
}
if (Missiontime - Ai_info[ship_p->ai_index].last_hit_time < fl2f(sinfo_p->shield_regen_hit_delay))
shield_delta = 0.0f;
shield_add_strength(objp, shield_delta);
// if strength now exceeds max, scale back segments proportionally
+1 -7
View File
@@ -55,13 +55,7 @@
#define HUD_SUPPORT_GAUGE 37
#define HUD_LAG_GAUGE 38
struct Legacy_HUD_gauge_pair
{
const char *hud_gauge_text;
int hud_gauge_type;
};
extern Legacy_HUD_gauge_pair Legacy_HUD_gauges[NUM_HUD_GAUGES]; // defined in hudparse.cpp!!!!
extern const char *HUD_gauge_text[NUM_HUD_GAUGES]; // defined in sexp.cpp!!!!
#endif /* __HUD_COMMON_H__ */
+112 -32
View File
@@ -12,7 +12,6 @@
#include "ai/ai.h"
#include "debugconsole/console.h"
#include "gamesequence/gamesequence.h"
#include "gamesnd/gamesnd.h"
#include "globalincs/linklist.h"
#include "hud/hudlock.h"
@@ -405,10 +404,46 @@ int hud_lock_has_homing_point()
int Nebula_sec_range = 0;
DCF_BOOL(nebula_sec_range, Nebula_sec_range);
int hud_lock_world_pos_in_range(vec3d *target_world_pos, vec3d *vec_to_target)
{
float dist_to_target, weapon_range;
weapon_info *wip;
ship_weapon *swp;
int target_in_range=1;
swp = &Player_ship->weapons;
wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
vm_vec_sub(vec_to_target, target_world_pos, &Player_obj->pos);
dist_to_target = vm_vec_mag(vec_to_target);
//local ssms are always in range :)
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
weapon_range=wip->lssm_lock_range;
else
// calculate the range of the weapon, and only display the lead target indicator when
// if the weapon can actually hit the target
weapon_range = MIN((wip->max_speed * wip->lifetime), wip->weapon_range);
// reduce firing range in nebula
if ((The_mission.flags[Mission::Mission_Flags::Fullneb]) && Nebula_sec_range) {
weapon_range *= 0.8f;
}
if (dist_to_target > weapon_range) {
target_in_range=0;
}
return target_in_range;
}
// Determine if point to lock on is in range
int hud_lock_target_in_range()
{
vec3d target_world_pos;
vec3d target_world_pos, vec_to_target;
object *targetp;
if ( !hud_lock_has_homing_point() ) {
@@ -429,10 +464,8 @@ int hud_lock_target_in_range()
target_world_pos = targetp->pos;
}
}
ship_weapon* swp = &Player_ship->weapons;
weapon_info* wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
return weapon_secondary_world_pos_in_range(Player_obj, wip, &target_world_pos);
return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
}
int hud_abort_lock()
@@ -730,9 +763,6 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
target_shipp = &Ships[target_objp->instance];
}
ship_weapon* swp = &Player_ship->weapons;
weapon_info* wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
// Reset target subsys in case it isn't needed
if (target_subsys != nullptr) target_subsys = nullptr;
@@ -741,8 +771,8 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
// check all the subsystems and the center of the ship
// assume best lock pos is the center of the ship
lock_in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &target_objp->pos);
vm_vec_normalized_dir(&vec_to_lock, &target_objp->pos, &Player_obj->pos);
lock_in_range = hud_lock_world_pos_in_range(&target_objp->pos, &vec_to_lock);
vm_vec_normalize(&vec_to_lock);
if ( lock_in_range ) {
best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
}
@@ -758,8 +788,8 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
// get world pos of subsystem
get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);
if ( weapon_secondary_world_pos_in_range(Player_obj, wip, &subsys_world_pos) ) {
vm_vec_normalized_dir(&vec_to_lock, &subsys_world_pos, &Player_obj->pos);
if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
vm_vec_normalize(&vec_to_lock);
lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
if ( lock_dot > best_lock_dot ) {
best_lock_dot=lock_dot;
@@ -777,16 +807,36 @@ void hud_lock_acquire_uncaged_subsystem(weapon_info *wip, lock_info *lock, float
Assert( lock->obj->type == OBJ_SHIP );
ship *sp = &Ships[lock->obj->instance];
ship_subsys *ss;
float ss_dot;
vec3d ss_pos;
vec3d vec_to_target;
int current_num_locks = 0;
if ( Ship_info[sp->ship_info_index].is_big_or_huge() ) {
for (ship_subsys* ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
if (!weapon_multilock_can_lock_on_subsys(Player_obj, lock->obj, ss, wip, &ss_dot))
for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
if (ss->flags[Ship::Subsystem_Flags::Untargetable]) {
continue;
}
get_subsystem_world_pos(lock->obj, ss, &ss_pos);
if ( !hud_lock_world_pos_in_range(&ss_pos, &vec_to_target) ) {
continue;
}
vm_vec_normalize(&vec_to_target);
ss_dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
if ( ss_dot < wip->lock_fov ) {
continue;
}
if ( !ship_subsystem_in_sight(lock->obj, ss, &Eye_position, &ss_pos) ) {
continue;
}
// check for existing locks
current_num_locks = 0;
@@ -821,8 +871,11 @@ void hud_lock_acquire_uncaged_subsystem(weapon_info *wip, lock_info *lock, float
void hud_lock_acquire_uncaged_target(lock_info *current_lock, weapon_info *wip)
{
object *A;
vec3d vec_to_target;
float dot;
ship *sp;
size_t i = 0;
object* best_obj = nullptr;
@@ -835,12 +888,45 @@ void hud_lock_acquire_uncaged_target(lock_info *current_lock, weapon_info *wip)
bool actively_locking = false;
for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
ship* sp = &Ships[A->instance];
if (!weapon_multilock_can_lock_on_target(Player_obj, A, wip, &dot))
if ( A->type != OBJ_SHIP ) {
continue;
}
bool in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &A->pos);
if ( hud_target_invalid_awacs(A) ) {
continue;
}
sp = &Ships[A->instance];
if ( A->flags[Object::Object_Flags::Should_be_dead] ) {
continue;
}
if ( sp->flags[Ship::Ship_Flags::Dying] ) {
continue;
}
if ( should_be_ignored(sp) ) {
continue;
}
// if this is part of the same team and doesn't have any iff restrictions, reject lock
if ( !weapon_has_iff_restrictions(wip) && Player_ship->team == obj_team(A) ) {
continue;
}
int in_range = hud_lock_world_pos_in_range(&A->pos, &vec_to_target);
vm_vec_normalize(&vec_to_target);
dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
/*if ( dot < 0.95f ) {
// broad test to see if we should bother to even check
continue;
}*/
if (!weapon_target_satisfies_lock_restrictions(wip, A)) {
continue;
}
if ( Ship_info[sp->ship_info_index].is_big_or_huge() ) {
lock_info temp_lock;
@@ -927,7 +1013,7 @@ void hud_lock_determine_lock_target(lock_info *lock_slot, weapon_info *wip)
vm_vec_normalized_dir(&vec_to_target, &target_pos, &Eye_position);
dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
if ( !weapon_secondary_world_pos_in_range(Player_obj, wip, &lock_slot->obj->pos) || dot < wip->lock_fov) {
if ( !hud_lock_world_pos_in_range(&target_pos, &vec_to_target) || dot < wip->lock_fov) {
// set this lock slot to empty
ship_clear_lock(lock_slot);
hud_lock_acquire_uncaged_target(lock_slot, wip);
@@ -1373,7 +1459,7 @@ void hud_calculate_lock_slot_position(lock_info *current_lock, float frametime)
// Determine if point to lock on is in range
int hud_lock_target_in_range(lock_info *lock_slot)
{
vec3d target_world_pos;
vec3d target_world_pos, vec_to_target;
if ( lock_slot == nullptr || lock_slot->obj == nullptr) {
return 0;
@@ -1390,9 +1476,8 @@ int hud_lock_target_in_range(lock_info *lock_slot)
target_world_pos = lock_slot->obj->pos;
}
}
ship_weapon* swp = &Player_ship->weapons;
return weapon_secondary_world_pos_in_range(Player_obj, &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]], &target_world_pos);
return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
}
void hud_do_lock_indicators(float frametime)
@@ -1405,11 +1490,6 @@ void hud_do_lock_indicators(float frametime)
return;
}
// do not continue locking if the game is paused (viewer pause still has hud on)
if (gameseq_get_state() == GS_STATE_GAME_PAUSED) {
return;
}
// be sure to unset this flag, then possibly set later in this function so that
// threat indicators work properly.
Player_ai->ai_flags.remove(AI::AI_Flags::Seek_lock);
@@ -2023,8 +2103,8 @@ void hud_lock_get_new_lock_pos(object *target_objp)
Player->locking_on_center=1;
Player->locking_subsys=NULL;
Player->locking_subsys_parent=-1;
lock_in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &lock_world_pos);
vm_vec_normalized_dir(&vec_to_lock, &lock_world_pos, &Player_obj->pos);
lock_in_range = hud_lock_world_pos_in_range(&lock_world_pos, &vec_to_lock);
vm_vec_normalize(&vec_to_lock);
if ( lock_in_range ) {
best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
}
@@ -2040,8 +2120,8 @@ void hud_lock_get_new_lock_pos(object *target_objp)
// get world pos of subsystem
get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);
if ( weapon_secondary_world_pos_in_range(Player_obj, wip, &subsys_world_pos) ) {
vm_vec_normalized_dir(&vec_to_lock, &subsys_world_pos, &Player_obj->pos);
if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
vm_vec_normalize(&vec_to_lock);
lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
if ( lock_dot > best_lock_dot ) {
best_lock_dot=lock_dot;
+24 -65
View File
@@ -53,9 +53,9 @@ int Hud_font = -1;
bool Chase_view_only_ex = false;
//WARNING: If you add gauges to this array, make sure to bump Num_builtin_gauges!
const int Num_builtin_gauges = 42;
static int Builtin_gauges[Num_builtin_gauges] = {
//WARNING: If you add gauges to this array, make sure to bump num_default_gauges!
int num_default_gauges = 42;
static int retail_gauges[] = {
HUD_OBJECT_MESSAGES,
HUD_OBJECT_TRAINING_MESSAGES,
HUD_OBJECT_SUPPORT,
@@ -100,52 +100,9 @@ static int Builtin_gauges[Num_builtin_gauges] = {
HUD_OBJECT_ETS_RETAIL
};
Legacy_HUD_gauge_pair Legacy_HUD_gauges[NUM_HUD_GAUGES] =
{
{ "LEAD_INDICATOR", HUD_OBJECT_LEAD },
{ "ORIENTATION_TEE", HUD_OBJECT_ORIENTATION_TEE },
{ "HOSTILE_TRIANGLE", HUD_OBJECT_HOSTILE_TRI },
{ "TARGET_TRIANGLE", HUD_OBJECT_TARGET_TRI },
{ "MISSION_TIME", HUD_OBJECT_MISSION_TIME },
{ "RETICLE_CIRCLE", -1 },
{ "THROTTLE_GAUGE", HUD_OBJECT_THROTTLE },
{ "RADAR", HUD_OBJECT_RADAR_STD },
{ "TARGET_MONITOR", HUD_OBJECT_TARGET_MONITOR },
{ "CENTER_RETICLE", HUD_OBJECT_CENTER_RETICLE },
{ "TARGET_MONITOR_EXTRA_DATA", HUD_OBJECT_EXTRA_TARGET_DATA },
{ "TARGET_SHIELD_ICON", HUD_OBJECT_TARGET_SHIELD },
{ "PLAYER_SHIELD_ICON", HUD_OBJECT_PLAYER_SHIELD },
{ "ETS_GAUGE", HUD_OBJECT_ETS_RETAIL },
{ "AUTO_TARGET", HUD_OBJECT_AUTO_TARGET },
{ "AUTO_SPEED", HUD_OBJECT_AUTO_SPEED },
{ "WEAPONS_GAUGE", HUD_OBJECT_WEAPONS },
{ "ESCORT_VIEW", HUD_OBJECT_ESCORT },
{ "DIRECTIVES_VIEW", HUD_OBJECT_DIRECTIVES },
{ "THREAT_GAUGE", HUD_OBJECT_THREAT },
{ "AFTERBURNER_ENERGY", HUD_OBJECT_AFTERBURNER },
{ "WEAPONS_ENERGY", HUD_OBJECT_WEAPON_ENERGY },
{ "WEAPON_LINKING_GAUGE", HUD_OBJECT_WEAPON_LINKING },
{ "TARGER_MINI_ICON", HUD_OBJECT_MINI_SHIELD },
{ "OFFSCREEN_INDICATOR", HUD_OBJECT_OFFSCREEN },
{ "TALKING_HEAD", HUD_OBJECT_TALKING_HEAD },
{ "DAMAGE_GAUGE", HUD_OBJECT_DAMAGE },
{ "MESSAGE_LINES", HUD_OBJECT_MESSAGES },
{ "MISSILE_WARNING_ARROW", HUD_OBJECT_MISSILE_TRI },
{ "CMEASURE_GAUGE", HUD_OBJECT_CMEASURES },
{ "OBJECTIVES_NOTIFY_GAUGE", HUD_OBJECT_OBJ_NOTIFY },
{ "WINGMEN_STATUS", HUD_OBJECT_WINGMAN_STATUS },
{ "OFFSCREEN RANGE", -1 },
{ "KILLS GAUGE", HUD_OBJECT_KILLS },
{ "ATTACKING TARGET COUNT", -1 },
{ "TEXT FLASH", HUD_OBJECT_TEXT_WARNINGS },
{ "MESSAGE BOX", HUD_OBJECT_SQUAD_MSG },
{ "SUPPORT GUAGE", HUD_OBJECT_SUPPORT },
{ "LAG GUAGE", HUD_OBJECT_LAG },
};
flag_def_list Hud_gauge_types[] = {
{ "Messages", HUD_OBJECT_MESSAGES, 0},
{ "Training messages", HUD_OBJECT_TRAINING_MESSAGES, 0}, // Not in legacy list
{ "Training messages", HUD_OBJECT_TRAINING_MESSAGES, 0},
{ "Support", HUD_OBJECT_SUPPORT, 0},
{ "Damage", HUD_OBJECT_DAMAGE, 0},
{ "Wingman status", HUD_OBJECT_WINGMAN_STATUS, 0},
@@ -163,14 +120,14 @@ flag_def_list Hud_gauge_types[] = {
{ "Target shield", HUD_OBJECT_TARGET_SHIELD, 0},
{ "Escort list", HUD_OBJECT_ESCORT, 0},
{ "Mission time", HUD_OBJECT_MISSION_TIME, 0},
{ "Ets weapons", HUD_OBJECT_ETS_WEAPONS, 0}, // Not in legacy list
{ "Ets shields", HUD_OBJECT_ETS_SHIELDS, 0}, // Not in legacy list
{ "Ets engines", HUD_OBJECT_ETS_ENGINES, 0}, // Not in legacy list
{ "Ets weapons", HUD_OBJECT_ETS_WEAPONS, 0},
{ "Ets shields", HUD_OBJECT_ETS_SHIELDS, 0},
{ "Ets engines", HUD_OBJECT_ETS_ENGINES, 0},
{ "Target monitor", HUD_OBJECT_TARGET_MONITOR, 0},
{ "Extra target data", HUD_OBJECT_EXTRA_TARGET_DATA, 0},
{ "Radar", HUD_OBJECT_RADAR_STD, 0},
{ "Radar orb", HUD_OBJECT_RADAR_ORB, 0}, // Not in legacy list
{ "Radar BSG", HUD_OBJECT_RADAR_BSG, 0}, // Not in legacy list
{ "Radar orb", HUD_OBJECT_RADAR_ORB, 0},
{ "Radar BSG", HUD_OBJECT_RADAR_BSG, 0},
{ "Afterburner energy", HUD_OBJECT_AFTERBURNER, 0},
{ "Weapon energy", HUD_OBJECT_WEAPON_ENERGY, 0},
{ "Text warnings", HUD_OBJECT_TEXT_WARNINGS, 0},
@@ -179,12 +136,12 @@ flag_def_list Hud_gauge_types[] = {
{ "Threat indicator", HUD_OBJECT_THREAT, 0},
{ "Lead indicator", HUD_OBJECT_LEAD, 0},
{ "Lead sight", HUD_OBJECT_LEAD_SIGHT, 0},
{ "Lock indicator", HUD_OBJECT_LOCK, 0}, // Not in legacy list
{ "Lock indicator", HUD_OBJECT_LOCK, 0},
{ "Weapon linking", HUD_OBJECT_WEAPON_LINKING, 0},
{ "Multiplayer messages", HUD_OBJECT_MULTI_MSG, 0}, // Not in legacy list
{ "Voice status", HUD_OBJECT_VOICE_STATUS, 0}, // Not in legacy list
{ "Ping", HUD_OBJECT_PING, 0}, // Not in legacy list
{ "Supernova", HUD_OBJECT_SUPERNOVA, 0}, // Not in legacy list
{ "Multiplayer messages", HUD_OBJECT_MULTI_MSG, 0},
{ "Voice status", HUD_OBJECT_VOICE_STATUS, 0},
{ "Ping", HUD_OBJECT_PING, 0},
{ "Supernova", HUD_OBJECT_SUPERNOVA, 0},
{ "Offscreen indicator", HUD_OBJECT_OFFSCREEN, 0},
{ "Targeting brackets", HUD_OBJECT_BRACKETS, 0},
{ "Orientation", HUD_OBJECT_ORIENTATION_TEE, 0},
@@ -192,9 +149,10 @@ flag_def_list Hud_gauge_types[] = {
{ "Target direction", HUD_OBJECT_TARGET_TRI, 0},
{ "Missile indicator", HUD_OBJECT_MISSILE_TRI, 0},
{ "Kills", HUD_OBJECT_KILLS, 0},
{ "Fixed messages", HUD_OBJECT_FIXED_MESSAGES, 0}, // Not in legacy list
{ "Fixed messages", HUD_OBJECT_FIXED_MESSAGES, 0},
{ "Ets retail", HUD_OBJECT_ETS_RETAIL, 0}
};
int Num_hud_gauge_types = sizeof(Hud_gauge_types)/sizeof(flag_def_list);
int parse_ship_start()
@@ -564,6 +522,7 @@ void hud_positions_init()
// load missing retail gauges for the default and ship-specific HUDs
load_missing_retail_gauges();
}
void load_missing_retail_gauges()
@@ -574,11 +533,11 @@ void load_missing_retail_gauges()
if(Hud_retail) {
int num_loaded_gauges = (int)default_hud_gauges.size();
for(int i = 0; i < Num_builtin_gauges; i++) {
for(int i = 0; i < num_default_gauges; i++) {
retail_gauge_loaded = false;
for(int j = 0; j < num_loaded_gauges; j++) {
if(Builtin_gauges[i] == default_hud_gauges[j]->getObjectType()) {
if(retail_gauges[i] == default_hud_gauges[j]->getObjectType()) {
retail_gauge_loaded = true;
break;
}
@@ -586,7 +545,7 @@ void load_missing_retail_gauges()
if(!retail_gauge_loaded) {
gauge_settings settings;
load_gauge(Builtin_gauges[i], &settings);
load_gauge(retail_gauges[i], &settings);
}
}
@@ -630,9 +589,9 @@ void load_missing_retail_gauges()
if(it->hud_enabled && it->hud_retail) {
int num_loaded_gauges = (int)it->hud_gauges.size();
for(int i = 0; i < Num_builtin_gauges; i++) {
for(int i = 0; i < num_default_gauges; i++) {
for(int j = 0; j < num_loaded_gauges; j++) {
if(Builtin_gauges[i] == it->hud_gauges[j]->getObjectType()) {
if(retail_gauges[i] == it->hud_gauges[j]->getObjectType()) {
retail_gauge_loaded = true;
}
}
@@ -640,7 +599,7 @@ void load_missing_retail_gauges()
if(!retail_gauge_loaded) {
gauge_settings settings;
settings.ship_idx = &sindex;
load_gauge(Builtin_gauges[i], &settings);
load_gauge(retail_gauges[i], &settings);
}
}
@@ -1493,7 +1452,7 @@ void load_gauge_custom(gauge_settings* settings)
stuff_string(gauge_string, F_NAME, MAX_FILENAME_LEN);
for(i = 0; i < NUM_HUD_GAUGES; i++) {
if(!strcmp(Legacy_HUD_gauges[i].hud_gauge_text, gauge_string)) {
if(!strcmp(HUD_gauge_text[i], gauge_string)) {
gauge_type = i;
break;
}
+5 -5
View File
@@ -236,7 +236,7 @@ void HudGaugeReticle::initBitmaps(char *fname)
{
crosshair.first_frame = bm_load_animation(fname, &crosshair.num_frames);
if (crosshair.first_frame < 0) {
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
mprintf(("Cannot load hud ani: %s\n", fname));
}
}
@@ -495,7 +495,7 @@ void HudGaugeThrottle::initBitmaps(char *fname)
throttle_frames.first_frame = bm_load_animation(fname, &throttle_frames.num_frames);
if (throttle_frames.first_frame < 0) {
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
mprintf(("Cannot load hud ani: %s\n", fname));
}
}
@@ -748,17 +748,17 @@ void HudGaugeThreatIndicator::initBitmaps(char *fname_arc, char *fname_laser, ch
{
threat_arc.first_frame = bm_load_animation(fname_arc, &threat_arc.num_frames);
if (threat_arc.first_frame < 0) {
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_arc);
mprintf(("Cannot load hud ani: %s\n", fname_arc));
}
laser_warn.first_frame = bm_load_animation(fname_laser, &laser_warn.num_frames);
if (laser_warn.first_frame < 0) {
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_laser);
mprintf(("Cannot load hud ani: %s\n", fname_laser));
}
lock_warn.first_frame = bm_load_animation(fname_lock, &lock_warn.num_frames);
if (lock_warn.first_frame < 0) {
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_lock);
mprintf(("Cannot load hud ani: %s\n", fname_lock));
}
}
+4 -16
View File
@@ -378,13 +378,7 @@ void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_off
break;
}
int num;
if (!(Ship_info[Ships[objp->instance].ship_info_index].flags[Ship::Info_Flags::Model_point_shields]))
num = Quadrant_xlate[i];
else
num = i;
if (objp->shield_quadrant[num] < 0.1f ) {
if (objp->shield_quadrant[Quadrant_xlate[i]] < 0.1f ) {
continue;
}
@@ -395,7 +389,7 @@ void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_off
}
range = HUD_color_alpha;
hud_color_index = (int)std::lround((objp->shield_quadrant[num] / max_shield) * range);
hud_color_index = (int)std::lround((objp->shield_quadrant[Quadrant_xlate[i]] / max_shield) * range);
Assert(hud_color_index >= 0 && hud_color_index <= range);
if ( hud_color_index < 0 ) {
@@ -981,13 +975,7 @@ void HudGaugeShieldMini::showMiniShields(object *objp)
break;
}
int num;
if (!(Ship_info[Ships[objp->instance].ship_info_index].flags[Ship::Info_Flags::Model_point_shields]))
num = Quadrant_xlate[i];
else
num = i;
if (objp->shield_quadrant[num] < 0.1f ) {
if ( objp->shield_quadrant[Quadrant_xlate[i]] < 0.1f ) {
continue;
}
@@ -998,7 +986,7 @@ void HudGaugeShieldMini::showMiniShields(object *objp)
}
range = HUD_color_alpha;
hud_color_index = (int)std::lround((objp->shield_quadrant[num] / max_shield) * range);
hud_color_index = (int)std::lround((objp->shield_quadrant[Quadrant_xlate[i]] / max_shield) * range);
Assert(hud_color_index >= 0 && hud_color_index <= range);
if ( hud_color_index < 0 ) {
+1 -1
View File
@@ -1823,7 +1823,7 @@ void hud_squadmsg_call_reinforcement(int reinforcement_num, int /*player_num*/)
break;
//if ( i > 0 )
// message_send_to_player( rp->yes_messages[Random::next(i)], rp->name, MESSAGE_PRIORITY_NORMAL, HUD_SOURCE_FRIENDLY );
// message_send_to_player( rp->yes_messages[myrand() % i], rp->name, MESSAGE_PRIORITY_NORMAL, HUD_SOURCE_FRIENDLY );
*/
mission_log_add_entry(LOG_PLAYER_CALLED_FOR_REINFORCEMENT, rp->name, NULL);
+9 -30
View File
@@ -7185,17 +7185,13 @@ void HudGaugeHardpoints::render(float /*frametime*/)
//secondary weapons
int num_secondaries_rendered = 0;
if ( draw_secondary_models ) {
auto ship_pm = model_get(sip->model_num);
for (i = 0; i < swp->num_secondary_banks; i++) {
auto wip = &Weapon_info[swp->secondary_bank_weapons[i]];
if (wip->external_model_num == -1 || !sip->draw_secondary_models[i])
if (Weapon_info[swp->secondary_bank_weapons[i]].external_model_num == -1 || !sip->draw_secondary_models[i])
continue;
auto bank = &ship_pm->missile_banks[i];
auto bank = &(model_get(sip->model_num))->missile_banks[i];
if (wip->wi_flags[Weapon::Info_Flags::External_weapon_lnch]) {
if (Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::External_weapon_lnch]) {
for(k = 0; k < bank->num_slots; k++) {
model_render_params weapon_render_info;
@@ -7206,12 +7202,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &bank->pnt[k], &object_orient);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, &model_orient, &bank->pnt[k]);
model_render_immediate(&weapon_render_info, Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &object_orient, &bank->pnt[k]);
}
} else {
num_secondaries_rendered = 0;
@@ -7223,7 +7214,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
if (num_secondaries_rendered >= sp->weapons.secondary_bank_ammo[i])
break;
if(sp->secondary_point_reload_pct.get(i, k) <= 0.0)
if(sp->secondary_point_reload_pct[i][k] <= 0.0)
continue;
model_render_params weapon_render_info;
@@ -7236,7 +7227,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
num_secondaries_rendered++;
vm_vec_scale_add2(&secondary_weapon_pos, &vmd_z_vector, -(1.0f-sp->secondary_point_reload_pct.get(i, k)) * model_get(wip->external_model_num)->rad);
vm_vec_scale_add2(&secondary_weapon_pos, &vmd_z_vector, -(1.0f-sp->secondary_point_reload_pct[i][k]) * model_get(Weapon_info[swp->secondary_bank_weapons[i]].external_model_num)->rad);
weapon_render_info.set_detail_level_lock(detail_level_lock);
weapon_render_info.set_flags(render_flags);
@@ -7245,12 +7236,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &secondary_weapon_pos, &object_orient);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, &model_orient, &world_position);
model_render_immediate(&weapon_render_info, Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &object_orient, &world_position);
}
}
}
@@ -7262,11 +7248,9 @@ void HudGaugeHardpoints::render(float /*frametime*/)
//primary weapons
if ( draw_primary_models ) {
auto ship_pm = model_get(sip->model_num);
for ( i = 0; i < swp->num_primary_banks; i++ ) {
auto wip = &Weapon_info[swp->primary_bank_weapons[i]];
auto bank = &ship_pm->gun_banks[i];
auto bank = &model_get(sip->model_num)->gun_banks[i];
for ( k = 0; k < bank->num_slots; k++ ) {
if ( wip->external_model_num < 0 || !sip->draw_primary_models[i] ) {
@@ -7294,12 +7278,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &bank->pnt[k], &object_orient);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, swp->primary_bank_external_model_instance[i], &model_orient, &world_position);
model_render_immediate(&weapon_render_info, wip->external_model_num, swp->primary_bank_external_model_instance[i], &object_orient, &world_position);
}
}
}
+19
View File
@@ -99,6 +99,24 @@ void hud_set_wingman_status_alive( int wing_index, int wing_pos)
HUD_wingman_status[wing_index].status[wing_pos] = HUD_WINGMAN_STATUS_ALIVE;
}
void hud_wingman_status_init_late_wings()
{
/*
int i, j, wing_index;
for ( i = 0; i < Num_wings; i++ ) {
wing_index = ship_squadron_wing_lookup(Wings[i].name);
if ( (wing_index >= 0) && (Wings[i].total_arrived_count == 0) ) {
HUD_wingman_status[wing_index].used = 1;
for (j = 0; j < Wings[i].wave_count; j++) {
HUD_wingman_status[wing_index].status[j] = HUD_WINGMAN_STATUS_NOT_HERE;
}
}
}
*/
}
// function which marks the other team wing as not used for the wingman status gauge
void hud_wingman_kill_multi_teams()
{
@@ -143,6 +161,7 @@ void hud_init_wingman_status_gauge()
}
}
hud_wingman_status_init_late_wings();
hud_wingman_kill_multi_teams();
hud_wingman_status_update();
}
+7 -11
View File
@@ -542,11 +542,9 @@ void key_mark( uint code, int state, uint latency )
Current_key_down |= KEY_CTRLED;
}
if (Script_system.IsActiveAction(CHA_KEYRELEASED)) {
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYRELEASED);
Script_system.RemHookVar("Key");
}
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYRELEASED);
Script_system.RemHookVar("Key");
} else {
// Key going down
keyd_last_pressed = scancode;
@@ -572,12 +570,10 @@ void key_mark( uint code, int state, uint latency )
Current_key_down |= KEY_CTRLED;
}
if (Script_system.IsActiveAction(CHA_KEYPRESSED)) {
// We use the universal value here to keep the scripting interface consistent regardless of the current language
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYPRESSED);
Script_system.RemHookVar("Key");
}
// We use the universal value here to keep the scripting interface consistent regardless of the current language
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYPRESSED);
Script_system.RemHookVar("Key");
} else if (!keyd_repeat) {
// Don't buffer repeating key if repeat mode is off
scancode = 0xAA;
+13 -4
View File
@@ -692,6 +692,15 @@ void process_debug_keys(int k)
case KEY_DEBUGGED + KEY_H:
hud_target_toggle_hidden_from_sensors();
break;
case KEY_DEBUGGED + KEY_F:
extern int wacky_scheme;
if(wacky_scheme == 3){
wacky_scheme = 0;
} else {
wacky_scheme++;
}
break;
case KEY_DEBUGGED + KEY_ALTED + KEY_F:
Framerate_delay += 10;
@@ -776,8 +785,8 @@ void process_debug_keys(int k)
// remove guardian flag -- kazan
Ships[objp->instance].ship_guardian_threshold = 0;
ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
break;
case OBJ_WEAPON:
Weapons[objp->instance].lifeleft = 0.01f;
@@ -847,7 +856,7 @@ void process_debug_keys(int k)
object *objp = &Objects[Player_ai->target_objnum];
if (objp->type == OBJ_SHIP) {
ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
}
}
break;
@@ -885,7 +894,7 @@ void process_debug_keys(int k)
vm_vec_rand_vec_quick(&randvec);
vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
hud_get_target_strength(Player_obj, &shield, &integrity);
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You whacked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
break;
+10 -9
View File
@@ -99,7 +99,7 @@ namespace
break;
default:
// SDL gave us an unknown button. Just log it
mprintf(("Unknown SDL button %i\n", e.button.button));
mprintf(("Unknown SDL button %i", e.button.button));
}
return true;
@@ -270,13 +270,14 @@ void mouse_mark_button( uint flags, int set)
Script_system.SetHookVar("MouseButton", 'i', flags);
if (Script_system.IsActiveAction(CHA_MOUSEPRESSED) || Script_system.IsActiveAction(CHA_MOUSERELEASED)) {
//WMC - On Mouse Pressed and On Mouse Released hooks
if (set == 1) {
Script_system.RunCondition(CHA_MOUSEPRESSED);
} else if (set == 0) {
Script_system.RunCondition(CHA_MOUSERELEASED);
}
//WMC - On Mouse Pressed and On Mouse Released hooks
if (set == 1)
{
Script_system.RunCondition(CHA_MOUSEPRESSED);
}
else if (set == 0)
{
Script_system.RunCondition(CHA_MOUSERELEASED);
}
Script_system.RemHookVar("MouseButton");
@@ -463,7 +464,7 @@ void mouse_event(int x, int y, int dx, int dy)
Mouse_dx += dx;
Mouse_dy += dy;
if (Script_system.IsActiveAction(CHA_MOUSEMOVED) && (Mouse_dx != 0 || Mouse_dy != 0))
if(Mouse_dx != 0 || Mouse_dy != 0)
{
Script_system.RunCondition(CHA_MOUSEMOVED);
}
+1 -5
View File
@@ -14,12 +14,8 @@
#include "globalincs/pstypes.h"
#include "utils/Random.h"
#include <cstdint>
using Random = util::Random;
//==========================================================================
// This installs the timer services and interrupts at the rate specified by
// count_val. If 'function' isn't 0, the function pointed to by function will
@@ -100,7 +96,7 @@ int timestamp();
// gets a timestamp randomly between a and b milliseconds in
// the future.
inline int timestamp_rand(int a, int b) {
return timestamp(Random::next(a, b));
return timestamp(myrand() % (b - a + 1) + a);
}
// Example that makes a ship fire in 1/2 second
+10 -18
View File
@@ -2,8 +2,6 @@
#include "lab/labv2_internal.h"
#include "ship/shiphit.h"
#include <array>
/**********************Click event handlers********************************************/
void destroy_subsystem(Tree* caller) {
@@ -64,8 +62,8 @@ void destroy_ship(Button* /*caller*/) {
std::map<AnimationTriggerType, std::map<int, bool>> manual_animation_triggers = {};
std::map<AnimationTriggerType, bool> manual_animations = {};
std::array<bool, MAX_SHIP_PRIMARY_BANKS> triggered_primary_banks;
std::array<bool, MAX_SHIP_SECONDARY_BANKS> triggered_secondary_banks;
bool triggered_primary_banks[MAX_SHIP_PRIMARY_BANKS];
bool triggered_secondary_banks[MAX_SHIP_SECONDARY_BANKS];
void reset_animations(Tree*) {
if (getLabManager()->isSafeForShips()) {
@@ -178,8 +176,7 @@ void Actions::open(Button* /*caller*/) {
getLabManager()->loadWeapons();
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Actions", gr_screen.center_offset_x + 250, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
int y = 0;
@@ -187,9 +184,8 @@ void Actions::open(Button* /*caller*/) {
dialogWindow->AddChild(btn);
y += btn->GetHeight();
for (auto &dialog : subDialogs) {
auto *dgo = new DialogOpener(dialog, 0, y);
dialog->setOpener(dgo);
for (auto dialog : subDialogs) {
auto dgo = new DialogOpener(dialog, 0, y);
dialogWindow->AddChild(dgo);
y += dgo->GetHeight();
}
@@ -198,7 +194,7 @@ void Actions::open(Button* /*caller*/) {
}
void Actions::update(LabMode newLabMode, int classIndex) {
for (auto &dialog : subDialogs) {
for (auto dialog : subDialogs) {
dialog->update(newLabMode, classIndex);
}
}
@@ -208,8 +204,7 @@ void DestroySubsystems::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Destroy Subsystems", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -239,8 +234,7 @@ void ChangeLoadout::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Change Loadout", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -355,8 +349,7 @@ void WeaponFire::open(Button* /*caller*/) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(
new DialogWindow("Fire weapons", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50)
);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -394,8 +387,7 @@ void AnimationTrigger::open(Button* /*caller*/) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(
new DialogWindow("Trigger animations", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50)
);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
+5 -20
View File
@@ -5,10 +5,7 @@
class DestroySubsystems : public LabDialog {
public:
~DestroySubsystems() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -34,10 +31,7 @@ private:
};
class ChangeLoadout : public LabDialog {
public:
~ChangeLoadout() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -63,10 +57,7 @@ private:
};
class WeaponFire : public LabDialog {
public:
~WeaponFire() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -92,10 +83,6 @@ private:
};
class AnimationTrigger : public LabDialog {
public:
~AnimationTrigger() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -118,14 +105,12 @@ private:
class Actions : public LabDialog {
public:
Actions() {
subDialogs.emplace_back(std::make_shared<DestroySubsystems>());
subDialogs.emplace_back(std::make_shared<ChangeLoadout>());
subDialogs.emplace_back(std::make_shared<WeaponFire>());
subDialogs.emplace_back(std::make_shared<AnimationTrigger>());
subDialogs.push_back(new DestroySubsystems());
subDialogs.push_back(new ChangeLoadout());
subDialogs.push_back(new WeaponFire());
subDialogs.push_back(new AnimationTrigger());
}
~Actions() override = default;
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -148,5 +133,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
SCP_vector<std::shared_ptr<LabDialog>> subDialogs;
SCP_vector<LabDialog*> subDialogs;
};
+1 -2
View File
@@ -36,8 +36,7 @@ void BackgroundDialog::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Mission Backgrounds", gr_screen.center_offset_x + 250, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
SCP_vector<SCP_string> missions;
-4
View File
@@ -4,10 +4,6 @@
class BackgroundDialog : public LabDialog {
public:
~BackgroundDialog() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+1 -2
View File
@@ -8,8 +8,7 @@ void Descriptions::open(Button* /*caller*/) {
gr_screen.center_offset_y + gr_screen.center_h - gr_screen.center_h / 6 - 50, gr_screen.center_w / 3,
gr_screen.center_h / 6)
);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
}
dialogWindow->DeleteChildren();
-4
View File
@@ -3,10 +3,6 @@
#include "lab/dialogs/lab_dialog.h"
class Descriptions : public LabDialog {
public:
~Descriptions() override = default;
private:
void open(Button* caller) override;
void close() override {
+1 -2
View File
@@ -7,8 +7,7 @@ void Options::open(Button* /*caller*/) {
if (dialogWindow == nullptr) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow(
"Flags Window", gr_screen.center_offset_x + gr_screen.center_w - 205, gr_screen.center_offset_y + 200));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
}
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
-4
View File
@@ -9,10 +9,6 @@ struct lab_flag {
};
class Options : public LabDialog {
public:
~Options() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+4 -5
View File
@@ -8,8 +8,7 @@ void Variables::open(Button* /*caller*/) {
if (dialogWindow == nullptr) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Variables", gr_screen.center_offset_x + gr_screen.center_w - 285,
gr_screen.center_offset_y + 200));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
}
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -75,8 +74,8 @@ void Variables::update(LabMode newLabMode, int classIndex) {
addHeader(y, "Techroom");
addVariable(&y, "Closeup zoom", sip->closeup_zoom);
addVariable(&y, "Closeup pos (x)", sip->closeup_pos.xyz.x);
addVariable(&y, "Closeup pos (y)", sip->closeup_pos.xyz.y);
addVariable(&y, "Closeup pos (z)", sip->closeup_pos.xyz.z);
addVariable(&y, "Closeup pos (y)", sip->closeup_pos.xyz.x);
addVariable(&y, "Closeup pos (z)", sip->closeup_pos.xyz.x);
break;
case LabMode::Weapon:
wip = &Weapon_info[classIndex];
@@ -90,7 +89,7 @@ void Variables::update(LabMode newLabMode, int classIndex) {
addVariable(&y, "Max speed", wip->max_speed);
addVariable(&y, "Lifetime", wip->lifetime);
addVariable(&y, "Range", wip->weapon_range);
addVariable(&y, "Min Range", wip->weapon_min_range);
addVariable(&y, "Min Range", wip->WeaponMinRange);
addHeader(y, "Damage");
addVariable(&y, "Fire wait", wip->fire_wait);
-4
View File
@@ -3,10 +3,6 @@
#include "lab/dialogs/lab_dialog.h"
class Variables : public LabDialog {
public:
~Variables() override = default;
private:
void open(Button* caller) override;
void close() override {
+2 -15
View File
@@ -3,12 +3,8 @@
#include "lab/wmcgui.h"
#include "lab/labv2.h"
class DialogOpener;
class LabDialog {
public:
virtual ~LabDialog() = default;
// Called when this dialog is opened via the top toolbar
virtual void open(Button* caller) = 0;
@@ -23,16 +19,13 @@ public:
// Returns true if it is safe to open this dialog
virtual bool safeToOpen(LabMode labMode) = 0;
void setOpener(const DialogOpener* opener) { Opener = opener; }
protected:
const DialogOpener *Opener = nullptr;
};
// This is a base class for Windows opened by the various dialogs. Since dialogs exist even when their Windows are closed,
// this introduces the concept of an "Owner", who gets notified when the DialogWindow is closed.
class DialogWindow : public Window {
public:
void SetOwner(LabDialog* owner) { Owner = owner; }
DialogWindow(const SCP_string& in_caption, int x_coord, int y_coord, int x_width = -1, int y_height = -1, int in_style = 0) :
Window(in_caption, x_coord, y_coord, x_width, y_height, in_style) {
}
@@ -41,12 +34,6 @@ public:
if (Owner != nullptr)
Owner->close();
}
void SetOwner(std::shared_ptr<LabDialog> owner)
{
Owner = std::move(owner);
}
private:
std::shared_ptr<LabDialog> Owner;
LabDialog* Owner = nullptr;
};
+2 -12
View File
@@ -49,12 +49,6 @@ void set_spec_flag(Checkbox* caller) {
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoSpecularMap, !value);
}
void set_reflect_flag(Checkbox* caller) {
auto value = caller->GetChecked();
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoReflectMap, !value);
}
void set_env_flag(Checkbox* caller) {
auto value = caller->GetChecked();
@@ -170,8 +164,7 @@ void RenderOptions::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Render Options", gr_screen.center_offset_x + gr_screen.center_w - 300, gr_screen.center_offset_y + 200));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
dialogWindow->DeleteChildren();
@@ -200,9 +193,6 @@ void RenderOptions::open(Button* /*caller*/) {
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Specular Map", 2, y, set_spec_flag));
y += cbp->GetHeight() + 2;
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Reflection Map", 2, y, set_reflect_flag));
y += cbp->GetHeight() + 2;
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Environment Map", 2, y, set_env_flag));
y += cbp->GetHeight() + 2;
@@ -253,7 +243,7 @@ void RenderOptions::open(Button* /*caller*/) {
y += direct_sldr->GetHeight() + 2;
auto bloom_sldr = new Slider("Bloom", 0, 200, 0, y + 2, set_bloom, dialogWindow->GetWidth());
bloom_sldr->SetSliderValue((float)gr_bloom_intensity());
bloom_sldr->SetSliderValue((float)Cmdline_bloom_intensity);
dialogWindow->AddChild(bloom_sldr);
y += bloom_sldr->GetHeight() + 2;
-4
View File
@@ -4,10 +4,6 @@
class RenderOptions : public LabDialog {
public:
~RenderOptions() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+4 -8
View File
@@ -12,8 +12,7 @@ void ShipClasses::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Ship Classes", gr_screen.center_offset_x + 50, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
auto tree = (Tree*)dialogWindow->AddChild(new Tree("Ship Tree", 0, 0));
/* Ship tree layout
@@ -50,16 +49,13 @@ void ShipClasses::update(LabMode newLabMode, int classIndex) {
if (Class_toolbar == nullptr) {
Class_toolbar = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Toolbar", gr_screen.center_offset_x + 0,
gr_screen.center_offset_y + getLabManager()->Toolbar->GetHeight(), -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
Assert(Opener != nullptr);
Class_toolbar->SetOwner(Opener->getDialog());
Class_toolbar->SetOwner(this);
}
Class_toolbar->DeleteChildren();
auto x = 0;
for (auto &subdialog : Subdialogs) {
auto *dgo = new DialogOpener(subdialog, x, 0);
subdialog->setOpener(dgo);
auto *cbp = Class_toolbar->AddChild(dgo);
for (auto subdialog : Subdialogs) {
auto cbp = Class_toolbar->AddChild(new DialogOpener(subdialog, x, 0));
x += cbp->GetWidth();
subdialog->update(newLabMode, classIndex);
+4 -6
View File
@@ -12,16 +12,14 @@
class ShipClasses : public LabDialog {
public:
ShipClasses() {
Subdialogs.emplace_back(std::make_shared<Descriptions>());
Subdialogs.emplace_back(std::make_shared<Options>());
Subdialogs.emplace_back(std::make_shared<Variables>());
Subdialogs.push_back(new Descriptions());
Subdialogs.push_back(new Options());
Subdialogs.push_back(new Variables());
dialogWindow = nullptr;
Class_toolbar = nullptr;
}
~ShipClasses() override = default;
SCP_string getTitle() override { return "Ship Classes"; }
bool safeToOpen(LabMode /*labMode*/) override { return true; }
@@ -45,5 +43,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
DialogWindow* Class_toolbar = nullptr;
SCP_vector<std::shared_ptr<LabDialog>> Subdialogs;
SCP_vector<LabDialog*> Subdialogs;
};
+4 -8
View File
@@ -13,8 +13,7 @@ void WeaponClasses::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Weapon Classes", gr_screen.center_offset_x + 50, gr_screen.center_offset_y + 50));
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->SetOwner(this);
auto tree = (Tree*)dialogWindow->AddChild(new Tree("Weapon Tree", 0, 0));
SCP_vector<TreeItem*> typeHeaders;
@@ -53,16 +52,13 @@ void WeaponClasses::update(LabMode newLabMode, int classIndex) {
if (Class_toolbar == nullptr) {
Class_toolbar = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Toolbar", gr_screen.center_offset_x + 0,
gr_screen.center_offset_y + getLabManager()->Toolbar->GetHeight(), -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
Assert(Opener != nullptr);
Class_toolbar->SetOwner(Opener->getDialog());
Class_toolbar->SetOwner(this);
}
Class_toolbar->DeleteChildren();
auto x = 0;
for (auto &subdialog : Subdialogs) {
auto *dgo = new DialogOpener(subdialog, x, 0);
subdialog->setOpener(dgo);
auto *cbp = Class_toolbar->AddChild(dgo);
for (auto subdialog : Subdialogs) {
auto cbp = Class_toolbar->AddChild(new DialogOpener(subdialog, x, 0));
x += cbp->GetWidth();
subdialog->update(newLabMode, classIndex);
+4 -6
View File
@@ -8,16 +8,14 @@
class WeaponClasses : public LabDialog {
public:
WeaponClasses() {
Subdialogs.emplace_back(std::make_shared<Descriptions>());
Subdialogs.emplace_back(std::make_shared<Options>());
Subdialogs.emplace_back(std::make_shared<Variables>());
Subdialogs.push_back(new Descriptions());
Subdialogs.push_back(new Options());
Subdialogs.push_back(new Variables());
dialogWindow = nullptr;
Class_toolbar = nullptr;
}
~WeaponClasses() override = default;
SCP_string getTitle() override { return "Weapon Classes"; }
bool safeToOpen(LabMode /*labMode*/) override { return true; }
@@ -41,5 +39,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
DialogWindow* Class_toolbar = nullptr;
SCP_vector<std::shared_ptr<LabDialog>> Subdialogs;
SCP_vector<LabDialog*> Subdialogs;
};
+5 -4
View File
@@ -3,11 +3,11 @@
#include "lab/manager/lab_manager.h"
#include "gamesequence/gamesequence.h"
static std::unique_ptr<LabManager> LMGR;
LabManager* LMGR = nullptr;
const std::unique_ptr<LabManager> &getLabManager() {
LabManager* getLabManager() {
if (LMGR == nullptr) {
LMGR.reset(new LabManager());
LMGR = new LabManager();
}
return LMGR;
@@ -18,7 +18,8 @@ void lab_init() {
}
void lab_close() {
LMGR.reset();
delete LMGR;
LMGR = nullptr;
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
}
Loaded 100 of 345 files, more files were not shown because too many files have changed in this diff. Show more