diff --git a/src/game/boe.items.cpp b/src/game/boe.items.cpp index cd7caf9d..242d64df 100644 --- a/src/game/boe.items.cpp +++ b/src/game/boe.items.cpp @@ -181,23 +181,27 @@ bool place_item(cItem item,location where,bool contained) { return univ.town.items.back().contained; } +cItem item_store; + void give_thing(short pc_num, short item_num) { short who_to,how_many = 0; - cItem item_store; bool take_given_item = true; if(univ.party[pc_num].equip[item_num] && univ.party[pc_num].items[item_num].cursed) add_string_to_buf("Give: Item is cursed."); else { item_store = univ.party[pc_num].items[item_num]; - who_to = select_pc(eSelectPC::ONLY_LIVING_WITH_ITEM_SLOT,"Give item to who?"); - if((overall_mode == MODE_COMBAT) && !adjacent(univ.party[pc_num].combat_pos,univ.party[who_to].combat_pos)) { - add_string_to_buf("Give: Must be adjacent."); - who_to = 6; + who_to = select_pc(eSelectPC::ONLY_CAN_GIVE_FROM_ACTIVE,"Give item to who?"); + // No party members can receive the item: + if(who_to == 8){ + if(overall_mode == MODE_COMBAT){ + ASB("Can't give: must be adjacent with enough carrying capacity.", 2); + }else{ + ASB("Can't give: no one has the carrying capacity.", 2); + } } - if((who_to < 6) && (who_to != pc_num) - && ((overall_mode != MODE_COMBAT) || (adjacent(univ.party[pc_num].combat_pos,univ.party[who_to].combat_pos)))) { + if((who_to < 6) && (who_to != pc_num)) { if((item_store.type_flag > 0) && (item_store.charges > 1)) { how_many = get_num_of_items(item_store.charges); if(how_many == 0) @@ -208,23 +212,10 @@ void give_thing(short pc_num, short item_num) { item_store.charges = how_many; } eBuyStatus give_status = univ.party[who_to].give_item(item_store,0); - switch(give_status){ - case eBuyStatus::OK: - if(take_given_item){ - univ.party[pc_num].take_item(item_num); - } - break; - case eBuyStatus::NO_SPACE: - ASB("Can't give: PC has max. # of items."); - if(false) // Skip first line of fallthrough - case eBuyStatus::TOO_HEAVY: - ASB("Can't give: PC carrying too much."); - // Can't give to the recipient. Put charges back in giver's inventory: - if(how_many > 0) - univ.party[pc_num].items[item_num].charges += how_many; - break; - default: - break; + if(give_status != eBuyStatus::OK){ + // This should be impossible, because select_pc() already checked that the options + // were viable. + showFatalError("Unexpectedly failed to give item!"); } } } @@ -941,15 +932,44 @@ short select_pc(eSelectPC mode, std::string title, bool allow_choose_all) { if(!title.empty()) selectPc["title"].setText(title); + bool any_options = false; for(short i = 0; i < 6; i++) { std::string n = boost::lexical_cast(i + 1); bool can_pick = true; + std::string disabled_reason = ""; if(univ.party[i].main_status == eMainStatus::ABSENT || univ.party[i].main_status == eMainStatus::FLED) can_pick = false; + else switch(mode) { - case eSelectPC::ONLY_LIVING_WITH_ITEM_SLOT: - if(!univ.party[i].has_space()) + case eSelectPC::ONLY_CAN_GIVE_FROM_ACTIVE: + if(i == univ.cur_pc){ can_pick = false; + break; + } + if((overall_mode == MODE_COMBAT) && !adjacent(univ.party[univ.cur_pc].combat_pos,univ.party[i].combat_pos)) { + can_pick = false; + disabled_reason = "too far away"; + break; + } + BOOST_FALLTHROUGH; + case eSelectPC::ONLY_CAN_GIVE: + switch(univ.party[i].can_give_item(item_store)){ + case eBuyStatus::TOO_HEAVY: + disabled_reason = "item too heavy"; + if(false) // skip first line of fallthrough + case eBuyStatus::NO_SPACE: + disabled_reason = "no item slot"; + can_pick = false; + break; + default: + break; + } + break; + case eSelectPC::ONLY_LIVING_WITH_ITEM_SLOT: + if(!univ.party[i].has_space()){ + can_pick = false; + disabled_reason = "no item slot"; + } BOOST_FALLTHROUGH; case eSelectPC::ONLY_LIVING: if(univ.party[i].main_status != eMainStatus::ALIVE) @@ -963,14 +983,22 @@ short select_pc(eSelectPC mode, std::string title, bool allow_choose_all) { default: break; } + selectPc["pc" + n].setText(univ.party[i].name); if(!can_pick) { selectPc["pick" + n].hide(); - selectPc["pc" + n].hide(); + if(disabled_reason.empty()) + selectPc["pc" + n].hide(); + else + selectPc["pc" + n].appendText(": " + disabled_reason); } else { - selectPc["pc" + n].setText(univ.party[i].name); + any_options = true; } } + if(!any_options){ + return 8; + } + if(!allow_choose_all){ selectPc["pick-all"].hide(); selectPc["all"].hide(); diff --git a/src/game/boe.items.hpp b/src/game/boe.items.hpp index 20fa46f7..730c6078 100644 --- a/src/game/boe.items.hpp +++ b/src/game/boe.items.hpp @@ -42,10 +42,17 @@ std::string get_text_response(std::string prompt = "", pic_num_t pic = 16); short get_num_response(short min, short max, std::string prompt, std::vector choice_names = {}, boost::optional cancel_value = boost::none); enum class eSelectPC { - ONLY_LIVING, ANY, + ONLY_LIVING, + ONLY_LIVING_WITH_ITEM_SLOT, + // Slightly different from the previous: this now checks not just for a slot, + // but also for carrying capacity, and will stack charges even if all slots are full. + // When you use this, you have to set the global item_store to your item, first. + ONLY_CAN_GIVE, + // Same as the previous, but in combat, only show *adjacent* living PCs who can take the item. + ONLY_CAN_GIVE_FROM_ACTIVE, ONLY_DEAD, - ONLY_LIVING_WITH_ITEM_SLOT }; -// Prompt the player to choose a party member. Returns 0-5 for a pc, 6 for cancel, or 7 for all. +// Prompt the player to choose a party member. Returns 0-5 for a pc, 6 for cancel, 7 for all, or 8 if no PCs fit the mode's filter. +// Pass a string poiner to no_choice_reason to get the reason why no choices were available, if none are. short select_pc(eSelectPC mode, std::string title="", bool allow_choose_all = false);