Gather all enchantment info into a single place

This also resolves several TODO notes about duplicate code and makes cPresetItem::ability an eEnchant
This commit is contained in:
2024-08-28 23:41:36 -04:00
committed by Celtic Minstrel
parent 71a9d11cd0
commit 6965b822dc
22 changed files with 216 additions and 83 deletions

View File

@@ -389,6 +389,7 @@
<ClCompile Include="..\..\..\src\gfx\tiling.cpp" /> <ClCompile Include="..\..\..\src\gfx\tiling.cpp" />
<ClCompile Include="..\..\..\src\alchemy.cpp" /> <ClCompile Include="..\..\..\src\alchemy.cpp" />
<ClCompile Include="..\..\..\src\damage.cpp" /> <ClCompile Include="..\..\..\src\damage.cpp" />
<ClCompile Include="..\..\..\src\enchant.cpp" />
<ClCompile Include="..\..\..\src\location.cpp" /> <ClCompile Include="..\..\..\src\location.cpp" />
<ClCompile Include="..\..\..\src\mathutil.cpp" /> <ClCompile Include="..\..\..\src\mathutil.cpp" />
<ClCompile Include="..\..\..\src\oldstructs.cpp" /> <ClCompile Include="..\..\..\src\oldstructs.cpp" />

View File

@@ -718,6 +718,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\alchemy.cpp" /> <ClCompile Include="..\..\..\src\alchemy.cpp" />
<ClCompile Include="..\..\..\src\damage.cpp" /> <ClCompile Include="..\..\..\src\damage.cpp" />
<ClCompile Include="..\..\..\src\enchant.cpp" />
<ClCompile Include="..\..\..\src\location.cpp" /> <ClCompile Include="..\..\..\src\location.cpp" />
<ClCompile Include="..\..\..\src\mathutil.cpp" /> <ClCompile Include="..\..\..\src\mathutil.cpp" />
<ClCompile Include="..\..\..\src\oldstructs.cpp" /> <ClCompile Include="..\..\..\src\oldstructs.cpp" />
@@ -955,6 +956,7 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\alchemy.hpp" /> <ClInclude Include="..\..\..\src\alchemy.hpp" />
<ClInclude Include="..\..\..\src\damage.hpp" /> <ClInclude Include="..\..\..\src\damage.hpp" />
<ClInclude Include="..\..\..\src\enchant.hpp" />
<ClInclude Include="..\..\..\src\fields.hpp" /> <ClInclude Include="..\..\..\src\fields.hpp" />
<ClInclude Include="..\..\..\src\global.hpp" /> <ClInclude Include="..\..\..\src\global.hpp" />
<ClInclude Include="..\..\..\src\location.hpp" /> <ClInclude Include="..\..\..\src\location.hpp" />

View File

