diff --git a/code/mission/missioncampaign.cpp b/code/mission/missioncampaign.cpp index f4b853d5b09..0101f3daaa3 100644 --- a/code/mission/missioncampaign.cpp +++ b/code/mission/missioncampaign.cpp @@ -731,8 +731,8 @@ void player_loadout_init() memset(Player_loadout.filename, 0, sizeof(Player_loadout.filename)); memset(Player_loadout.last_modified, 0, sizeof(Player_loadout.last_modified)); - Player_loadout.ship_pool.assign(ship_info_size(), 0); - Player_loadout.weapon_pool.assign(weapon_info_size(), 0); + Player_loadout.ship_pool.clear(); + Player_loadout.weapon_pool.clear(); for ( i = 0; i < MAX_WSS_SLOTS; i++ ) { Player_loadout.unit_data[i].ship_class = -1; diff --git a/code/missionui/missionscreencommon.cpp b/code/missionui/missionscreencommon.cpp index fdd987afbc6..f4e66df3ccd 100644 --- a/code/missionui/missionscreencommon.cpp +++ b/code/missionui/missionscreencommon.cpp @@ -91,13 +91,13 @@ loadout_data Player_loadout; // what the ship and weapon loadout is... used sinc //int Wss_num_wings; // number of player wings wss_unit Wss_slots_teams[MAX_TVT_TEAMS][MAX_WSS_SLOTS]; -int Wl_pool_teams[MAX_TVT_TEAMS][MAX_WEAPON_TYPES]; -int Ss_pool_teams[MAX_TVT_TEAMS][MAX_SHIP_CLASSES]; +SCP_map Wl_pool_teams[MAX_TVT_TEAMS]; +SCP_map Ss_pool_teams[MAX_TVT_TEAMS]; int Wss_num_wings_teams[MAX_TVT_TEAMS]; wss_unit *Wss_slots = NULL; -int *Wl_pool = NULL; -int *Ss_pool = NULL; +SCP_map *Wl_pool = nullptr; +SCP_map *Ss_pool = nullptr; int Wss_num_wings; ////////////////////////////////////////////////////////////////// @@ -501,8 +501,8 @@ void common_set_team_pointers(int team) Assert( (team >= 0) && (team < MAX_TVT_TEAMS) ); Wss_slots = Wss_slots_teams[team]; - Ss_pool = Ss_pool_teams[team]; - Wl_pool = Wl_pool_teams[team]; + Ss_pool = &Ss_pool_teams[team]; + Wl_pool = &Wl_pool_teams[team]; ss_set_team_pointers(team); wl_set_team_pointers(team); @@ -517,8 +517,8 @@ void common_reset_team_pointers() // these are done last so that we can make use of the Assert()'s in the above // functions to make sure the screens are exited and this is safe Wss_slots = NULL; - Ss_pool = NULL; - Wl_pool = NULL; + Ss_pool = nullptr; + Wl_pool = nullptr; } // common_select_init() will load in animations and bitmaps that are common to the @@ -1100,14 +1100,10 @@ void wss_save_loadout() Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) ); // save the ship pool - for ( i = 0; i < ship_info_size(); i++ ) { - Player_loadout.ship_pool[i] = Ss_pool[i]; - } + Player_loadout.ship_pool = *Ss_pool; // save the weapons pool - for ( i = 0; i < weapon_info_size(); i++ ) { - Player_loadout.weapon_pool[i] = Wl_pool[i]; - } + Player_loadout.weapon_pool = *Wl_pool; // save the ship class / weapons for each slot for ( i = 0; i < MAX_WSS_SLOTS; i++ ) { @@ -1174,21 +1170,25 @@ void wss_maybe_restore_loadout() // now compare the two, adding in what was left in the pools. If there are less of a ship or weapon class in the mission now // than there were last time, we can't restore and must abort. - for (i = 0; i < ship_info_size(); i++) { - if (Ss_pool[i] >= 1) { - this_loadout_ships[i] += Ss_pool[i]; + for (const auto &[ship_class, count] : *Ss_pool) { + if (count >= 1) { + this_loadout_ships[ship_class] += count; } + } + for (i = 0; i < ship_info_size(); i++) { if ( this_loadout_ships[i] < last_loadout_ships[i]) { - return; + return; } } - - for (i = 0; i < weapon_info_size(); i++) { - if (Wl_pool[i] >= 1) { - this_loadout_weapons[i] += Wl_pool[i]; + + for (const auto &[weapon_class, count] : *Wl_pool) { + if (count >= 1) { + this_loadout_weapons[weapon_class] += count; } + } + for (i = 0; i < weapon_info_size(); i++) { if ( this_loadout_weapons[i] < last_loadout_weapons[i]) { - return; + return; } } @@ -1215,14 +1215,25 @@ void wss_maybe_restore_loadout() } } - // restore the ship pool + // restore the ship pool. Update counts for classes already in the loadout, then add any class the + // previous runthrough used that isn't in it (two passes so we don't iterate over mid-loop inserts). + for (auto &[ship_class, count] : *Ss_pool) { + count = this_loadout_ships[ship_class]; + } for ( i = 0; i < ship_info_size(); i++ ) { - Ss_pool[i] = this_loadout_ships[i]; + if (this_loadout_ships[i] > 0 && !Ss_pool->contains(i)) { + (*Ss_pool)[i] = this_loadout_ships[i]; + } } // restore the weapons pool + for (auto &[weapon_class, count] : *Wl_pool) { + count = this_loadout_weapons[weapon_class]; + } for ( i = 0; i < weapon_info_size(); i++ ) { - Wl_pool[i] = this_loadout_weapons[i]; + if (this_loadout_weapons[i] > 0 && !Wl_pool->contains(i)) { + (*Wl_pool)[i] = this_loadout_weapons[i]; + } } } @@ -1381,10 +1392,10 @@ int store_wss_data(ubyte *data, __UNUSED const unsigned int max_size, interface_ if ( !(Game_mode & GM_MULTIPLAYER) ) return 0; - // write the ship pool + // write the ship pool (only positive counts; the pool map can also hold exhausted 0-count entries) pool_size = 0; - for (i = 0; i < ship_info_size(); i++) { - if (Ss_pool[i] > 0) { + for (const auto &[ship_class, count] : *Ss_pool) { + if (count > 0) { ++pool_size; } } @@ -1393,17 +1404,17 @@ int store_wss_data(ubyte *data, __UNUSED const unsigned int max_size, interface_ Assertion((((sizeof(short)+sizeof(short)) * pool_size) + packet_size) < max_size, "Size of ship pool exceeds max data size!"); - for (i = 0; i < ship_info_size(); i++) { - if (Ss_pool[i] > 0) { - ADD_SHORT(static_cast(i)); - ADD_SHORT(static_cast(Ss_pool[i])); + for (const auto &[ship_class, count] : *Ss_pool) { + if (count > 0) { + ADD_SHORT(static_cast(ship_class)); + ADD_SHORT(static_cast(count)); } } // write the weapon pool pool_size = 0; - for (i = 0; i < weapon_info_size(); i++) { - if (Wl_pool[i] > 0) { + for (const auto &[weapon_class, count] : *Wl_pool) { + if (count > 0) { ++pool_size; } } @@ -1412,10 +1423,10 @@ int store_wss_data(ubyte *data, __UNUSED const unsigned int max_size, interface_ Assertion((((sizeof(short)+sizeof(short)) * pool_size) + packet_size) < max_size, "Size of weapon pool exceeds max data size!"); - for (i = 0; i < weapon_info_size(); i++) { - if (Wl_pool[i] > 0) { - ADD_SHORT(static_cast(i)); - ADD_SHORT(static_cast(Wl_pool[i])); + for (const auto &[weapon_class, count] : *Wl_pool) { + if (count > 0) { + ADD_SHORT(static_cast(weapon_class)); + ADD_SHORT(static_cast(count)); } } @@ -1470,28 +1481,28 @@ int restore_wss_data(ubyte *data) return 0; // restore ship pool - memset(Ss_pool, 0, MAX_SHIP_CLASSES*sizeof(int)); + Ss_pool->clear(); GET_USHORT(pool_size); for (i = 0; i < pool_size; i++) { GET_SHORT(b1); GET_SHORT(b2); - if (b1 < MAX_SHIP_CLASSES) { - Ss_pool[b1] = b2; + if (Ship_info.in_bounds(b1)) { + (*Ss_pool)[b1] = b2; } } // restore weapons pool - memset(Wl_pool, 0, MAX_WEAPON_TYPES*sizeof(int)); + Wl_pool->clear(); GET_USHORT(pool_size); for (i = 0; i < pool_size; i++) { GET_SHORT(b1); GET_SHORT(b2); - if (b1 < MAX_SHIP_CLASSES) { - Wl_pool[b1] = b2; + if (Weapon_info.in_bounds(b1)) { + (*Wl_pool)[b1] = b2; } } diff --git a/code/missionui/missionscreencommon.h b/code/missionui/missionscreencommon.h index 28fac68c9ae..ed84fc7f0bf 100644 --- a/code/missionui/missionscreencommon.h +++ b/code/missionui/missionscreencommon.h @@ -190,14 +190,16 @@ extern int Wss_num_wings_teams[MAX_TVT_TEAMS]; ////////////////////////////////////////////// // Weapon pool ////////////////////////////////////////////// -extern int Wl_pool_teams[MAX_TVT_TEAMS][MAX_WEAPON_TYPES]; -extern int *Wl_pool; +// weapon class index -> count remaining; an absent entry means the class is not in this mission's loadout +extern SCP_map Wl_pool_teams[MAX_TVT_TEAMS]; +extern SCP_map *Wl_pool; ////////////////////////////////////////////// // Ship pool ////////////////////////////////////////////// -extern int Ss_pool_teams[MAX_TVT_TEAMS][MAX_SHIP_CLASSES]; -extern int *Ss_pool; +// ship class index -> count remaining; an absent entry means the class is not in this mission's loadout +extern SCP_map Ss_pool_teams[MAX_TVT_TEAMS]; +extern SCP_map *Ss_pool; ////////////////////////////////////////////// // Saving loadout @@ -207,8 +209,8 @@ typedef struct loadout_data char filename[MAX_FILENAME_LEN]; // mission filename char last_modified[DATE_TIME_LENGTH]; // when mission was last modified wss_unit unit_data[MAX_WSS_SLOTS]; // ship and weapon data - SCP_vector weapon_pool; // available weapons - SCP_vector ship_pool; // available ships + SCP_map weapon_pool; // available weapons: class index -> count; absent serialized as 0 + SCP_map ship_pool; // available ships: class index -> count; absent serialized as -1 (Ss_pool's not-in-loadout sentinel) } loadout_data; extern loadout_data Player_loadout; diff --git a/code/missionui/missionshipchoice.cpp b/code/missionui/missionshipchoice.cpp index 197fd027b21..a3b90c3dcd4 100644 --- a/code/missionui/missionshipchoice.cpp +++ b/code/missionui/missionshipchoice.cpp @@ -482,7 +482,6 @@ void active_list_remove(int ship_class) // can choose from. void init_active_list() { - int i; ss_active_item *sai; Assert( Ss_pool != NULL ); @@ -490,11 +489,11 @@ void init_active_list() clear_active_list(); // build the active list - for ( i = 0; i < ship_info_size(); i++ ) { - if ( Ss_pool[i] > 0 ) { + for ( const auto &[ship_class, count] : *Ss_pool ) { + if ( count > 0 ) { sai = get_free_active_list_node(); if ( sai != NULL ) { - sai->ship_class = i; + sai->ship_class = ship_class; list_append(&SS_active_head, sai); SS_active_list_size++; } @@ -1680,7 +1679,7 @@ void draw_ship_icon_with_number(int screen_offset, int ship_class) } } - if ( Ss_pool[ship_class] <= 0 ) { + if ( Ss_pool->value_or(ship_class, -1) <= 0 ) { return; } @@ -1713,7 +1712,7 @@ void draw_ship_icon_with_number(int screen_offset, int ship_class) } // blit the number - sprintf(buf, "%d", Ss_pool[ship_class] ); + sprintf(buf, "%d", Ss_pool->value_or(ship_class, -1) ); gr_set_color_fast(&Color_white); gr_string(num_x, num_y, buf, GR_RESIZE_MENU); } @@ -2058,14 +2057,13 @@ int pick_from_ship_list(int screen_offset, int ship_class) if ( ss_icon_being_carried() ) return rval; - if ( Ss_pool[ship_class] > 0 ) { + if ( Ss_pool->value_or(ship_class, -1) > 0 ) { int mouse_x, mouse_y; ss_set_carried_icon(-1, ship_class); mouse_get_pos_unscaled( &mouse_x, &mouse_y ); Ss_delta_x = Ship_list_coords[gr_screen.res][screen_offset][0] - mouse_x; Ss_delta_y = Ship_list_coords[gr_screen.res][screen_offset][1] - mouse_y; - Assert( Ss_pool[ship_class] >= 0 ); rval = 0; } @@ -2778,9 +2776,9 @@ void ss_reset_selected_ship() } // get the first ship class found in the pool - for ( i = 0; i < ship_info_size(); i++ ) { - if ( Ss_pool[i] > 0 ) { - Selected_ss_class = i; + for ( const auto &[ship_class, count] : *Ss_pool ) { + if ( count > 0 ) { + Selected_ss_class = ship_class; return; } } @@ -2886,16 +2884,12 @@ void ss_init_pool(team_data *pteam) Assert( Ss_pool != NULL ); - for ( i = 0; i < MAX_SHIP_CLASSES; i++ ) { - Ss_pool[i] = -1; - } + Ss_pool->clear(); // set number of available ships based on counts in team_data + // (auto-insert starts new entries at 0, so classes listed with a count of 0 stay in the pool as exhausted) for ( i = 0; i < pteam->num_ship_choices; i++ ) { - if (Ss_pool[pteam->ship_list[i]] == -1) { - Ss_pool[pteam->ship_list[i]] = 0; - } - Ss_pool[pteam->ship_list[i]] += pteam->ship_count[i]; + (*Ss_pool)[pteam->ship_list[i]] += pteam->ship_count[i]; } } @@ -2947,7 +2941,7 @@ void ss_load_all_icons() } Ss_icons[i].model_index = -1; - if ( Ss_pool[i] >= 0 ) { + if ( Ss_pool->contains(i) ) { ss_load_icons(i); } } @@ -3394,13 +3388,13 @@ int ss_dump_to_list(int from_slot, int to_list, interface_snd_id *sound) } // put ship back in list - Ss_pool[to_list]++; // return to list + (*Ss_pool)[to_list]++; // return to list slot->ship_class = -1; // remove from slot // put weapons back in list for ( i = 0; i < MAX_SHIP_WEAPONS; i++ ) { if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) { - Wl_pool[slot->wep[i]] += slot->wep_count[i]; + (*Wl_pool)[slot->wep[i]] += slot->wep_count[i]; slot->wep[i] = -1; slot->wep_count[i] = 0; } @@ -3421,7 +3415,7 @@ int ss_grab_from_list(int from_list, int to_slot, interface_snd_id *sound) slot = &Wss_slots[to_slot]; // ensure that pool has ship - if ( Ss_pool[from_list] <= 0 ) + if ( Ss_pool->value_or(from_list, -1) <= 0 ) { *sound=InterfaceSounds::ICON_DROP; return 0; @@ -3430,7 +3424,7 @@ int ss_grab_from_list(int from_list, int to_slot, interface_snd_id *sound) Assert(slot->ship_class < 0 ); // slot should be empty // take ship from list->slot - Ss_pool[from_list]--; + (*Ss_pool)[from_list]--; slot->ship_class = from_list; // take weapons from list->slot @@ -3455,7 +3449,7 @@ int ss_swap_list_slot(int from_list, int to_slot, interface_snd_id *sound) Assert( (Ss_pool != NULL) && (Wl_pool != NULL) && (Wss_slots != NULL) ); // ensure that pool has ship - if ( Ss_pool[from_list] <= 0 ) + if ( Ss_pool->value_or(from_list, -1) <= 0 ) { *sound=InterfaceSounds::ICON_DROP; return 0; @@ -3465,21 +3459,21 @@ int ss_swap_list_slot(int from_list, int to_slot, interface_snd_id *sound) Assert(slot->ship_class >= 0 ); // slot should be filled // put ship from slot->list - Ss_pool[Wss_slots[to_slot].ship_class]++; + (*Ss_pool)[Wss_slots[to_slot].ship_class]++; // put weapons from slot->list for ( i = 0; i < MAX_SHIP_WEAPONS; i++ ) { if ( (slot->wep[i] >= 0) && (slot->wep_count[i] > 0) ) { - Wl_pool[slot->wep[i]] += slot->wep_count[i]; + (*Wl_pool)[slot->wep[i]] += slot->wep_count[i]; slot->wep[i] = -1; slot->wep_count[i] = 0; } } // take ship from list->slot - Ss_pool[from_list]--; + (*Ss_pool)[from_list]--; slot->ship_class = from_list; // take weapons from list->slot diff --git a/code/missionui/missionweaponchoice.cpp b/code/missionui/missionweaponchoice.cpp index 4b857ee01bb..4c0a5ff760d 100644 --- a/code/missionui/missionweaponchoice.cpp +++ b/code/missionui/missionweaponchoice.cpp @@ -1371,12 +1371,10 @@ void wl_init_pool(team_data *td) Assert( Wl_pool != NULL ); - for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) { - Wl_pool[i] = 0; - } + Wl_pool->clear(); for ( i = 0; i < td->num_weapon_choices; i++ ) { - Wl_pool[td->weaponry_pool[i]] += td->weaponry_count[i]; // read from mission + (*Wl_pool)[td->weaponry_pool[i]] += td->weaponry_count[i]; // read from mission } } @@ -1446,7 +1444,7 @@ void wl_load_all_icons() Wl_icons[i].model_index = -1; Wl_icons[i].laser_bmap = -1; - if ( Wl_pool[i] > 0 ) { + if ( Wl_pool->value_or(i, 0) > 0 ) { wl_load_icons(i); } } @@ -1889,8 +1887,9 @@ void wl_remove_weps_from_pool(int *wep, int *wep_count, int ship_class) for ( bank = 0; bank < MAX_SHIP_WEAPONS; bank++ ) { wi_index = wep[bank]; if ( wi_index >= 0 ) { - if ( (wep_count[bank] > 0) && ((Wl_pool[wi_index] - wep_count[bank]) >= 0) ) { - Wl_pool[wi_index] -= wep_count[bank]; + int pool_count = Wl_pool->value_or(wi_index, 0); + if ( (wep_count[bank] > 0) && ((pool_count - wep_count[bank]) >= 0) ) { + (*Wl_pool)[wi_index] -= wep_count[bank]; } else { // not enough weapons in pool // TEMP HACK: FRED doesn't fill in a weapons pool if there are no starting wings... so @@ -1899,12 +1898,12 @@ void wl_remove_weps_from_pool(int *wep, int *wep_count, int ship_class) wl_add_index_to_list(wi_index); } else { - if ( (Wl_pool[wi_index] <= 0) || (wep_count[bank] == 0) ) { + if ( (pool_count <= 0) || (wep_count[bank] == 0) ) { // fresh out of this weapon, pick an alternate pool weapon if we can for (const auto &new_index : Player_weapon_precedence) { Assertion(new_index >= 0, "Somehow, a negative index (%d) got into Player_weapon_precedence; this should not happen. Get a coder!", new_index); - if ( Wl_pool[new_index] <= 0 ) { + if ( Wl_pool->value_or(new_index, 0) <= 0 ) { continue; } @@ -1943,10 +1942,14 @@ void wl_remove_weps_from_pool(int *wep, int *wep_count, int ship_class) new_wep_count = wl_calc_missile_fit(wi_index, si.secondary_bank_ammo_capacity[secondary_bank_index]); } - wep_count[bank] = MIN(new_wep_count, Wl_pool[wi_index]); + // re-read the count, since the precedence loop may have picked a different weapon + pool_count = Wl_pool->value_or(wi_index, 0); + wep_count[bank] = MIN(new_wep_count, pool_count); Assert(wep_count[bank] >= 0); - Wl_pool[wi_index] -= wep_count[bank]; - if ( wep_count[bank] <= 0 ) { + if ( wep_count[bank] > 0 ) { + (*Wl_pool)[wi_index] -= wep_count[bank]; + } else { + // nothing to take wep[bank] = -1; } } @@ -2004,12 +2007,12 @@ void wl_init_icon_lists() Slist[i] = -1; } - for ( i = 0; i < weapon_info_size(); i++ ) { - if ( Wl_pool[i] > 0 ) { - if ( Weapon_info[i].subtype == WP_MISSILE ) { - Slist[Slist_size++] = i; + for ( const auto &[weapon_class, count] : *Wl_pool ) { + if ( count > 0 ) { + if ( Weapon_info[weapon_class].subtype == WP_MISSILE ) { + Slist[Slist_size++] = weapon_class; } else { - Plist[Plist_size++] = i; + Plist[Plist_size++] = weapon_class; } } } @@ -3244,7 +3247,7 @@ void draw_wl_icon_with_number(int list_count, int weapon_class) } wl_render_icon(weapon_class, Wl_weapon_icon_coords[gr_screen.res][list_count][0], Wl_weapon_icon_coords[gr_screen.res][list_count][1], - Wl_pool[weapon_class], 1, list_count, -1, weapon_class); + Wl_pool->value_or(weapon_class, 0), 1, list_count, -1, weapon_class); } /** @@ -3305,7 +3308,7 @@ void wl_pick_icon_from_list(int index) Assert( Wl_pool != NULL ); // no weapons left of that class - if ( Wl_pool[weapon_class] <= 0 ) { + if ( Wl_pool->value_or(weapon_class, 0) <= 0 ) { return; } @@ -3653,7 +3656,7 @@ void wl_saturate_bank(int ship_slot, int bank) slot->wep_count[bank] -= overflow; // add overflow back to pool - Wl_pool[slot->wep[bank]] += overflow; + (*Wl_pool)[slot->wep[bank]] += overflow; } } @@ -3726,7 +3729,7 @@ int wl_swap_slot_slot(int from_bank, int to_bank, int ship_slot, interface_snd_i // so return the "to" to the list and just move the "from" // put to_bank back into list - Wl_pool[slot->wep[to_bank]] += slot->wep_count[to_bank]; // return to list + (*Wl_pool)[slot->wep[to_bank]] += slot->wep_count[to_bank]; // return to list slot->wep[to_bank] = -1; // remove from slot slot->wep_count[to_bank] = 0; *sound=InterfaceSounds::ICON_DROP; // unless it changes later @@ -3737,7 +3740,7 @@ int wl_swap_slot_slot(int from_bank, int to_bank, int ship_slot, interface_snd_i if ( class_mismatch_flag ) { // put from_bank back into list - Wl_pool[slot->wep[from_bank]] += slot->wep_count[from_bank]; // return to list + (*Wl_pool)[slot->wep[from_bank]] += slot->wep_count[from_bank]; // return to list slot->wep[from_bank] = -1; // remove from slot slot->wep_count[from_bank] = 0; *sound=InterfaceSounds::ICON_DROP; @@ -3812,7 +3815,7 @@ int wl_dump_to_list(int from_bank, int to_list, int ship_slot, interface_snd_id } // put weapon bank to the list - Wl_pool[to_list] += slot->wep_count[from_bank]; // return to list + (*Wl_pool)[to_list] += slot->wep_count[from_bank]; // return to list slot->wep[from_bank] = -1; // remove from slot slot->wep_count[from_bank] = 0; *sound=InterfaceSounds::ICON_DROP; @@ -3852,7 +3855,7 @@ int wl_grab_from_list(int from_list, int to_bank, int ship_slot, interface_snd_i Assert(slot->wep[to_bank] < 0); // ensure that pool has weapon - if ( Wl_pool[from_list] <= 0 ) { + if ( Wl_pool->value_or(from_list, 0) <= 0 ) { return 0; } @@ -3885,11 +3888,12 @@ int wl_grab_from_list(int from_list, int to_bank, int ship_slot, interface_snd_i } // take weapon from list - if ( Wl_pool[from_list] < max_fit ) { - max_fit = Wl_pool[from_list]; + int pool_count = Wl_pool->value_or(from_list, 0); + if ( pool_count < max_fit ) { + max_fit = pool_count; update=2; } - Wl_pool[from_list] -= max_fit; + (*Wl_pool)[from_list] -= max_fit; // put on the slot slot->wep[to_bank] = from_list; @@ -3929,7 +3933,7 @@ int wl_swap_list_slot(int from_list, int to_bank, int ship_slot, interface_snd_i Assert(slot->wep[to_bank] >= 0); // ensure that pool has weapon - if ( Wl_pool[from_list] <= 0 ) { + if ( Wl_pool->value_or(from_list, 0) <= 0 ) { return 0; } @@ -3952,7 +3956,7 @@ int wl_swap_list_slot(int from_list, int to_bank, int ship_slot, interface_snd_i } // dump slot weapon back into list - Wl_pool[slot->wep[to_bank]] += slot->wep_count[to_bank]; + (*Wl_pool)[slot->wep[to_bank]] += slot->wep_count[to_bank]; slot->wep_count[to_bank] = 0; slot->wep[to_bank] = -1; @@ -3966,10 +3970,11 @@ int wl_swap_list_slot(int from_list, int to_bank, int ship_slot, interface_snd_i } // take weapon from list - if ( Wl_pool[from_list] < max_fit ) { - max_fit = Wl_pool[from_list]; + int pool_count = Wl_pool->value_or(from_list, 0); + if ( pool_count < max_fit ) { + max_fit = pool_count; } - Wl_pool[from_list] -= max_fit; + (*Wl_pool)[from_list] -= max_fit; // put on the slot slot->wep[to_bank] = from_list; diff --git a/code/network/multiteamselect.cpp b/code/network/multiteamselect.cpp index 9c9e188acde..e1a3f87b627 100644 --- a/code/network/multiteamselect.cpp +++ b/code/network/multiteamselect.cpp @@ -784,8 +784,8 @@ void multi_ts_sync_interface() // item 1 - determine how many ship types are available in the ship pool Multi_ts_avail_count = 0; - for(idx = 0; idx < ship_info_size(); idx++) { - if(Ss_pool[idx] > 0){ + for(const auto &[ship_class, count] : *Ss_pool) { + if(count > 0){ Multi_ts_avail_count++; } } @@ -1307,23 +1307,23 @@ void multi_ts_blit_wing_callsigns() // blit the ships on the avail list void multi_ts_blit_avail_ships() { - int display_count,ship_count,idx; + int display_count,ship_count; char count[6]; // blit the availability of all ship counts display_count = 0; ship_count = 0; - for(idx = 0; idx < ship_info_size(); idx++) { - if(Ss_pool[idx] > 0){ + for(const auto &[ship_class, pool_count] : *Ss_pool) { + if(pool_count > 0){ // if our starting display index is after this, then skip it if(ship_count < Multi_ts_avail_start){ ship_count++; } else { - // blit the icon - ss_blit_ship_icon(Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_X_COORD],Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_Y_COORD],idx,multi_ts_avail_bmap_num(display_count)); + // blit the icon + ss_blit_ship_icon(Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_X_COORD],Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_Y_COORD],ship_class,multi_ts_avail_bmap_num(display_count)); // blit the ship count available - sprintf(count,"%d",Ss_pool[idx]); + sprintf(count,"%d",pool_count); gr_set_color_fast(&Color_normal); gr_string(Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_X_COORD] - 20,Multi_ts_avail_coords[display_count][gr_screen.res][MULTI_TS_Y_COORD],count,GR_RESIZE_MENU); @@ -1820,7 +1820,7 @@ void multi_ts_handle_mouse() if(ship_class == -1){ region_empty = 1; } else { - region_empty = (Ss_pool[ship_class] > 0) ? 0 : 1; + region_empty = (Ss_pool->value_or(ship_class, -1) > 0) ? 0 : 1; } break; case MULTI_TS_SLOT_LIST: @@ -1984,7 +1984,7 @@ int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,i switch(op_type){ case TS_GRAB_FROM_LIST: // if there are no more of this ship class, its no go - if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){ + if(Ss_pool_teams[pl->p_info.team].value_or(ship_class, -1) <= 0){ return 0; } @@ -2001,7 +2001,7 @@ int multi_ts_can_perform(int from_type,int from_index,int to_type,int to_index,i case TS_SWAP_LIST_SLOT: // if there are no more of this ship class, its no go - if(Ss_pool_teams[pl->p_info.team][ship_class] <= 0){ + if(Ss_pool_teams[pl->p_info.team].value_or(ship_class, -1) <= 0){ return 0; } @@ -2388,22 +2388,17 @@ int multi_ts_move_player(int from_index,int to_index,interface_snd_id *sound,int // get the ship class of the current index in the avail list or -1 if none exists int multi_ts_get_avail_ship_class(int index) { - int ship_count,class_index; - - ship_count = index + Multi_ts_avail_start; - class_index = 0; - while((ship_count >= 0) && (class_index < ship_info_size())){ - if(Ss_pool[class_index] > 0){ + int ship_count = index + Multi_ts_avail_start; + + // find the Nth class with ships still available (the map iterates in ascending class + // order, which is the same order the avail list is rendered in) + for(const auto &[ship_class, count] : *Ss_pool){ + if(count > 0){ + if(ship_count == 0){ + return ship_class; + } ship_count--; } - - if(ship_count >= 0){ - class_index++; - } - } - - if(ship_count < 0){ - return class_index; } return -1; diff --git a/code/pilotfile/csg.cpp b/code/pilotfile/csg.cpp index 6f8a0f8af5b..c4f9ca62b04 100644 --- a/code/pilotfile/csg.cpp +++ b/code/pilotfile/csg.cpp @@ -567,22 +567,26 @@ void pilotfile::csg_read_loadout() cfread_string_len(Player_loadout.filename, MAX_FILENAME_LEN, cfp); cfread_string_len(Player_loadout.last_modified, DATE_TIME_LENGTH, cfp); - // ship pool + // clear out any values from a previously loaded CSG + Player_loadout.ship_pool.clear(); + Player_loadout.weapon_pool.clear(); + + // ship pool (-1 means the class is not in the loadout, which is the same as absent) list_size = ship_list.size(); for (idx = 0; idx < list_size; idx++) { count = cfread_int(cfp); - if (ship_list[idx].index >= 0) { + if (ship_list[idx].index >= 0 && count != -1) { Player_loadout.ship_pool[ship_list[idx].index] = count; } } - // weapon pool + // weapon pool (0 means the class is not in the loadout, which is the same as absent) list_size = weapon_list.size(); for (idx = 0; idx < list_size; idx++) { count = cfread_int(cfp); - if (weapon_list[idx].index >= 0) { + if (weapon_list[idx].index >= 0 && count != 0) { Player_loadout.weapon_pool[weapon_list[idx].index] = count; } } @@ -677,14 +681,14 @@ void pilotfile::csg_write_loadout() cfwrite_string_len(Player_loadout.filename, cfp); cfwrite_string_len(Player_loadout.last_modified, cfp); - // ship pool + // ship pool (absent classes are not in the loadout, i.e. -1) for (idx = 0; idx < ship_info_size(); idx++) { - cfwrite_int(Player_loadout.ship_pool[idx], cfp); + cfwrite_int(Player_loadout.ship_pool.value_or(idx, -1), cfp); } - // weapon pool + // weapon pool (absent classes are not in the loadout, i.e. 0) for (idx = 0; idx < weapon_info_size(); idx++) { - cfwrite_int(Player_loadout.weapon_pool[idx], cfp); + cfwrite_int(Player_loadout.weapon_pool.value_or(idx, 0), cfp); } // play ship loadout diff --git a/code/scripting/api/libs/ui.cpp b/code/scripting/api/libs/ui.cpp index 5f97d18499b..25da4f575dc 100644 --- a/code/scripting/api/libs/ui.cpp +++ b/code/scripting/api/libs/ui.cpp @@ -1521,7 +1521,7 @@ ADE_INDEXER(l_Ship_Pool, if (!ade_get_args(L, "*i|i", &idx, &amount)) return ADE_RETURN_NIL; - if (idx < 0 || idx > ship_info_size()) { + if (idx < 1 || idx > ship_info_size()) { return ADE_RETURN_NIL; }; @@ -1533,13 +1533,14 @@ ADE_INDEXER(l_Ship_Pool, return ADE_RETURN_NIL; } if (amount < 0) { - Ss_pool[idx] = 0; + (*Ss_pool)[idx] = 0; } else { - Ss_pool[idx] = amount; + (*Ss_pool)[idx] = amount; } } - return ade_set_args(L, "i", Ss_pool[idx]); + // an absent entry means the class is not in this mission's loadout, which scripts see as -1 + return ade_set_args(L, "i", Ss_pool->value_or(idx, -1)); } ADE_FUNC(__len, l_Ship_Pool, nullptr, "The number of ship classes in the pool", "number", "The number of ship classes.") @@ -1559,7 +1560,7 @@ ADE_INDEXER(l_Weapon_Pool, if (!ade_get_args(L, "*i|i", &idx, &amount)) return ADE_RETURN_NIL; - if (idx < 0 || idx > weapon_info_size()) { + if (idx < 1 || idx > weapon_info_size()) { return ADE_RETURN_NIL; }; @@ -1571,13 +1572,13 @@ ADE_INDEXER(l_Weapon_Pool, return ADE_RETURN_NIL; } if (amount < 0) { - Wl_pool[idx] = 0; + (*Wl_pool)[idx] = 0; } else { - Wl_pool[idx] = amount; + (*Wl_pool)[idx] = amount; } } - return ade_set_args(L, "i", Wl_pool[idx]); + return ade_set_args(L, "i", Wl_pool->value_or(idx, 0)); } ADE_FUNC(__len,