Fix off-by-one in save slot memory

Save menus have a non-selectable first element used to allocate extra
space for the save game's embedded screenshot.  The memorized save game
slot failed to account for this, causing the game to suggest a slot one
less than the last used slot.  Attentive users could override the
suggestion, but the game should suggest the correct slot automatically.

Reported-by: ziplantil <https://github.com/dxx-rebirth/dxx-rebirth/issues/524>
This commit is contained in:
Kp 2020-07-22 03:11:18 +00:00
parent d7bc4fb0df
commit 1d24a2f942

View file

@ -754,6 +754,7 @@ namespace {
//-------------------------------------------------------------------
struct state_userdata
{
static constexpr std::integral_constant<unsigned, 1> decorative_item_count = {};
unsigned citem;
std::array<grs_bitmap_ptr, NUM_SAVES> sc_bmp;
};
@ -769,7 +770,8 @@ static int state_callback(newmenu *menu,const d_event &event, state_userdata *co
userdata->citem = static_cast<const d_select_event &>(event).citem;
else if (event.type == EVENT_NEWMENU_DRAW && (citem = newmenu_get_citem(menu)) > 0)
{
if ( sc_bmp[citem-1] ) {
if (sc_bmp[citem - userdata->decorative_item_count])
{
const auto &&fspacx = FSPACX();
const auto &&fspacy = FSPACY();
#if !DXX_USE_OGL
@ -822,10 +824,11 @@ namespace dsx {
static d_game_unique_state::save_slot state_get_savegame_filename(d_game_unique_state::savegame_file_path &fname, d_game_unique_state::savegame_description *const dsc, const char *const caption, const blind_save entry_blind)
{
int version, nsaves;
std::array<newmenu_item, NUM_SAVES + 1> m;
std::array<d_game_unique_state::savegame_file_path, NUM_SAVES> filename;
std::array<d_game_unique_state::savegame_description, NUM_SAVES> desc;
state_userdata userdata;
constexpr auto decorative_item_count = userdata.decorative_item_count;
std::array<newmenu_item, NUM_SAVES + decorative_item_count> m;
auto &sc_bmp = userdata.sc_bmp;
char id[4];
int valid;
@ -837,11 +840,12 @@ static d_game_unique_state::save_slot state_get_savegame_filename(d_game_unique_
* saves should not access the last slot. The last slot is reserved
* for autosaves.
*/
const unsigned max_slots_shown = dsc ? m.size() - 2 : m.size() - 1;
const unsigned max_slots_shown = (dsc ? m.size() - 1 : m.size()) - decorative_item_count;
range_for (const unsigned i, xrange(max_slots_shown))
{
state_format_savegame_filename(filename[i], i);
valid = 0;
auto &mi = m[i + decorative_item_count];
if (const auto fp = PHYSFSX_openReadBuffered(filename[i].data()))
{
//Read id
@ -859,7 +863,7 @@ static d_game_unique_state::save_slot state_get_savegame_filename(d_game_unique_
PHYSFS_read(fp, desc[i].data(), desc[i].size(), 1);
desc[i].back() = 0;
if (!dsc)
m[i + 1].type = NM_TYPE_MENU;
mi.type = NM_TYPE_MENU;
// Read thumbnail
sc_bmp[i] = gr_create_bitmap(THUMBNAIL_W,THUMBNAIL_H );
PHYSFS_read(fp, sc_bmp[i]->get_bitmap_data(), THUMBNAIL_W * THUMBNAIL_H, 1);
@ -875,13 +879,12 @@ static d_game_unique_state::save_slot state_get_savegame_filename(d_game_unique_
}
}
}
auto &mi = m[i + 1];
mi.text = desc[i].data();
if (!valid) {
strcpy(desc[i].data(), TXT_EMPTY);
if (!dsc)
mi.type = NM_TYPE_TEXT;
}
mi.text = desc[i].data();
if (dsc)
{
mi.type = NM_TYPE_INPUT_MENU;
@ -911,10 +914,10 @@ static d_game_unique_state::save_slot state_get_savegame_filename(d_game_unique_
? quicksave_selection
: (
userdata.citem = 0,
newmenu_do2(nullptr, caption, max_slots_shown + 1, m.data(), state_callback, &userdata, GameUniqueState.valid_save_slot(quicksave_selection) ? static_cast<unsigned>(quicksave_selection) : 0, nullptr),
newmenu_do2(nullptr, caption, max_slots_shown + decorative_item_count, m.data(), state_callback, &userdata, (GameUniqueState.valid_save_slot(quicksave_selection) ? static_cast<unsigned>(quicksave_selection) : 0) + decorative_item_count, nullptr),
userdata.citem == 0
? d_game_unique_state::save_slot::None
: static_cast<d_game_unique_state::save_slot>(userdata.citem - 1)
: static_cast<d_game_unique_state::save_slot>(userdata.citem - decorative_item_count)
);
if (valid_selection(choice))
@ -1082,7 +1085,7 @@ int state_save_all(const secret_save secret, const blind_save blind_save)
const int rval = state_save_all_sub(filename, desc.data());
if (rval && secret == secret_save::none)
HUD_init_message_literal(HM_DEFAULT, "Game saved");
HUD_init_message(HM_DEFAULT, "Game saved to \"%s\": \"%s\"", filename, desc.data());
return rval;
}