@@ -106,6 +106,8 @@
9153C7A01A994A1700D7F8A7 /* SFML.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; }; 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 */; }; 915473BF2C7E11B900EB1C94 /* damage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473BE2C7E11B900EB1C94 /* damage.cpp */; };
915473C62C7FCDBB00EB1C94 /* alchemy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 915473C52C7FCDBB00EB1C94 /* alchemy.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 */; }; 915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B13A81BBE2B54009905A4 /* scrollpane.cpp */; };
9176FEC71D550EFE006EF694 /* out_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9176FEC01D550EFC006EF694 /* out_legacy.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 */; }; 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 = "<group>"; }; 915325181A2E37EE000A9A1C /* special_parse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = special_parse.cpp; sourceTree = "<group>"; };
915473BE2C7E11B900EB1C94 /* damage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = damage.cpp; sourceTree = "<group>"; }; 915473BE2C7E11B900EB1C94 /* damage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = damage.cpp; sourceTree = "<group>"; };
915473C52C7FCDBB00EB1C94 /* alchemy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = alchemy.cpp; sourceTree = "<group>"; }; 915473C52C7FCDBB00EB1C94 /* alchemy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = alchemy.cpp; sourceTree = "<group>"; };
915473CC2C800AB000EB1C94 /* enchant.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = enchant.hpp; sourceTree = "<group>"; };
915473CD2C800AB000EB1C94 /* enchant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = enchant.cpp; sourceTree = "<group>"; };
91574CC323CB97C5004766F8 /* enum_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = enum_map.hpp; sourceTree = "<group>"; }; 91574CC323CB97C5004766F8 /* enum_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = enum_map.hpp; sourceTree = "<group>"; };
91597A6C1A3BED2D00BE7BF9 /* spell.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = spell.hpp; sourceTree = "<group>"; }; 91597A6C1A3BED2D00BE7BF9 /* spell.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = spell.hpp; sourceTree = "<group>"; };
91597A6E1A3BEDC700BE7BF9 /* spell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spell.cpp; sourceTree = "<group>"; }; 91597A6E1A3BEDC700BE7BF9 /* spell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spell.cpp; sourceTree = "<group>"; };
@@ -1335,6 +1339,7 @@
children = ( children = (
915473C52C7FCDBB00EB1C94 /* alchemy.cpp */, 915473C52C7FCDBB00EB1C94 /* alchemy.cpp */,
915473BE2C7E11B900EB1C94 /* damage.cpp */, 915473BE2C7E11B900EB1C94 /* damage.cpp */,
915473CD2C800AB000EB1C94 /* enchant.cpp */,
91279BE10F9D0F73007B0D52 /* location.cpp */, 91279BE10F9D0F73007B0D52 /* location.cpp */,
91B3F11E0F97801F00BF5B67 /* mathutil.cpp */, 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */,
915325161A2E1DA8000A9A1C /* oldstructs.cpp */, 915325161A2E1DA8000A9A1C /* oldstructs.cpp */,
@@ -1345,6 +1350,7 @@
91B0D5D01E34428E002BE4DA /* view_dialogs.cpp */, 91B0D5D01E34428E002BE4DA /* view_dialogs.cpp */,
9185BD9B1EA02B8F0027C346 /* alchemy.hpp */, 9185BD9B1EA02B8F0027C346 /* alchemy.hpp */,
9185BD961EA0234A0027C346 /* damage.hpp */, 9185BD961EA0234A0027C346 /* damage.hpp */,
915473CC2C800AB000EB1C94 /* enchant.hpp */,
9185BD991EA027B80027C346 /* fields.hpp */, 9185BD991EA027B80027C346 /* fields.hpp */,
9185BDA01EA02FF80027C346 /* global.hpp */, 9185BDA01EA02FF80027C346 /* global.hpp */,
91279BE00F9D0F73007B0D52 /* location.hpp */, 91279BE00F9D0F73007B0D52 /* location.hpp */,
@@ -1664,6 +1670,7 @@
9149924E25913E3F00B5BE97 /* led.hpp in Headers */, 9149924E25913E3F00B5BE97 /* led.hpp in Headers */,
9143044B2970EDC1003A3967 /* keymods.hpp in Headers */, 9143044B2970EDC1003A3967 /* keymods.hpp in Headers */,
9149925025913E3F00B5BE97 /* ledgroup.hpp in Headers */, 9149925025913E3F00B5BE97 /* ledgroup.hpp in Headers */,
915473CE2C800AB000EB1C94 /* enchant.hpp in Headers */,
91499254259140FF00B5BE97 /* keycodes.hpp in Headers */, 91499254259140FF00B5BE97 /* keycodes.hpp in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2078,6 +2085,7 @@
919CC27E1B37743B00273FDA /* undo.cpp in Sources */, 919CC27E1B37743B00273FDA /* undo.cpp in Sources */,
919CC27F1B37744000273FDA /* winutil.mac.mm in Sources */, 919CC27F1B37744000273FDA /* winutil.mac.mm in Sources */,
D384F6A32C1B9D4000A806C3 /* replay.cpp in Sources */, D384F6A32C1B9D4000A806C3 /* replay.cpp in Sources */,
915473CF2C800AB000EB1C94 /* enchant.cpp in Sources */,
915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */, 915AF9E81BBF8B5C008AEF49 /* scrollpane.cpp in Sources */,
91E128E71BC1E6DD00C8BE1D /* basicbtns.cpp in Sources */, 91E128E71BC1E6DD00C8BE1D /* basicbtns.cpp in Sources */,
91E128ED1BC2076B00C8BE1D /* 3choice.cpp in Sources */, 91E128ED1BC2076B00C8BE1D /* 3choice.cpp in Sources */,

View File

