Skip to content

Commit f4d84ec

Browse files
authored
Support Rearm Pool, Limits, and Other Features (scp-fs2open#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
1 parent 31f77e5 commit f4d84ec

35 files changed

Lines changed: 1843 additions & 253 deletions

code/ai/aicode.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11249,6 +11249,12 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
1124911249
aip->ai_flags.remove(AI::AI_Flags::Awaiting_repair);
1125011250
stamp = timestamp(-1);
1125111251

11252+
if (repair_objp != nullptr && scripting::hooks::OnSupportRearmStarted->isActive()) {
11253+
scripting::hooks::OnSupportRearmStarted->run(
11254+
scripting::hook_param_list(scripting::hook_param("Support Ship", 'o', repair_objp),
11255+
scripting::hook_param("Target Ship", 'o', repaired_objp)));
11256+
}
11257+
1125211258
// if this is a player ship, then subtract the repair penalty from this player's score
1125311259
if ( repaired_objp->flags[Object::Object_Flags::Player_ship] ) {
1125411260
if ( !(Game_mode & GM_MULTIPLAYER) ) {
@@ -11321,6 +11327,12 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
1132111327
mission_log_add_entry(LOG_PLAYER_ABORTED_REARM, Ships[repaired_objp->instance].ship_name, NULL);
1132211328
}
1132311329

11330+
if (repair_objp != nullptr && scripting::hooks::OnSupportRearmFinished->isActive()) {
11331+
scripting::hooks::OnSupportRearmFinished->run(
11332+
scripting::hook_param_list(scripting::hook_param("Support Ship", 'o', repair_objp),
11333+
scripting::hook_param("Target Ship", 'o', repaired_objp)));
11334+
}
11335+
1132411336
stamp = timestamp((int) ((30 + 10*frand()) * 1000));
1132511337
break;
1132611338

code/mission/mission_flags.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace Mission {
3737
Fullneb_background_bitmaps, // Show background bitmaps despite fullneb
3838
Preload_subspace, // Preload the subspace tunnel for both the sexp and specs checkbox (for scripts) - MjnMixael
3939
Large_ships_no_collide_by_default, // Automatically puts all large ships in a shared collision group
40+
Limited_support_rearm_pool, // Support ships can only rearm weapons while mission-level pool is available - MjnMixael
4041

4142
NUM_VALUES
4243
};

code/mission/missionparse.cpp

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@ flag_def_list_new<Mission::Mission_Flags> Parse_mission_flags[] = {
421421
{"Nebula Fog Color Override", Mission::Mission_Flags::Neb2_fog_color_override, true, true},
422422
{"Full Nebula Background Bitmaps", Mission::Mission_Flags::Fullneb_background_bitmaps, true, true},
423423
{"Preload Subspace Tunnel", Mission::Mission_Flags::Preload_subspace, true, false},
424-
{"Large Ships Do Not Collide By Default", Mission::Mission_Flags::Large_ships_no_collide_by_default, true, false}
424+
{"Large Ships Do Not Collide By Default", Mission::Mission_Flags::Large_ships_no_collide_by_default, true, false},
425+
{"Limit Support Rearm to Mission Pool", Mission::Mission_Flags::Limited_support_rearm_pool, true, true}
425426
};
426427

427428
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
456457
{Mission::Mission_Flags::Fullneb_background_bitmaps, "Show background bitmaps despite full nebula"},
457458
{Mission::Mission_Flags::Preload_subspace, "Preload the subspace tunnel for both the sexp and specs checkbox"},
458459
{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"},
460+
{Mission::Mission_Flags::Limited_support_rearm_pool, "Support ships can only rearm from the mission weapon pool"},
459461
};
460462

461463
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)
970972
pm->support_ships.max_support_ships = (temp > 0) ? 0 : -1;
971973
}
972974

975+
if (optional_string("+Disallow Support Rearm:")) {
976+
int temp;
977+
stuff_int(&temp);
978+
pm->support_ships.disallow_rearm = (temp != 0);
979+
}
980+
981+
if (optional_string("+Allow Support Rearm Weapon Precedence:")) {
982+
int temp;
983+
stuff_int(&temp);
984+
pm->support_ships.allow_rearm_weapon_precedence = (temp != 0);
985+
}
986+
973987
if ( optional_string("+Hull Repair Ceiling:"))
974988
{
975989
float temp;
@@ -992,6 +1006,12 @@ void parse_mission_info(mission *pm, bool basic = false)
9921006
}
9931007
}
9941008

