Move abil_chart to be private to cItem and fix missing entries for summoning and quickfire abilities

This commit is contained in:
2019-11-23 21:37:25 -05:00
parent 4f785e2650
commit dc25cf6ffb
4 changed files with 82 additions and 55 deletions

View File

@@ -80,15 +80,6 @@ static void start_cartoon() {
cartoon_happening = true;
}
// 0 - can't use 1 - combat only 2 - town only 3 - town & combat only 4 - everywhere 5 - outdoor
// + 10 - mag. inept can use
std::map<eItemAbil, short> abil_chart = {
{eItemAbil::POISON_WEAPON,13}, {eItemAbil::AFFECT_STATUS,3}, {eItemAbil::BLISS_DOOM,3}, {eItemAbil::AFFECT_EXPERIENCE,4},
{eItemAbil::AFFECT_SKILL_POINTS,4}, {eItemAbil::AFFECT_HEALTH,4}, {eItemAbil::AFFECT_SPELL_POINTS,4},
{eItemAbil::LIGHT,13}, {eItemAbil::AFFECT_PARTY_STATUS,3}, {eItemAbil::HEALTH_POISON,4},
{eItemAbil::CALL_SPECIAL,4}, {eItemAbil::CAST_SPELL,4}, {eItemAbil::MESSAGE,14},
};
// which is unused
//short mode; // 0 - pre 1 - end by victory 2 - end by flight
// wanderin spec 99 -> generic spec
@@ -553,47 +544,19 @@ void use_spec_item(short item) {
void use_item(short pc,short item) {
bool take_charge = true,inept_ok = false;
short level,item_use_code,str,r1;
bool take_charge = true;
short level,str,r1;
short sp[3] = {}; // Dummy values to pass to run_special; not actually used
std::string str1, str2; // Used by books
eStatus status;
eItemUse type;
eSpell spell;
location user_loc;
eItemAbil abil = univ.party[pc].items[item].ability;
const cItem& item_rec = univ.party[pc].items[item];
eItemAbil abil = item_rec.ability;
bool inept_ok = !item_rec.use_magic();
level = univ.party[pc].items[item].item_level;
// TODO: Replace abil_chart with a cItem member function
item_use_code = abil_chart[abil];
if(item_use_code >= 10) {
item_use_code -= 10;
inept_ok = true;
}
if(abil == eItemAbil::AFFECT_STATUS) {
status = eStatus(univ.party[pc].items[item].abil_data[1]);
if(status == eStatus::POISON || status == eStatus::DISEASE || status == eStatus::HASTE_SLOW || status == eStatus:: BLESS_CURSE)
item_use_code = 4;
} else if(abil == eItemAbil::CAST_SPELL) {
spell = eSpell(univ.party[pc].items[item].abil_data[1]);
int when = (*spell).when_cast;
// Rather than trying to translate the spell's "when cast" value to the less expressive item_use_code,
// simply check if it's useable in the current context.
if(is_out() && when & WHEN_OUTDOORS)
item_use_code = 5;
else if(is_town() && when & WHEN_TOWN)
item_use_code = 2;
else if(is_combat() && when & WHEN_COMBAT)
item_use_code = 1;
else {
// It's not useable in the current context, so translate to the item_use_code that gives the best error message
if(is_town() || is_out())
item_use_code = 1;
else item_use_code = 2;
}
} else if(abil == eItemAbil::AFFECT_PARTY_STATUS && univ.party[pc].items[item].abil_data[1] == int(ePartyStatus::FLIGHT))
item_use_code = 5;
if(is_out())
user_loc = univ.party.out_loc;
if(is_town())
@@ -601,7 +564,7 @@ void use_item(short pc,short item) {
if(is_combat())
user_loc = univ.current_pc().combat_pos;
if(item_use_code == 0) {
if(!item_rec.can_use()) {
add_string_to_buf("Use: Can't use this item.");
take_charge = false;
}
@@ -610,25 +573,23 @@ void use_item(short pc,short item) {
take_charge = false;
}
// 0 - can't use 1 - combat only 2 - town only 3 - town & combat only 4 - everywhere 5 - outdoor
if(take_charge) {
if(overall_mode == MODE_OUTDOORS && item_use_code < 4) {
if(overall_mode == MODE_OUTDOORS && !item_rec.use_outdoors()) {
add_string_to_buf("Use: Not while outdoors.");
take_charge = false;
}
// TODO: Almost all of these look wrong!
if((overall_mode == MODE_TOWN) && (item_use_code == 1)) {
if((overall_mode != MODE_OUTDOORS) && !item_rec.use_in_town() && !item_rec.use_in_combat()){
add_string_to_buf("Use: Only outdoors.");
take_charge = false;
}
if((overall_mode == MODE_TOWN) && !item_rec.use_in_town()) {
add_string_to_buf("Use: Not while in town.");
take_charge = false;
}
if((overall_mode == MODE_COMBAT) && (item_use_code == 2)) {
if((overall_mode == MODE_COMBAT) && !item_rec.use_in_combat()) {
add_string_to_buf("Use: Not in combat.");
take_charge = false;
}
if((overall_mode != MODE_OUTDOORS) && (item_use_code == 5)){
add_string_to_buf("Use: Only outdoors.");
take_charge = false;
}
}
if(take_charge) {
cItem& the_item = univ.party[pc].items[item];

View File

@@ -72,7 +72,6 @@ extern enum_map(eItemButton, bool) item_area_button_active[8];
extern enum_map(ePlayerButton, bool) pc_area_button_active[6];
extern rectangle item_screen_button_rects[9];
extern std::vector<int> spec_item_array;
extern std::map<eItemAbil, short> abil_chart;
// combat globals
extern short item_bottom_button_active[9];
extern cUniverse univ;
@@ -322,7 +321,7 @@ void put_item_screen(eItemWinMode screen_num) {
if((stat_screen_mode == MODE_SHOP) &&
((is_town()) || (is_out()) || ((is_combat()) && (pc == univ.cur_pc)))) { // place give and drop and use
place_item_graphic(i,univ.party[pc].items[i_num].graphic_num);
if(abil_chart[univ.party[pc].items[i_num].ability]) // place use if can
if(item.can_use()) // place use if can
place_item_button(ITEMBTN_NORM,i);
else place_item_button(ITEMBTN_ALL,i);
}
@@ -333,7 +332,7 @@ void put_item_screen(eItemWinMode screen_num) {
((is_town()) || (is_out()) || ((is_combat()) && (pc == univ.cur_pc)))) { // place give and drop and use
place_item_button(1,i,ITEMBTN_GIVE);
place_item_button(2,i,ITEMBTN_DROP);
if(abil_chart[item.ability]) // place use if can
if(item.can_use()) // place use if can
place_item_button(0,i,ITEMBTN_USE);
}
}

View File

@@ -1358,3 +1358,65 @@ void cItem::readFrom(std::istream& sin){
else if(cur == "UNSELLABLE") unsellable = true;
}
}
enum {USE_COMBAT = 1, USE_TOWN = 2, USE_OUTDOORS = 4, USE_MAGIC = 8};
std::map<eItemAbil, short> abil_chart = {
{eItemAbil::POISON_WEAPON, USE_TOWN | USE_COMBAT},
{eItemAbil::AFFECT_STATUS, USE_TOWN | USE_COMBAT | USE_MAGIC}, // This is the default, some statuses can also be used outdoors though
// CAST_SPELL is omitted, taken from the spell's info
{eItemAbil::BLISS_DOOM, USE_TOWN | USE_COMBAT | USE_MAGIC},
{eItemAbil::AFFECT_EXPERIENCE, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::AFFECT_SKILL_POINTS, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::AFFECT_HEALTH, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::AFFECT_SPELL_POINTS, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::LIGHT, USE_TOWN | USE_COMBAT},
{eItemAbil::AFFECT_PARTY_STATUS, USE_TOWN | USE_COMBAT | USE_MAGIC},
{eItemAbil::HEALTH_POISON, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::CALL_SPECIAL, USE_TOWN | USE_COMBAT | USE_OUTDOORS | USE_MAGIC},
{eItemAbil::SUMMONING, USE_TOWN | USE_COMBAT | USE_MAGIC},
{eItemAbil::MASS_SUMMONING, USE_TOWN | USE_COMBAT | USE_MAGIC},
{eItemAbil::QUICKFIRE, USE_TOWN | USE_COMBAT | USE_MAGIC},
{eItemAbil::MESSAGE, USE_TOWN | USE_COMBAT | USE_OUTDOORS},
};
bool cItem::use_in_combat() const {
if(ability == eItemAbil::CAST_SPELL) {
auto spell = eSpell(abil_data[1]);
int when = (*spell).when_cast;
return when & WHEN_COMBAT;
} else if(ability == eItemAbil::AFFECT_PARTY_STATUS && abil_data[1] == int(ePartyStatus::FLIGHT))
return false;
return abil_chart[ability] & USE_COMBAT;
}
bool cItem::use_in_town() const {
if(ability == eItemAbil::CAST_SPELL) {
auto spell = eSpell(abil_data[1]);
int when = (*spell).when_cast;
return when & WHEN_TOWN;
} else if(ability == eItemAbil::AFFECT_PARTY_STATUS && abil_data[1] == int(ePartyStatus::FLIGHT))
return false;
return abil_chart[ability] & USE_TOWN;
}
bool cItem::use_outdoors() const {
if(ability == eItemAbil::CAST_SPELL) {
auto spell = eSpell(abil_data[1]);
int when = (*spell).when_cast;
return when & WHEN_OUTDOORS;
} else if(ability == eItemAbil::AFFECT_STATUS) {
auto status = eStatus(abil_data[1]);
if(status == eStatus::POISON || status == eStatus::DISEASE || status == eStatus::HASTE_SLOW || status == eStatus:: BLESS_CURSE)
return true;
}
return abil_chart[ability] & USE_OUTDOORS;
}
bool cItem::use_magic() const {
return abil_chart[ability] & USE_MAGIC;
}
bool cItem::can_use() const {
return use_in_town() || use_in_combat() || use_outdoors();
}

View File

@@ -52,6 +52,11 @@ public:
void enchant_weapon(eEnchant enchant_type, short new_val);
bool abil_harms() const;
bool abil_group() const;
bool can_use() const;
bool use_in_combat() const;
bool use_in_town() const;
bool use_outdoors() const;
bool use_magic() const;
cItem();
explicit cItem(long preset);