@@ -17,6 +17,17 @@
<xs:enumeration value="hostile-b"/> <xs:enumeration value="hostile-b"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
<xs:simpleType name="enchantment">
<xs:restriction base="xs:token">
<xs:enumeration value="+1"/>
<xs:enumeration value="+2"/>
<xs:enumeration value="+3"/>
<xs:enumeration value="+5"/>
<xs:enumeration value="shoot-flame"/>
<xs:enumeration value="flaming"/>
<xs:enumeration value="blessed"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="town"> <xs:element name="town">
<xs:complexType> <xs:complexType>
@@ -129,7 +140,7 @@
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="type" type="xs:integer"/> <xs:element name="type" type="xs:integer"/>
<xs:element name="mod" type="xs:integer" minOccurs="0"/> <xs:element name="mod" type="enchantment" minOccurs="0"/>
<xs:element name="charges" type="xs:integer" minOccurs="0"/> <xs:element name="charges" type="xs:integer" minOccurs="0"/>
<xs:element name="always" type="bool" minOccurs="0"/> <xs:element name="always" type="bool" minOccurs="0"/>
<xs:element name="property" type="bool" minOccurs="0"/> <xs:element name="property" type="bool" minOccurs="0"/>
@@ -211,4 +222,4 @@
<xs:field xpath='@id'/> <xs:field xpath='@id'/>
</xs:unique> </xs:unique>
</xs:element> </xs:element>
</xs:schema> </xs:schema>

76
src/enchant.cpp Normal file
View File

@@ -0,0 +1,76 @@
//
// enchant.cpp
// BoE
//
// Created by Celtic Minstrel on 2023-08-28.
//
//
#include "enchant.hpp"
#include "mathutil.hpp"
std::map<eEnchant, cEnchant> 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);

61
src/enchant.hpp Normal file
View File

@@ -0,0 +1,61 @@
//
// enchant.hpp
// BoE
//
// Created by Celtic Minstrel on 2023-08-28.
//
//
#ifndef BoE_ENCHANT_HPP
#define BoE_ENCHANT_HPP
#include <iosfwd>
#include <map>
#include <string>
#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<eEnchant, cEnchant> 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

View File

@@ -743,3 +743,18 @@ std::istream& operator>> (std::istream& in, eCreatureStatus& status) {
in.setstate(std::ios::failbit); in.setstate(std::ios::failbit);
return in; 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;
}

View File

@@ -979,7 +979,7 @@ void handle_item_shop_action(short item_hit) {
play_sound(51); play_sound(51);
ASB("Your item is now enchanted."); ASB("Your item is now enchanted.");
eEnchant ench = eEnchant(shop_identify_cost); eEnchant ench = eEnchant(shop_identify_cost);
target.enchant_weapon(ench,store_selling_values[i]); target.enchant_weapon(ench);
} }
break; break;
case MODE_INVEN: case MODE_SHOP: case MODE_INVEN: case MODE_SHOP:

View File

