Support Rearm Pool, Limits, and Other Features (#7249)

* framework for support ship rearm pool and flags

* scripting api

* FRED support

* QtFRED support

* do not save non-player-allowed weapons

* tvt and mission versioning

* fix variable name

* minor fixes and clarity

* oops

* add qtfred help docs

* fixes and cleanup

* clang and readability

* address feedback

* address feedback
This commit is contained in:
Mike Nelson authored and GitHub committed 2026-06-05 11:33:19 +02:00
1 parent 31f77e5a32
commit f4d84ec47a
35 files changed
+1852 -262

No files matched your search

+12
View File
@@ -11249,6 +11249,12 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
aip->ai_flags.remove(AI::AI_Flags::Awaiting_repair);
stamp = timestamp(-1);
if (repair_objp != nullptr && scripting::hooks::OnSupportRearmStarted->isActive()) {
scripting::hooks::OnSupportRearmStarted->run(
scripting::hook_param_list(scripting::hook_param("Support Ship", 'o', repair_objp),
scripting::hook_param("Target Ship", 'o', repaired_objp)));
}
// if this is a player ship, then subtract the repair penalty from this player's score
if ( repaired_objp->flags[Object::Object_Flags::Player_ship] ) {
if ( !(Game_mode & GM_MULTIPLAYER) ) {
@@ -11321,6 +11327,12 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
mission_log_add_entry(LOG_PLAYER_ABORTED_REARM, Ships[repaired_objp->instance].ship_name, NULL);
}
if (repair_objp != nullptr && scripting::hooks::OnSupportRearmFinished->isActive()) {
scripting::hooks::OnSupportRearmFinished->run(
scripting::hook_param_list(scripting::hook_param("Support Ship", 'o', repair_objp),
scripting::hook_param("Target Ship", 'o', repaired_objp)));
}
stamp = timestamp((int) ((30 + 10*frand()) * 1000));
break;
+1
View File
@@ -37,6 +37,7 @@ namespace Mission {
Fullneb_background_bitmaps, // Show background bitmaps despite fullneb
Preload_subspace, // Preload the subspace tunnel for both the sexp and specs checkbox (for scripts) - MjnMixael
Large_ships_no_collide_by_default, // Automatically puts all large ships in a shared collision group
Limited_support_rearm_pool, // Support ships can only rearm weapons while mission-level pool is available - MjnMixael
NUM_VALUES
};
+99 -3
View File
@@ -421,7 +421,8 @@ flag_def_list_new<Mission::Mission_Flags> Parse_mission_flags[] = {
{"Nebula Fog Color Override", Mission::Mission_Flags::Neb2_fog_color_override, true, true},
{"Full Nebula Background Bitmaps", Mission::Mission_Flags::Fullneb_background_bitmaps, true, true},
{"Preload Subspace Tunnel", Mission::Mission_Flags::Preload_subspace, true, false},
{"Large Ships Do Not Collide By Default", Mission::Mission_Flags::Large_ships_no_collide_by_default, true, false}
{"Large Ships Do Not Collide By Default", Mission::Mission_Flags::Large_ships_no_collide_by_default, true, false},
{"Limit Support Rearm to Mission Pool", Mission::Mission_Flags::Limited_support_rearm_pool, true, true}
};
parse_object_flag_description<Mission::Mission_Flags> Parse_mission_flag_descriptions[] = {
@@ -456,6 +457,7 @@ parse_object_flag_description<Mission::Mission_Flags> Parse_mission_flag_descrip
{Mission::Mission_Flags::Fullneb_background_bitmaps, "Show background bitmaps despite full nebula"},
{Mission::Mission_Flags::Preload_subspace, "Preload the subspace tunnel for both the sexp and specs checkbox"},
{Mission::Mission_Flags::Large_ships_no_collide_by_default, "Automatically places all large ships in the configured collision group, preventing large ships from colliding with each other"},
{Mission::Mission_Flags::Limited_support_rearm_pool, "Support ships can only rearm from the mission weapon pool"},
};
const size_t Num_parse_mission_flags = sizeof(Parse_mission_flags) / sizeof(flag_def_list_new<Mission::Mission_Flags>);
@@ -970,6 +972,18 @@ void parse_mission_info(mission *pm, bool basic = false)
pm->support_ships.max_support_ships = (temp > 0) ? 0 : -1;
}
if (optional_string("+Disallow Support Rearm:")) {
int temp;
stuff_int(&temp);
pm->support_ships.disallow_rearm = (temp != 0);
}
if (optional_string("+Allow Support Rearm Weapon Precedence:")) {
int temp;
stuff_int(&temp);
pm->support_ships.allow_rearm_weapon_precedence = (temp != 0);
}
if ( optional_string("+Hull Repair Ceiling:"))
{
float temp;
@@ -992,6 +1006,12 @@ void parse_mission_info(mission *pm, bool basic = false)
}
}
if (optional_string("+Support Rearm Pool From Loadout:")) {
int temp;
stuff_int(&temp);
pm->support_ships.rearm_pool_from_loadout = (temp != 0);
}
if (optional_string("+All Teams Attack")){
Mission_all_attack = 1;
}
@@ -1196,13 +1216,17 @@ void parse_player_info(mission *pm)
void parse_player_info2(mission *pm)
{
int nt, i;
SCP_vector<loadout_row> list, list2;
SCP_vector<loadout_row> list, list2, support_rearm_list;
team_data *ptr;
if (OnLoadoutAboutToParseHook->isActive()) {
OnLoadoutAboutToParseHook->run();
}
// The support rearm pool starts at -1 (unlimited) per-weapon from support_ship_info::reset().
// Entries are overridden below for explicit "+Support Rearm Pool:" data, or seeded from the
// loadout when "+Support Rearm Pool From Loadout:" is set.
// read in a ship/weapon pool for each team.
for ( nt = 0; nt < Num_teams; nt++ ) {
int num_choices;
@@ -1292,6 +1316,14 @@ void parse_player_info2(mission *pm)
num_choices = 0;
// When seeding the rearm pool from the loadout, reset this team's row to 0 so the per-weapon
// loadout counts below accumulate from a clean baseline (rather than the -1 "unlimited" default).
if (pm->support_ships.rearm_pool_from_loadout) {
for (int wep = 0; wep < MAX_WEAPON_TYPES; ++wep) {
pm->support_ships.rearm_weapon_pool[nt][wep] = 0;
}
}
// check weapon class loadout entries
for (auto &wc : list2) {
// in a campaign, see if the player is allowed the weapons or not. Remove them from the
@@ -1307,12 +1339,19 @@ void parse_player_info2(mission *pm)
// always allow the pool to be added in FRED, it is a verbal warning
// to let the mission dev know about the problem
if ( !(Weapon_info[wc.index].wi_flags[Weapon::Info_Flags::Player_allowed]) && !Fred_running ) {
WarningEx(LOCATION, "Weapon '%s' in weapon pool isn't allowed on player loadout! Ignoring it ...\n", Weapon_info[wc.index].name);
error_display(0, "Weapon '%s' in weapon pool isn't allowed on player loadout! Ignoring it ...\n", Weapon_info[wc.index].name);
continue;
}
ptr->weaponry_pool[num_choices] = wc.index;
ptr->weaponry_count[num_choices] = wc.count;
if (pm->support_ships.rearm_pool_from_loadout) {
if (Weapon_info[wc.index].disallow_rearm) {
pm->support_ships.rearm_weapon_pool[nt][wc.index] = 0;
} else if (wc.count > 0 && pm->support_ships.rearm_weapon_pool[nt][wc.index] >= 0) {
pm->support_ships.rearm_weapon_pool[nt][wc.index] += wc.count;
}
}
// if the list isn't set by a variable leave the variable name empty
if (wc.index_sexp_var == NOT_SET_BY_SEXP_VARIABLE) {
@@ -1334,6 +1373,40 @@ void parse_player_info2(mission *pm)
}
ptr->num_weapon_choices = num_choices;
if (optional_string("+Support Rearm Pool:")) {
support_rearm_list.clear();
stuff_loadout_list(support_rearm_list, ParseLookupType::MISSION_LOADOUT_WEAPON_LIST);
if (pm->support_ships.rearm_pool_from_loadout) {
error_display(0, "+Support Rearm Pool is set but +Support Rearm Pool From Loadout is also enabled! The explicit pool will be ignored.\n");
} else {
for (const auto& wc : support_rearm_list) {
if (wc.index < 0 || wc.index >= weapon_info_size()) {
continue;
}
if (!(Weapon_info[wc.index].wi_flags[Weapon::Info_Flags::Player_allowed]) && !Fred_running) {
error_display(0,
"Weapon '%s' in support rearm pool isn't allowed on player loadout! Ignoring it ...\n",
Weapon_info[wc.index].name);
continue;
}
auto& slot = pm->support_ships.rearm_weapon_pool[nt][wc.index];
if (Weapon_info[wc.index].disallow_rearm) {
slot = 0;
} else if (wc.count < 0) {
slot = -1;
} else if (wc.count == 0) {
slot = 0;
} else if (wc.count > 0) {
// First explicit entry replaces the -1 (unlimited) default; later duplicate entries accumulate.
slot = (slot < 0) ? wc.count : slot + wc.count;
}
}
}
}
memset(ptr->weapon_required, 0, MAX_WEAPON_TYPES * sizeof(bool));
if (optional_string("+Required for mission:"))
{
@@ -7328,6 +7401,12 @@ void support_ship_info::reset()
ship_class = -1; // ship class will be determined by the summoning ship's species
tally = 0;
support_available_for_species = 0; // will be filled in by the next loop
for (auto& team_pool : rearm_weapon_pool) {
std::fill(std::begin(team_pool), std::end(team_pool), -1); // -1 == unlimited per-weapon
}
disallow_rearm = false;
allow_rearm_weapon_precedence = false;
rearm_pool_from_loadout = false;
// for each species, store whether support is available
for (int species = 0; species < sz2i(Species_info.size()); species++) {
@@ -9668,6 +9747,23 @@ bool check_for_25_1_data()
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && !Neb2_fog_save_legacy_values)
return true;
if (The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool]) {
return true;
}
if (The_mission.support_ships.disallow_rearm || The_mission.support_ships.allow_rearm_weapon_precedence ||
The_mission.support_ships.rearm_pool_from_loadout) {
return true;
}
for (int team = 0; team < Num_teams; ++team) {
for (int pool_wep = 0; pool_wep < MAX_WEAPON_TYPES; ++pool_wep) {
if (The_mission.support_ships.rearm_weapon_pool[team][pool_wep] != -1) {
return true;
}
}
}
constexpr auto defaultLayer = "Default";
for (const auto& so : list_range(&Ship_obj_list))
+4
View File
@@ -112,6 +112,10 @@ struct support_ship_info
int ship_class; // ship class of support ship
int tally; // number of support ships so far
int support_available_for_species; // whether support is available for a given species (this is a bitfield)
bool disallow_rearm; // if true, support ships can only repair and will not rearm weapons
bool allow_rearm_weapon_precedence; // if true, support ships may swap to precedence weapons when rearm pool is empty
bool rearm_pool_from_loadout; // initialize rearm pool from mission loadout after filling starting loadout ships
int rearm_weapon_pool[MAX_TVT_TEAMS][MAX_WEAPON_TYPES]; // mission stockpile used to limit support ship rearming
void reset();
};
+48
View File
@@ -2858,6 +2858,24 @@ int Fred_mission_save::save_mission_info()
// this is compatible with non-SCP variants - Goober5000
fout(" %d", (The_mission.support_ships.max_support_ships == 0) ? 1 : 0);
if (save_config.save_format != MissionFormat::RETAIL) {
if (optional_string_fred("+Disallow Support Rearm:")) {
parse_comments(2);
} else {
fout("\n+Disallow Support Rearm:");
}
fout(" %d", The_mission.support_ships.disallow_rearm ? 1 : 0);
if (optional_string_fred("+Allow Support Rearm Weapon Precedence:")) {
parse_comments(2);
} else {
fout("\n+Allow Support Rearm Weapon Precedence:");
}
fout(" %d", The_mission.support_ships.allow_rearm_weapon_precedence ? 1 : 0);
}
// here be WMCoolmon's hull and subsys repair stuff
if (save_config.save_format != MissionFormat::RETAIL) {
if (optional_string_fred("+Hull Repair Ceiling:")) {
@@ -2873,6 +2891,13 @@ int Fred_mission_save::save_mission_info()
fout("\n+Subsystem Repair Ceiling:");
}
fout(" %f", The_mission.support_ships.max_subsys_repair_val);
if (optional_string_fred("+Support Rearm Pool From Loadout:")) {
parse_comments(1);
} else {
fout("\n+Support Rearm Pool From Loadout:");
}
fout(" %d", The_mission.support_ships.rearm_pool_from_loadout ? 1 : 0);
}
if (Mission_all_attack) {
@@ -4484,6 +4509,29 @@ int Fred_mission_save::save_players()
fout(")");
if (save_config.save_format != MissionFormat::RETAIL && !The_mission.support_ships.rearm_pool_from_loadout) {
if (optional_string_fred("+Support Rearm Pool:", "$Starting Shipname:")) {
parse_comments(2);
} else {
fout("\n\n+Support Rearm Pool:");
}
fout(" (\n");
for (j = 0; j < weapon_info_size(); j++) {
if (!Weapon_info[j].wi_flags[Weapon::Info_Flags::Player_allowed]) {
continue;
}
// Default is -1 (unlimited). Skip disallow_rearm weapons too, parse normalizes them to 0 anyway.
if (Weapon_info[j].disallow_rearm) {
continue;
}
if (The_mission.support_ships.rearm_weapon_pool[i][j] != -1) {
fout("\t\"%s\"\t%d\n", Weapon_info[j].name, The_mission.support_ships.rearm_weapon_pool[i][j]);
}
}
fout(")");
}
// sanity check
if (save_config.save_format == MissionFormat::RETAIL && wrote_fso_data) {
// this is such an unlikely (and hard-to-fix) case that a warning should be sufficient
+37
View File
@@ -65,6 +65,7 @@
#include "scripting/api/objs/ship.h"
#include "scripting/api/objs/shipclass.h"
#include "scripting/api/objs/sound.h"
#include "scripting/api/objs/support_rearm_pool.h"
#include "scripting/api/objs/team.h"
#include "scripting/api/objs/vecmath.h"
#include "scripting/api/objs/volumetric.h"
@@ -262,6 +263,42 @@ ADE_FUNC(runSEXP, l_Mission, "string", "Runs the defined SEXP script within a `w
return ADE_RETURN_FALSE;
}
//****SUBLIBRARY: Mission/SupportRearmPools
ADE_LIB_DERIV(l_Mission_SupportRearmPools,
"SupportRearmPools",
nullptr,
"Per-team mission support rearm pools (team indexed).",
l_Mission);
ADE_INDEXER(l_Mission_SupportRearmPools,
"number TeamIndex",
"Gets support rearm pool handle for a specific team.",
"support_rearm_pool_team",
"Support rearm pool team handle, or invalid handle if index is out of range.")
{
int idx = -1;
if (!ade_get_args(L, "*i", &idx)) {
return ade_set_error(L, "o", l_SupportRearmPoolTeam.Set(-1));
}
idx--; // Lua to C++ index
if (idx < 0 || idx >= Num_teams || idx >= MAX_TVT_TEAMS) {
return ade_set_error(L, "o", l_SupportRearmPoolTeam.Set(-1));
}
return ade_set_args(L, "o", l_SupportRearmPoolTeam.Set(idx));
}
ADE_FUNC(__len,
l_Mission_SupportRearmPools,
nullptr,
"The number of support rearm pool teams.",
"number",
"The number of TVT/loadout teams with support rearm pools.")
{
return ade_set_args(L, "i", MIN(Num_teams, MAX_TVT_TEAMS));
}
//****SUBLIBRARY: Mission/Asteroids
ADE_LIB_DERIV(l_Mission_Asteroids, "Asteroids", NULL, "Asteroids in the mission", l_Mission);
@@ -0,0 +1,79 @@
//
//
#include "support_rearm_pool.h"
#include "mission/missionparse.h"
#include "scripting/api/objs/weaponclass.h"
#include "weapon/weapon.h"
namespace scripting::api {
//****HANDLE: support_rearm_pool_team
ADE_OBJ(l_SupportRearmPoolTeam, int, "support_rearm_pool_team", "Support rearm pool team handle");
ADE_INDEXER(l_SupportRearmPoolTeam,
"number/weaponclass IndexOrClass, number amount",
"Gets/sets support rearm pool value for a weapon class on this team.\n"
"Values: -1 = unlimited, 0 = unavailable, >0 = limited amount.\n"
"If a weapon has $Disallow Support Rearm, this always returns 0 and ignores writes.",
"number",
"Current pool value for the weapon class.")
{
int team_idx = -1;
int idx = -1;
int amount;
if (lua_isnumber(L, 2)) {
if (!ade_get_args(L, "oi|i", l_SupportRearmPoolTeam.Get(&team_idx), &idx, &amount)) {
return ADE_RETURN_NIL;
}
if (idx < 1 || idx > weapon_info_size()) {
return ADE_RETURN_NIL;
}
idx--; // Lua to C++ index
} else {
if (!ade_get_args(L, "oo|i", l_SupportRearmPoolTeam.Get(&team_idx), l_Weaponclass.Get(&idx), &amount)) {
return ADE_RETURN_NIL;
}
if (idx < 0 || idx >= weapon_info_size()) {
return ADE_RETURN_NIL;
}
}
if (team_idx < 0 || team_idx >= Num_teams || team_idx >= MAX_TVT_TEAMS) {
return ADE_RETURN_NIL;
}
if (ADE_SETTING_VAR) {
if (!Weapon_info[idx].disallow_rearm) {
if (amount < 0) {
The_mission.support_ships.rearm_weapon_pool[team_idx][idx] = -1;
} else {
The_mission.support_ships.rearm_weapon_pool[team_idx][idx] = amount;
}
} else {
The_mission.support_ships.rearm_weapon_pool[team_idx][idx] = 0;
}
}
if (Weapon_info[idx].disallow_rearm) {
return ade_set_args(L, "i", 0);
}
return ade_set_args(L, "i", The_mission.support_ships.rearm_weapon_pool[team_idx][idx]);
}
ADE_FUNC(__len,
l_SupportRearmPoolTeam,
nullptr,
"The number of weapon classes in this support rearm pool.",
"number",
"The number of weapon classes.")
{
return ade_set_args(L, "i", weapon_info_size());
}
} // namespace scripting::api
@@ -0,0 +1,12 @@
#pragma once
#include "globalincs/pstypes.h"
#include "scripting/ade.h"
#include "scripting/ade_api.h"
namespace scripting::api {
DECLARE_ADE_OBJ(l_SupportRearmPoolTeam, int);
} // namespace scripting::api
+10
View File
@@ -140,6 +140,16 @@ const std::shared_ptr<Hook<ShipSourceConditions>> OnAfterburnerEnd = Hook<ShipSo
"Invoked whenever a ship stops using its afterburners",
{ { "Ship", "ship", "The ship which had been using its afterburners" } });
const std::shared_ptr<Hook<>> OnSupportRearmStarted = Hook<>::Factory("On Support Rearm Started",
"Invoked when a support ship begins actively rearming/repairing a target ship.",
{ { "Support Ship", "ship", "The support ship performing the service." },
{ "Target Ship", "ship", "The ship being serviced by the support ship." } });
const std::shared_ptr<Hook<>> OnSupportRearmFinished = Hook<>::Factory("On Support Rearm Finished",
"Invoked when a support ship finishes rearming/repairing a target ship.",
{ { "Support Ship", "ship", "The support ship that performed the service." },
{ "Target Ship", "ship", "The ship that was serviced." } });
const std::shared_ptr<Hook<ShipSourceConditions>> OnWaypointsDone = Hook<ShipSourceConditions>::Factory("On Waypoints Done",
"Invoked whenever a ship stops using its afterburners",
{
+2
View File
@@ -35,6 +35,8 @@ extern const std::shared_ptr<Hook<>> OnMouseReleased;
extern const std::shared_ptr<Hook<ShipSourceConditions>> OnAfterburnerStart;
extern const std::shared_ptr<Hook<ShipSourceConditions>> OnAfterburnerEnd;
extern const std::shared_ptr<Hook<>> OnSupportRearmStarted;
extern const std::shared_ptr<Hook<>> OnSupportRearmFinished;
extern const std::shared_ptr<Hook<ShipSourceConditions>> OnWaypointsDone;
extern const std::shared_ptr<Hook<ShipSourceConditions>> OnGoalsCleared;
+310 -129
View File
@@ -11067,6 +11067,16 @@ void ship_process_post(object * obj, float frametime)
{
shipp->weapons.secondary_bank_start_ammo[i] = shipp->weapons.secondary_bank_ammo[i];
}
if (The_mission.support_ships.rearm_pool_from_loadout && shipp->flags[Ship_Flags::From_player_wing]) {
const int weapon_class = shipp->weapons.secondary_bank_weapons[i];
if (SCP_vector_inbounds(Weapon_info, weapon_class)) {
auto& slot = The_mission.support_ships.rearm_weapon_pool[shipp->team][weapon_class];
if (slot >= 0) {
slot = MAX(0, slot - shipp->weapons.secondary_bank_ammo[i]);
}
}
}
}
for ( int i=0; i<MAX_SHIP_PRIMARY_BANKS; i++ )
@@ -11080,6 +11090,15 @@ void ship_process_post(object * obj, float frametime)
{
shipp->weapons.primary_bank_start_ammo[i] = shipp->weapons.primary_bank_ammo[i];
}
const int weapon_class = shipp->weapons.primary_bank_weapons[i];
if (The_mission.support_ships.rearm_pool_from_loadout && shipp->flags[Ship_Flags::From_player_wing] &&
SCP_vector_inbounds(Weapon_info, weapon_class) && Weapon_info[weapon_class].wi_flags[Weapon::Info_Flags::Ballistic]) {
auto& slot = The_mission.support_ships.rearm_weapon_pool[shipp->team][weapon_class];
if (slot >= 0) {
slot = MAX(0, slot - shipp->weapons.primary_bank_ammo[i]);
}
}
}
shipp->flags.set(Ship_Flags::Ammo_count_recorded);
@@ -16236,7 +16255,136 @@ float ship_calculate_rearm_duration( object *objp )
return shield_rep_time + hull_rep_time + subsys_rep_time + prim_rearm_time + sec_rearm_time + 1.2f;
}
static int get_mission_rearm_pool_for_weapon(int weapon_class, int team)
{
if ((weapon_class < 0) || (weapon_class >= MAX_WEAPON_TYPES)) {
return 0;
}
if (Weapon_info[weapon_class].disallow_rearm) {
return 0;
}
if (!(The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool])) {
return -1;
}
// The pool only exists for player loadout teams; ships on any other team are unrestricted.
if (team < 0 || team >= Num_teams) {
return -1;
}
return The_mission.support_ships.rearm_weapon_pool[team][weapon_class];
}
static bool weapon_allowed_for_current_game_type(int weapon_flags)
{
if (MULTI_DOGFIGHT) {
return (weapon_flags & DOGFIGHT_WEAPON) != 0;
}
return (weapon_flags & REGULAR_WEAPON) != 0;
}
static bool support_rearm_bank_allows_weapon(const ship_info* sip, int bank_index, int weapon_class)
{
if (!weapon_allowed_for_current_game_type(sip->allowed_weapons[weapon_class])) {
return false;
}
if (bank_index >= 0 && !sip->restricted_loadout_flag.empty()) {
if (weapon_allowed_for_current_game_type(sip->restricted_loadout_flag[bank_index])) {
if (sip->allowed_bank_restricted_weapons.empty() ||
!weapon_allowed_for_current_game_type(sip->allowed_bank_restricted_weapons[bank_index][weapon_class])) {
return false;
}
}
}
return true;
}
static int find_precedence_rearm_weapon(const ship* shipp, int bank_index, bool is_secondary_bank)
{
Assertion(shipp != nullptr, "ship pointer cannot be null");
const ship_info* sip = &Ship_info[shipp->ship_info_index];
const int current_weapon = is_secondary_bank ? shipp->weapons.secondary_bank_weapons[bank_index] : shipp->weapons.primary_bank_weapons[bank_index];
for (const auto& weapon_id : Player_weapon_precedence) {
if (weapon_id < 0 || weapon_id >= weapon_info_size()) {
continue;
}
if (weapon_id == current_weapon) {
continue;
}
if (is_secondary_bank) {
if (Weapon_info[weapon_id].subtype != WP_MISSILE) {
continue;
}
} else {
if (!Weapon_info[weapon_id].wi_flags[Weapon::Info_Flags::Ballistic]) {
continue;
}
}
if (!support_rearm_bank_allows_weapon(sip, (is_secondary_bank ? MAX_SHIP_PRIMARY_BANKS : 0) + bank_index, weapon_id)) {
continue;
}
if (get_mission_rearm_pool_for_weapon(weapon_id, shipp->team) != 0) {
return weapon_id;
}
}
return -1;
}
static bool maybe_swap_to_precedence_rearm_weapon(ship* shipp, int bank_index, bool is_secondary_bank)
{
const int replacement_weapon = find_precedence_rearm_weapon(shipp, bank_index, is_secondary_bank);
if (replacement_weapon < 0) {
return false;
}
if (is_secondary_bank) {
shipp->weapons.secondary_bank_weapons[bank_index] = replacement_weapon;
shipp->weapons.secondary_bank_start_ammo[bank_index] =
get_max_ammo_count_for_bank(shipp->ship_info_index, bank_index, replacement_weapon);
shipp->weapons.secondary_bank_ammo[bank_index] = 0;
} else {
shipp->weapons.primary_bank_weapons[bank_index] = replacement_weapon;
shipp->weapons.primary_bank_start_ammo[bank_index] =
get_max_ammo_count_for_primary_bank(shipp->ship_info_index, bank_index, replacement_weapon);
shipp->weapons.primary_bank_ammo[bank_index] = 0;
}
return true;
}
static void use_mission_rearm_pool_for_weapon(int weapon_class, int amount, int team)
{
if (!(The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool]) || amount <= 0) {
return;
}
if ((weapon_class < 0) || (weapon_class >= MAX_WEAPON_TYPES)) {
return;
}
// The pool only exists for player loadout teams; ships on any other team don't draw from it.
if (team < 0 || team >= Num_teams) {
return;
}
if (The_mission.support_ships.rearm_weapon_pool[team][weapon_class] < 0) {
return;
}
The_mission.support_ships.rearm_weapon_pool[team][weapon_class] =
MAX(0, The_mission.support_ships.rearm_weapon_pool[team][weapon_class] - amount);
}
// ==================================================================================
// ship_do_rearm_frame()
@@ -16375,150 +16523,183 @@ int ship_do_rearm_frame( object *objp, float frametime )
// they can be rearmed. We can rearm multiple banks at once.
banks_full = 0;
primary_banks_full = 0;
// Skip rearming entirely if the mission disallows it, but still count the banks as full so that the "rearm
// complete" state can be reached.
if (The_mission.support_ships.disallow_rearm) {
banks_full = swp->num_secondary_banks;
primary_banks_full = swp->num_primary_banks;
}
if ( subsys_all_ok )
{
for (i = 0; i < swp->num_secondary_banks; i++ )
{
// Actual loading of missiles is preceded by a sound effect which is the missile
// loading equipment moving into place
if ( aip->rearm_first_missile == TRUE )
{
swp->secondary_bank_rearm_time[i] = timestamp((int)gamesnd_get_max_duration(gamesnd_get_game_sound(GameSounds::MISSILE_START_LOAD)));
}
if ( swp->secondary_bank_ammo[i] < swp->secondary_bank_start_ammo[i] )
{
float rearm_time;
if ( objp == Player_obj )
{
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
if ( timestamp_elapsed(swp->secondary_bank_rearm_time[i]) )
{
rearm_time = Weapon_info[swp->secondary_bank_weapons[i]].rearm_rate;
swp->secondary_bank_rearm_time[i] = timestamp((int)(rearm_time * 1000.0f));
snd_play_3d( gamesnd_get_game_sound(GameSounds::MISSILE_LOAD), &objp->pos, &View_position );
if (objp == Player_obj)
joy_ff_play_reload_effect();
swp->secondary_bank_ammo[i] += Weapon_info[swp->secondary_bank_weapons[i]].reloaded_per_batch;
if ( swp->secondary_bank_ammo[i] > swp->secondary_bank_start_ammo[i] )
{
swp->secondary_bank_ammo[i] = swp->secondary_bank_start_ammo[i];
}
}
else
{
}
}
else
{
banks_full++;
}
if ((aip->rearm_first_missile == TRUE) && (i == swp->num_secondary_banks - 1))
{
if ((banks_full != swp->num_secondary_banks))
snd_play_3d( gamesnd_get_game_sound(GameSounds::MISSILE_START_LOAD), &objp->pos, &View_position );
aip->rearm_first_missile = FALSE;
}
} // end for
// rearm ballistic primaries - Goober5000
if ( aip->rearm_first_ballistic_primary == TRUE)
{
for (i = 0; i < swp->num_primary_banks; i++ )
{
if ( Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Ballistic] )
last_ballistic_idx = i;
}
}
for (i = 0; i < swp->num_primary_banks; i++ )
{
if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Ballistic])
{
// Actual loading of bullets is preceded by a sound effect which is the bullet
if (!The_mission.support_ships.disallow_rearm) {
for (i = 0; i < swp->num_secondary_banks; i++) {
// Actual loading of missiles is preceded by a sound effect which is the missile
// loading equipment moving into place
if ( aip->rearm_first_ballistic_primary == TRUE )
{
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_START_LOAD))
sound_index = GameSounds::BALLISTIC_START_LOAD;
else
sound_index = GameSounds::MISSILE_START_LOAD;
if (sound_index.isValid())
swp->primary_bank_rearm_time[i] = timestamp((int)gamesnd_get_max_duration(gamesnd_get_game_sound(sound_index)));
else
swp->primary_bank_rearm_time[i] = timestamp(0);
if (aip->rearm_first_missile == TRUE) {
swp->secondary_bank_rearm_time[i] = timestamp(
(int)gamesnd_get_max_duration(gamesnd_get_game_sound(GameSounds::MISSILE_START_LOAD)));
}
if ( swp->primary_bank_ammo[i] < swp->primary_bank_start_ammo[i] )
{
float rearm_time;
if ( objp == Player_obj )
{
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
if (swp->secondary_bank_ammo[i] < swp->secondary_bank_start_ammo[i]) {
const int weapon_class = swp->secondary_bank_weapons[i];
const int rearm_pool = get_mission_rearm_pool_for_weapon(weapon_class, shipp->team);
if ( timestamp_elapsed(swp->primary_bank_rearm_time[i]) )
{
rearm_time = Weapon_info[swp->primary_bank_weapons[i]].rearm_rate;
swp->primary_bank_rearm_time[i] = timestamp( (int)(rearm_time * 1000.f) );
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_LOAD))
sound_index = GameSounds::BALLISTIC_LOAD;
else
sound_index = GameSounds::MISSILE_LOAD;
if (rearm_pool == 0) {
// Pool exhausted: try a precedence swap; otherwise this bank is unrearmable this frame.
// Either way, fall through so the trailing "first missile" block still clears the flag.
const bool swapped = The_mission.support_ships.allow_rearm_weapon_precedence &&
swp->secondary_bank_ammo[i] == 0 &&
maybe_swap_to_precedence_rearm_weapon(shipp, i, true);
if (!swapped) {
banks_full++;
}
} else {
if (objp == Player_obj) {
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
if (sound_index.isValid())
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &View_position );
swp->primary_bank_ammo[i] += Weapon_info[swp->primary_bank_weapons[i]].reloaded_per_batch;
if ( swp->primary_bank_ammo[i] > swp->primary_bank_start_ammo[i] )
{
swp->primary_bank_ammo[i] = swp->primary_bank_start_ammo[i];
if (timestamp_elapsed(swp->secondary_bank_rearm_time[i])) {
float rearm_time = Weapon_info[weapon_class].rearm_rate;
swp->secondary_bank_rearm_time[i] = timestamp((int)(rearm_time * 1000.0f));
int reload_amount = Weapon_info[weapon_class].reloaded_per_batch;
if (rearm_pool > 0) {
reload_amount = MIN(reload_amount, rearm_pool);
}
reload_amount =
MIN(reload_amount, swp->secondary_bank_start_ammo[i] - swp->secondary_bank_ammo[i]);
if (reload_amount <= 0) {
banks_full++;
} else {
snd_play_3d(gamesnd_get_game_sound(GameSounds::MISSILE_LOAD), &objp->pos, &View_position);
if (objp == Player_obj)
joy_ff_play_reload_effect();
const int prev_ammo = swp->secondary_bank_ammo[i];
swp->secondary_bank_ammo[i] += reload_amount;
if (swp->secondary_bank_ammo[i] > swp->secondary_bank_start_ammo[i]) {
swp->secondary_bank_ammo[i] = swp->secondary_bank_start_ammo[i];
}
use_mission_rearm_pool_for_weapon(weapon_class, swp->secondary_bank_ammo[i] - prev_ammo, shipp->team);
}
}
}
} else {
banks_full++;
}
else
{
if ((aip->rearm_first_missile == TRUE) && (i == swp->num_secondary_banks - 1)) {
if ((banks_full != swp->num_secondary_banks))
snd_play_3d(gamesnd_get_game_sound(GameSounds::MISSILE_START_LOAD), &objp->pos, &View_position);
aip->rearm_first_missile = FALSE;
}
} // end for
// rearm ballistic primaries - Goober5000
if (aip->rearm_first_ballistic_primary == TRUE) {
for (i = 0; i < swp->num_primary_banks; i++) {
if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Ballistic])
last_ballistic_idx = i;
}
}
for (i = 0; i < swp->num_primary_banks; i++) {
if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Ballistic]) {
// Actual loading of bullets is preceded by a sound effect which is the bullet
// loading equipment moving into place
if (aip->rearm_first_ballistic_primary == TRUE) {
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_START_LOAD))
sound_index = GameSounds::BALLISTIC_START_LOAD;
else
sound_index = GameSounds::MISSILE_START_LOAD;
if (sound_index.isValid())
swp->primary_bank_rearm_time[i] =
timestamp((int)gamesnd_get_max_duration(gamesnd_get_game_sound(sound_index)));
else
swp->primary_bank_rearm_time[i] = timestamp(0);
}
if (swp->primary_bank_ammo[i] < swp->primary_bank_start_ammo[i]) {
const int weapon_class = swp->primary_bank_weapons[i];
const int rearm_pool = get_mission_rearm_pool_for_weapon(weapon_class, shipp->team);
if (rearm_pool == 0) {
// Pool exhausted: try a precedence swap; otherwise this bank is unrearmable this frame.
// Either way, fall through so the trailing "first ballistic" block still clears the flag.
const bool swapped = The_mission.support_ships.allow_rearm_weapon_precedence &&
swp->primary_bank_ammo[i] == 0 &&
maybe_swap_to_precedence_rearm_weapon(shipp, i, false);
if (!swapped) {
primary_banks_full++;
}
} else {
if (objp == Player_obj) {
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
if (timestamp_elapsed(swp->primary_bank_rearm_time[i])) {
float rearm_time = Weapon_info[weapon_class].rearm_rate;
swp->primary_bank_rearm_time[i] = timestamp((int)(rearm_time * 1000.f));
int reload_amount = Weapon_info[weapon_class].reloaded_per_batch;
if (rearm_pool > 0) {
reload_amount = MIN(reload_amount, rearm_pool);
}
reload_amount =
MIN(reload_amount, swp->primary_bank_start_ammo[i] - swp->primary_bank_ammo[i]);
if (reload_amount <= 0) {
primary_banks_full++;
} else {
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_LOAD))
sound_index = GameSounds::BALLISTIC_LOAD;
else
sound_index = GameSounds::MISSILE_LOAD;
if (sound_index.isValid())
snd_play_3d(gamesnd_get_game_sound(sound_index), &objp->pos, &View_position);
const int prev_primary_ammo = swp->primary_bank_ammo[i];
swp->primary_bank_ammo[i] += reload_amount;
if (swp->primary_bank_ammo[i] > swp->primary_bank_start_ammo[i]) {
swp->primary_bank_ammo[i] = swp->primary_bank_start_ammo[i];
}
use_mission_rearm_pool_for_weapon(weapon_class, swp->primary_bank_ammo[i] - prev_primary_ammo, shipp->team);
}
}
}
} else {
primary_banks_full++;
}
}
// if the bank is not a ballistic
else {
primary_banks_full++;
}
}
// if the bank is not a ballistic
else
{
primary_banks_full++;
}
if ((aip->rearm_first_ballistic_primary == TRUE) && (i == last_ballistic_idx))
{
if (primary_banks_full != swp->num_primary_banks)
{
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_START_LOAD))
sound_index = GameSounds::BALLISTIC_START_LOAD;
else
sound_index = GameSounds::MISSILE_START_LOAD;
if ((aip->rearm_first_ballistic_primary == TRUE) && (i == last_ballistic_idx)) {
if (primary_banks_full != swp->num_primary_banks) {
// Goober5000
gamesnd_id sound_index;
if (gamesnd_game_sound_try_load(GameSounds::BALLISTIC_START_LOAD))
sound_index = GameSounds::BALLISTIC_START_LOAD;
else
sound_index = GameSounds::MISSILE_START_LOAD;
if (sound_index.isValid())
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &View_position );
if (sound_index.isValid())
snd_play_3d(gamesnd_get_game_sound(sound_index), &objp->pos, &View_position);
}
aip->rearm_first_ballistic_primary = FALSE;
}
aip->rearm_first_ballistic_primary = FALSE;
}
} // end for
} // end for
}
} // end if (subsys_all_ok)
if ( banks_full == swp->num_secondary_banks )
+2
View File
@@ -1523,6 +1523,8 @@ add_file_folder("Scripting\\\\Api\\\\Objs"
scripting/api/objs/sound.h
scripting/api/objs/species.cpp
scripting/api/objs/species.h
scripting/api/objs/support_rearm_pool.cpp
scripting/api/objs/support_rearm_pool.h
scripting/api/objs/streaminganim.cpp
scripting/api/objs/streaminganim.h
scripting/api/objs/subsystem.cpp
+1
View File
@@ -489,6 +489,7 @@ struct weapon_info
float cargo_size; // cargo space taken up by individual weapon (missiles only)
float autoaim_fov; // the weapon specific auto-aim field of view
float rearm_rate; // rate per second at which secondary weapons are loaded during rearming
bool disallow_rearm; // if true, support ships cannot rearm this weapon
int reloaded_per_batch; // number of munitions rearmed per batch
float weapon_range; // max range weapon can be effectively fired. (May be less than life * speed)
float optimum_range; // causes ai fighters to prefer this distance when attacking with the weapon
+5
View File
@@ -2126,6 +2126,10 @@ int parse_weapon(int subtype, bool replace, const char *filename)
wip->reloaded_per_batch = REARM_NUM_BALLISTIC_PRIMARIES_PER_BATCH;
}
}
if (optional_string("$Disallow Support Rearm:")) {
stuff_boolean(&wip->disallow_rearm);
}
if (optional_string("+Weapon Range:")) {
stuff_float(&wip->weapon_range);
@@ -9929,6 +9933,7 @@ void weapon_info::reset()
this->cargo_size = 1.0f;
this->autoaim_fov = 0.0f;
this->rearm_rate = 1.0f;
this->disallow_rearm = false;
this->reloaded_per_batch = -1;
this->weapon_range = WEAPON_DEFAULT_TABLED_MAX_RANGE;
// *Minimum weapon range, default is 0 -Et1
+2
View File
@@ -134,6 +134,8 @@ set(FRED2_SOURCES
shiptexturesdlg.h
soundenvironmentdlg.cpp
soundenvironmentdlg.h
supportrearmdlg.cpp
supportrearmdlg.h
starfieldeditor.cpp
starfieldeditor.h
stdafx.cpp
+36 -10
View File
@@ -938,16 +938,8 @@ BEGIN
EDITTEXT IDC_LOADING_SCREEN640,47,225,97,14,ES_AUTOHSCROLL
PUSHBUTTON "1024x768",IDC_LOADING_SCREEN_BUTTON1024,7,241,40,16
EDITTEXT IDC_LOADING_SCREEN1024,47,241,97,16,ES_AUTOHSCROLL
GROUPBOX "Support Ships",IDC_STATIC,160,6,152,71
CONTROL "Disallow Support Ships",IDC_SUPPORT_ALLOWED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,164,16,95,10
CONTROL "Support Ships Repair Hull",IDC_SUPPORT_REPAIRS_HULL,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,164,27,123,10
LTEXT "Hull Repair Ceiling",IDC_STATIC,164,43,60,8
EDITTEXT IDC_MAX_HULL_REPAIR_VAL,244,41,49,14,ES_AUTOHSCROLL
LTEXT "%",IDC_STATIC,298,46,8,8
LTEXT "Subsytem Repair Ceiling",IDC_STATIC,164,64,75,8
EDITTEXT IDC_MAX_SUBSYS_REPAIR_VAL,244,59,49,14,ES_AUTOHSCROLL
LTEXT "%",IDC_STATIC,298,60,8,8
GROUPBOX "Support Ships",IDC_STATIC,160,6,152,40
PUSHBUTTON "Support Options...",IDC_SUPPORT_REARM_OPTIONS,165,20,140,14
GROUPBOX "Ship Trails",IDC_STATIC,160,81,154,41
CONTROL "Toggle (off in nebula; on elsewhere)",IDC_SPECS_TOGGLE_TRAILS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,162,92,141,10
@@ -1006,6 +998,40 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,424,0,50,14
END
IDD_SUPPORT_REARM_OPTIONS DIALOGEX 0, 0, 356, 258
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Support Rearm Options"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
CONTROL "Disallow Support Ships",IDC_DISALLOW_SUPPORT_SHIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,8,130,10
CONTROL "Support Ships Repair Hull",IDC_SUPPORT_REPAIRS_HULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,20,130,10
LTEXT "Hull Repair Ceiling",IDC_STATIC,8,35,66,8
EDITTEXT IDC_MAX_HULL_REPAIR_VAL,78,32,48,14,ES_AUTOHSCROLL
LTEXT "%",IDC_STATIC,130,35,8,8
LTEXT "Subsystem Repair Ceiling",IDC_STATIC,8,52,80,8
EDITTEXT IDC_MAX_SUBSYS_REPAIR_VAL,78,49,48,14,ES_AUTOHSCROLL
LTEXT "%",IDC_STATIC,130,52,8,8
GROUPBOX "Rearm Behavior",IDC_STATIC,148,4,200,74
CONTROL "Disallow Support Rearm",IDC_DISALLOW_SUPPORT_REARM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,16,187,10
CONTROL "Limit Rearm to Mission Pool",IDC_LIMIT_SUPPORT_REARM_TO_POOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,28,187,10
CONTROL "Set Rearm Pool from Loadout Pool surplus",IDC_SUPPORT_REARM_POOL_FROM_LOADOUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,40,187,10
CONTROL "Use Weapon Precedence when pool is empty",IDC_ALLOW_SUPPORT_REARM_PRECEDENCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,52,187,10
GROUPBOX "Support Rearm Pool",IDC_STATIC,4,80,346,158
LTEXT "Pool Team",IDC_STATIC,10,94,29,8
COMBOBOX IDC_SUPPORT_REARM_POOL_TEAM,42,90,82,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LISTBOX IDC_SUPPORT_REARM_WEAPON_LIST,10,106,226,120,LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
LTEXT "Pool Amount",IDC_STATIC,246,95,47,8
EDITTEXT IDC_SUPPORT_REARM_POOL_AMOUNT,246,107,94,14,ES_AUTOHSCROLL
PUSHBUTTON "Set Amount",IDC_SUPPORT_REARM_SET_AMOUNT,246,127,94,14
PUSHBUTTON "Set Unlimited (-1)",IDC_SUPPORT_REARM_SET_UNLIMITED,246,145,94,14
PUSHBUTTON "Set Zero",IDC_SUPPORT_REARM_SET_ZERO,246,163,94,14
PUSHBUTTON "Set ALL to Amount",IDC_SUPPORT_REARM_SET_ALL_AMOUNT,246,181,94,14
PUSHBUTTON "Set ALL to Unlimited",IDC_SUPPORT_REARM_SET_ALL_UNLIMITED,246,199,94,14
PUSHBUTTON "Set ALL to Zero",IDC_SUPPORT_REARM_SET_ALL_ZERO,246,217,94,14
DEFPUSHBUTTON "OK",IDOK,245,240,50,14
PUSHBUTTON "Cancel",IDCANCEL,300,240,50,14
END
IDD_PREFERENCES DIALOG 0, 0, 333, 81
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Preferences"
+9 -21
View File
@@ -21,6 +21,7 @@
#include "mission/missionparse.h"
#include "mission/missionmessage.h"
#include "scripting/global_hooks.h"
#include "supportrearmdlg.h"
#ifdef _DEBUG
#undef THIS_FILE
@@ -58,13 +59,11 @@ CMissionNotesDlg::CMissionNotesDlg(CWnd* pParent /*=NULL*/) : CDialog(CMissionNo
m_scramble = FALSE;
m_num_respawns = 0;
m_max_respawn_delay = -1;
m_disallow_support = 0;
m_no_promotion = FALSE;
m_no_builtin_msgs = FALSE;
m_no_builtin_command_msgs = FALSE;
m_no_traitor = FALSE;
m_toggle_trails = FALSE;
m_support_repairs_hull = FALSE;
m_beam_free_all_by_default = FALSE;
m_player_start_using_ai = FALSE;
m_toggle_start_chase_view = FALSE;
@@ -77,8 +76,6 @@ CMissionNotesDlg::CMissionNotesDlg(CWnd* pParent /*=NULL*/) : CDialog(CMissionNo
m_end_to_mainhall = FALSE;
m_override_hashcommand = FALSE;
m_preload_subspace = FALSE;
m_max_hull_repair_val = 0.0f;
m_max_subsys_repair_val = 100.0f;
m_contrail_threshold = CONTRAIL_THRESHOLD_DEFAULT;
m_contrail_threshold_flag = FALSE;
//}}AFX_DATA_INIT
@@ -112,13 +109,11 @@ void CMissionNotesDlg::DoDataExchange(CDataExchange* pDX)
DDV_MinMaxUInt(pDX, m_num_respawns, 0, 99);
DDX_Text(pDX, IDC_MAX_RESPAWN_DELAY, m_max_respawn_delay);
DDV_MinMaxInt(pDX, m_max_respawn_delay, -1, 999);
DDX_Check(pDX, IDC_SUPPORT_ALLOWED, m_disallow_support);
DDX_Check(pDX, IDC_NO_PROMOTION, m_no_promotion);
DDX_Check(pDX, IDC_DISABLE_BUILTIN_MSGS, m_no_builtin_msgs);
DDX_Check(pDX, IDC_DISABLE_BUILTIN_COMMAND_MSGS, m_no_builtin_command_msgs);
DDX_Check(pDX, IDC_NO_TRAITOR, m_no_traitor);
DDX_Check(pDX, IDC_SPECS_TOGGLE_TRAILS, m_toggle_trails);
DDX_Check(pDX, IDC_SUPPORT_REPAIRS_HULL, m_support_repairs_hull);
DDX_Check(pDX, IDC_BEAM_FREE_ALL_BY_DEFAULT, m_beam_free_all_by_default);
DDX_Check(pDX, IDC_PLAYER_START_AI, m_player_start_using_ai);
DDX_Check(pDX, IDC_TOGGLE_START_CHASE, m_toggle_start_chase_view);
@@ -131,10 +126,6 @@ void CMissionNotesDlg::DoDataExchange(CDataExchange* pDX)
DDX_Check(pDX, IDC_END_TO_MAINHALL, m_end_to_mainhall);
DDX_Check(pDX, IDC_OVERRIDE_HASHCOMMAND, m_override_hashcommand);
DDX_Check(pDX, IDC_PRELOAD_SUBSPACE, m_preload_subspace);
DDX_Text(pDX, IDC_MAX_HULL_REPAIR_VAL, m_max_hull_repair_val);
DDV_MinMaxFloat(pDX, m_max_hull_repair_val, 0, 100);
DDX_Text(pDX, IDC_MAX_SUBSYS_REPAIR_VAL, m_max_subsys_repair_val);
DDV_MinMaxFloat(pDX, m_max_subsys_repair_val, 0, 100);
DDX_Text(pDX, IDC_CONTRAIL_THRESHOLD, m_contrail_threshold);
DDV_MinMaxInt(pDX, m_contrail_threshold, 0, 1000);
DDX_Check(pDX, IDC_CONTRAIL_THRESHOLD_CHECK, m_contrail_threshold_flag);
@@ -155,6 +146,7 @@ BEGIN_MESSAGE_MAP(CMissionNotesDlg, CDialog)
ON_BN_CLICKED(IDC_SOUND_ENVIRONMENT_BUTTON, OnSoundEnvironment)
ON_BN_CLICKED(IDC_OPEN_CUSTOM_DATA, OnCustomData)
ON_BN_CLICKED(IDC_OPEN_CUSTOM_STRINGS, OnCustomStrings)
ON_BN_CLICKED(IDC_SUPPORT_REARM_OPTIONS, OnSupportRearmOptions)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
@@ -232,9 +224,6 @@ void CMissionNotesDlg::OnOK()
MODIFY(The_mission.game_type, new_m_type );
MODIFY(The_mission.num_respawns, (int)m_num_respawns );
MODIFY(The_mission.max_respawn_delay, m_max_respawn_delay );
MODIFY(The_mission.support_ships.max_support_ships, (m_disallow_support) ? 0 : -1);
MODIFY(The_mission.support_ships.max_hull_repair_val, m_max_hull_repair_val);
MODIFY(The_mission.support_ships.max_subsys_repair_val, m_max_subsys_repair_val);
flags = The_mission.flags;
@@ -266,9 +255,6 @@ void CMissionNotesDlg::OnOK()
The_mission.contrail_threshold = CONTRAIL_THRESHOLD_DEFAULT;
}
//set support ship repairing flags
The_mission.flags.set(Mission::Mission_Flags::Support_repairs_hull, m_support_repairs_hull != 0);
// set default beam free
The_mission.flags.set(Mission::Mission_Flags::Beam_free_all_by_default, m_beam_free_all_by_default != 0);
@@ -399,13 +385,11 @@ BOOL CMissionNotesDlg::OnInitDialog()
m_red_alert = (The_mission.flags[Mission::Mission_Flags::Red_alert]) ? 1 : 0;
m_scramble = (The_mission.flags[Mission::Mission_Flags::Scramble]) ? 1 : 0;
m_full_war = Mission_all_attack;
m_disallow_support = (The_mission.support_ships.max_support_ships == 0) ? 1 : 0;
m_no_promotion = (The_mission.flags[Mission::Mission_Flags::No_promotion]) ? 1 : 0;
m_no_builtin_msgs = (The_mission.flags[Mission::Mission_Flags::No_builtin_msgs]) ? 1 : 0;
m_no_builtin_command_msgs = (The_mission.flags[Mission::Mission_Flags::No_builtin_command]) ? 1 : 0;
m_no_traitor = (The_mission.flags[Mission::Mission_Flags::No_traitor]) ? 1 : 0;
m_toggle_trails = (The_mission.flags[Mission::Mission_Flags::Toggle_ship_trails]) ? 1 : 0;
m_support_repairs_hull = (The_mission.flags[Mission::Mission_Flags::Support_repairs_hull]) ? 1 : 0;
m_beam_free_all_by_default = (The_mission.flags[Mission::Mission_Flags::Beam_free_all_by_default]) ? 1 : 0;
m_player_start_using_ai = (The_mission.flags[Mission::Mission_Flags::Player_start_ai]) ? 1 : 0;
m_toggle_start_chase_view = (The_mission.flags[Mission::Mission_Flags::Toggle_start_chase_view]) ? 1 : 0;
@@ -511,8 +495,6 @@ BOOL CMissionNotesDlg::OnInitDialog()
m_max_respawn_delay_spin.SetRange(-1, 999);
m_num_respawns = The_mission.num_respawns;
m_max_respawn_delay = The_mission.max_respawn_delay;
m_max_hull_repair_val = The_mission.support_ships.max_hull_repair_val;
m_max_subsys_repair_val = The_mission.support_ships.max_subsys_repair_val;
m_contrail_threshold = The_mission.contrail_threshold;
m_contrail_threshold_flag = (m_contrail_threshold != CONTRAIL_THRESHOLD_DEFAULT);
@@ -670,7 +652,13 @@ void CMissionNotesDlg::OnLoad640()
}
}
void CMissionNotesDlg::OnSupportRearmOptions()
{
CSupportRearmDlg dlg(this);
if (dlg.DoModal() == IDOK) {
set_modified();
}
}
void CMissionNotesDlg::OnEnChangeLoadingScreen641()
{
+1 -4
View File
@@ -48,13 +48,11 @@ public:
BOOL m_scramble;
UINT m_num_respawns;
int m_max_respawn_delay;
int m_disallow_support;
BOOL m_no_promotion;
BOOL m_no_builtin_msgs;
BOOL m_no_builtin_command_msgs;
BOOL m_no_traitor;
BOOL m_toggle_trails;
BOOL m_support_repairs_hull;
BOOL m_beam_free_all_by_default;
BOOL m_player_start_using_ai;
BOOL m_toggle_start_chase_view;
@@ -67,8 +65,6 @@ public:
BOOL m_end_to_mainhall;
BOOL m_override_hashcommand;
BOOL m_preload_subspace;
float m_max_hull_repair_val;
float m_max_subsys_repair_val;
BOOL m_contrail_threshold_flag;
int m_contrail_threshold;
//}}AFX_DATA
@@ -105,6 +101,7 @@ protected:
afx_msg void OnSoundEnvironment();
afx_msg void OnCustomData();
afx_msg void OnCustomStrings();
afx_msg void OnSupportRearmOptions();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
+18 -2
View File
@@ -137,6 +137,7 @@
#define IDD_MUSIC_PLAYER 330
#define IDD_VOLUMETRICS 332
#define IDD_EDIT_CUSTOM_STRINGS 333
#define IDD_SUPPORT_REARM_OPTIONS 334
#define IDC_SHIP_CLASS 1003
#define IDC_SHIP_WING 1004
#define IDC_SOUND_CLIP_NAME 1007
@@ -1274,6 +1275,21 @@
#define IDC_NEB2_FOG_NEAR_DIST 1714
#define IDC_NEB2_FOG_SKYBOX_CLIP 1715
#define IDC_NEB2_FOG_CLIP 1716
#define IDC_SUPPORT_REARM_OPTIONS 1717
#define IDC_DISALLOW_SUPPORT_SHIPS 1718
#define IDC_LIMIT_SUPPORT_REARM_TO_POOL 1719
#define IDC_DISALLOW_SUPPORT_REARM 1720
#define IDC_ALLOW_SUPPORT_REARM_PRECEDENCE 1721
#define IDC_SUPPORT_REARM_POOL_FROM_LOADOUT 1722
#define IDC_SUPPORT_REARM_WEAPON_LIST 1723
#define IDC_SUPPORT_REARM_POOL_AMOUNT 1724
#define IDC_SUPPORT_REARM_SET_AMOUNT 1725
#define IDC_SUPPORT_REARM_SET_UNLIMITED 1726
#define IDC_SUPPORT_REARM_SET_ZERO 1727
#define IDC_SUPPORT_REARM_SET_ALL_AMOUNT 1728
#define IDC_SUPPORT_REARM_SET_ALL_UNLIMITED 1729
#define IDC_SUPPORT_REARM_SET_ALL_ZERO 1730
#define IDC_SUPPORT_REARM_POOL_TEAM 1731
#define IDC_SEXP_POPUP_LIST 32770
#define ID_FILE_MISSIONNOTES 32771
#define ID_DUPLICATE 32774
@@ -1589,8 +1605,8 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 335
#define _APS_NEXT_COMMAND_VALUE 33104
#define _APS_NEXT_CONTROL_VALUE 1717
#define _APS_NEXT_COMMAND_VALUE 33112
#define _APS_NEXT_CONTROL_VALUE 1732
#define _APS_NEXT_SYMED_VALUE 105
#endif
#endif
+400
View File
@@ -0,0 +1,400 @@
#include "stdafx.h"
#include "FRED.h"
#include "FREDDoc.h"
#include "supportrearmdlg.h"
#include "mission/missionparse.h"
#include "weapon/weapon.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CSupportRearmDlg::CSupportRearmDlg(CWnd* pParent) : CDialog(CSupportRearmDlg::IDD, pParent)
{
m_disallow_support_ships = FALSE;
m_limit_rearm_to_pool = FALSE;
m_support_repairs_hull = FALSE;
m_disallow_support_rearm = FALSE;
m_allow_weapon_precedence = FALSE;
m_rearm_pool_from_loadout = FALSE;
m_max_hull_repair_val = 0.0f;
m_max_subsys_repair_val = 100.0f;
m_weapon_pool_amount = 0;
m_rearm_pool_team = 0;
memset(m_rearm_weapon_pool, 0, sizeof(m_rearm_weapon_pool));
}
void CSupportRearmDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Check(pDX, IDC_DISALLOW_SUPPORT_SHIPS, m_disallow_support_ships);
DDX_Check(pDX, IDC_LIMIT_SUPPORT_REARM_TO_POOL, m_limit_rearm_to_pool);
DDX_Check(pDX, IDC_SUPPORT_REPAIRS_HULL, m_support_repairs_hull);
DDX_Check(pDX, IDC_DISALLOW_SUPPORT_REARM, m_disallow_support_rearm);
DDX_Check(pDX, IDC_ALLOW_SUPPORT_REARM_PRECEDENCE, m_allow_weapon_precedence);
DDX_Check(pDX, IDC_SUPPORT_REARM_POOL_FROM_LOADOUT, m_rearm_pool_from_loadout);
DDX_Text(pDX, IDC_MAX_HULL_REPAIR_VAL, m_max_hull_repair_val);
DDV_MinMaxFloat(pDX, m_max_hull_repair_val, 0.0f, 100.0f);
DDX_Text(pDX, IDC_MAX_SUBSYS_REPAIR_VAL, m_max_subsys_repair_val);
DDV_MinMaxFloat(pDX, m_max_subsys_repair_val, 0.0f, 100.0f);
DDX_Text(pDX, IDC_SUPPORT_REARM_POOL_AMOUNT, m_weapon_pool_amount);
DDX_CBIndex(pDX, IDC_SUPPORT_REARM_POOL_TEAM, m_rearm_pool_team);
}
BEGIN_MESSAGE_MAP(CSupportRearmDlg, CDialog)
ON_LBN_SELCHANGE(IDC_SUPPORT_REARM_WEAPON_LIST, OnSelchangeWeaponList)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_AMOUNT, OnSetPoolAmount)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_UNLIMITED, OnSetPoolUnlimited)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_ZERO, OnSetPoolZero)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_ALL_AMOUNT, OnSetAllPoolAmount)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_ALL_UNLIMITED, OnSetAllPoolUnlimited)
ON_BN_CLICKED(IDC_SUPPORT_REARM_SET_ALL_ZERO, OnSetAllPoolZero)
ON_CBN_SELCHANGE(IDC_SUPPORT_REARM_POOL_TEAM, OnSelchangePoolTeam)
ON_BN_CLICKED(IDC_DISALLOW_SUPPORT_SHIPS, OnOptionChanged)
ON_BN_CLICKED(IDC_SUPPORT_REPAIRS_HULL, OnOptionChanged)
ON_BN_CLICKED(IDC_DISALLOW_SUPPORT_REARM, OnOptionChanged)
ON_BN_CLICKED(IDC_LIMIT_SUPPORT_REARM_TO_POOL, OnOptionChanged)
ON_BN_CLICKED(IDC_SUPPORT_REARM_POOL_FROM_LOADOUT, OnOptionChanged)
ON_BN_CLICKED(IDC_ALLOW_SUPPORT_REARM_PRECEDENCE, OnOptionChanged)
ON_WM_DRAWITEM()
END_MESSAGE_MAP()
BOOL CSupportRearmDlg::OnInitDialog()
{
m_disallow_support_ships = (The_mission.support_ships.max_support_ships == 0) ? TRUE : FALSE;
m_limit_rearm_to_pool = The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool] ? TRUE : FALSE;
m_support_repairs_hull = The_mission.flags[Mission::Mission_Flags::Support_repairs_hull] ? TRUE : FALSE;
m_disallow_support_rearm = The_mission.support_ships.disallow_rearm ? TRUE : FALSE;
m_allow_weapon_precedence = The_mission.support_ships.allow_rearm_weapon_precedence ? TRUE : FALSE;
m_rearm_pool_from_loadout = The_mission.support_ships.rearm_pool_from_loadout ? TRUE : FALSE;
m_max_hull_repair_val = The_mission.support_ships.max_hull_repair_val;
m_max_subsys_repair_val = The_mission.support_ships.max_subsys_repair_val;
memcpy(m_rearm_weapon_pool, The_mission.support_ships.rearm_weapon_pool, sizeof(m_rearm_weapon_pool));
m_rearm_pool_team = 0;
CDialog::OnInitDialog();
populate_team_list();
populate_weapon_list();
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list != nullptr && weapon_list->GetCount() > 0) {
weapon_list->SetCurSel(0);
}
update_weapon_amount_display();
UpdateData(FALSE);
update_control_states();
return TRUE;
}
void CSupportRearmDlg::populate_team_list()
{
auto* team_combo = (CComboBox*)GetDlgItem(IDC_SUPPORT_REARM_POOL_TEAM);
if (team_combo == nullptr) {
return;
}
team_combo->ResetContent();
for (int i = 0; i < Num_teams && i < MAX_TVT_TEAMS; ++i) {
CString text;
text.Format("Team %d", i + 1);
team_combo->AddString(text);
}
if (team_combo->GetCount() > 0) {
team_combo->SetCurSel(m_rearm_pool_team);
}
}
CString CSupportRearmDlg::format_weapon_pool_entry(int weapon_class) const
{
CString text;
const auto& wi = Weapon_info[weapon_class];
int amount = m_rearm_weapon_pool[m_rearm_pool_team][weapon_class];
if (wi.disallow_rearm) {
text.Format("%s - 0 (disabled by weapon settings)", wi.name);
return text;
}
if (amount < 0) {
text.Format("%s - Unlimited", wi.name);
} else {
text.Format("%s - %d", wi.name, amount);
}
return text;
}
void CSupportRearmDlg::populate_weapon_list()
{
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list == nullptr) {
return;
}
weapon_list->ResetContent();
for (int i = 0; i < weapon_info_size(); ++i) {
if (!Weapon_info[i].wi_flags[Weapon::Info_Flags::Player_allowed]) {
continue;
}
int list_index = weapon_list->AddString(format_weapon_pool_entry(i));
weapon_list->SetItemData(list_index, i);
}
}
int CSupportRearmDlg::get_selected_weapon_class() const
{
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list == nullptr) {
return -1;
}
int sel = weapon_list->GetCurSel();
if (sel == LB_ERR) {
return -1;
}
return (int)weapon_list->GetItemData(sel);
}
void CSupportRearmDlg::update_weapon_amount_display()
{
int weapon_class = get_selected_weapon_class();
if (weapon_class < 0 || weapon_class >= weapon_info_size()) {
m_weapon_pool_amount = 0;
} else {
m_weapon_pool_amount = m_rearm_weapon_pool[m_rearm_pool_team][weapon_class];
}
UpdateData(FALSE);
}
void CSupportRearmDlg::set_selected_weapon_amount(int amount)
{
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list == nullptr) {
return;
}
const int sel = weapon_list->GetCurSel();
const int weapon_class = get_selected_weapon_class();
if (sel == LB_ERR || weapon_class < 0 || weapon_class >= weapon_info_size()) {
return;
}
if (Weapon_info[weapon_class].disallow_rearm) {
amount = 0;
} else if (amount < 0) {
amount = -1;
}
m_rearm_weapon_pool[m_rearm_pool_team][weapon_class] = amount;
weapon_list->DeleteString(sel);
weapon_list->InsertString(sel, format_weapon_pool_entry(weapon_class));
weapon_list->SetItemData(sel, weapon_class);
weapon_list->SetCurSel(sel);
update_weapon_amount_display();
}
void CSupportRearmDlg::set_all_weapon_amount(int amount)
{
const int normalized_amount = (amount < 0) ? -1 : amount;
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list != nullptr) {
for (int i = 0; i < weapon_list->GetCount(); ++i) {
const int weapon_class = static_cast<int>(weapon_list->GetItemData(i));
if (weapon_class < 0 || weapon_class >= weapon_info_size()) {
continue;
}
if (Weapon_info[weapon_class].disallow_rearm) {
m_rearm_weapon_pool[m_rearm_pool_team][weapon_class] = 0;
} else {
m_rearm_weapon_pool[m_rearm_pool_team][weapon_class] = normalized_amount;
}
}
const int previous_sel = weapon_list->GetCurSel();
populate_weapon_list();
if (previous_sel != LB_ERR && previous_sel < weapon_list->GetCount()) {
weapon_list->SetCurSel(previous_sel);
} else if (weapon_list->GetCount() > 0) {
weapon_list->SetCurSel(0);
}
}
update_weapon_amount_display();
}
void CSupportRearmDlg::update_control_states()
{
const bool support_enabled = (m_disallow_support_ships == FALSE);
const bool rearm_allowed = support_enabled && (m_disallow_support_rearm == FALSE);
const bool pool_controls_enabled =
rearm_allowed && (m_limit_rearm_to_pool != FALSE) && (m_rearm_pool_from_loadout == FALSE);
const int selected_weapon_class = get_selected_weapon_class();
const bool selected_weapon_disallow_rearm =
(selected_weapon_class >= 0 && selected_weapon_class < weapon_info_size() &&
Weapon_info[selected_weapon_class].disallow_rearm);
const bool right_controls_enabled = pool_controls_enabled && !selected_weapon_disallow_rearm;
auto enable = [this](int control_id, bool state) {
if (auto* ctrl = GetDlgItem(control_id)) {
ctrl->EnableWindow(state ? TRUE : FALSE);
}
};
enable(IDC_SUPPORT_REPAIRS_HULL, support_enabled);
enable(IDC_MAX_HULL_REPAIR_VAL, support_enabled);
enable(IDC_MAX_SUBSYS_REPAIR_VAL, support_enabled);
enable(IDC_DISALLOW_SUPPORT_REARM, support_enabled);
const bool limited_pool_enabled = rearm_allowed && (m_limit_rearm_to_pool != FALSE);
enable(IDC_LIMIT_SUPPORT_REARM_TO_POOL, rearm_allowed);
enable(IDC_SUPPORT_REARM_POOL_FROM_LOADOUT, limited_pool_enabled);
enable(IDC_ALLOW_SUPPORT_REARM_PRECEDENCE, limited_pool_enabled);
enable(IDC_SUPPORT_REARM_WEAPON_LIST, pool_controls_enabled);
enable(IDC_SUPPORT_REARM_POOL_TEAM, pool_controls_enabled);
enable(IDC_SUPPORT_REARM_POOL_AMOUNT, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_AMOUNT, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_UNLIMITED, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_ZERO, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_ALL_AMOUNT, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_ALL_UNLIMITED, right_controls_enabled);
enable(IDC_SUPPORT_REARM_SET_ALL_ZERO, right_controls_enabled);
}
void CSupportRearmDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (nIDCtl != IDC_SUPPORT_REARM_WEAPON_LIST || lpDrawItemStruct == nullptr) {
CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
if (lpDrawItemStruct->itemID == static_cast<UINT>(-1)) {
return;
}
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list == nullptr) {
return;
}
CDC* dc = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect(lpDrawItemStruct->rcItem);
const bool selected = (lpDrawItemStruct->itemState & ODS_SELECTED) != 0;
const bool focus = (lpDrawItemStruct->itemState & ODS_FOCUS) != 0;
const int weapon_class = static_cast<int>(weapon_list->GetItemData(lpDrawItemStruct->itemID));
const bool disallow_rearm =
(weapon_class >= 0 && weapon_class < weapon_info_size()) ? Weapon_info[weapon_class].disallow_rearm : false;
COLORREF bk = selected ? GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_WINDOW);
COLORREF text = selected ? GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_WINDOWTEXT);
if (disallow_rearm) {
text = GetSysColor(COLOR_GRAYTEXT);
}
dc->FillSolidRect(&rect, bk);
dc->SetBkMode(TRANSPARENT);
dc->SetTextColor(text);
CString item_text;
weapon_list->GetText(lpDrawItemStruct->itemID, item_text);
CRect text_rect = rect;
text_rect.DeflateRect(2, 0);
dc->DrawText(item_text, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
if (focus) {
dc->DrawFocusRect(&rect);
}
}
void CSupportRearmDlg::OnOptionChanged()
{
if (!UpdateData(TRUE)) {
return;
}
update_control_states();
}
void CSupportRearmDlg::OnSelchangeWeaponList()
{
update_weapon_amount_display();
update_control_states();
}
void CSupportRearmDlg::OnSelchangePoolTeam()
{
if (!UpdateData(TRUE)) {
return;
}
populate_weapon_list();
auto* weapon_list = (CListBox*)GetDlgItem(IDC_SUPPORT_REARM_WEAPON_LIST);
if (weapon_list != nullptr && weapon_list->GetCount() > 0) {
weapon_list->SetCurSel(0);
}
update_weapon_amount_display();
update_control_states();
}
void CSupportRearmDlg::OnSetPoolAmount()
{
if (!UpdateData(TRUE)) {
return;
}
set_selected_weapon_amount(m_weapon_pool_amount);
}
void CSupportRearmDlg::OnSetPoolUnlimited()
{
set_selected_weapon_amount(-1);
}
void CSupportRearmDlg::OnSetPoolZero()
{
set_selected_weapon_amount(0);
}
void CSupportRearmDlg::OnSetAllPoolAmount()
{
if (!UpdateData(TRUE)) {
return;
}
set_all_weapon_amount(m_weapon_pool_amount);
}
void CSupportRearmDlg::OnSetAllPoolUnlimited()
{
set_all_weapon_amount(-1);
}
void CSupportRearmDlg::OnSetAllPoolZero()
{
set_all_weapon_amount(0);
}
void CSupportRearmDlg::OnOK()
{
if (!UpdateData(TRUE)) {
return;
}
The_mission.support_ships.max_support_ships = (m_disallow_support_ships != FALSE) ? 0 : -1;
The_mission.flags.set(Mission::Mission_Flags::Limited_support_rearm_pool, m_limit_rearm_to_pool != FALSE);
The_mission.flags.set(Mission::Mission_Flags::Support_repairs_hull, m_support_repairs_hull != FALSE);
The_mission.support_ships.disallow_rearm = (m_disallow_support_rearm != FALSE);
The_mission.support_ships.allow_rearm_weapon_precedence = (m_allow_weapon_precedence != FALSE);
The_mission.support_ships.rearm_pool_from_loadout = (m_rearm_pool_from_loadout != FALSE);
The_mission.support_ships.max_hull_repair_val = m_max_hull_repair_val;
The_mission.support_ships.max_subsys_repair_val = m_max_subsys_repair_val;
memcpy(The_mission.support_ships.rearm_weapon_pool, m_rearm_weapon_pool, sizeof(m_rearm_weapon_pool));
CDialog::OnOK();
}
+48
View File
@@ -0,0 +1,48 @@
#pragma once
class CSupportRearmDlg : public CDialog {
public:
CSupportRearmDlg(CWnd* pParent = nullptr);
enum {
IDD = IDD_SUPPORT_REARM_OPTIONS
};
BOOL OnInitDialog() override;
void DoDataExchange(CDataExchange* pDX) override;
void OnOK() override;
protected:
afx_msg void OnSelchangeWeaponList();
afx_msg void OnSetPoolAmount();
afx_msg void OnSetPoolUnlimited();
afx_msg void OnSetPoolZero();
afx_msg void OnSetAllPoolAmount();
afx_msg void OnSetAllPoolUnlimited();
afx_msg void OnSetAllPoolZero();
afx_msg void OnSelchangePoolTeam();
afx_msg void OnOptionChanged();
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
DECLARE_MESSAGE_MAP()
private:
void update_control_states();
void populate_team_list();
void populate_weapon_list();
void update_weapon_amount_display();
int get_selected_weapon_class() const;
void set_selected_weapon_amount(int amount);
void set_all_weapon_amount(int amount);
CString format_weapon_pool_entry(int weapon_class) const;
BOOL m_disallow_support_ships;
BOOL m_limit_rearm_to_pool;
BOOL m_support_repairs_hull;
BOOL m_disallow_support_rearm;
BOOL m_allow_weapon_precedence;
BOOL m_rearm_pool_from_loadout;
float m_max_hull_repair_val;
float m_max_subsys_repair_val;
int m_weapon_pool_amount;
int m_rearm_pool_team;
int m_rearm_weapon_pool[MAX_TVT_TEAMS][MAX_WEAPON_TYPES];
};
@@ -71,18 +71,9 @@ to all subsequent missions.</p>
</table>
<h2>Support Ships</h2>
<table>
<tr><th>Control</th><th>Description</th></tr>
<tr><td>Disallow support ships</td><td>Prevents any support ship from appearing
in this mission.</td></tr>
<tr><td>Enable hull repair</td><td>Allows the support ship to repair hull damage
in addition to subsystems. Subsystem repair is always available when a support
ship is present.</td></tr>
<tr><td>Hull repair ceiling</td><td>Maximum percentage of hull the support ship
can restore, when hull repair is enabled.</td></tr>
<tr><td>Subsystem repair ceiling</td><td>Maximum percentage of subsystem
integrity the support ship can restore.</td></tr>
</table>
<p>Opens the <a href="SupportRearmDialog.html">Support Options</a> sub-dialog,
which controls support ship availability, hull and subsystem repair ceilings, rearm
permissions, and the per-weapon rearm pool.</p>
<h2>Ship Trails</h2>
<p>Controls engine contrail visibility. By default, trails are <em>on</em> in
@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Support Options - QtFRED Help</title>
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
</head>
<body>
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Mission &rsaquo;
<a href="MissionSpecsDialog.html">Mission Specs</a> &rsaquo; Support Options</nav>
<h1>Support Options</h1>
<p>Opens via <strong>Editors &rsaquo; Mission Specs &rsaquo; Support Options</strong>.</p>
<p>Controls whether support ships appear in the mission, how much they can repair, whether
they can rearm weapons, and how many of each weapon they carry in their rearm pool.</p>
<h2>Repair settings</h2>
<table>
<tr><th>Control</th><th>Description</th></tr>
<tr><td>Allow Support Ships</td><td>When unchecked, no support ship can appear in
this mission regardless of the loadout.</td></tr>
<tr><td>Support Ships Repair Hull</td><td>Allows support ships to repair hull damage
in addition to subsystems. Subsystem repair is always available when support ships
are allowed.</td></tr>
<tr><td>Hull Repair Ceiling</td><td>Maximum percentage of hull integrity a support
ship can restore. Only meaningful when hull repair is enabled.</td></tr>
<tr><td>Subsystem Repair Ceiling</td><td>Maximum percentage of subsystem integrity a
support ship can restore.</td></tr>
</table>
<h2>Rearm options</h2>
<table>
<tr><th>Control</th><th>Description</th></tr>
<tr><td>Disallow Support Rearm</td><td>Prevents support ships from rearming any
weapons. Repair is still permitted if support ships are allowed.</td></tr>
<tr><td>Limit Rearm to Mission Pool</td><td>Restricts rearming to the quantities
defined in the <strong>Support Rearm Pool</strong> table below. Once a weapon's
pool is exhausted, support ships cannot supply more of it. A pool value of
<strong>-1</strong> means unlimited for that weapon.</td></tr>
<tr><td>Set Rearm Pool from Loadout Pool surplus</td><td>Initialises each weapon's
pool amount from any surplus left over in the player loadout pool at mission
start, in addition to any values set manually.</td></tr>
<tr><td>Use Weapon Precedence when pool is empty</td><td>When a weapon's pool is
exhausted, the support ship substitutes a weapon from the precedence list defined
in the weapon tables rather than simply refusing to rearm.</td></tr>
</table>
<h2>Support Rearm Pool</h2>
<p>Sets how many of each weapon the support ships can supply across the entire mission.
Only active when <strong>Limit Rearm to Mission Pool</strong> is checked. Each team in
a Team vs. Team mission has its own independent pool; use <strong>Pool Team</strong> to
switch between them.</p>
<p>Select a weapon in the list to edit its pool amount, then use the buttons to apply a
value. The amount field accepts any integer; use <strong>-1</strong> for unlimited.</p>
<table>
<tr><th>Control</th><th>Description</th></tr>
<tr><td>Pool Team</td><td>Selects which team's pool is shown. In non-Team vs. Team
missions only one team entry is present.</td></tr>
<tr><td>Weapon list</td><td>Lists all player-allowed weapons. Select a weapon to
target it with the amount buttons.</td></tr>
<tr><td>Pool Amount</td><td>Amount to apply when clicking <strong>Set Amount</strong>
or <strong>Set ALL to Amount</strong>.</td></tr>
<tr><td>Set Amount</td><td>Sets the selected weapon's pool to the value in
<strong>Pool Amount</strong>.</td></tr>
<tr><td>Set Unlimited (-1)</td><td>Sets the selected weapon's pool to -1
(unlimited).</td></tr>
<tr><td>Set Zero</td><td>Sets the selected weapon's pool to 0, preventing support
ships from supplying it entirely.</td></tr>
<tr><td>Set ALL to Amount</td><td>Applies the <strong>Pool Amount</strong> value to
every weapon in the list at once.</td></tr>
<tr><td>Set ALL to Unlimited</td><td>Sets every weapon's pool to -1.</td></tr>
<tr><td>Set ALL to Zero</td><td>Sets every weapon's pool to 0.</td></tr>
</table>
</body>
</html>
+3
View File
@@ -36,6 +36,7 @@
<section title="Custom Strings" ref="dialogs/CustomStringsDialog.html"/>
<section title="Custom Wing Names" ref="dialogs/CustomWingNamesDialog.html"/>
<section title="Sound Environment" ref="dialogs/SoundEnvironmentDialog.html"/>
<section title="Support Options" ref="dialogs/SupportRearmDialog.html"/>
</section>
<section title="Mission Statistics" ref="dialogs/MissionStatsDialog.html"/>
<section title="Reinforcements" ref="dialogs/ReinforcementsEditorDialog.html"/>
@@ -112,6 +113,7 @@
<keyword name="Mission Events" id="MissionEventsDialog" ref="dialogs/MissionEventsDialog.html"/>
<keyword name="Mission Goals" id="MissionGoalsDialog" ref="dialogs/MissionGoalsDialog.html"/>
<keyword name="Mission Specs" id="MissionSpecDialog" ref="dialogs/MissionSpecsDialog.html"/>
<keyword name="Support Options" id="SupportRearmDialog" ref="dialogs/SupportRearmDialog.html"/>
<keyword name="Custom Wing Names" id="CustomWingNamesDialog" ref="dialogs/CustomWingNamesDialog.html"/>
<keyword name="Sound Environment" id="SoundEnvironmentDialog" ref="dialogs/SoundEnvironmentDialog.html"/>
<keyword name="Custom Strings" id="CustomStringsDialog" ref="dialogs/CustomStringsDialog.html"/>
@@ -175,6 +177,7 @@
<file>dialogs/MissionEventsDialog.html</file>
<file>dialogs/MissionGoalsDialog.html</file>
<file>dialogs/MissionSpecsDialog.html</file>
<file>dialogs/SupportRearmDialog.html</file>
<file>dialogs/CustomWingNamesDialog.html</file>
<file>dialogs/CustomStringsDialog.html</file>
<file>dialogs/SoundEnvironmentDialog.html</file>
+5
View File
@@ -120,6 +120,8 @@ add_file_folder("Source/Mission/Dialogs/MissionSpecs"
src/mission/dialogs/MissionSpecs/CustomWingNamesDialogModel.h
src/mission/dialogs/MissionSpecs/SoundEnvironmentDialogModel.cpp
src/mission/dialogs/MissionSpecs/SoundEnvironmentDialogModel.h
src/mission/dialogs/MissionSpecs/SupportRearmDialogModel.cpp
src/mission/dialogs/MissionSpecs/SupportRearmDialogModel.h
)
add_file_folder("Source/Mission/Dialogs/ShipEditor"
src/mission/dialogs/ShipEditor/ShipEditorDialogModel.h
@@ -245,6 +247,8 @@ add_file_folder("Source/UI/Dialogs/MissionSpecs"
src/ui/dialogs/MissionSpecs/CustomWingNamesDialog.h
src/ui/dialogs/MissionSpecs/SoundEnvironmentDialog.cpp
src/ui/dialogs/MissionSpecs/SoundEnvironmentDialog.h
src/ui/dialogs/MissionSpecs/SupportRearmDialog.cpp
src/ui/dialogs/MissionSpecs/SupportRearmDialog.h
)
add_file_folder("Source/UI/Dialogs/ShipEditor"
src/ui/dialogs/ShipEditor/ShipEditorDialog.h
@@ -365,6 +369,7 @@ add_file_folder("UI"
ui/RelativeCoordinatesDialog.ui
ui/ShieldSystemDialog.ui
ui/SoundEnvironmentDialog.ui
ui/SupportRearmDialog.ui
ui/TableViewerDialog.ui
ui/VoiceActingManager.ui
ui/VolumetricNebulaDialog.ui
@@ -68,6 +68,20 @@ void MissionSpecDialogModel::initializeData() {
_m_max_hull_repair_val = The_mission.support_ships.max_hull_repair_val;
_m_max_subsys_repair_val = The_mission.support_ships.max_subsys_repair_val;
_m_support_rearm_settings.disallowSupportShips = (The_mission.support_ships.max_support_ships == 0);
_m_support_rearm_settings.supportRepairsHull = The_mission.flags[Mission::Mission_Flags::Support_repairs_hull];
_m_support_rearm_settings.maxHullRepair = The_mission.support_ships.max_hull_repair_val;
_m_support_rearm_settings.maxSubsysRepair = The_mission.support_ships.max_subsys_repair_val;
_m_support_rearm_settings.disallowSupportRearm = The_mission.support_ships.disallow_rearm;
_m_support_rearm_settings.limitRearmToPool = The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool];
_m_support_rearm_settings.rearmPoolFromLoadout = The_mission.support_ships.rearm_pool_from_loadout;
_m_support_rearm_settings.allowWeaponPrecedence = The_mission.support_ships.allow_rearm_weapon_precedence;
for (int team = 0; team < MAX_TVT_TEAMS; ++team) {
for (int i = 0; i < MAX_WEAPON_TYPES; ++i) {
_m_support_rearm_settings.rearmWeaponPool[team][i] = The_mission.support_ships.rearm_weapon_pool[team][i];
}
}
_m_contrail_threshold = The_mission.contrail_threshold;
_m_contrail_threshold_flag = (_m_contrail_threshold != CONTRAIL_THRESHOLD_DEFAULT);
_m_large_ship_no_collide_collision_group = The_mission.large_ship_no_collide_collision_group;
@@ -123,10 +137,19 @@ bool MissionSpecDialogModel::apply() {
The_mission.num_respawns = _m_num_respawns;
The_mission.max_respawn_delay = _m_max_respawn_delay;
Entry_delay_time = fl2f(_m_player_entry_delay);
The_mission.support_ships.max_support_ships = (_m_disallow_support) ? 0 : -1;
The_mission.support_ships.max_hull_repair_val = _m_max_hull_repair_val;
The_mission.support_ships.max_subsys_repair_val = _m_max_subsys_repair_val;
The_mission.large_ship_no_collide_collision_group = _m_large_ship_no_collide_collision_group;
The_mission.support_ships.max_support_ships = (_m_support_rearm_settings.disallowSupportShips) ? 0 : -1;
The_mission.support_ships.max_hull_repair_val = _m_support_rearm_settings.maxHullRepair;
The_mission.support_ships.max_subsys_repair_val = _m_support_rearm_settings.maxSubsysRepair;
The_mission.support_ships.disallow_rearm = _m_support_rearm_settings.disallowSupportRearm;
The_mission.support_ships.allow_rearm_weapon_precedence = _m_support_rearm_settings.allowWeaponPrecedence;
The_mission.support_ships.rearm_pool_from_loadout = _m_support_rearm_settings.rearmPoolFromLoadout;
for (int team = 0; team < MAX_TVT_TEAMS; ++team) {
for (int i = 0; i < weapon_info_size(); ++i) {
The_mission.support_ships.rearm_weapon_pool[team][i] = _m_support_rearm_settings.rearmWeaponPool[team][i];
}
}
// Copy mission flags
The_mission.flags = _m_flags;
@@ -326,6 +349,7 @@ SCP_string MissionSpecDialogModel::getHighResLoadingScren() {
void MissionSpecDialogModel::setDisallowSupport(bool m_disallow_support) {
modify(_m_disallow_support, m_disallow_support);
_m_support_rearm_settings.disallowSupportShips = m_disallow_support;
}
bool MissionSpecDialogModel::getDisallowSupport() {
@@ -334,6 +358,7 @@ bool MissionSpecDialogModel::getDisallowSupport() {
void MissionSpecDialogModel::setHullRepairMax(float m_max_hull_repair_val) {
modify(_m_max_hull_repair_val, m_max_hull_repair_val);
_m_support_rearm_settings.maxHullRepair = m_max_hull_repair_val;
}
int MissionSpecDialogModel::getHullRepairMax() {
@@ -348,6 +373,21 @@ int MissionSpecDialogModel::getSubsysRepairMax() {
return _m_max_subsys_repair_val;
}
SupportRearmSettings MissionSpecDialogModel::getSupportRearmSettings() const
{
return _m_support_rearm_settings;
}
void MissionSpecDialogModel::setSupportRearmSettings(const SupportRearmSettings& settings)
{
modify(_m_support_rearm_settings, settings);
_m_disallow_support = settings.disallowSupportShips;
_m_max_hull_repair_val = settings.maxHullRepair;
_m_max_subsys_repair_val = settings.maxSubsysRepair;
setMissionFlagDirect(Mission::Mission_Flags::Support_repairs_hull, settings.supportRepairsHull);
setMissionFlagDirect(Mission::Mission_Flags::Limited_support_rearm_pool, settings.limitRearmToPool);
}
void MissionSpecDialogModel::setTrailThresholdFlag(bool m_contrail_threshold_flag) {
modify(_m_contrail_threshold_flag, m_contrail_threshold_flag);
}
@@ -11,6 +11,32 @@
namespace fso::fred::dialogs {
struct SupportRearmSettings {
bool disallowSupportShips = false;
bool supportRepairsHull = true;
float maxHullRepair = 100.0f;
float maxSubsysRepair = 100.0f;
bool disallowSupportRearm = false;
bool limitRearmToPool = false;
bool rearmPoolFromLoadout = false;
bool allowWeaponPrecedence = false;
std::array<std::array<int, MAX_WEAPON_TYPES>, MAX_TVT_TEAMS> rearmWeaponPool{};
bool operator==(const SupportRearmSettings& rhs) const
{
return disallowSupportShips == rhs.disallowSupportShips && supportRepairsHull == rhs.supportRepairsHull &&
maxHullRepair == rhs.maxHullRepair && maxSubsysRepair == rhs.maxSubsysRepair &&
disallowSupportRearm == rhs.disallowSupportRearm && limitRearmToPool == rhs.limitRearmToPool &&
rearmPoolFromLoadout == rhs.rearmPoolFromLoadout && allowWeaponPrecedence == rhs.allowWeaponPrecedence &&
rearmWeaponPool == rhs.rearmWeaponPool;
}
bool operator!=(const SupportRearmSettings& rhs) const
{
return !(*this == rhs);
}
};
class MissionSpecDialogModel : public AbstractDialogModel {
private:
@@ -56,6 +82,7 @@ private:
SCP_vector<SCP_string> _m_squadLogoList;
int _m_type;
SupportRearmSettings _m_support_rearm_settings;
public:
MissionSpecDialogModel(QObject* parent, EditorViewport* viewport);
@@ -103,6 +130,9 @@ public:
void setSubsysRepairMax(float);
int getSubsysRepairMax();
SupportRearmSettings getSupportRearmSettings() const;
void setSupportRearmSettings(const SupportRearmSettings& settings);
void setTrailThresholdFlag(bool);
bool getTrailThresholdFlag();
void setTrailDisplaySpeed(int);
@@ -0,0 +1,108 @@
#include "SupportRearmDialogModel.h"
#include "weapon/weapon.h"
namespace fso::fred::dialogs {
SupportRearmDialogModel::SupportRearmDialogModel(QObject* parent, EditorViewport* viewport)
: AbstractDialogModel(parent, viewport)
{
for (int i = 0; i < weapon_info_size(); ++i) {
if (Weapon_info[i].wi_flags[Weapon::Info_Flags::Player_allowed]) {
_visibleWeaponClasses.push_back(i);
}
}
}
bool SupportRearmDialogModel::apply()
{
// No direct application; the parent MissionSpecDialogModel reads settings() and applies them.
return true;
}
void SupportRearmDialogModel::reject()
{
// No direct rejection; the parent simply discards this model on cancel/close.
}
void SupportRearmDialogModel::setInitial(const SupportRearmSettings& settings)
{
_working = settings;
}
const SupportRearmSettings& SupportRearmDialogModel::settings() const
{
return _working;
}
const SCP_vector<int>& SupportRearmDialogModel::visibleWeaponClasses() const
{
return _visibleWeaponClasses;
}
void SupportRearmDialogModel::setDisallowSupportShips(bool value)
{
modify(_working.disallowSupportShips, value);
}
void SupportRearmDialogModel::setSupportRepairsHull(bool value)
{
modify(_working.supportRepairsHull, value);
}
void SupportRearmDialogModel::setMaxHullRepair(float value)
{
modify(_working.maxHullRepair, value);
}
void SupportRearmDialogModel::setMaxSubsysRepair(float value)
{
modify(_working.maxSubsysRepair, value);
}
void SupportRearmDialogModel::setDisallowSupportRearm(bool value)
{
modify(_working.disallowSupportRearm, value);
}
void SupportRearmDialogModel::setLimitRearmToPool(bool value)
{
modify(_working.limitRearmToPool, value);
}
void SupportRearmDialogModel::setRearmPoolFromLoadout(bool value)
{
modify(_working.rearmPoolFromLoadout, value);
}
void SupportRearmDialogModel::setAllowWeaponPrecedence(bool value)
{
modify(_working.allowWeaponPrecedence, value);
}
void SupportRearmDialogModel::setWeaponPoolEntry(int team, int weaponClass, int amount)
{
if (team < 0 || team >= MAX_TVT_TEAMS) {
return;
}
if (weaponClass < 0 || weaponClass >= weapon_info_size()) {
return;
}
const int normalized = Weapon_info[weaponClass].disallow_rearm ? 0 : ((amount < 0) ? -1 : amount);
modify(_working.rearmWeaponPool[team][weaponClass], normalized);
}
void SupportRearmDialogModel::setAllVisibleWeaponPoolEntries(int team, int amount)
{
if (team < 0 || team >= MAX_TVT_TEAMS) {
return;
}
for (auto cls : _visibleWeaponClasses) {
const int normalized = Weapon_info[cls].disallow_rearm ? 0 : ((amount < 0) ? -1 : amount);
modify(_working.rearmWeaponPool[team][cls], normalized);
}
}
} // namespace fso::fred::dialogs
@@ -0,0 +1,38 @@
#pragma once
#include "mission/dialogs/AbstractDialogModel.h"
#include "mission/dialogs/MissionSpecDialogModel.h"
namespace fso::fred::dialogs {
class SupportRearmDialogModel final : public AbstractDialogModel {
public:
SupportRearmDialogModel(QObject* parent, EditorViewport* viewport);
bool apply() override;
void reject() override;
void setInitial(const SupportRearmSettings& settings);
const SupportRearmSettings& settings() const;
void setDisallowSupportShips(bool value);
void setSupportRepairsHull(bool value);
void setMaxHullRepair(float value);
void setMaxSubsysRepair(float value);
void setDisallowSupportRearm(bool value);
void setLimitRearmToPool(bool value);
void setRearmPoolFromLoadout(bool value);
void setAllowWeaponPrecedence(bool value);
// Pool edits. `amount < 0` becomes -1 (unlimited); disallow_rearm weapons are always pinned to 0.
void setWeaponPoolEntry(int team, int weaponClass, int amount);
void setAllVisibleWeaponPoolEntries(int team, int amount);
const SCP_vector<int>& visibleWeaponClasses() const;
private:
SupportRearmSettings _working;
SCP_vector<int> _visibleWeaponClasses;
};
} // namespace fso::fred::dialogs
+10 -5
View File
@@ -8,6 +8,7 @@
#include <ui/dialogs/MissionSpecs/CustomStringsDialog.h>
#include <ui/dialogs/MissionSpecs/CustomWingNamesDialog.h>
#include <ui/dialogs/MissionSpecs/SoundEnvironmentDialog.h>
#include <ui/dialogs/MissionSpecs/SupportRearmDialog.h>
#include <ui/util/default_dir.h>
#include <ui/util/SignalBlockers.h>
#include "mission/util.h"
@@ -96,11 +97,6 @@ void MissionSpecDialog::updateUi() {
ui->lowResScreen->setText(_model->getLowResLoadingScren().c_str());
ui->highResScreen->setText(_model->getHighResLoadingScren().c_str());
ui->toggleSupportShip->setChecked(_model->getDisallowSupport());
ui->toggleHullRepair->setChecked(_model->getMissionFlag(Mission::Mission_Flags::Support_repairs_hull));
ui->hullRepairMax->setValue(_model->getHullRepairMax());
ui->subsysRepairMax->setValue(_model->getSubsysRepairMax());
ui->toggleTrail->setChecked(_model->getMissionFlag(Mission::Mission_Flags::Toggle_ship_trails));
ui->toggleSpeedDisplay->setChecked(_model->getTrailThresholdFlag());
ui->minDisplaySpeed->setEnabled(_model->getTrailThresholdFlag());
@@ -388,6 +384,15 @@ void MissionSpecDialog::on_highResScreenButton_clicked() {
}
}
void MissionSpecDialog::on_supportRearmOptionsButton_clicked()
{
SupportRearmDialog dlg(this, _viewport);
dlg.setInitial(_model->getSupportRearmSettings());
if (dlg.exec() == QDialog::Accepted) {
_model->setSupportRearmSettings(dlg.settings());
}
}
void MissionSpecDialog::on_toggleSupportShip_toggled(bool enabled) {
_model->setDisallowSupport(enabled);
}
@@ -47,6 +47,7 @@ private slots:
void on_squadronLogoButton_clicked();
void on_lowResScreenButton_clicked();
void on_highResScreenButton_clicked();
void on_supportRearmOptionsButton_clicked();
// Middle column
void on_toggleSupportShip_toggled(bool checked);
@@ -0,0 +1,269 @@
#include "SupportRearmDialog.h"
#include "ui_SupportRearmDialog.h"
#include "ui/util/SignalBlockers.h"
#include "weapon/weapon.h"
#include <QCloseEvent>
namespace fso::fred::dialogs {
SupportRearmDialog::SupportRearmDialog(QWidget* parent, EditorViewport* viewport)
: QDialog(parent), ui(new Ui::SupportRearmDialog()), _model(new SupportRearmDialogModel(this, viewport))
{
ui->setupUi(this);
populateTeamCombo();
}
SupportRearmDialog::~SupportRearmDialog() = default;
void SupportRearmDialog::setInitial(const SupportRearmSettings& settings)
{
_model->setInitial(settings);
_activePoolTeam = 0;
syncUiFromModel();
}
SupportRearmSettings SupportRearmDialog::settings() const
{
return _model->settings();
}
void SupportRearmDialog::closeEvent(QCloseEvent* e)
{
reject();
e->ignore();
}
QString SupportRearmDialog::weaponEntryText(int weaponClass) const
{
const auto& wi = Weapon_info[weaponClass];
if (wi.disallow_rearm) {
return QString::fromStdString(SCP_string(wi.name) + " - 0 (disabled by weapon settings)");
}
const int amount = _model->settings().rearmWeaponPool[_activePoolTeam][weaponClass];
if (amount < 0) {
return QString::fromStdString(SCP_string(wi.name) + " - Unlimited");
}
return QString::fromStdString(SCP_string(wi.name) + " - " + std::to_string(amount));
}
void SupportRearmDialog::populateTeamCombo()
{
util::SignalBlockers blockers(this);
ui->poolTeamCombo->clear();
for (int i = 0; i < Num_teams && i < MAX_TVT_TEAMS; ++i) {
ui->poolTeamCombo->addItem(QString("Team %1").arg(i + 1), i);
}
if (ui->poolTeamCombo->count() > 0) {
ui->poolTeamCombo->setCurrentIndex(_activePoolTeam);
}
}
void SupportRearmDialog::syncUiFromModel()
{
const auto& s = _model->settings();
{
util::SignalBlockers blockers(this);
ui->supportEnabledCheck->setChecked(!s.disallowSupportShips);
ui->repairHullCheck->setChecked(s.supportRepairsHull);
ui->hullRepairSpin->setValue(s.maxHullRepair);
ui->subsysRepairSpin->setValue(s.maxSubsysRepair);
ui->disallowRearmCheck->setChecked(s.disallowSupportRearm);
ui->limitPoolCheck->setChecked(s.limitRearmToPool);
ui->fromLoadoutCheck->setChecked(s.rearmPoolFromLoadout);
ui->precedenceCheck->setChecked(s.allowWeaponPrecedence);
if (ui->poolTeamCombo->count() > 0) {
ui->poolTeamCombo->setCurrentIndex(_activePoolTeam);
}
}
populateWeaponList();
if (ui->weaponList->count() > 0) {
ui->weaponList->setCurrentRow(0);
}
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::populateWeaponList()
{
auto prev = selectedWeaponClass();
ui->weaponList->clear();
for (auto cls : _model->visibleWeaponClasses()) {
auto* item = new QListWidgetItem(weaponEntryText(cls));
item->setData(Qt::UserRole, cls);
if (Weapon_info[cls].disallow_rearm) {
item->setForeground(palette().color(QPalette::Disabled, QPalette::Text));
}
ui->weaponList->addItem(item);
}
for (int i = 0; i < ui->weaponList->count(); ++i) {
if (ui->weaponList->item(i)->data(Qt::UserRole).toInt() == prev) {
ui->weaponList->setCurrentRow(i);
break;
}
}
}
int SupportRearmDialog::selectedWeaponClass() const
{
auto* item = ui->weaponList->currentItem();
if (!item)
return -1;
return item->data(Qt::UserRole).toInt();
}
void SupportRearmDialog::updateFromSelection()
{
const int cls = selectedWeaponClass();
if (cls < 0 || cls >= weapon_info_size()) {
ui->poolAmountSpin->setValue(0);
} else if (Weapon_info[cls].disallow_rearm) {
ui->poolAmountSpin->setValue(0);
} else {
ui->poolAmountSpin->setValue(_model->settings().rearmWeaponPool[_activePoolTeam][cls]);
}
}
void SupportRearmDialog::updateControlStates()
{
const auto& s = _model->settings();
const bool supportEnabled = !s.disallowSupportShips;
const bool rearmAllowed = supportEnabled && !s.disallowSupportRearm;
const bool poolEnabled = rearmAllowed && s.limitRearmToPool && !s.rearmPoolFromLoadout;
const int cls = selectedWeaponClass();
const bool selectedDisallowed = (cls >= 0 && cls < weapon_info_size() && Weapon_info[cls].disallow_rearm);
const bool rightEnabled = poolEnabled && !selectedDisallowed;
ui->repairHullCheck->setEnabled(supportEnabled);
ui->hullRepairSpin->setEnabled(supportEnabled);
ui->subsysRepairSpin->setEnabled(supportEnabled);
ui->disallowRearmCheck->setEnabled(supportEnabled);
const bool limitedPoolEnabled = rearmAllowed && s.limitRearmToPool;
ui->limitPoolCheck->setEnabled(rearmAllowed);
ui->fromLoadoutCheck->setEnabled(limitedPoolEnabled);
ui->precedenceCheck->setEnabled(limitedPoolEnabled);
ui->weaponList->setEnabled(poolEnabled);
ui->poolTeamCombo->setEnabled(poolEnabled);
ui->poolAmountSpin->setEnabled(rightEnabled);
ui->setAmountButton->setEnabled(rightEnabled);
ui->setUnlimitedButton->setEnabled(rightEnabled);
ui->setZeroButton->setEnabled(rightEnabled);
ui->setAllAmountButton->setEnabled(rightEnabled);
ui->setAllUnlimitedButton->setEnabled(rightEnabled);
ui->setAllZeroButton->setEnabled(rightEnabled);
}
void SupportRearmDialog::on_okAndCancelButtons_accepted()
{
accept();
}
void SupportRearmDialog::on_okAndCancelButtons_rejected()
{
reject();
}
void SupportRearmDialog::on_weaponList_currentRowChanged(int)
{
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setAmountButton_clicked()
{
_model->setWeaponPoolEntry(_activePoolTeam, selectedWeaponClass(), ui->poolAmountSpin->value());
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setUnlimitedButton_clicked()
{
_model->setWeaponPoolEntry(_activePoolTeam, selectedWeaponClass(), -1);
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setZeroButton_clicked()
{
_model->setWeaponPoolEntry(_activePoolTeam, selectedWeaponClass(), 0);
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setAllAmountButton_clicked()
{
_model->setAllVisibleWeaponPoolEntries(_activePoolTeam, ui->poolAmountSpin->value());
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setAllUnlimitedButton_clicked()
{
_model->setAllVisibleWeaponPoolEntries(_activePoolTeam, -1);
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_setAllZeroButton_clicked()
{
_model->setAllVisibleWeaponPoolEntries(_activePoolTeam, 0);
populateWeaponList();
updateFromSelection();
updateControlStates();
}
void SupportRearmDialog::on_supportEnabledCheck_toggled(bool checked)
{
_model->setDisallowSupportShips(!checked);
updateControlStates();
}
void SupportRearmDialog::on_repairHullCheck_toggled(bool checked)
{
_model->setSupportRepairsHull(checked);
}
void SupportRearmDialog::on_disallowRearmCheck_toggled(bool checked)
{
_model->setDisallowSupportRearm(checked);
updateControlStates();
}
void SupportRearmDialog::on_limitPoolCheck_toggled(bool checked)
{
_model->setLimitRearmToPool(checked);
updateControlStates();
}
void SupportRearmDialog::on_fromLoadoutCheck_toggled(bool checked)
{
_model->setRearmPoolFromLoadout(checked);
updateControlStates();
}
void SupportRearmDialog::on_precedenceCheck_toggled(bool checked)
{
_model->setAllowWeaponPrecedence(checked);
updateControlStates();
}
void SupportRearmDialog::on_hullRepairSpin_valueChanged(double value)
{
_model->setMaxHullRepair(static_cast<float>(value));
}
void SupportRearmDialog::on_subsysRepairSpin_valueChanged(double value)
{
_model->setMaxSubsysRepair(static_cast<float>(value));
}
void SupportRearmDialog::on_poolTeamCombo_currentIndexChanged(int index)
{
if (index < 0 || index >= ui->poolTeamCombo->count()) {
return;
}
_activePoolTeam = ui->poolTeamCombo->itemData(index).toInt();
populateWeaponList();
if (ui->weaponList->count() > 0) {
ui->weaponList->setCurrentRow(0);
}
updateFromSelection();
updateControlStates();
}
} // namespace fso::fred::dialogs
@@ -0,0 +1,60 @@
#pragma once
#include "mission/dialogs/MissionSpecs/SupportRearmDialogModel.h"
#include <QDialog>
namespace fso::fred::dialogs {
namespace Ui {
class SupportRearmDialog;
}
class SupportRearmDialog : public QDialog {
Q_OBJECT
public:
explicit SupportRearmDialog(QWidget* parent, EditorViewport* viewport);
~SupportRearmDialog() override;
void setInitial(const SupportRearmSettings& settings);
SupportRearmSettings settings() const;
protected:
void closeEvent(QCloseEvent* e) override;
private slots:
void on_okAndCancelButtons_accepted();
void on_okAndCancelButtons_rejected();
void on_weaponList_currentRowChanged(int currentRow);
void on_setAmountButton_clicked();
void on_setUnlimitedButton_clicked();
void on_setZeroButton_clicked();
void on_setAllAmountButton_clicked();
void on_setAllUnlimitedButton_clicked();
void on_setAllZeroButton_clicked();
void on_supportEnabledCheck_toggled(bool);
void on_repairHullCheck_toggled(bool);
void on_disallowRearmCheck_toggled(bool);
void on_limitPoolCheck_toggled(bool);
void on_fromLoadoutCheck_toggled(bool);
void on_precedenceCheck_toggled(bool);
void on_hullRepairSpin_valueChanged(double);
void on_subsysRepairSpin_valueChanged(double);
void on_poolTeamCombo_currentIndexChanged(int);
private: // NOLINT(readability-redundant-access-specifiers)
void populateTeamCombo();
void populateWeaponList();
void syncUiFromModel();
void updateFromSelection();
void updateControlStates();
int selectedWeaponClass() const;
QString weaponEntryText(int weaponClass) const;
std::unique_ptr<Ui::SupportRearmDialog> ui;
std::unique_ptr<SupportRearmDialogModel> _model;
int _activePoolTeam = 0;
};
} // namespace fso::fred::dialogs
+2 -73
View File
@@ -501,83 +501,12 @@
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="toggleSupportShip">
<widget class="QPushButton" name="supportRearmOptionsButton">
<property name="text">
<string>Disallow Support Ships</string>
<string>Support Options</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggleHullRepair">
<property name="text">
<string>Support Ships Repair Hull</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="hullRepairLabel">
<property name="text">
<string>Hull Repair Ceiling</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="subsysRepairPercentLabel">
<property name="text">
<string>%</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="subsysRepairLabel">
<property name="text">
<string>Subsystem Repair</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="hullRepairPercentLabel">
<property name="text">
<string>%</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="hullRepairMax">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="subsysRepairMax">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
+70
View File
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<ui version="4.0">
<class>fso::fred::dialogs::SupportRearmDialog</class>
<widget class="QDialog" name="fso::fred::dialogs::SupportRearmDialog">
<property name="geometry"><rect><x>0</x><y>0</y><width>650</width><height>420</height></rect></property>
<property name="windowTitle"><string>Support Options</string></property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="topLayout">
<item>
<layout class="QVBoxLayout" name="leftOpts">
<item><widget class="QCheckBox" name="supportEnabledCheck"><property name="text"><string>Allow Support Ships</string></property></widget></item>
<item><widget class="QCheckBox" name="repairHullCheck"><property name="text"><string>Support Ships Repair Hull</string></property></widget></item>
<item><layout class="QFormLayout" name="repairForm">
<item row="0" column="0"><widget class="QLabel" name="hullLabel"><property name="text"><string>Hull Repair Ceiling</string></property></widget></item>
<item row="0" column="1"><widget class="QDoubleSpinBox" name="hullRepairSpin"><property name="minimum"><double>0.0</double></property><property name="maximum"><double>100.0</double></property><property name="decimals"><number>0</number></property></widget></item>
<item row="1" column="0"><widget class="QLabel" name="subsysLabel"><property name="text"><string>Subsystem Repair Ceiling</string></property></widget></item>
<item row="1" column="1"><widget class="QDoubleSpinBox" name="subsysRepairSpin"><property name="minimum"><double>0.0</double></property><property name="maximum"><double>100.0</double></property><property name="decimals"><number>0</number></property></widget></item>
</layout></item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="rightOpts">
<item><widget class="QCheckBox" name="disallowRearmCheck"><property name="text"><string>Disallow Support Rearm</string></property></widget></item>
<item><widget class="QCheckBox" name="limitPoolCheck"><property name="text"><string>Limit Rearm to Mission Pool</string></property></widget></item>
<item><widget class="QCheckBox" name="fromLoadoutCheck"><property name="text"><string>Set Rearm Pool from Loadout Pool surplus</string></property></widget></item>
<item><widget class="QCheckBox" name="precedenceCheck"><property name="text"><string>Use Weapon Precedence when pool is empty</string></property></widget></item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="poolGroup"><property name="title"><string>Support Rearm Pool</string></property>
<layout class="QHBoxLayout" name="poolLayout">
<item>
<layout class="QVBoxLayout" name="poolEditorLeftLayout">
<item>
<widget class="QLabel" name="poolTeamLabel">
<property name="text">
<string>Pool Team</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="poolTeamCombo"/>
</item>
<item>
<widget class="QListWidget" name="weaponList"/>
</item>
</layout>
</item>
<item><layout class="QVBoxLayout" name="rightButtons">
<item><widget class="QLabel" name="poolAmountLabel"><property name="text"><string>Pool Amount</string></property></widget></item>
<item><widget class="QSpinBox" name="poolAmountSpin"><property name="minimum"><number>-1</number></property><property name="maximum"><number>100000</number></property></widget></item>
<item><widget class="QPushButton" name="setAmountButton"><property name="text"><string>Set Amount</string></property></widget></item>
<item><widget class="QPushButton" name="setUnlimitedButton"><property name="text"><string>Set Unlimited (-1)</string></property></widget></item>
<item><widget class="QPushButton" name="setZeroButton"><property name="text"><string>Set Zero</string></property></widget></item>
<item><widget class="QPushButton" name="setAllAmountButton"><property name="text"><string>Set ALL to Amount</string></property></widget></item>
<item><widget class="QPushButton" name="setAllUnlimitedButton"><property name="text"><string>Set ALL to Unlimited</string></property></widget></item>
<item><widget class="QPushButton" name="setAllZeroButton"><property name="text"><string>Set ALL to Zero</string></property></widget></item>
</layout></item>
</layout>
</widget>
</item>
<item><widget class="QDialogButtonBox" name="okAndCancelButtons"><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item>
</layout>
</widget>
<resources/>
<connections/>
</ui>