diff --git a/proj/vs2017/Common/Common.vcxproj b/proj/vs2017/Common/Common.vcxproj index eb8d5be2..4fa044c8 100644 --- a/proj/vs2017/Common/Common.vcxproj +++ b/proj/vs2017/Common/Common.vcxproj @@ -389,6 +389,7 @@ + diff --git a/proj/vs2017/Common/Common.vcxproj.filters b/proj/vs2017/Common/Common.vcxproj.filters index a2f34252..d9565515 100644 --- a/proj/vs2017/Common/Common.vcxproj.filters +++ b/proj/vs2017/Common/Common.vcxproj.filters @@ -718,6 +718,7 @@ + @@ -955,6 +956,7 @@ + diff --git a/proj/xc12/BoE.xcodeproj/project.pbxproj b/proj/xc12/BoE.xcodeproj/project.pbxproj index f4e64a33..77c12586 100755 --- a/proj/xc12/BoE.xcodeproj/project.pbxproj +++ b/proj/xc12/BoE.xcodeproj/project.pbxproj @@ -106,6 +106,8 @@ 9153C7A01A994A1700D7F8A7 /* SFML.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; }; 915473BF2C7E11B900EB1C94 /* damage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473BE2C7E11B900EB1C94 /* damage.cpp */; }; 915473C62C7FCDBB00EB1C94 /* alchemy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473C52C7FCDBB00EB1C94 /* alchemy.cpp */; }; + 915473CE2C800AB000EB1C94 /* enchant.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 915473CC2C800AB000EB1C94 /* enchant.hpp */; }; + 915473CF2C800AB000EB1C94 /* enchant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473CD2C800AB000EB1C94 /* enchant.cpp */; }; 915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B13A81BBE2B54009905A4 /* scrollpane.cpp */; }; 9176FEC71D550EFE006EF694 /* out_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9176FEC01D550EFC006EF694 /* out_legacy.cpp */; }; 9176FEC81D550EFE006EF694 /* scen_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9176FEC11D550EFC006EF694 /* scen_legacy.cpp */; }; @@ -694,6 +696,8 @@ 915325181A2E37EE000A9A1C /* special_parse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = special_parse.cpp; sourceTree = ""; }; 915473BE2C7E11B900EB1C94 /* damage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = damage.cpp; sourceTree = ""; }; 915473C52C7FCDBB00EB1C94 /* alchemy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = alchemy.cpp; sourceTree = ""; }; + 915473CC2C800AB000EB1C94 /* enchant.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = enchant.hpp; sourceTree = ""; }; + 915473CD2C800AB000EB1C94 /* enchant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = enchant.cpp; sourceTree = ""; }; 91574CC323CB97C5004766F8 /* enum_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = enum_map.hpp; sourceTree = ""; }; 91597A6C1A3BED2D00BE7BF9 /* spell.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = spell.hpp; sourceTree = ""; }; 91597A6E1A3BEDC700BE7BF9 /* spell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spell.cpp; sourceTree = ""; }; @@ -1335,6 +1339,7 @@ children = ( 915473C52C7FCDBB00EB1C94 /* alchemy.cpp */, 915473BE2C7E11B900EB1C94 /* damage.cpp */, + 915473CD2C800AB000EB1C94 /* enchant.cpp */, 91279BE10F9D0F73007B0D52 /* location.cpp */, 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */, 915325161A2E1DA8000A9A1C /* oldstructs.cpp */, @@ -1345,6 +1350,7 @@ 91B0D5D01E34428E002BE4DA /* view_dialogs.cpp */, 9185BD9B1EA02B8F0027C346 /* alchemy.hpp */, 9185BD961EA0234A0027C346 /* damage.hpp */, + 915473CC2C800AB000EB1C94 /* enchant.hpp */, 9185BD991EA027B80027C346 /* fields.hpp */, 9185BDA01EA02FF80027C346 /* global.hpp */, 91279BE00F9D0F73007B0D52 /* location.hpp */, @@ -1664,6 +1670,7 @@ 9149924E25913E3F00B5BE97 /* led.hpp in Headers */, 9143044B2970EDC1003A3967 /* keymods.hpp in Headers */, 9149925025913E3F00B5BE97 /* ledgroup.hpp in Headers */, + 915473CE2C800AB000EB1C94 /* enchant.hpp in Headers */, 91499254259140FF00B5BE97 /* keycodes.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2078,6 +2085,7 @@ 919CC27E1B37743B00273FDA /* undo.cpp in Sources */, 919CC27F1B37744000273FDA /* winutil.mac.mm in Sources */, D384F6A32C1B9D4000A806C3 /* replay.cpp in Sources */, + 915473CF2C800AB000EB1C94 /* enchant.cpp in Sources */, 915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */, 91E128E71BC1E6DD00C8BE1D /* basicbtns.cpp in Sources */, 91E128ED1BC2076B00C8BE1D /* 3choice.cpp in Sources */, diff --git a/rsrc/schemas/town.xsd b/rsrc/schemas/town.xsd index 5e3404de..6f2f6552 100644 --- a/rsrc/schemas/town.xsd +++ b/rsrc/schemas/town.xsd @@ -17,6 +17,17 @@ + + + + + + + + + + + @@ -129,7 +140,7 @@ - + @@ -211,4 +222,4 @@ - \ No newline at end of file + diff --git a/src/enchant.cpp b/src/enchant.cpp new file mode 100644 index 00000000..85d50881 --- /dev/null +++ b/src/enchant.cpp @@ -0,0 +1,76 @@ +// +// enchant.cpp +// BoE +// +// Created by Celtic Minstrel on 2023-08-28. +// +// + +#include "enchant.hpp" +#include "mathutil.hpp" + +std::map cEnchant::dictionary; + +cEnchant::cEnchant(eEnchant id, std::string suf) : id(id), suffix(suf) {} + +cEnchant& cEnchant::withCost(short cost) { + aug_cost = cost; + return *this; +} + +cEnchant& cEnchant::withBonus(int bonus) { + add_bonus = bonus; + return *this; +} + +cEnchant& cEnchant::withAbility(eItemAbil abil, unsigned int stren) { + add_ability = abil; + abil_strength = stren; + return *this; +} + +cEnchant& cEnchant::withAbility(eItemAbil abil, unsigned int stren, eSpell spell) { + withAbility(abil, stren); + abil_data.spell = spell; + return *this; +} + +cEnchant& cEnchant::withAbility(eItemAbil abil, unsigned int stren, eDamageType dmg) { + withAbility(abil, stren); + abil_data.damage = dmg; + return *this; +} + +cEnchant& cEnchant::withAbility(eItemAbil abil, unsigned int stren, eStatus status) { + withAbility(abil, stren); + abil_data.status = status; + return *this; +} + +cEnchant& cEnchant::withCharges(int c) { + charges = c; + return *this; +} + +const cEnchant& cEnchant::finish() { + dictionary.emplace(id, *this); + return *this; +} + +int cEnchant::adjust_value(int initial_value) const { + return max(aug_cost * 100, initial_value * (5 + aug_cost)); +} + +const cEnchant& operator* (eEnchant ench) { + static cEnchant none{eEnchant::NONE, ""}; + if(ench == eEnchant::NONE) return none; + return cEnchant::dictionary.at(ench); +} + +cEnchant E_PLUS_ONE = cEnchant(eEnchant::PLUS_ONE, "+1").withCost(4).withBonus(1).finish(); +cEnchant E_PLUS_TWO = cEnchant(eEnchant::PLUS_TWO, "+2").withCost(7).withBonus(2).finish(); +cEnchant E_PLUS_THREE = cEnchant(eEnchant::PLUS_THREE, "+3").withCost(10).withBonus(3).finish(); +cEnchant E_SHOOT_FLAME = cEnchant(eEnchant::SHOOT_FLAME, "F").withCost(8).withAbility(eItemAbil::CAST_SPELL, 5, eSpell::FLAME).withCharges(8).finish(); +cEnchant E_FLAMING = cEnchant(eEnchant::FLAMING, "F!").withCost(15).withAbility(eItemAbil::DAMAGING_WEAPON, 5, eDamageType::FIRE).finish(); +cEnchant E_PLUS_FIVE = cEnchant(eEnchant::PLUS_FIVE, "+5").withCost(15).withBonus(5).finish(); +cEnchant E_BLESSED = cEnchant(eEnchant::BLESSED, "B").withCost(10).withBonus(1).withAbility(eItemAbil::AFFECT_STATUS, 5, eStatus::BLESS_CURSE); diff --git a/src/enchant.hpp b/src/enchant.hpp new file mode 100644 index 00000000..5cd0082c --- /dev/null +++ b/src/enchant.hpp @@ -0,0 +1,61 @@ +// +// enchant.hpp +// BoE +// +// Created by Celtic Minstrel on 2023-08-28. +// +// + +#ifndef BoE_ENCHANT_HPP +#define BoE_ENCHANT_HPP + +#include +#include +#include +#include "damage.hpp" +#include "scenario/item_abilities.hpp" +#include "spell.hpp" + +enum class eEnchant { + NONE = -1, + PLUS_ONE, + PLUS_TWO, + PLUS_THREE, + SHOOT_FLAME, + FLAMING, + PLUS_FIVE, + BLESSED, +}; + +class cEnchant { + static std::map dictionary; + friend const cEnchant& operator* (eEnchant ench); +public: + static const int MAX = int(eEnchant::BLESSED); + cEnchant(eEnchant id, std::string suf); + cEnchant& withCost(short cost); + cEnchant& withBonus(int bonus); + cEnchant& withAbility(eItemAbil abil, unsigned int stren); + cEnchant& withAbility(eItemAbil abil, unsigned int stren, eSpell spell); + cEnchant& withAbility(eItemAbil abil, unsigned int stren, eDamageType dmg); + cEnchant& withAbility(eItemAbil abil, unsigned int stren, eStatus status); + cEnchant& withCharges(int charges); + const cEnchant& finish(); + eEnchant id; + std::string suffix; + short aug_cost; + int add_bonus = 0; + eItemAbil add_ability = eItemAbil::NONE; + unsigned int abil_strength = 0; + uItemAbilData abil_data; + int charges = 0; + int adjust_value(int initial_value) const; +}; + +// Need to declare this a second time in order for it to be in scope where it's needed +const cEnchant& operator* (eEnchant ench); + +std::ostream& operator<< (std::ostream& out, eEnchant ench); +std::istream& operator>> (std::istream& in, eEnchant& ench); + +#endif diff --git a/src/fileio/estreams.cpp b/src/fileio/estreams.cpp index 4a764f70..4349f2f0 100644 --- a/src/fileio/estreams.cpp +++ b/src/fileio/estreams.cpp @@ -743,3 +743,18 @@ std::istream& operator>> (std::istream& in, eCreatureStatus& status) { in.setstate(std::ios::failbit); return in; } + +// MARK: eEnchant + +cEnumLookup enchant_strs = {"+1", "+2", "+3", "shoot-flame", "flaming", "+5", "blessed"}; + +std::ostream& operator<< (std::ostream& out, eEnchant ench) { + writeEnum(out, ench, enchant_strs, "+1"); + return out; +} + +std::istream& operator>> (std::istream& in, eEnchant& ench) { + if(!readEnum(in, ench, enchant_strs, eEnchant::NONE)) + in.setstate(std::ios::failbit); + return in; +} diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp index 7fa0cc75..cfe042c6 100644 --- a/src/game/boe.actions.cpp +++ b/src/game/boe.actions.cpp @@ -979,7 +979,7 @@ void handle_item_shop_action(short item_hit) { play_sound(51); ASB("Your item is now enchanted."); eEnchant ench = eEnchant(shop_identify_cost); - target.enchant_weapon(ench,store_selling_values[i]); + target.enchant_weapon(ench); } break; case MODE_INVEN: case MODE_SHOP: diff --git a/src/game/boe.specials.cpp b/src/game/boe.specials.cpp index fa13e329..4cd4ea39 100644 --- a/src/game/boe.specials.cpp +++ b/src/game/boe.specials.cpp @@ -3246,10 +3246,7 @@ void affect_spec(const runtime_state& ctx) { 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); + to_give.enchant_weapon(eEnchant(spec.ex1b)); } if(to_give.charges > 0 && spec.ex1c >= 0) to_give.charges = spec.ex1c; diff --git a/src/game/boe.text.cpp b/src/game/boe.text.cpp index a3f49650..14c757a4 100644 --- a/src/game/boe.text.cpp +++ b/src/game/boe.text.cpp @@ -370,8 +370,6 @@ void place_buy_button(short position,short pc_num,short item_num) { rectangle dest_rect,source_rect; rectangle button_sources[3] = {{24,0,36,30},{36,0,48,30},{48,0,60,30}}; short val_to_place; - // TODO: This is now duplicated here and in start_town_mode() - short aug_cost[10] = {4,7,10,8, 15,15,10, 0,0,0}; const cPlayer& pc = univ.party[pc_num]; const cItem& item = pc.items[item_num]; @@ -416,7 +414,7 @@ void place_buy_button(short position,short pc_num,short item_num) { if((item.variety == eItemType::ONE_HANDED || item.variety == eItemType::TWO_HANDED) && item.ident && item.ability == eItemAbil::NONE && !item.magic) { item_area_button_active[position][ITEMBTN_SPEC] = true; source_rect = button_sources[2]; - val_to_place = max(aug_cost[shop_identify_cost] * 100, item.value * (5 + aug_cost[shop_identify_cost])); + val_to_place = (*eEnchant(shop_identify_cost)).adjust_value(item.value); } break; case MODE_INVEN: case MODE_SHOP: diff --git a/src/game/boe.town.cpp b/src/game/boe.town.cpp index 04a7c7ce..d1f42804 100644 --- a/src/game/boe.town.cpp +++ b/src/game/boe.town.cpp @@ -386,18 +386,12 @@ void start_town_mode(short which_town, short entry_dir) { } // Not use the items data flags, starting with forcing an ability - if(preset.ability >= 0) { + if(preset.ability != eEnchant::NONE) { // TODO: What other ways might there be to use this? switch(item.variety) { case eItemType::ONE_HANDED: case eItemType::TWO_HANDED: { - if(preset.ability > int(eEnchant::BLESSED)) - break; - // TODO: This array and accompanying calculation is now duplicated here and in place_buy_button() - const short aug_cost[10] = {4,7,10,8, 15,15,10, 0,0,0}; - int ench = preset.ability; - int val = max(aug_cost[ench] * 100, item.value * (5 + aug_cost[ench])); - item.enchant_weapon(eEnchant(ench), val); + item.enchant_weapon(preset.ability); break; } default: break; // Silence compiler warning diff --git a/src/scenario/item.cpp b/src/scenario/item.cpp index 4d95bd74..c9eabb38 100644 --- a/src/scenario/item.cpp +++ b/src/scenario/item.cpp @@ -348,57 +348,25 @@ cItem::cItem(eAlchemy recipe) : cItem(ITEM_POTION) { magic_use_type = info.magic_use_type; } -void cItem::enchant_weapon(eEnchant enchant_type,short new_val) { +void cItem::enchant_weapon(eEnchant enchant_type) { if(magic || ability != eItemAbil::NONE) return; if(variety != eItemType::ONE_HANDED && variety != eItemType::TWO_HANDED) return; magic = true; enchanted = true; - std::string store_name = full_name; - switch(enchant_type) { - case eEnchant::PLUS_ONE: - store_name += " (+1)"; - bonus++; - value = new_val; - break; - case eEnchant::PLUS_TWO: - store_name += " (+2)"; - bonus += 2; - value = new_val; - break; - case eEnchant::PLUS_THREE: - store_name += " (+3)"; - bonus += 3; - value = new_val; - break; - case eEnchant::SHOOT_FLAME: - store_name += " (F)"; - ability = eItemAbil::CAST_SPELL; - abil_strength = 5; - abil_data.spell = eSpell::FLAME; - charges = 8; - break; - case eEnchant::FLAMING: - store_name += " (F!)"; - value = new_val; - ability = eItemAbil::DAMAGING_WEAPON; - abil_strength = 5; - abil_data.damage = eDamageType::FIRE; - break; - case eEnchant::PLUS_FIVE: - store_name += " (+5)"; - value = new_val; - bonus += 5; - break; - case eEnchant::BLESSED: - store_name += " (B)"; - bonus++; - ability = eItemAbil::AFFECT_STATUS; - abil_strength = 5; - abil_data.status = eStatus::BLESS_CURSE; - charges = 8; - break; + const cEnchant& info = *enchant_type; + std::string store_name = full_name + " ("; + store_name += info.suffix + ")"; + bonus += info.add_bonus; + value = info.adjust_value(value); + if(info.add_ability != eItemAbil::NONE) { + ability = info.add_ability; + abil_strength = info.abil_strength; + abil_data = info.abil_data; + } + if(info.charges > 0) { + charges = info.charges; } if(value > 15000) value = 15000; diff --git a/src/scenario/item.hpp b/src/scenario/item.hpp index e3d24d69..b6bea57a 100644 --- a/src/scenario/item.hpp +++ b/src/scenario/item.hpp @@ -17,6 +17,7 @@ #include "item_variety.hpp" #include "skills_traits.hpp" #include "alchemy.hpp" +#include "enchant.hpp" namespace legacy { struct item_record_type; }; @@ -69,7 +70,7 @@ public: std::string interesting_string() const; std::string getAbilName() const; - void enchant_weapon(eEnchant enchant_type, short new_val); + void enchant_weapon(eEnchant enchant_type); bool abil_harms() const; bool abil_group() const; bool can_use() const; diff --git a/src/scenario/item_variety.hpp b/src/scenario/item_variety.hpp index 14f76ed6..bf92afb7 100644 --- a/src/scenario/item_variety.hpp +++ b/src/scenario/item_variety.hpp @@ -59,8 +59,6 @@ const item_variety_t& operator*(eItemType type); enum class eItemUse {HELP_ONE, HARM_ONE, HELP_ALL, HARM_ALL}; -enum class eEnchant {PLUS_ONE, PLUS_TWO, PLUS_THREE, SHOOT_FLAME, FLAMING, PLUS_FIVE, BLESSED}; - std::ostream& operator << (std::ostream& out, eItemUse e); std::istream& operator >> (std::istream& in, eItemUse& e); std::ostream& operator << (std::ostream& out, eItemType e); diff --git a/src/scenario/town.cpp b/src/scenario/town.cpp index a02e8a44..5ed6eb10 100644 --- a/src/scenario/town.cpp +++ b/src/scenario/town.cpp @@ -226,7 +226,7 @@ short cTown::light_obscurity(short x,short y) const { cTown::cItem::cItem() { loc = {80,80}; code = -1; - ability = -1; + ability = eEnchant::NONE; charges = 0; always_there = false; property = false; diff --git a/src/scenario/town.hpp b/src/scenario/town.hpp index faf75484..999e4ac1 100644 --- a/src/scenario/town.hpp +++ b/src/scenario/town.hpp @@ -55,7 +55,8 @@ public: class cItem { // formerly preset_item_type public: location loc; - short code,ability; + short code; + eEnchant ability; int charges = -1; bool always_there = false, property = false, contained = false; diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp index f29a9ea9..0dd9b558 100644 --- a/src/scenedit/scen.fileio.cpp +++ b/src/scenedit/scen.fileio.cpp @@ -767,7 +767,7 @@ void writeTownToXml(ticpp::Printer&& data, cTown& town) { data.PushElement("type", town.preset_items[i].code); if(town.preset_items[i].charges > 0) data.PushElement("charges", town.preset_items[i].charges); - if(town.preset_items[i].ability >= 0) + if(town.preset_items[i].ability != eEnchant::NONE) data.PushElement("mod", town.preset_items[i].ability); if(town.preset_items[i].always_there) data.PushElement("always", true); diff --git a/src/scenedit/scen.townout.cpp b/src/scenedit/scen.townout.cpp index ffef9103..2fbd119e 100644 --- a/src/scenedit/scen.townout.cpp +++ b/src/scenedit/scen.townout.cpp @@ -231,8 +231,8 @@ cTownperson edit_placed_monst_adv(cTownperson initial, short which, cDialog& par static bool put_placed_item_in_dlog(cDialog& me, const cTown::cItem& item, const short which) { std::ostringstream loc; cItem base = scenario.scen_items[item.code]; - if(item.ability >= 0 && item.ability <= int(eEnchant::BLESSED) && (base.variety == eItemType::ONE_HANDED || base.variety == eItemType::TWO_HANDED)) { - base.enchant_weapon(eEnchant(item.ability), 0); + if(item.ability != eEnchant::NONE && (base.variety == eItemType::ONE_HANDED || base.variety == eItemType::TWO_HANDED)) { + base.enchant_weapon(item.ability); } me["num"].setTextToNum(which); @@ -240,7 +240,7 @@ static bool put_placed_item_in_dlog(cDialog& me, const cTown::cItem& item, const me["loc"].setText(loc.str()); me["name"].setText(base.full_name); me["charges"].setTextToNum(item.charges); - me["abil"].setTextToNum(item.ability); + me["abil"].setTextToNum(int(item.ability)); if(item.always_there) dynamic_cast(me["always"]).setState(led_red); if(item.property) @@ -258,7 +258,7 @@ static bool put_placed_item_in_dlog(cDialog& me, const cTown::cItem& item, const if(base.variety == eItemType::GOLD || base.variety == eItemType::FOOD) { me["charges-lbl"].setText("Amount:"); - } else if(base.charges == 0 && item.ability != 3) { + } else if(base.charges == 0 && (*item.ability).charges == 0) { me["charges-lbl"].hide(); me["charges"].hide(); } else { @@ -294,7 +294,8 @@ static bool get_placed_item_in_dlog(cDialog& me, cTown::cItem& item, const short item.always_there = dynamic_cast(me["always"]).getState() != led_off; item.property = dynamic_cast(me["owned"]).getState() != led_off; item.contained = dynamic_cast(me["contained"]).getState() != led_off; - item.ability = me["abil"].getTextAsNum(); + int ench = me["abil"].getTextAsNum(); + if(ench >= 0 && ench <= cEnchant::MAX) item.ability = eEnchant(ench); town->preset_items[which] = item; return true; @@ -312,13 +313,13 @@ static bool edit_placed_item_type(cDialog& me, cTown::cItem& item, const short w static bool edit_placed_item_abil(cDialog& me, std::string item_hit, cTown::cItem& item, const short which) { item.charges = me["charges"].getTextAsNum(); cItem& base = scenario.scen_items[item.code]; - short i = item.ability; + short i = short(item.ability); if(item_hit == "abil") { // User entered a number directly i = me["abil"].getTextAsNum(); } else if(base.variety == eItemType::ONE_HANDED || base.variety == eItemType::TWO_HANDED) { - i = choose_text(STRT_ENCHANT, item.ability, &me, "Which enchantment?"); + i = choose_text(STRT_ENCHANT, i, &me, "Which enchantment?"); } - if(i >= -1) item.ability = i; + if(i >= -1 && i <= cEnchant::MAX) item.ability = eEnchant(i); put_placed_item_in_dlog(me, item, which); return true; } @@ -961,7 +962,7 @@ static bool check_talk_xtra(cDialog& me, std::stack& talk_edit_stack "Cost adjustment must be from 0 (cheapest) to 6 (most expensive).", "Which shop must refer to an existing shop (0 - {max}).", "Quest must be an existing quest (0 - {max}).", - "Enchantment type must be from 0 to 6. See the documentation for a list of possible abilities.", + "Enchantment type must be from 0 to {max}. See the documentation for a list of possible abilities.", // 10 "The first boat/horse must be in the legal range (0 - {max}).", "The special item must be in the legal range (0 - {max}).", @@ -1026,7 +1027,7 @@ static bool check_talk_xtra(cDialog& me, std::stack& talk_edit_stack break; case eTalkNode::ENCHANT: if(which == 0) { - lo = 0; hi = 6; + lo = 0; hi = cEnchant::MAX; msg = 9; } break; diff --git a/src/tools/SConscript b/src/tools/SConscript index ee0798e1..1903adc4 100644 --- a/src/tools/SConscript +++ b/src/tools/SConscript @@ -9,6 +9,7 @@ tools = Split(""" replay.cpp ../alchemy.cpp ../damage.cpp + ../enchant.cpp ../location.cpp ../mathutil.cpp ../porting.cpp diff --git a/test/town_legacy.cpp b/test/town_legacy.cpp index 83eaf44b..c88d534e 100644 --- a/test/town_legacy.cpp +++ b/test/town_legacy.cpp @@ -86,7 +86,7 @@ TEST_CASE("Converting legacy town data") { CHECK(town.preset_items[0].loc == loc(7,8)); CHECK(town.preset_items[0].code == 3); CHECK(town.preset_items[0].charges == 9); - CHECK(town.preset_items[0].ability == -1); + CHECK(town.preset_items[0].ability == eEnchant::NONE); CHECK(town.preset_items[0].always_there); CHECK(town.preset_items[0].property); CHECK(town.preset_items[0].contained); diff --git a/test/town_read.cpp b/test/town_read.cpp index 337df010..a79275fd 100644 --- a/test/town_read.cpp +++ b/test/town_read.cpp @@ -169,7 +169,7 @@ TEST_CASE("Loading a town definition") { CHECK(town->spec_strs[7] == "Here is a town string."); REQUIRE(town->preset_items.size() >= 3); CHECK(town->preset_items[2].code == 120); - CHECK(town->preset_items[2].ability == 2); + CHECK(town->preset_items[2].ability == eEnchant::PLUS_THREE); CHECK(town->preset_items[2].charges == 17); CHECK(town->preset_items[2].always_there); CHECK(town->preset_items[2].property); diff --git a/test/town_write.cpp b/test/town_write.cpp index 91e8a5ff..2972e1ba 100644 --- a/test/town_write.cpp +++ b/test/town_write.cpp @@ -108,7 +108,7 @@ TEST_CASE("Saving a town") { SECTION("With a preset item") { town->preset_items.emplace_back(); town->preset_items.back().code = 52; - town->preset_items.back().ability = 9; + town->preset_items.back().ability = eEnchant::BLESSED; town->preset_items.back().charges = 102; town->preset_items.back().always_there = true; town->preset_items.back().property = true; @@ -116,7 +116,7 @@ TEST_CASE("Saving a town") { in_and_out("item", town, scen); REQUIRE(town->preset_items.size() >= 1); CHECK(town->preset_items[0].code == 52); - CHECK(town->preset_items[0].ability == 9); + CHECK(town->preset_items[0].ability == eEnchant::BLESSED); CHECK(town->preset_items[0].charges == 102); CHECK(town->preset_items[0].always_there); CHECK(town->preset_items[0].property);