diff --git a/code/mission/missioncampaign.cpp b/code/mission/missioncampaign.cpp index f4b853d5b09..a271bca3e46 100644 --- a/code/mission/missioncampaign.cpp +++ b/code/mission/missioncampaign.cpp @@ -82,10 +82,9 @@ const char *campaign_types[MAX_CAMPAIGN_TYPES] = //XSTR:ON }; -// modules local variables to deal with getting new ships/weapons available to the player -int Num_granted_ships, Num_granted_weapons; // per mission counts of new ships and weapons -int Granted_ships[MAX_SHIP_CLASSES]; -int Granted_weapons[MAX_WEAPON_TYPES]; +// module-local sets of new ships/weapons granted to the player during the current mission +static SCP_set Granted_ships; +static SCP_set Granted_weapons; // variables to control the UI stuff for loading campaigns LOCAL UI_WINDOW Campaign_window; @@ -397,16 +396,16 @@ void mission_campaign_get_sw_info() SCP_vector ship_list; stuff_int_list(ship_list, ParseLookupType::SHIP_INFO_TYPE); - // now set the array elements stating which ships we are allowed + // now note which ships we are allowed for (int idx : ship_list) { if (Ship_info[idx].flags[Ship::Info_Flags::Player_ship]) - Campaign.ships_allowed[idx] = 1; + Campaign.ships_allowed.insert(idx); } } else { // set allowable ships to the SIF_PLAYER_SHIPs for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) { if (it->flags[Ship::Info_Flags::Player_ship]) - Campaign.ships_allowed[std::distance(Ship_info.cbegin(), it)] = 1; + Campaign.ships_allowed.insert(static_cast(std::distance(Ship_info.cbegin(), it))); } } @@ -414,16 +413,16 @@ void mission_campaign_get_sw_info() SCP_vector weapon_list; stuff_int_list(weapon_list, ParseLookupType::WEAPON_POOL_TYPE); - // now set the array elements stating which weapons we are allowed + // now note which weapons we are allowed for (int idx : weapon_list) { if (Weapon_info[idx].wi_flags[Weapon::Info_Flags::Player_allowed]) - Campaign.weapons_allowed[idx] = 1; + Campaign.weapons_allowed.insert(idx); } } else { // set allowable weapons to the player-allowed ones for (auto it = Weapon_info.cbegin(); it != Weapon_info.cend(); ++it) { if (it->wi_flags[Weapon::Info_Flags::Player_allowed]) - Campaign.weapons_allowed[std::distance(Weapon_info.cbegin(), it)] = 1; + Campaign.weapons_allowed.insert(static_cast(std::distance(Weapon_info.cbegin(), it))); } } } @@ -837,9 +836,9 @@ int mission_campaign_next_mission() Campaign.loop_enabled = 0; } - // reset the number of persistent ships and weapons for the next campaign mission - Num_granted_ships = 0; - Num_granted_weapons = 0; + // reset the persistent ships and weapons for the next campaign mission + Granted_ships.clear(); + Granted_weapons.clear(); return 0; } @@ -876,8 +875,8 @@ int mission_campaign_previous_mission() Player->stats.assign( Campaign.missions[Campaign.current_mission].stats ); strcpy_s( Game_current_mission_filename, Campaign.missions[Campaign.current_mission].name ); - Num_granted_ships = 0; - Num_granted_weapons = 0; + Granted_ships.clear(); + Granted_weapons.clear(); return 1; } @@ -1119,7 +1118,7 @@ void mission_campaign_store_goals_and_events_and_variables(bool store_red_alert_ */ void mission_campaign_mission_over(bool do_next_mission) { - int mission_num, i; + int mission_num; cmission *mission_obj; // I don't think that we should have a record for these -- maybe we might?????? If we do, @@ -1133,13 +1132,8 @@ void mission_campaign_mission_over(bool do_next_mission) mission_obj = &Campaign.missions[mission_num]; // determine if any ships/weapons were granted this mission - for ( i=0; i(std::distance(Ship_info.begin(), it)); - Campaign.ships_allowed[i] = 1; + for (i = 0; i < ship_info_size(); i++) { + Campaign.ships_allowed.insert(i); } for (i = 0; i < weapon_info_size(); i++) { - Campaign.weapons_allowed[i] = 1; + Campaign.weapons_allowed.insert(i); } } diff --git a/code/mission/missioncampaign.h b/code/mission/missioncampaign.h index 069c2303094..41d7042023e 100644 --- a/code/mission/missioncampaign.h +++ b/code/mission/missioncampaign.h @@ -129,8 +129,8 @@ class campaign int loop_reentry; // mission number to return to after loop is finished int realign_required; // are any missions missing alignment info? (Fred) int num_players; // valid in multiplayer campaigns -- number of players campaign supports. - SCP_vector ships_allowed; // which ships the player can use - SCP_vector weapons_allowed; // which weapons the player can use + SCP_set ships_allowed; // class indices of ships the player can use; absent = not allowed + SCP_set weapons_allowed; // class indices of weapons the player can use; absent = not allowed cmission missions[MAX_CAMPAIGN_MISSIONS]; // decription of the missions SCP_vector persistent_variables; // These variables will be saved at the end of a mission SCP_vector red_alert_variables; // state of the variables in the previous mission of a Red Alert scenario. diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp index b5090b26fd0..487d5fba92a 100644 --- a/code/mission/missionparse.cpp +++ b/code/mission/missionparse.cpp @@ -1251,16 +1251,15 @@ void parse_player_info2(mission *pm) // check ship class loadout entries for (auto &sc : list) { + if (!Ship_info.in_bounds(sc.index)) + continue; + // in a campaign, see if the player is allowed the ships or not. Remove them from the // pool if they are not allowed if (Game_mode & GM_CAMPAIGN_MODE || (MULTIPLAYER_CLIENT)) { - if ( !Campaign.ships_allowed[sc.index] ) + if ( !Campaign.ships_allowed.contains(sc.index) ) continue; } - if (sc.index < 0 || sc.index >= ship_info_size()) - continue; - - ptr->ship_list[num_choices] = sc.index; // if the list isn't set by a variable leave the variable name empty if (sc.index_sexp_var == NOT_SET_BY_SEXP_VARIABLE) { @@ -1270,6 +1269,7 @@ void parse_player_info2(mission *pm) strcpy_s(ptr->ship_list_variables[num_choices], Sexp_variables[sc.index_sexp_var].variable_name); } + ptr->ship_list[num_choices] = sc.index; ptr->ship_count[num_choices] = sc.count; ptr->loadout_total += sc.count; @@ -1297,9 +1297,9 @@ void parse_player_info2(mission *pm) // see if the player's default ship is an allowable ship (campaign only). If not, then what // do we do? choose the first allowable one? if (Game_mode & GM_CAMPAIGN_MODE || (MULTIPLAYER_CLIENT)) { - if ( !(Campaign.ships_allowed[ptr->default_ship]) ) { + if ( !Campaign.ships_allowed.contains(ptr->default_ship) ) { for (i = 0; i < ship_info_size(); i++ ) { - if ( Campaign.ships_allowed[i] ) { + if ( Campaign.ships_allowed.contains(i) ) { ptr->default_ship = i; break; } @@ -1327,15 +1327,16 @@ void parse_player_info2(mission *pm) // check weapon class loadout entries for (auto &wc : list2) { + if (!Weapon_info.in_bounds(wc.index)) + continue; + // in a campaign, see if the player is allowed the weapons or not. Remove them from the // pool if they are not allowed if (Game_mode & GM_CAMPAIGN_MODE || (MULTIPLAYER_CLIENT)) { - if ( !Campaign.weapons_allowed[wc.index] ) { + if ( !Campaign.weapons_allowed.contains(wc.index) ) { continue; } } - if (wc.index < 0 || wc.index >= weapon_info_size()) - continue; // always allow the pool to be added in FRED, it is a verbal warning // to let the mission dev know about the problem @@ -1346,6 +1347,7 @@ 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; diff --git a/code/missioneditor/campaignsave.cpp b/code/missioneditor/campaignsave.cpp index 6ffec6635bb..a36b02e05b2 100644 --- a/code/missioneditor/campaignsave.cpp +++ b/code/missioneditor/campaignsave.cpp @@ -88,9 +88,8 @@ int Fred_campaign_save::save_campaign_file(const char* pathname, const SCP_vecto fout("\n\n+Starting Ships:"); } fout(" ("); - for (int i = 0; i < ship_info_size(); i++) { - if (Campaign.ships_allowed[i]) - fout(" \"%s\"", Ship_info[i].name); + for (int ship_class : Campaign.ships_allowed) { + fout(" \"%s\"", Ship_info[ship_class].name); } fout(" )"); @@ -100,9 +99,8 @@ int Fred_campaign_save::save_campaign_file(const char* pathname, const SCP_vecto fout("\n\n+Starting Weapons:"); } fout(" ("); - for (int i = 0; i < weapon_info_size(); i++) { - if (Campaign.weapons_allowed[i]) - fout(" \"%s\"", Weapon_info[i].name); + for (int weapon_class : Campaign.weapons_allowed) { + fout(" \"%s\"", Weapon_info[weapon_class].name); } fout(" )"); diff --git a/code/network/multi_campaign.cpp b/code/network/multi_campaign.cpp index 5c5454adf51..2f89aa7303d 100644 --- a/code/network/multi_campaign.cpp +++ b/code/network/multi_campaign.cpp @@ -270,25 +270,25 @@ void multi_campaign_process_update(ubyte *data, header *hinfo) if(!val){ // all ships for(idx = 0; idx < ship_info_size(); idx++) { - Campaign.ships_allowed[idx] = 1; + Campaign.ships_allowed.insert(idx); } // all weapons for(idx = 0; idx < weapon_info_size(); idx++) { - Campaign.weapons_allowed[idx] = 1; + Campaign.weapons_allowed.insert(idx); } } else { - // clear the ships and weapons allowed arrays - Campaign.ships_allowed.assign(ship_info_size(), 0); - Campaign.weapons_allowed.assign(weapon_info_size(), 0); + // clear the ships and weapons allowed sets + Campaign.ships_allowed.clear(); + Campaign.weapons_allowed.clear(); // get all ship classes GET_USHORT(spool_size); for(idx=0;idx(spool_size)); - for(idx = 0; idx < ship_info_size(); idx++) { - if(Campaign.ships_allowed[idx]){ - ADD_USHORT(static_cast(idx)); - } + for(int ship_class : Campaign.ships_allowed) { + ADD_USHORT(static_cast(ship_class)); } // add all weapon types ADD_USHORT(static_cast(wpool_size)); - for(idx = 0; idx < weapon_info_size(); idx++){ - if(Campaign.weapons_allowed[idx]){ - ADD_USHORT(static_cast(idx)); - } + for(int weapon_class : Campaign.weapons_allowed) { + ADD_USHORT(static_cast(weapon_class)); } } diff --git a/code/pilotfile/csg.cpp b/code/pilotfile/csg.cpp index 6f8a0f8af5b..9efd6b565c6 100644 --- a/code/pilotfile/csg.cpp +++ b/code/pilotfile/csg.cpp @@ -163,7 +163,7 @@ void pilotfile::csg_read_info() if (allowed) { if (ship_list[idx].index >= 0) { - Campaign.ships_allowed[ship_list[idx].index] = 1; + Campaign.ships_allowed.insert(ship_list[idx].index); } else { mprintf(("Found invalid ship \"%s\" in campaign save file. Skipping...\n", ship_list[idx].name.c_str())); } @@ -177,7 +177,7 @@ void pilotfile::csg_read_info() if (allowed) { if (weapon_list[idx].index >= 0) { - Campaign.weapons_allowed[weapon_list[idx].index] = 1; + Campaign.weapons_allowed.insert(weapon_list[idx].index); } else { mprintf(("Found invalid weapon \"%s\" in campaign save file. Skipping...\n", weapon_list[idx].name.c_str())); @@ -247,12 +247,12 @@ void pilotfile::csg_write_info() // allowed ships for (idx = 0; idx < ship_info_size(); idx++) { - cfwrite_ubyte(Campaign.ships_allowed[idx], cfp); + cfwrite_ubyte(Campaign.ships_allowed.contains(idx) ? 1 : 0, cfp); } // allowed weapons for (idx = 0; idx < weapon_info_size(); idx++) { - cfwrite_ubyte(Campaign.weapons_allowed[idx], cfp); + cfwrite_ubyte(Campaign.weapons_allowed.contains(idx) ? 1 : 0, cfp); } // single/campaign squad name & image @@ -1610,8 +1610,8 @@ void pilotfile::csg_reset_data(bool reset_ships_and_weapons) // zero out allowed ships/weapons if (reset_ships_and_weapons) { - Campaign.ships_allowed.assign(ship_info_size(), 0); - Campaign.weapons_allowed.assign(weapon_info_size(), 0); + Campaign.ships_allowed.clear(); + Campaign.weapons_allowed.clear(); } // reset campaign status diff --git a/code/scripting/api/objs/shipclass.cpp b/code/scripting/api/objs/shipclass.cpp index b1482807e7d..51dddcba68c 100644 --- a/code/scripting/api/objs/shipclass.cpp +++ b/code/scripting/api/objs/shipclass.cpp @@ -962,10 +962,14 @@ ADE_VIRTVAR(AllowedInCampaign, l_Shipclass, "boolean", "Gets or sets whether thi return ade_set_error(L, "b", false); if (ADE_SETTING_VAR) { - Campaign.ships_allowed[idx] = new_value; + if (new_value) { + Campaign.ships_allowed.insert(idx); + } else { + Campaign.ships_allowed.erase(idx); + } } - return Campaign.ships_allowed[idx] ? ADE_RETURN_TRUE : ADE_RETURN_FALSE; + return Campaign.ships_allowed.contains(idx) ? ADE_RETURN_TRUE : ADE_RETURN_FALSE; } ADE_VIRTVAR(PowerOutput, l_Shipclass, "number", "Gets or sets a ship class' power output", "number", "The ship class' current power output") diff --git a/code/scripting/api/objs/weaponclass.cpp b/code/scripting/api/objs/weaponclass.cpp index 86a69c0eb18..d4a159c5e8c 100644 --- a/code/scripting/api/objs/weaponclass.cpp +++ b/code/scripting/api/objs/weaponclass.cpp @@ -828,10 +828,14 @@ ADE_VIRTVAR(AllowedInCampaign, l_Weaponclass, "boolean", "Gets or sets whether t return ade_set_error(L, "b", false); if (ADE_SETTING_VAR) { - Campaign.weapons_allowed[idx] = new_value; + if (new_value) { + Campaign.weapons_allowed.insert(idx); + } else { + Campaign.weapons_allowed.erase(idx); + } } - return Campaign.weapons_allowed[idx] ? ADE_RETURN_TRUE : ADE_RETURN_FALSE; + return Campaign.weapons_allowed.contains(idx) ? ADE_RETURN_TRUE : ADE_RETURN_FALSE; } ADE_VIRTVAR(CargoSize, l_Weaponclass, "number", "The cargo size of this weapon class", "number", "The new cargo size or -1 on error") diff --git a/fred2/initialships.cpp b/fred2/initialships.cpp index 773449291a1..b3aa4db5841 100644 --- a/fred2/initialships.cpp +++ b/fred2/initialships.cpp @@ -67,9 +67,9 @@ BOOL InitialShips::OnInitDialog() if ( m_initial_items == INITIAL_SHIPS ) { for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) { if (it->flags[Ship::Info_Flags::Player_ship]) { - auto i = std::distance(Ship_info.cbegin(), it); + int i = static_cast(std::distance(Ship_info.cbegin(), it)); m_initial_list.AddString(it->name); - if (Campaign.ships_allowed[i]) { + if (Campaign.ships_allowed.contains(i)) { m_initial_list.SetCheck(m_list_count, 1); } else if ((strlen(Campaign.filename) == 0) && strstr(it->name, "Myrmidon")) { //-V805 @@ -104,7 +104,7 @@ BOOL InitialShips::OnInitDialog() if ( allowed_weapons[i] ) { m_initial_list.AddString( Weapon_info[i].name ); int add_weapon = 0; - if ( Campaign.weapons_allowed[i] ) { + if ( Campaign.weapons_allowed.contains(i) ) { add_weapon = 1; } else if ( strlen(Campaign.filename) == 0 ) { //-V805 if ( strstr(Weapon_info[i].name, "Subach")) { @@ -142,25 +142,24 @@ void InitialShips::OnOK() { int i; - // zero out whichever array we are setting + // zero out whichever set we are setting if ( m_initial_items == INITIAL_SHIPS ) { - Campaign.ships_allowed.assign(ship_info_size(), 0); + Campaign.ships_allowed.clear(); } else if ( m_initial_items == INITIAL_WEAPONS ) { - Campaign.weapons_allowed.assign(weapon_info_size(), 0); + Campaign.weapons_allowed.clear(); } for ( i = 0; i < m_list_count; i++ ) { if ( m_initial_list.GetCheck(i) ) { // this item is checked. Get the index into either the ship info array or the weapons // array - auto index = m_initial_list.GetItemData(i); + int index = static_cast(m_initial_list.GetItemData(i)); if ( m_initial_items == INITIAL_SHIPS ) { - Campaign.ships_allowed[index] = 1; + Campaign.ships_allowed.insert(index); } else if ( m_initial_items == INITIAL_WEAPONS ) { - Campaign.weapons_allowed[index] = 1; + Campaign.weapons_allowed.insert(index); } else Int3(); - } } diff --git a/qtfred/src/mission/dialogs/CampaignEditorDialogModel.cpp b/qtfred/src/mission/dialogs/CampaignEditorDialogModel.cpp index 9663ea83b9e..6455baedc83 100644 --- a/qtfred/src/mission/dialogs/CampaignEditorDialogModel.cpp +++ b/qtfred/src/mission/dialogs/CampaignEditorDialogModel.cpp @@ -151,8 +151,8 @@ void CampaignEditorDialogModel::initializeData(const char* filename) } // Copy ship and weapon permissions from the global Campaign struct - m_ships_allowed.assign(Campaign.ships_allowed.begin(), Campaign.ships_allowed.end()); - m_weapons_allowed.assign(Campaign.weapons_allowed.begin(), Campaign.weapons_allowed.end()); + m_ships_allowed = Campaign.ships_allowed; + m_weapons_allowed = Campaign.weapons_allowed; } else { // CREATING A NEW CAMPAIGN @@ -164,9 +164,6 @@ void CampaignEditorDialogModel::initializeData(const char* filename) m_campaign_type = CAMPAIGN_TYPE_SINGLE; m_num_players = 0; m_flags = CF_DEFAULT_VALUE; - - m_ships_allowed.assign(ship_info_size(), false); - m_weapons_allowed.assign(weapon_info_size(), false); } // Load the list of available mission files from the directory. @@ -319,8 +316,8 @@ void CampaignEditorDialogModel::commitWorkingCopyToGlobal() Campaign.custom_data = m_custom_data; // Copy ship and weapon permissions - Campaign.ships_allowed.assign(m_ships_allowed.begin(), m_ships_allowed.end()); - Campaign.weapons_allowed.assign(m_weapons_allowed.begin(), m_weapons_allowed.end()); + Campaign.ships_allowed = m_ships_allowed; + Campaign.weapons_allowed = m_weapons_allowed; // Copy mission data for (int i = 0; i < Campaign.num_missions; ++i) { @@ -1581,7 +1578,7 @@ SCP_vector> CampaignEditorDialogModel::getAllo SCP_vector> ship_list; for (int i = 0; i < static_cast(Ship_info.size()); i++) { if (Ship_info[i].flags[Ship::Info_Flags::Player_ship]) { - ship_list.emplace_back(Ship_info[i].name, i, m_ships_allowed[i]); + ship_list.emplace_back(Ship_info[i].name, i, m_ships_allowed.contains(i)); } } return ship_list; @@ -1589,9 +1586,13 @@ SCP_vector> CampaignEditorDialogModel::getAllo void CampaignEditorDialogModel::setAllowedShip(int ship_class_index, bool allowed) { - if (SCP_vector_inbounds(m_ships_allowed, ship_class_index)) { - if (m_ships_allowed[ship_class_index] != allowed) { - m_ships_allowed[ship_class_index] = allowed; + if (Ship_info.in_bounds(ship_class_index)) { + if (m_ships_allowed.contains(ship_class_index) != allowed) { + if (allowed) { + m_ships_allowed.insert(ship_class_index); + } else { + m_ships_allowed.erase(ship_class_index); + } set_modified(); } } @@ -1602,7 +1603,7 @@ SCP_vector> CampaignEditorDialogModel::getAllo SCP_vector> weapon_list; for (int i = 0; i < static_cast(Weapon_info.size()); i++) { if (Weapon_info[i].wi_flags[Weapon::Info_Flags::Player_allowed]) { - weapon_list.emplace_back(Weapon_info[i].name, i, m_weapons_allowed[i]); + weapon_list.emplace_back(Weapon_info[i].name, i, m_weapons_allowed.contains(i)); } } return weapon_list; @@ -1610,9 +1611,13 @@ SCP_vector> CampaignEditorDialogModel::getAllo void CampaignEditorDialogModel::setAllowedWeapon(int weapon_class_index, bool allowed) { - if (SCP_vector_inbounds(m_weapons_allowed, weapon_class_index)) { - if (m_weapons_allowed[weapon_class_index] != allowed) { - m_weapons_allowed[weapon_class_index] = allowed; + if (Weapon_info.in_bounds(weapon_class_index)) { + if (m_weapons_allowed.contains(weapon_class_index) != allowed) { + if (allowed) { + m_weapons_allowed.insert(weapon_class_index); + } else { + m_weapons_allowed.erase(weapon_class_index); + } set_modified(); } } diff --git a/qtfred/src/mission/dialogs/CampaignEditorDialogModel.h b/qtfred/src/mission/dialogs/CampaignEditorDialogModel.h index c7616547c8e..ad0eb0b10c2 100644 --- a/qtfred/src/mission/dialogs/CampaignEditorDialogModel.h +++ b/qtfred/src/mission/dialogs/CampaignEditorDialogModel.h @@ -187,8 +187,8 @@ class CampaignEditorDialogModel : public AbstractDialogModel { int m_campaign_type = CAMPAIGN_TYPE_SINGLE; int m_num_players = -1; int m_flags = 0; - SCP_vector m_ships_allowed; - SCP_vector m_weapons_allowed; + SCP_set m_ships_allowed; + SCP_set m_weapons_allowed; SCP_map m_custom_data; SCP_vector m_missions;