@@ -3246,10 +3246,7 @@ void affect_spec(const runtime_state& ctx) {
if(spec.ex1a >= 0 && spec.ex1a < univ.scenario.scen_items.size()) { if(spec.ex1a >= 0 && spec.ex1a < univ.scenario.scen_items.size()) {
cItem to_give = univ.scenario.scen_items[spec.ex1a]; cItem to_give = univ.scenario.scen_items[spec.ex1a];
if(spec.ex1b >= 0 && spec.ex1b <= 6) { 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() to_give.enchant_weapon(eEnchant(spec.ex1b));
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) if(to_give.charges > 0 && spec.ex1c >= 0)
to_give.charges = spec.ex1c; to_give.charges = spec.ex1c;

View File

@@ -370,8 +370,6 @@ void place_buy_button(short position,short pc_num,short item_num) {
rectangle dest_rect,source_rect; rectangle dest_rect,source_rect;
rectangle button_sources[3] = {{24,0,36,30},{36,0,48,30},{48,0,60,30}}; rectangle button_sources[3] = {{24,0,36,30},{36,0,48,30},{48,0,60,30}};
short val_to_place; 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 cPlayer& pc = univ.party[pc_num];
const cItem& item = pc.items[item_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) { 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; item_area_button_active[position][ITEMBTN_SPEC] = true;
source_rect = button_sources[2]; 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; break;
case MODE_INVEN: case MODE_SHOP: case MODE_INVEN: case MODE_SHOP:

View File

@@ -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 // 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? // TODO: What other ways might there be to use this?
switch(item.variety) { switch(item.variety) {
case eItemType::ONE_HANDED: case eItemType::ONE_HANDED:
case eItemType::TWO_HANDED: { case eItemType::TWO_HANDED: {
if(preset.ability > int(eEnchant::BLESSED)) item.enchant_weapon(preset.ability);
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);
break; break;
} }
default: break; // Silence compiler warning default: break; // Silence compiler warning

View File

@@ -348,57 +348,25 @@ cItem::cItem(eAlchemy recipe) : cItem(ITEM_POTION) {
magic_use_type = info.magic_use_type; 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) if(magic || ability != eItemAbil::NONE)
return; return;
if(variety != eItemType::ONE_HANDED && variety != eItemType::TWO_HANDED) if(variety != eItemType::ONE_HANDED && variety != eItemType::TWO_HANDED)
return; return;
magic = true; magic = true;
enchanted = true; enchanted = true;
std::string store_name = full_name; const cEnchant& info = *enchant_type;
switch(enchant_type) { std::string store_name = full_name + " (";
case eEnchant::PLUS_ONE: store_name += info.suffix + ")";
store_name += " (+1)"; bonus += info.add_bonus;
bonus++; value = info.adjust_value(value);
value = new_val; if(info.add_ability != eItemAbil::NONE) {
break; ability = info.add_ability;
case eEnchant::PLUS_TWO: abil_strength = info.abil_strength;
store_name += " (+2)"; abil_data = info.abil_data;
bonus += 2; }
value = new_val; if(info.charges > 0) {
break; charges = info.charges;
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;
} }
if(value > 15000) if(value > 15000)
value = 15000; value = 15000;

View File

@@ -17,6 +17,7 @@
#include "item_variety.hpp" #include "item_variety.hpp"
#include "skills_traits.hpp" #include "skills_traits.hpp"
#include "alchemy.hpp" #include "alchemy.hpp"
#include "enchant.hpp"
namespace legacy { struct item_record_type; }; namespace legacy { struct item_record_type; };
@@ -69,7 +70,7 @@ public:
std::string interesting_string() const; std::string interesting_string() const;
std::string getAbilName() 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_harms() const;
bool abil_group() const; bool abil_group() const;
bool can_use() const; bool can_use() const;

View File

@@ -59,8 +59,6 @@ const item_variety_t& operator*(eItemType type);
enum class eItemUse {HELP_ONE, HARM_ONE, HELP_ALL, HARM_ALL}; 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::ostream& operator << (std::ostream& out, eItemUse e);
std::istream& operator >> (std::istream& in, eItemUse& e); std::istream& operator >> (std::istream& in, eItemUse& e);
std::ostream& operator << (std::ostream& out, eItemType e); std::ostream& operator << (std::ostream& out, eItemType e);

View File

@@ -226,7 +226,7 @@ short cTown::light_obscurity(short x,short y) const {
cTown::cItem::cItem() { cTown::cItem::cItem() {
loc = {80,80}; loc = {80,80};
code = -1; code = -1;
ability = -1; ability = eEnchant::NONE;
charges = 0; charges = 0;
always_there = false; always_there = false;
property = false; property = false;

View File

@@ -55,7 +55,8 @@ public:
class cItem { // formerly preset_item_type class cItem { // formerly preset_item_type
public: public:
location loc; location loc;
short code,ability; short code;
eEnchant ability;
int charges = -1; int charges = -1;
bool always_there = false, property = false, contained = false; bool always_there = false, property = false, contained = false;

View File

@@ -767,7 +767,7 @@ void writeTownToXml(ticpp::Printer&& data, cTown& town) {
data.PushElement("type", town.preset_items[i].code); data.PushElement("type", town.preset_items[i].code);
if(town.preset_items[i].charges > 0) if(town.preset_items[i].charges > 0)
data.PushElement("charges", town.preset_items[i].charges); 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); data.PushElement("mod", town.preset_items[i].ability);
if(town.preset_items[i].always_there) if(town.preset_items[i].always_there)
data.PushElement("always", true); data.PushElement("always", true);

View File

@@ -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) { static bool put_placed_item_in_dlog(cDialog& me, const cTown::cItem& item, const short which) {
std::ostringstream loc; std::ostringstream loc;
cItem base = scenario.scen_items[item.code]; 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)) { if(item.ability != eEnchant::NONE && (base.variety == eItemType::ONE_HANDED || base.variety == eItemType::TWO_HANDED)) {
base.enchant_weapon(eEnchant(item.ability), 0); base.enchant_weapon(item.ability);
} }
me["num"].setTextToNum(which); 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["loc"].setText(loc.str());
me["name"].setText(base.full_name); me["name"].setText(base.full_name);
me["charges"].setTextToNum(item.charges); me["charges"].setTextToNum(item.charges);
me["abil"].setTextToNum(item.ability); me["abil"].setTextToNum(int(item.ability));
if(item.always_there) if(item.always_there)
dynamic_cast<cLed&>(me["always"]).setState(led_red); dynamic_cast<cLed&>(me["always"]).setState(led_red);
if(item.property) 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) { if(base.variety == eItemType::GOLD || base.variety == eItemType::FOOD) {
me["charges-lbl"].setText("Amount:"); 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-lbl"].hide();
me["charges"].hide(); me["charges"].hide();
} else { } else {
@@ -294,7 +294,8 @@ static bool get_placed_item_in_dlog(cDialog& me, cTown::cItem& item, const short
item.always_there = dynamic_cast<cLed&>(me["always"]).getState() != led_off; item.always_there = dynamic_cast<cLed&>(me["always"]).getState() != led_off;
item.property = dynamic_cast<cLed&>(me["owned"]).getState() != led_off; item.property = dynamic_cast<cLed&>(me["owned"]).getState() != led_off;
item.contained = dynamic_cast<cLed&>(me["contained"]).getState() != led_off; item.contained = dynamic_cast<cLed&>(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; town->preset_items[which] = item;
return true; 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) { static bool edit_placed_item_abil(cDialog& me, std::string item_hit, cTown::cItem& item, const short which) {
item.charges = me["charges"].getTextAsNum(); item.charges = me["charges"].getTextAsNum();
cItem& base = scenario.scen_items[item.code]; 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 if(item_hit == "abil") { // User entered a number directly
i = me["abil"].getTextAsNum(); i = me["abil"].getTextAsNum();
} else if(base.variety == eItemType::ONE_HANDED || base.variety == eItemType::TWO_HANDED) { } 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); put_placed_item_in_dlog(me, item, which);
return true; return true;
} }
@@ -961,7 +962,7 @@ static bool check_talk_xtra(cDialog& me, std::stack<node_ref_t>& talk_edit_stack
"Cost adjustment must be from 0 (cheapest) to 6 (most expensive).", "Cost adjustment must be from 0 (cheapest) to 6 (most expensive).",
"Which shop must refer to an existing shop (0 - {max}).", "Which shop must refer to an existing shop (0 - {max}).",
"Quest must be an existing quest (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 // 10
"The first boat/horse must be in the legal range (0 - {max}).", "The first boat/horse must be in the legal range (0 - {max}).",
"The special item 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<node_ref_t>& talk_edit_stack
break; break;
case eTalkNode::ENCHANT: case eTalkNode::ENCHANT:
if(which == 0) { if(which == 0) {
lo = 0; hi = 6; lo = 0; hi = cEnchant::MAX;
msg = 9; msg = 9;
} }
break; break;

View File

@@ -9,6 +9,7 @@ tools = Split("""
replay.cpp replay.cpp
../alchemy.cpp ../alchemy.cpp
../damage.cpp ../damage.cpp
../enchant.cpp
../location.cpp ../location.cpp
../mathutil.cpp ../mathutil.cpp
../porting.cpp ../porting.cpp

View File

@@ -86,7 +86,7 @@ TEST_CASE("Converting legacy town data") {
CHECK(town.preset_items[0].loc == loc(7,8)); CHECK(town.preset_items[0].loc == loc(7,8));
CHECK(town.preset_items[0].code == 3); CHECK(town.preset_items[0].code == 3);
CHECK(town.preset_items[0].charges == 9); 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].always_there);
CHECK(town.preset_items[0].property); CHECK(town.preset_items[0].property);
CHECK(town.preset_items[0].contained); CHECK(town.preset_items[0].contained);

View File

@@ -169,7 +169,7 @@ TEST_CASE("Loading a town definition") {
CHECK(town->spec_strs[7] == "Here is a town string."); CHECK(town->spec_strs[7] == "Here is a town string.");
REQUIRE(town->preset_items.size() >= 3); REQUIRE(town->preset_items.size() >= 3);
CHECK(town->preset_items[2].code == 120); 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].charges == 17);
CHECK(town->preset_items[2].always_there); CHECK(town->preset_items[2].always_there);
CHECK(town->preset_items[2].property); CHECK(town->preset_items[2].property);

View File

@@ -108,7 +108,7 @@ TEST_CASE("Saving a town") {
SECTION("With a preset item") { SECTION("With a preset item") {
town->preset_items.emplace_back(); town->preset_items.emplace_back();
town->preset_items.back().code = 52; 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().charges = 102;
town->preset_items.back().always_there = true; town->preset_items.back().always_there = true;
town->preset_items.back().property = true; town->preset_items.back().property = true;
@@ -116,7 +116,7 @@ TEST_CASE("Saving a town") {
in_and_out("item", town, scen); in_and_out("item", town, scen);
REQUIRE(town->preset_items.size() >= 1); REQUIRE(town->preset_items.size() >= 1);
CHECK(town->preset_items[0].code == 52); 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].charges == 102);
CHECK(town->preset_items[0].always_there); CHECK(town->preset_items[0].always_there);
CHECK(town->preset_items[0].property); CHECK(town->preset_items[0].property);