Add Give Equipment node for giving a specific PC an item,

possibly with modifiers (like equipping it)
This commit is contained in:
2015-06-24 01:47:12 -04:00
parent c30c9fca5f
commit 0fbb872b73
10 changed files with 116 additions and 21 deletions

View File

@@ -91,7 +91,7 @@ name
level level
morale morale
soul-crystal soul-crystal
give-item
monst-target monst-target
monst-attack monst-attack
monst-statistic monst-statistic

View File

@@ -222,20 +222,20 @@ Unused
Unused Unused
Special to Jump To Special to Jump To
-------------------- --------------------
Unused Node Give Equipment
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused Unused
Unused Unused
First part of message
Second part of message
Unused Unused
Special to call if inventory full
Unused Unused
Which item
Which enchantment (if weapon)
Number of charges (-1 = default)
ID? (-1 - normal, 0 - no, 1 - yes, 2 - full)
Cursed? (-1 - default, 0 - no, 1 - yes)
Equip? (-1 - no, 0 - soft, 1 - try, 2 - force)
Special to Jump To Special to Jump To
-------------------- --------------------
Affect Monster Target Affect Monster Target

View File

@@ -3254,6 +3254,31 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
// TODO: Verify this actually works! It's possible the monster ignores this and just recalculates its target each turn. // TODO: Verify this actually works! It's possible the monster ignores this and just recalculates its target each turn.
dynamic_cast<cCreature*>(pc)->target = spec.ex1a; dynamic_cast<cCreature*>(pc)->target = spec.ex1a;
break; break;
case eSpecType::GIVE_ITEM:
if(pc_num >= 100) break;
if(spec.ex1a >= 0 && spec.ex1a < univ.scenario.scen_items.size()) {
cItem to_give = univ.scenario.scen_items[spec.ex1a];
if(spec.ex1b >= 0 && spec.ex1b <= 6) {
// TODO: This array and accompanying calculation is now duplicated here, in start_town_mode(), and in place_buy_button()
const short aug_cost[10] = {4,7,10,8, 15,15,10, 0,0,0};
int val = max(aug_cost[spec.ex1b] * 100, to_give.value * (5 + aug_cost[spec.ex1b]));
to_give.enchant_weapon(eEnchant(spec.ex1b), val);
}
if(to_give.charges > 0 && spec.ex1c >= 0)
to_give.charges = spec.ex1c;
if(spec.ex2a == 1) to_give.ident = true;
else if(spec.ex2a == 0) to_give.ident = false;
if(spec.ex2b == 1) to_give.cursed = to_give.unsellable = true;
else if(spec.ex2b == 0) to_give.cursed = to_give.unsellable = false;
int equip_type = 0;
if(spec.ex2c == 0) equip_type = GIVE_EQUIP_SOFT;
else if(spec.ex2c == 1) equip_type = GIVE_EQUIP_TRY;
else if(spec.ex2c >= 2) equip_type = GIVE_EQUIP_FORCE;
for(i = 0; i < 6; i++)
if(pc_num == 6 || pc_num == i)
univ.party[i].give_item(to_give, equip_type | GIVE_ALLOW_OVERLOAD);
}
break;
default: default:
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!"); giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
break; break;

View File

