Give item: more sensible button selection

This commit is contained in:
2025-03-19 20:22:23 -05:00
parent 85baeb454c
commit 1a85fc25ae
2 changed files with 66 additions and 31 deletions

View File

@@ -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<std::string>(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();

View File

@@ -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<std::string> choice_names = {}, boost::optional<short> 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);