Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions code/ai/aicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11138,6 +11138,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) ) {
Expand Down Expand Up @@ -11210,6 +11216,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;

Expand Down
1 change: 1 addition & 0 deletions code/mission/mission_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
100 changes: 98 additions & 2 deletions code/mission/missionparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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>);
Expand Down Expand Up @@ -936,6 +938,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;
Expand All @@ -958,6 +972,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;
}
Expand Down Expand Up @@ -1162,13 +1182,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;
Expand Down Expand Up @@ -1258,6 +1282,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
Expand All @@ -1279,6 +1311,13 @@ void parse_player_info2(mission *pm)

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) {
Expand All @@ -1300,6 +1339,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) {
WarningEx(LOCATION, "+Support Rearm Pool is set but +Support Rearm Pool From Loadout is also enabled! The explicit pool will be ignored.\n");
} else {
for (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) {
WarningEx(LOCATION,
"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:"))
{
Expand Down Expand Up @@ -7273,6 +7346,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++) {
Expand Down Expand Up @@ -9619,6 +9698,23 @@ bool check_for_25_1_data()
if (count_items_with_value(Props) > 0)
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))
Expand Down
4 changes: 4 additions & 0 deletions code/mission/missionparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
Expand Down
48 changes: 48 additions & 0 deletions code/missioneditor/missionsave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,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:")) {
Expand All @@ -2809,6 +2827,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) {
Expand Down Expand Up @@ -4415,6 +4440,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
Expand Down
37 changes: 37 additions & 0 deletions code/scripting/api/libs/mission.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);

Expand Down
Loading
Loading