diff --git a/data/items/items.xml b/data/items/items.xml index 42fd8ec1bf..54a54348ae 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -729,7 +729,7 @@ - + @@ -737,7 +737,7 @@ - + @@ -19687,12 +19687,12 @@ - + - + @@ -30117,12 +30117,12 @@ - + - + diff --git a/data/lib/compat/compat.lua b/data/lib/compat/compat.lua index f1637ecb9f..777d74a38c 100644 --- a/data/lib/compat/compat.lua +++ b/data/lib/compat/compat.lua @@ -1640,6 +1640,8 @@ function table.maxn(t) return max end +ItemType.getDuration = ItemType.getDurationMin + function getFormattedWorldTime() return Game.getFormattedWorldTime() end diff --git a/src/enums.h b/src/enums.h index 64606fb708..b1ee0eda61 100644 --- a/src/enums.h +++ b/src/enums.h @@ -83,6 +83,8 @@ enum itemAttrTypes : uint32_t ITEM_ATTRIBUTE_STOREITEM = 1 << 25, ITEM_ATTRIBUTE_ATTACK_SPEED = 1 << 26, ITEM_ATTRIBUTE_OPENCONTAINER = 1 << 27, + ITEM_ATTRIBUTE_DURATION_MIN = ITEM_ATTRIBUTE_DURATION, + ITEM_ATTRIBUTE_DURATION_MAX = 1 << 28, ITEM_ATTRIBUTE_CUSTOM = 1U << 31 }; diff --git a/src/item.cpp b/src/item.cpp index a0611db458..c28d4dac1c 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -238,7 +238,7 @@ void Item::setID(uint16_t newid) id = newid; const ItemType& it = Item::items[newid]; - uint32_t newDuration = it.decayTime * 1000; + uint32_t newDuration = normal_random(it.decayTimeMin, it.decayTimeMax) * 1000; if (newDuration == 0 && !it.stopTime && it.decayTo < 0) { removeAttribute(ITEM_ATTRIBUTE_DECAYSTATE); @@ -1050,13 +1050,25 @@ void Item::setUniqueId(uint16_t n) } } +void Item::setDefaultDuration() +{ + uint32_t duration = getDefaultDurationMin(); + if (uint32_t durationMax = getDefaultDurationMax()) { + duration = normal_random(duration, durationMax); + } + + if (duration != 0) { + setDuration(duration); + } +} + bool Item::canDecay() const { if (isRemoved()) { return false; } - if (getDecayTo() < 0 || getDecayTime() == 0) { + if (getDecayTo() < 0 || (getDecayTimeMin() == 0 && getDecayTimeMax() == 0)) { return false; } @@ -1247,7 +1259,7 @@ bool Item::hasMarketAttributes() const } } else if (attr.type == ITEM_ATTRIBUTE_DURATION) { uint32_t duration = static_cast(attr.value.integer); - if (duration != getDefaultDuration()) { + if (duration <= getDefaultDurationMin()) { return false; } } else { diff --git a/src/item.h b/src/item.h index 54577fb39a..27a846fd6c 100644 --- a/src/item.h +++ b/src/item.h @@ -687,12 +687,19 @@ class Item : virtual public Thing return static_cast(getIntAttr(ITEM_ATTRIBUTE_DECAYSTATE)); } - int32_t getDecayTime() const + int32_t getDecayTimeMin() const { - if (hasAttribute(ITEM_ATTRIBUTE_DURATION)) { - return getIntAttr(ITEM_ATTRIBUTE_DURATION); + if (hasAttribute(ITEM_ATTRIBUTE_DURATION_MIN)) { + return getIntAttr(ITEM_ATTRIBUTE_DURATION_MIN); } - return items[id].decayTime; + return items[id].decayTimeMin; + } + int32_t getDecayTimeMax() const + { + if (hasAttribute(ITEM_ATTRIBUTE_DURATION_MAX)) { + return getIntAttr(ITEM_ATTRIBUTE_DURATION_MAX); + } + return items[id].decayTimeMax; } void setDecayTo(int32_t decayTo) { setIntAttr(ITEM_ATTRIBUTE_DECAYTO, decayTo); } @@ -868,14 +875,9 @@ class Item : virtual public Thing void setUniqueId(uint16_t n); - void setDefaultDuration() - { - uint32_t duration = getDefaultDuration(); - if (duration != 0) { - setDuration(duration); - } - } - uint32_t getDefaultDuration() const { return items[id].decayTime * 1000; } + void setDefaultDuration(); + uint32_t getDefaultDurationMin() const { return items[id].decayTimeMin * 1000; } + uint32_t getDefaultDurationMax() const { return items[id].decayTimeMax * 1000; } bool canDecay() const; virtual bool canRemove() const { return true; } diff --git a/src/items.cpp b/src/items.cpp index 62befdc18b..631fa550df 100644 --- a/src/items.cpp +++ b/src/items.cpp @@ -661,8 +661,17 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id) } pugi::xml_attribute valueAttribute = attributeNode.attribute("value"); + pugi::xml_attribute maxValueAttr; if (!valueAttribute) { - continue; + valueAttribute = attributeNode.attribute("minvalue"); + if (!valueAttribute) { + continue; + } + + maxValueAttr = attributeNode.attribute("maxvalue"); + if (!maxValueAttr) { + continue; + } } std::string tmpStrValue = boost::algorithm::to_lower_copy(keyAttribute.as_string()); @@ -931,7 +940,11 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id) } case ITEM_PARSE_DURATION: { - it.decayTime = pugi::cast(valueAttribute.value()); + it.decayTimeMin = pugi::cast(valueAttribute.value()); + + if (maxValueAttr) { + it.decayTimeMax = pugi::cast(maxValueAttr.value()); + } break; } diff --git a/src/items.h b/src/items.h index 0f33e2061a..73f6054bff 100644 --- a/src/items.h +++ b/src/items.h @@ -337,7 +337,8 @@ class ItemType uint32_t attackSpeed = 0; uint32_t weight = 0; uint32_t levelDoor = 0; - uint32_t decayTime = 0; + uint32_t decayTimeMin = 0; + uint32_t decayTimeMax = 0; uint32_t wieldInfo = 0; uint32_t minReqLevel = 0; uint32_t minReqMagicLevel = 0; diff --git a/src/luascript.cpp b/src/luascript.cpp index 6b2a5f68d2..42d1de9cf1 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -1664,6 +1664,8 @@ void LuaScriptInterface::registerFunctions() registerEnum(ITEM_ATTRIBUTE_STOREITEM); registerEnum(ITEM_ATTRIBUTE_ATTACK_SPEED); registerEnum(ITEM_ATTRIBUTE_OPENCONTAINER); + registerEnum(ITEM_ATTRIBUTE_DURATION_MIN); + registerEnum(ITEM_ATTRIBUTE_DURATION_MAX); registerEnum(ITEM_TYPE_DEPOT); registerEnum(ITEM_TYPE_MAILBOX); @@ -3004,7 +3006,8 @@ void LuaScriptInterface::registerFunctions() registerMethod("ItemType", "hasShowDuration", LuaScriptInterface::luaItemTypeHasShowDuration); registerMethod("ItemType", "hasAllowDistRead", LuaScriptInterface::luaItemTypeHasAllowDistRead); registerMethod("ItemType", "getWieldInfo", LuaScriptInterface::luaItemTypeGetWieldInfo); - registerMethod("ItemType", "getDuration", LuaScriptInterface::luaItemTypeGetDuration); + registerMethod("ItemType", "getDurationMin", LuaScriptInterface::luaItemTypeGetDurationMin); + registerMethod("ItemType", "getDurationMax", LuaScriptInterface::luaItemTypeGetDurationMax); registerMethod("ItemType", "getLevelDoor", LuaScriptInterface::luaItemTypeGetLevelDoor); registerMethod("ItemType", "getRuneSpellName", LuaScriptInterface::luaItemTypeGetRuneSpellName); registerMethod("ItemType", "getVocationString", LuaScriptInterface::luaItemTypeGetVocationString); @@ -13332,12 +13335,24 @@ int LuaScriptInterface::luaItemTypeGetWieldInfo(lua_State* L) return 1; } -int LuaScriptInterface::luaItemTypeGetDuration(lua_State* L) +int LuaScriptInterface::luaItemTypeGetDurationMin(lua_State* L) { - // itemType:getDuration() + // itemType:getDurationMin() const ItemType* itemType = getUserdata(L, 1); if (itemType) { - lua_pushinteger(L, itemType->decayTime); + lua_pushinteger(L, itemType->decayTimeMin); + } else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaItemTypeGetDurationMax(lua_State* L) +{ + // itemType:getDurationMax() + const ItemType* itemType = getUserdata(L, 1); + if (itemType) { + lua_pushinteger(L, itemType->decayTimeMax); } else { lua_pushnil(L); } @@ -18043,7 +18058,13 @@ int LuaScriptInterface::luaWeaponDuration(lua_State* L) uint16_t id = weapon->getID(); ItemType& it = Item::items.getItemType(id); - it.decayTime = getNumber(L, 2); + if (isTable(L, 2)) { + it.decayTimeMin = getField(L, 2, "min"); + it.decayTimeMax = getField(L, 2, "max"); + } else { + it.decayTimeMin = getNumber(L, 2); + } + it.showDuration = showDuration; pushBoolean(L, true); } else { diff --git a/src/luascript.h b/src/luascript.h index a33293d1ce..167f5770b5 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -1259,7 +1259,8 @@ class LuaScriptInterface static int luaItemTypeHasShowDuration(lua_State* L); static int luaItemTypeHasAllowDistRead(lua_State* L); static int luaItemTypeGetWieldInfo(lua_State* L); - static int luaItemTypeGetDuration(lua_State* L); + static int luaItemTypeGetDurationMin(lua_State* L); + static int luaItemTypeGetDurationMax(lua_State* L); static int luaItemTypeGetLevelDoor(lua_State* L); static int luaItemTypeGetRuneSpellName(lua_State* L); static int luaItemTypeGetVocationString(lua_State* L); diff --git a/src/networkmessage.cpp b/src/networkmessage.cpp index b176947911..319e1dd394 100644 --- a/src/networkmessage.cpp +++ b/src/networkmessage.cpp @@ -106,7 +106,7 @@ void NetworkMessage::addItem(uint16_t id, uint8_t count) add(it.charges); addByte(0x00); // boolean (is brand new) } else if (it.showClientDuration) { - add(it.decayTime); + add(it.decayTimeMin); addByte(0x00); // boolean (is brand new) }