@@ -445,9 +445,9 @@ int cParty::calc_day() const {
return (age / 3700) + 1; return (age / 3700) + 1;
} }
bool cParty::give_item(cItem item,bool do_print) { bool cParty::give_item(cItem item,int flags) {
for(int i = 0; i < 6; i++) { for(int i = 0; i < 6; i++) {
if(adven[i]->give_item(item,do_print)) if(adven[i]->give_item(item,flags))
return true; return true;
} }
return false; return false;

View File

@@ -182,7 +182,7 @@ public:
void writeTo(std::ostream& file) const; void writeTo(std::ostream& file) const;
void readFrom(std::istream& file); void readFrom(std::istream& file);
bool give_item(cItem item,bool do_print); bool give_item(cItem item,int flags);
bool forced_give(item_num_t item_num,eItemAbil abil,short dat = -1); bool forced_give(item_num_t item_num,eItemAbil abil,short dat = -1);
bool has_abil(eItemAbil abil, short dat = -1); bool has_abil(eItemAbil abil, short dat = -1);
bool take_abil(eItemAbil abil, short dat = -1); bool take_abil(eItemAbil abil, short dat = -1);

View File

@@ -419,8 +419,14 @@ void cPlayer::sort_items() {
} }
} }
bool cPlayer::give_item(cItem item, bool do_print, bool allow_overload) { bool cPlayer::give_item(cItem item, int flags) {
if(main_status != eMainStatus::ALIVE)
return false;
short free_space; short free_space;
bool do_print = flags & GIVE_DO_PRINT;
bool allow_overload = flags & GIVE_ALLOW_OVERLOAD;
int equip_type = flags & GIVE_EQUIP_FORCE;
if(item.variety == eItemType::NO_ITEM) if(item.variety == eItemType::NO_ITEM)
return true; return true;
@@ -476,6 +482,59 @@ bool cPlayer::give_item(cItem item, bool do_print, bool allow_overload) {
print_result(announce.str()); print_result(announce.str());
} }
if(equip_type != 0 && equippable.count(item.variety)) {
if(!equip_item(free_space, false) && equip_type != GIVE_EQUIP_SOFT) {
int exclude = 0;
if(num_hands_to_use.count(item.variety))
exclude = 100;
else exclude = excluding_types[item.variety];
int rem1 = 24, rem2 = 24;
for(int i = 0; i < 24; i++) {
if(i == free_space) continue;
if(!equip[i]) continue;
int check_exclude = 0;
if(num_hands_to_use.count(items[i].variety))
check_exclude = 100;
else check_exclude = excluding_types[items[i].variety];
if(exclude != check_exclude) continue;
if(exclude == 0 && item.variety != items[i].variety)
continue;
if(exclude == 100) {
if(rem1 == 24) {
if(item.variety == eItemType::ONE_HANDED || item.variety == eItemType::TWO_HANDED || rem2 < 24)
rem1 = i;
if(rem1 < 24) continue;
}
if(rem2 == 24) {
if(item.variety == eItemType::SHIELD || item.variety == eItemType::SHIELD_2 || rem1 < 24)
rem2 = i;
}
} else if(rem1 < 24)
rem1 = i;
}
bool can_rem1 = rem1 < 24 && (!items[rem1].cursed || equip_type == GIVE_EQUIP_FORCE);
bool can_rem2 = rem2 < 24 && (!items[rem2].cursed || equip_type == GIVE_EQUIP_FORCE);
if(exclude == 100) {
if(item.variety == eItemType::TWO_HANDED) {
if(can_rem1) equip[rem1] = false;
if(can_rem2) equip[rem2] = false;
} else if(item.variety == eItemType::ONE_HANDED) {
if(can_rem1) equip[rem1] = false;
else if(can_rem2) equip[rem2] = false;
} else { // It's a shield
if(can_rem2 && items[rem2].variety != item.variety)
equip[rem2] = false;
else if(can_rem1 && items[rem1].variety != item.variety)
equip[rem1] = false;
}
if((rem1 == weap_poisoned && !equip[rem1]) || (rem2 == weap_poisoned && !equip[rem2]))
status[eStatus::POISONED_WEAPON] = 0;
} else if(can_rem1)
equip[rem1] = false;
equip_item(free_space, false);
}
}
combine_things(); combine_things();
sort_items(); sort_items();
return true; return true;

View File

@@ -23,6 +23,15 @@ namespace legacy { struct pc_record_type; };
enum class eBuyStatus {OK, NO_SPACE, NEED_GOLD, TOO_HEAVY, HAVE_LOTS}; enum class eBuyStatus {OK, NO_SPACE, NEED_GOLD, TOO_HEAVY, HAVE_LOTS};
enum {
GIVE_DO_PRINT = 1,
GIVE_ALLOW_OVERLOAD = 2,
// These three are mutually exclusive:
GIVE_EQUIP_SOFT = 4,
GIVE_EQUIP_TRY = 8,
GIVE_EQUIP_FORCE = 12,
};
class cParty; class cParty;
class cPlayer : public iLiving { class cPlayer : public iLiving {
@@ -85,7 +94,7 @@ public:
void combine_things(); void combine_things();
void sort_items(); void sort_items();
bool give_item(cItem item, bool do_print, bool allow_overload = false); bool give_item(cItem item, int flags);
bool equip_item(int which_item, bool do_print); bool equip_item(int which_item, bool do_print);
bool unequip_item(int which_item, bool do_print); bool unequip_item(int which_item, bool do_print);
void take_item(int which_item); void take_item(int which_item);

View File

@@ -644,7 +644,7 @@ enum class eSpecType {
AFFECT_LEVEL = 91, AFFECT_LEVEL = 91,
AFFECT_MORALE = 92, AFFECT_MORALE = 92,
AFFECT_SOUL_CRYSTAL = 93, AFFECT_SOUL_CRYSTAL = 93,
UNUSED2 = 94, GIVE_ITEM = 94,
AFFECT_MONST_TARG = 95, AFFECT_MONST_TARG = 95,
AFFECT_MONST_ATT = 96, AFFECT_MONST_ATT = 96,
AFFECT_MONST_STAT = 97, AFFECT_MONST_STAT = 97,

View File

@@ -383,6 +383,7 @@ void cSpecial::append(legacy::special_node_type& old){
// j - Choose button to select a quest // j - Choose button to select a quest
// J - Choose button to select a quest status // J - Choose button to select a quest status
// < - Choose button to select a cardinal direction // < - Choose button to select a cardinal direction
// ~ - Choose button to select a weapon enchantment
// 0..9 - Choose button to select a specific type of picture // 0..9 - Choose button to select a specific type of picture
// (terrain, monster, dialog, talk, item, pc, field, boom, missile, status) // (terrain, monster, dialog, talk, item, pc, field, boom, missile, status)
static const char*const button_dict[7][11] = { static const char*const button_dict[7][11] = {
@@ -411,13 +412,13 @@ static const char*const button_dict[7][11] = {
"s s s S", // ex2b "s s s S", // ex2b
" ", // ex2c " ", // ex2c
}, { // affect pc nodes }, { // affect pc nodes
"mmmmmmmmmmmmm mmmmmmmmmmmmm", // msg1 "mmmmmmmmmmmmmmmmmmmmmmmmmmmm", // msg1
" ", // msg2 " ", // msg2
" M M ", // msg3 " M M ", // msg3
" 5 ", // pic " s 5 ", // pic
" s ", // pictype " s ", // pictype
" w q AP a ", // ex1a " w q i AP a ", // ex1a
" s", // ex1b " ~ s", // ex1b
" e Q ", // ex1c " e Q ", // ex1c
" CK E ", // ex2a " CK E ", // ex2a
" D ", // ex2b " D ", // ex2b

View File

@@ -874,6 +874,7 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
case '&': strt = STRT_SHOP; title = "Which shop?"; break; case '&': strt = STRT_SHOP; title = "Which shop?"; break;
case '%': strt = STRT_COST_ADJ; title = "What cost adjust?"; break; case '%': strt = STRT_COST_ADJ; title = "What cost adjust?"; break;
case '*': strt = STRT_CONTEXT; title = "What context?"; break; case '*': strt = STRT_CONTEXT; title = "What context?"; break;
case '~': strt = STRT_ENCHANT; title = "Which enchantment?"; break;
case '^': strt = STRT_POS_MODE; title = "Select positioning mode:"; break; case '^': strt = STRT_POS_MODE; title = "Select positioning mode:"; break;
case ':': strt = STRT_STAIR_MODE; title = "Select trigger limitations:"; break; case ':': strt = STRT_STAIR_MODE; title = "Select trigger limitations:"; break;
case 'w': strt = STRT_STATUS; title = "Select status:"; str_adj = 1; break; case 'w': strt = STRT_STATUS; title = "Select status:"; str_adj = 1; break;