1009+
if (optional_string("+Support Rearm Pool From Loadout:")) {
1010+
int temp;
1011+
stuff_int(&temp);
1012+
pm->support_ships.rearm_pool_from_loadout = (temp != 0);
1013+
}
1014+
9951015
if (optional_string("+All Teams Attack")){
9961016
Mission_all_attack = 1;
9971017
}
@@ -1196,13 +1216,17 @@ void parse_player_info(mission *pm)
11961216
void parse_player_info2(mission *pm)
11971217
{
11981218
int nt, i;
1199-
SCP_vector<loadout_row> list, list2;
1219+
SCP_vector<loadout_row> list, list2, support_rearm_list;
12001220
team_data *ptr;
12011221

12021222
if (OnLoadoutAboutToParseHook->isActive()) {
12031223
OnLoadoutAboutToParseHook->run();
12041224
}
12051225

1226+
// The support rearm pool starts at -1 (unlimited) per-weapon from support_ship_info::reset().
1227+
// Entries are overridden below for explicit "+Support Rearm Pool:" data, or seeded from the
1228+
// loadout when "+Support Rearm Pool From Loadout:" is set.
1229+
12061230
// read in a ship/weapon pool for each team.
12071231
for ( nt = 0; nt < Num_teams; nt++ ) {
12081232
int num_choices;
@@ -1292,6 +1316,14 @@ void parse_player_info2(mission *pm)
12921316

12931317
num_choices = 0;
12941318

1319+
// When seeding the rearm pool from the loadout, reset this team's row to 0 so the per-weapon
1320+
// loadout counts below accumulate from a clean baseline (rather than the -1 "unlimited" default).
1321+
if (pm->support_ships.rearm_pool_from_loadout) {
1322+
for (int wep = 0; wep < MAX_WEAPON_TYPES; ++wep) {
1323+
pm->support_ships.rearm_weapon_pool[nt][wep] = 0;
1324+
}
1325+
}
1326+
12951327
// check weapon class loadout entries
12961328
for (auto &wc : list2) {
12971329
// 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)
13071339
// always allow the pool to be added in FRED, it is a verbal warning
13081340
// to let the mission dev know about the problem
13091341
if ( !(Weapon_info[wc.index].wi_flags[Weapon::Info_Flags::Player_allowed]) && !Fred_running ) {
1310-
WarningEx(LOCATION, "Weapon '%s' in weapon pool isn't allowed on player loadout! Ignoring it ...\n", Weapon_info[wc.index].name);
1342+
error_display(0, "Weapon '%s' in weapon pool isn't allowed on player loadout! Ignoring it ...\n", Weapon_info[wc.index].name);
13111343
continue;
13121344
}
13131345

13141346
ptr->weaponry_pool[num_choices] = wc.index;
13151347
ptr->weaponry_count[num_choices] = wc.count;
1348+
if (pm->support_ships.rearm_pool_from_loadout) {
1349+
if (Weapon_info[wc.index].disallow_rearm) {
1350+
pm->support_ships.rearm_weapon_pool[nt][wc.index] = 0;
1351+
} else if (wc.count > 0 && pm->support_ships.rearm_weapon_pool[nt][wc.index] >= 0) {
1352+
pm->support_ships.rearm_weapon_pool[nt][wc.index] += wc.count;
1353+
}
1354+
}
13161355

13171356
// if the list isn't set by a variable leave the variable name empty
13181357
if (wc.index_sexp_var == NOT_SET_BY_SEXP_VARIABLE) {
@@ -1334,6 +1373,40 @@ void parse_player_info2(mission *pm)
13341373
}
13351374
ptr->num_weapon_choices = num_choices;
13361375

1376+
if (optional_string("+Support Rearm Pool:")) {
1377+
support_rearm_list.clear();
1378+
stuff_loadout_list(support_rearm_list, ParseLookupType::MISSION_LOADOUT_WEAPON_LIST);
1379+
1380+
if (pm->support_ships.rearm_pool_from_loadout) {
1381+
error_display(0, "+Support Rearm Pool is set but +Support Rearm Pool From Loadout is also enabled! The explicit pool will be ignored.\n");
1382+
} else {
1383+
for (const auto& wc : support_rearm_list) {
1384+
if (wc.index < 0 || wc.index >= weapon_info_size()) {
1385+
continue;
1386+
}
1387+
1388+
if (!(Weapon_info[wc.index].wi_flags[Weapon::Info_Flags::Player_allowed]) && !Fred_running) {
1389+
error_display(0,
1390+
"Weapon '%s' in support rearm pool isn't allowed on player loadout! Ignoring it ...\n",
1391+
Weapon_info[wc.index].name);
1392+
continue;
1393+
}
1394+
1395+
auto& slot = pm->support_ships.rearm_weapon_pool[nt][wc.index];
1396+
if (Weapon_info[wc.index].disallow_rearm) {
1397+
slot = 0;
1398+
} else if (wc.count < 0) {
1399+
slot = -1;
1400+
} else if (wc.count == 0) {
1401+
slot = 0;
1402+
} else if (wc.count > 0) {
1403+
// First explicit entry replaces the -1 (unlimited) default; later duplicate entries accumulate.
1404+
slot = (slot < 0) ? wc.count : slot + wc.count;
1405+
}
1406+
}
1407+
}
1408+
}
1409+
13371410
memset(ptr->weapon_required, 0, MAX_WEAPON_TYPES * sizeof(bool));
13381411
if (optional_string("+Required for mission:"))
13391412
{
@@ -7328,6 +7401,12 @@ void support_ship_info::reset()
73287401
ship_class = -1; // ship class will be determined by the summoning ship's species
73297402
tally = 0;
73307403
support_available_for_species = 0; // will be filled in by the next loop
7404+
for (auto& team_pool : rearm_weapon_pool) {
7405+
std::fill(std::begin(team_pool), std::end(team_pool), -1); // -1 == unlimited per-weapon
7406+
}
7407+
disallow_rearm = false;
7408+
allow_rearm_weapon_precedence = false;
7409+
rearm_pool_from_loadout = false;
73317410

73327411
// for each species, store whether support is available
73337412
for (int species = 0; species < sz2i(Species_info.size()); species++) {
@@ -9668,6 +9747,23 @@ bool check_for_25_1_data()
96689747
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && !Neb2_fog_save_legacy_values)
96699748
return true;
96709749

9750+
if (The_mission.flags[Mission::Mission_Flags::Limited_support_rearm_pool]) {
9751+
return true;
9752+
}
9753+
9754+
if (The_mission.support_ships.disallow_rearm || The_mission.support_ships.allow_rearm_weapon_precedence ||
9755+
The_mission.support_ships.rearm_pool_from_loadout) {
9756+
return true;
9757+
}
9758+
9759+
for (int team = 0; team < Num_teams; ++team) {
9760+
for (int pool_wep = 0; pool_wep < MAX_WEAPON_TYPES; ++pool_wep) {
9761+
if (The_mission.support_ships.rearm_weapon_pool[team][pool_wep] != -1) {
9762+
return true;
9763+
}
9764+
}
9765+
}
9766+
96719767
constexpr auto defaultLayer = "Default";
96729768

96739769
for (const auto& so : list_range(&Ship_obj_list))

code/mission/missionparse.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ struct support_ship_info
112112
int ship_class; // ship class of support ship
113113
int tally; // number of support ships so far
114114
int support_available_for_species; // whether support is available for a given species (this is a bitfield)
115+
bool disallow_rearm; // if true, support ships can only repair and will not rearm weapons
116+
bool allow_rearm_weapon_precedence; // if true, support ships may swap to precedence weapons when rearm pool is empty
117+
bool rearm_pool_from_loadout; // initialize rearm pool from mission loadout after filling starting loadout ships
118+
int rearm_weapon_pool[MAX_TVT_TEAMS][MAX_WEAPON_TYPES]; // mission stockpile used to limit support ship rearming
115119

116120
void reset();
117121
};

code/missioneditor/missionsave.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2858,6 +2858,24 @@ int Fred_mission_save::save_mission_info()
28582858
// this is compatible with non-SCP variants - Goober5000
28592859
fout(" %d", (The_mission.support_ships.max_support_ships == 0) ? 1 : 0);
28602860

2861+
if (save_config.save_format != MissionFormat::RETAIL) {
2862+
if (optional_string_fred("+Disallow Support Rearm:")) {
2863+
parse_comments(2);
2864+
} else {
2865+
fout("\n+Disallow Support Rearm:");
2866+
}
2867+
2868+
fout(" %d", The_mission.support_ships.disallow_rearm ? 1 : 0);
2869+
2870+
if (optional_string_fred("+Allow Support Rearm Weapon Precedence:")) {
2871+
parse_comments(2);
2872+
} else {
2873+
fout("\n+Allow Support Rearm Weapon Precedence:");
2874+
}
2875+
2876+
fout(" %d", The_mission.support_ships.allow_rearm_weapon_precedence ? 1 : 0);
2877+
}
2878+
28612879
// here be WMCoolmon's hull and subsys repair stuff
28622880
if (save_config.save_format != MissionFormat::RETAIL) {
28632881
if (optional_string_fred("+Hull Repair Ceiling:")) {
@@ -2873,6 +2891,13 @@ int Fred_mission_save::save_mission_info()
28732891
fout("\n+Subsystem Repair Ceiling:");
28742892
}
28752893
fout(" %f", The_mission.support_ships.max_subsys_repair_val);
2894+
2895+
if (optional_string_fred("+Support Rearm Pool From Loadout:")) {
2896+
parse_comments(1);
2897+
} else {
2898+
fout("\n+Support Rearm Pool From Loadout:");
2899+
}
2900+
fout(" %d", The_mission.support_ships.rearm_pool_from_loadout ? 1 : 0);
28762901
}
28772902

28782903
if (Mission_all_attack) {
@@ -4484,6 +4509,29 @@ int Fred_mission_save::save_players()
44844509

44854510
fout(")");
44864511

4512+
if (save_config.save_format != MissionFormat::RETAIL && !The_mission.support_ships.rearm_pool_from_loadout) {
4513+
if (optional_string_fred("+Support Rearm Pool:", "$Starting Shipname:")) {
4514+
parse_comments(2);
4515+
} else {
4516+
fout("\n\n+Support Rearm Pool:");
4517+
}
4518+
4519+
fout(" (\n");
4520+
for (j = 0; j < weapon_info_size(); j++) {
4521+
if (!Weapon_info[j].wi_flags[Weapon::Info_Flags::Player_allowed]) {
4522+
continue;
4523+
}
4524+
// Default is -1 (unlimited). Skip disallow_rearm weapons too, parse normalizes them to 0 anyway.
4525+
if (Weapon_info[j].disallow_rearm) {
4526+
continue;
4527+
}
4528+
if (The_mission.support_ships.rearm_weapon_pool[i][j] != -1) {
4529+
fout("\t\"%s\"\t%d\n", Weapon_info[j].name, The_mission.support_ships.rearm_weapon_pool[i][j]);
4530+
}
4531+
}
4532+
fout(")");
4533+
}
4534+
44874535
// sanity check
44884536
if (save_config.save_format == MissionFormat::RETAIL && wrote_fso_data) {
44894537
// this is such an unlikely (and hard-to-fix) case that a warning should be sufficient

code/scripting/api/libs/mission.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include "scripting/api/objs/ship.h"
6666
#include "scripting/api/objs/shipclass.h"
6767
#include "scripting/api/objs/sound.h"
68+
#include "scripting/api/objs/support_rearm_pool.h"
6869
#include "scripting/api/objs/team.h"
6970
#include "scripting/api/objs/vecmath.h"
7071
#include "scripting/api/objs/volumetric.h"
@@ -262,6 +263,42 @@ ADE_FUNC(runSEXP, l_Mission, "string", "Runs the defined SEXP script within a `w
262263
return ADE_RETURN_FALSE;
263264
}
264265

266+
//****SUBLIBRARY: Mission/SupportRearmPools
267+
ADE_LIB_DERIV(l_Mission_SupportRearmPools,
268+
"SupportRearmPools",
269+
nullptr,
270+
"Per-team mission support rearm pools (team indexed).",
271+
l_Mission);
272+
273+
ADE_INDEXER(l_Mission_SupportRearmPools,
274+
"number TeamIndex",
275+
"Gets support rearm pool handle for a specific team.",
276+
"support_rearm_pool_team",
277+
"Support rearm pool team handle, or invalid handle if index is out of range.")
278+
{
279+
int idx = -1;
280+
if (!ade_get_args(L, "*i", &idx)) {
281+
return ade_set_error(L, "o", l_SupportRearmPoolTeam.Set(-1));
282+
}
283+
284+
idx--; // Lua to C++ index
285+
if (idx < 0 || idx >= Num_teams || idx >= MAX_TVT_TEAMS) {
286+
return ade_set_error(L, "o", l_SupportRearmPoolTeam.Set(-1));
287+
}
288+
289+
return ade_set_args(L, "o", l_SupportRearmPoolTeam.Set(idx));
290+
}
291+
292+
ADE_FUNC(__len,
293+
l_Mission_SupportRearmPools,
294+
nullptr,
295+
"The number of support rearm pool teams.",
296+
"number",
297+
"The number of TVT/loadout teams with support rearm pools.")
298+
{
299+
return ade_set_args(L, "i", MIN(Num_teams, MAX_TVT_TEAMS));
300+
}
301+
265302
//****SUBLIBRARY: Mission/Asteroids
266303
ADE_LIB_DERIV(l_Mission_Asteroids, "Asteroids", NULL, "Asteroids in the mission", l_Mission);
267304

0 commit comments

Comments
 (0)