diff --git a/data/scripts/talkactions/god/attributes.lua b/data/scripts/talkactions/god/attributes.lua index 1c1ed8a9bf1..6faed0ea041 100644 --- a/data/scripts/talkactions/god/attributes.lua +++ b/data/scripts/talkactions/god/attributes.lua @@ -95,6 +95,12 @@ local itemFunctions = { return item:setAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE, target) end, }, + ["element"] = { + isActive = true, + targetFunction = function(item, target) + return item:setAttribute(ITEM_ATTRIBUTE_ELEMENT, target) + end, + }, ["charge"] = { isActive = true, targetFunction = function(item, target) diff --git a/src/enums/item_attribute.hpp b/src/enums/item_attribute.hpp index a3d76fde70f..e31693f5123 100644 --- a/src/enums/item_attribute.hpp +++ b/src/enums/item_attribute.hpp @@ -47,6 +47,7 @@ enum class ItemAttribute_t : uint64_t { STORE_INBOX_CATEGORY = 34, OBTAINCONTAINER = 35, AUGMENTS = 36, + ELEMENT = 37, }; enum ItemDecayState_t : uint8_t { diff --git a/src/items/functions/item/attribute.hpp b/src/items/functions/item/attribute.hpp index 3d99187d93a..3e3a66f73b3 100644 --- a/src/items/functions/item/attribute.hpp +++ b/src/items/functions/item/attribute.hpp @@ -24,6 +24,7 @@ class ItemAttributeHelper { case ItemAttribute_t::ATTACK: case ItemAttribute_t::DEFENSE: case ItemAttribute_t::EXTRADEFENSE: + case ItemAttribute_t::ELEMENT: case ItemAttribute_t::ARMOR: case ItemAttribute_t::HITCHANCE: case ItemAttribute_t::SHOOTRANGE: diff --git a/src/items/item.cpp b/src/items/item.cpp index 14af2cfb47f..180d6227e68 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -684,6 +684,16 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream &propStream) { break; } + case ATTR_ELEMENT: { + int32_t element; + if (!propStream.read(element)) { + return ATTR_READ_ERROR; + } + + setAttribute(ItemAttribute_t::ELEMENT, element); + break; + } + case ATTR_IMBUEMENT_SLOT: { int32_t imbuementSlot; if (!propStream.read(imbuementSlot)) { @@ -1038,6 +1048,11 @@ void Item::serializeAttr(PropWriteStream &propWriteStream) const { propWriteStream.write(getAttribute(ItemAttribute_t::EXTRADEFENSE)); } + if (hasAttribute(ItemAttribute_t::ELEMENT)) { + propWriteStream.write(ATTR_ELEMENT); + propWriteStream.write(getAttribute(ItemAttribute_t::ELEMENT)); + } + if (hasAttribute(ItemAttribute_t::IMBUEMENT_SLOT)) { propWriteStream.write(ATTR_IMBUEMENT_SLOT); propWriteStream.write(getAttribute(ItemAttribute_t::IMBUEMENT_SLOT)); @@ -1258,6 +1273,7 @@ Item::getDescriptions(const ItemType &it, const std::shared_ptr &item /*= } int32_t attack = item->getAttack(); + int32_t element = item->getElementDamage(); if (it.isRanged()) { bool separator = false; if (attack != 0) { @@ -1283,7 +1299,7 @@ Item::getDescriptions(const ItemType &it, const std::shared_ptr &item /*= } else { std::string attackDescription; if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) { - attackDescription = fmt::format("{} {}", it.abilities->elementDamage, getCombatName(it.abilities->elementType)); + attackDescription = fmt::format("{} {}", ((element > 0) ? element : it.abilities->elementDamage), getCombatName(it.abilities->elementType)); } if (attack != 0 && !attackDescription.empty()) { @@ -1682,6 +1698,7 @@ Item::getDescriptions(const ItemType &it, const std::shared_ptr &item /*= } int32_t attack = it.attack; + int32_t element = it.element; if (it.isRanged()) { bool separator = false; if (attack != 0) { @@ -1707,7 +1724,7 @@ Item::getDescriptions(const ItemType &it, const std::shared_ptr &item /*= } else { std::string attackDescription; if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) { - attackDescription = fmt::format("{} {}", it.abilities->elementDamage, getCombatName(it.abilities->elementType)); + attackDescription = fmt::format("{} {}", ((element > 0) ? element : it.abilities->elementDamage), getCombatName(it.abilities->elementType)); } if (attack != 0 && !attackDescription.empty()) { @@ -2726,15 +2743,17 @@ std::string Item::getDescription(const ItemType &it, int32_t lookDistance, const } else if (it.weaponType != WEAPON_AMMO) { bool begin = true; - int32_t attack, defense, extraDefense; + int32_t attack, defense, extraDefense, element; if (item) { attack = item->getAttack(); defense = item->getDefense(); extraDefense = item->getExtraDefense(); + element = item->getElementDamage(); } else { attack = it.attack; defense = it.defense; extraDefense = it.extraDefense; + element = it.element; } if (it.isContainer() || (item && item->getContainer())) { @@ -2766,10 +2785,10 @@ std::string Item::getDescription(const ItemType &it, int32_t lookDistance, const } if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0 && !begin) { - s << " physical + " << it.abilities->elementDamage << ' ' << getCombatName(it.abilities->elementType); + s << " physical + " << ((element > 0) ? element : it.abilities->elementDamage) << ' ' << getCombatName(it.abilities->elementType); } else if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0 && begin) { begin = false; - s << " (" << it.abilities->elementDamage << ' ' << getCombatName(it.abilities->elementType); + s << " (" << ((element > 0) ? element : it.abilities->elementDamage) << ' ' << getCombatName(it.abilities->elementType); } if (defense != 0 || extraDefense != 0 || it.isMissile()) { diff --git a/src/items/item.hpp b/src/items/item.hpp index d199fab15cf..5bb00ce0604 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -404,6 +404,12 @@ class Item : virtual public Thing, public ItemProperties, public SharedObject { } return items[id].extraDefense; } + int32_t getElementDamage() const { + if (hasAttribute(ItemAttribute_t::ELEMENT)) { + return getAttribute(ItemAttribute_t::ELEMENT); + } + return items[id].element; + } std::vector> getAugments() const { return items[id].augments; } diff --git a/src/items/items.hpp b/src/items/items.hpp index b977f0bf7a9..a68118342c8 100644 --- a/src/items/items.hpp +++ b/src/items/items.hpp @@ -280,6 +280,7 @@ class ItemType { int32_t attack = 0; int32_t defense = 0; int32_t extraDefense = 0; + int32_t element = 0; int32_t armor = 0; int32_t rotateTo = 0; int32_t runeMagLevel = 0; diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp index 9b6990c0cb7..d7b54c834ef 100644 --- a/src/items/items_definitions.hpp +++ b/src/items/items_definitions.hpp @@ -244,6 +244,7 @@ enum AttrTypes_t { ATTR_STORE_INBOX_CATEGORY = 42, ATTR_OWNER = 43, ATTR_OBTAINCONTAINER = 44, + ATTR_ELEMENT = 45, // Always the last ATTR_NONE = 0 diff --git a/src/items/weapons/weapons.cpp b/src/items/weapons/weapons.cpp index 2ec09945f36..2e38a6ae298 100644 --- a/src/items/weapons/weapons.cpp +++ b/src/items/weapons/weapons.cpp @@ -598,9 +598,9 @@ int32_t WeaponMelee::getElementDamage(const std::shared_ptr &player, con if (elementType == COMBAT_NONE) { return 0; } - + const int32_t element = item->getElementDamage(); const int32_t attackSkill = player->getWeaponSkill(item); - const int32_t attackValue = elementDamage; + const int32_t attackValue = (element > 0) ? element : elementDamage; const float attackFactor = player->getAttackFactor(); const uint32_t level = player->getLevel(); @@ -833,8 +833,8 @@ int32_t WeaponDistance::getElementDamage(const std::shared_ptr &player, if (elementType == COMBAT_NONE) { return 0; } - - int32_t attackValue = elementDamage; + int32_t element = item->getElementDamage(); + int32_t attackValue = (element > 0) ? element : elementDamage; if (item && player && item->getWeaponType() == WEAPON_AMMO) { const auto &weapon = player->getWeapon(true); if (weapon) { diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp index 57c9c873282..ecc2594914f 100644 --- a/src/utils/tools.cpp +++ b/src/utils/tools.cpp @@ -1218,6 +1218,9 @@ ItemAttribute_t stringToItemAttribute(const std::string &str) { if (str == "extradefense") { return ItemAttribute_t::EXTRADEFENSE; } + if (str == "element") { + return ItemAttribute_t::ELEMENT; + } if (str == "armor") { return ItemAttribute_t::ARMOR; }