From 9ca2f05c0b0c4b9a55aa45a9aca35f1b9c01c75c Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Thu, 6 Mar 2025 20:26:25 -0600 Subject: [PATCH] Don't display 'no item' response if another PC can shop. (#679) These are the rules: - If the active PC gets an empty shop, iterate from the first to last PC until finding someone who can see a shop item - If none can shop, show the 'no item' response - When the active PC buys something, if this clears out the shop, iterate from the first to last PC until finding someone who can see a shop item - if none can see an item, stay on the empty shop of the PC that was active when the last item was bought. - When shopping ends, if the shop interface was the last thing to change the player's active PC, it puts it back how it was. Fix #669 --- src/game/boe.actions.cpp | 8 ++++++ src/game/boe.dlgutil.cpp | 62 ++++++++++++++++++++++++++++++++++------ src/game/boe.dlgutil.hpp | 2 +- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp index 435fa45b..f8e9f7c5 100644 --- a/src/game/boe.actions.cpp +++ b/src/game/boe.actions.cpp @@ -895,6 +895,14 @@ void handle_switch_pc(short which_pc, bool& need_redraw, bool& need_reprint) { add_string_to_buf("Set active: PC must be here & active."); else { univ.cur_pc = which_pc; + + // The shop interface may have taken control of the active PC. If the player + // manually sets active PC before shopping ends, don't restore the active PC from before + // shopping switched it. Unless the player buys something again, forcing it to store again. + extern short store_cur_pc; + if(store_cur_pc != -1) + store_cur_pc = -1; + set_stat_window_for_pc(which_pc); add_string_to_buf("Now " + std::string(overall_mode == MODE_SHOPPING ? "shopping" : "active") + ": " + pc.name); adjust_spell_menus(); diff --git a/src/game/boe.dlgutil.cpp b/src/game/boe.dlgutil.cpp index d2d8ff27..a8e62444 100644 --- a/src/game/boe.dlgutil.cpp +++ b/src/game/boe.dlgutil.cpp @@ -98,8 +98,38 @@ std::vector shop_array; cShop active_shop; short active_shop_num; +short store_cur_pc = -1; -bool start_shop_mode(short which,short cost_adj,std::string store_name, bool cancel_when_empty) { +// For healing shops, other PCs might be able to buy something if +// the active PC can't +bool start_shop_mode_other_pc(bool allow_empty = false) { + // The shop might change the current PC multiple times, but we want to restore + // it to the original active PC when shopping ends, so only store if we're + // not yet storing + if(store_cur_pc == -1) + store_cur_pc = univ.cur_pc; + + // But I actually want to store the PC that's active now, so if no one can buy anything but + // we want to leave an empty shop, we can leave the PC selection where it is. + short pc_buying = univ.cur_pc; + + bool other_pc_can_buy = false; + for(int i = 0; i < 6; ++i){ + if(univ.party[i].main_status != eMainStatus::ABSENT){ + univ.cur_pc = i; + if(start_shop_mode(active_shop_num,active_shop.getCostAdjust(),save_talk_str1,true,true)){ + other_pc_can_buy = true; + break; + } + } + } + if(!other_pc_can_buy && allow_empty){ + start_shop_mode(active_shop_num,active_shop.getCostAdjust(),save_talk_str1,false,true); + } + return other_pc_can_buy; +} + +bool start_shop_mode(short which,short cost_adj,std::string store_name, bool cancel_when_empty, bool already_started) { rectangle area_rect; if(which < 0 || which >= univ.scenario.shops.size()) { showError("The scenario tried to place you in a nonexistent shop!"); @@ -138,7 +168,8 @@ bool start_shop_mode(short which,short cost_adj,std::string store_name, bool can area_rect = talk_area_rect; talk_gworld().create(area_rect.width(), area_rect.height()); - store_pre_shop_mode = overall_mode; + if(!already_started) + store_pre_shop_mode = overall_mode; overall_mode = MODE_SHOPPING; stat_screen_mode = MODE_SHOP; shop_sbar->setPosition(0); @@ -167,6 +198,11 @@ void end_shop_mode() { record_action("end_shop_mode", ""); } + if(store_cur_pc >= 0){ + univ.cur_pc = store_cur_pc; + store_cur_pc = -1; + } + rectangle dummy_rect = {0,0,0,0}; // This would be a place to show the text box, if I add it (and if this is not an outdoor shop). @@ -427,8 +463,12 @@ void handle_sale(int i) { // This looks to be redundant, but I'm just preserving the previous behavior of the code. set_up_shop_array(); draw_shop_graphics(false,false,{}); -} + // When buying from a healer, we want to select the next PC who needs healing + if(shop_array.empty()){ + start_shop_mode_other_pc(true); + } +} void handle_info_request(int what_picked) { if(recording){ @@ -899,12 +939,16 @@ void handle_talk_node(int which_talk_entry) { case eTalkNode::SHOP: if(!start_shop_mode(b,a,save_talk_str1,true)){ - // Second string of shop talk node: Custom message for when shop is empty - if(!save_talk_str2.empty()){ - save_talk_str1 = save_talk_str2; - save_talk_str2 = ""; - }else{ - save_talk_str1 = "There is nothing available to buy."; + if(!start_shop_mode_other_pc()){ + univ.cur_pc = store_cur_pc; + + // Second string of shop talk node: Custom message for when shop is empty + if(!save_talk_str2.empty()){ + save_talk_str1 = save_talk_str2; + save_talk_str2 = ""; + }else{ + save_talk_str1 = "There is nothing available to buy."; + } } }else{ can_save_talk = false; diff --git a/src/game/boe.dlgutil.hpp b/src/game/boe.dlgutil.hpp index 54f74ad0..3367da60 100644 --- a/src/game/boe.dlgutil.hpp +++ b/src/game/boe.dlgutil.hpp @@ -5,7 +5,7 @@ #include "dialogxml/dialogs/dialog.hpp" #include "scenario/shop.hpp" -bool start_shop_mode(short which,short cost_adj,std::string store_name, bool cancel_when_empty = false); +bool start_shop_mode(short which,short cost_adj,std::string store_name, bool cancel_when_empty = false, bool already_started = false); void end_shop_mode(); bool handle_shop_event(location p, cFramerateLimiter& fps_limiter); void handle_sale(int i);