diff --git a/data/actions/actions.xml b/data/actions/actions.xml index 3c967422..639b1d8c 100644 --- a/data/actions/actions.xml +++ b/data/actions/actions.xml @@ -154,9 +154,6 @@ - - - diff --git a/data/actions/scripts/other/change_gold.lua b/data/actions/scripts/other/change_gold.lua deleted file mode 100644 index 6af63855..00000000 --- a/data/actions/scripts/other/change_gold.lua +++ /dev/null @@ -1,19 +0,0 @@ -local config = { - [ITEM_GOLD_COIN] = {changeTo = ITEM_PLATINUM_COIN}, - [ITEM_PLATINUM_COIN] = {changeBack = ITEM_GOLD_COIN, changeTo = ITEM_CRYSTAL_COIN}, - [ITEM_CRYSTAL_COIN] = {changeBack = ITEM_PLATINUM_COIN} -} - -function onUse(player, item, fromPosition, target, toPosition, isHotkey) - local coin = config[item:getId()] - if coin.changeTo and item.type == 100 then - item:remove() - player:addItem(coin.changeTo, 1) - elseif coin.changeBack then - item:remove(1) - player:addItem(coin.changeBack, 100) - else - return false - end - return true -end diff --git a/data/items/items.xml b/data/items/items.xml index 7c2ccd38..697b0e36 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -2185,6 +2185,7 @@ + @@ -2198,6 +2199,7 @@ + @@ -2222,6 +2224,7 @@ + diff --git a/data/lib/core/player.lua b/data/lib/core/player.lua index aeadbb3a..bb7d3982 100644 --- a/data/lib/core/player.lua +++ b/data/lib/core/player.lua @@ -171,40 +171,20 @@ function Player.canCarryMoney(self, amount) local totalWeight = 0 local inventorySlots = 0 - -- Add crystal coins to totalWeight and inventorySlots - local type_crystal = ItemType(ITEM_CRYSTAL_COIN) - local crystalCoins = math.floor(amount / 10000) - if crystalCoins > 0 then - amount = amount - (crystalCoins * 10000) - while crystalCoins > 0 do - local count = math.min(100, crystalCoins) - totalWeight = totalWeight + type_crystal:getWeight(count) - crystalCoins = crystalCoins - count - inventorySlots = inventorySlots + 1 - end - end - - -- Add platinum coins to totalWeight and inventorySlots - local type_platinum = ItemType(ITEM_PLATINUM_COIN) - local platinumCoins = math.floor(amount / 100) - if platinumCoins > 0 then - amount = amount - (platinumCoins * 100) - while platinumCoins > 0 do - local count = math.min(100, platinumCoins) - totalWeight = totalWeight + type_platinum:getWeight(count) - platinumCoins = platinumCoins - count - inventorySlots = inventorySlots + 1 - end - end - - -- Add gold coins to totalWeight and inventorySlots - local type_gold = ItemType(ITEM_GOLD_COIN) - if amount > 0 then - while amount > 0 do - local count = math.min(100, amount) - totalWeight = totalWeight + type_gold:getWeight(count) - amount = amount - count - inventorySlots = inventorySlots + 1 + local currencyItems = Game.getCurrencyItems() + for index = #currencyItems, 1, -1 do + local currency = currencyItems[index] + -- Add currency coins to totalWeight and inventorySlots + local worth = currency:getWorth() + local currencyCoins = math.floor(amount / worth) + if currencyCoins > 0 then + amount = amount - (currencyCoins * worth) + while currencyCoins > 0 do + local count = math.min(100, currencyCoins) + totalWeight = totalWeight + currency:getWeight(count) + currencyCoins = currencyCoins - count + inventorySlots = inventorySlots + 1 + end end end diff --git a/data/npc/lib/npc.lua b/data/npc/lib/npc.lua index 690db5ee..e387e290 100644 --- a/data/npc/lib/npc.lua +++ b/data/npc/lib/npc.lua @@ -127,10 +127,15 @@ function getMoneyCount(string) end function getMoneyWeight(money) - local gold = money - local crystal = math.floor(gold / 10000) - gold = gold - crystal * 10000 - local platinum = math.floor(gold / 100) - gold = gold - platinum * 100 - return (ItemType(ITEM_CRYSTAL_COIN):getWeight() * crystal) + (ItemType(ITEM_PLATINUM_COIN):getWeight() * platinum) + (ItemType(ITEM_GOLD_COIN):getWeight() * gold) + local weight, currencyItems = 0, Game.getCurrencyItems() + for index = #currencyItems, 1, -1 do + local currency = currencyItems[index] + local worth = currency:getWorth() + local currencyCoins = math.floor(money / worth) + if currencyCoins > 0 then + money = money - (currencyCoins * worth) + weight = weight + currency:getWeight(currencyCoins) + end + end + return weight end diff --git a/data/scripts/actions/others/change_gold.lua b/data/scripts/actions/others/change_gold.lua new file mode 100644 index 00000000..fa1e61cc --- /dev/null +++ b/data/scripts/actions/others/change_gold.lua @@ -0,0 +1,27 @@ +local config = {} + +local changeGold = Action() + +function changeGold.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local coin = config[item:getId()] + if coin.changeTo and item.type == 100 then + item:remove() + player:addItem(coin.changeTo, 1) + elseif coin.changeBack then + item:remove(1) + player:addItem(coin.changeBack, 100) + else + return false + end + return true +end + +local currencyItems = Game.getCurrencyItems() +for index, currency in pairs(currencyItems) do + local back, to = currencyItems[index-1], currencyItems[index+1] + local currencyId = currency:getId() + config[currencyId] = { changeBack = back and back:getId(), changeTo = to and to:getId() } + changeGold:id(currencyId) +end + +changeGold:register() diff --git a/data/scripts/actions/tools/gold_converter.lua b/data/scripts/actions/tools/gold_converter.lua index b366536a..bc6c5063 100644 --- a/data/scripts/actions/tools/gold_converter.lua +++ b/data/scripts/actions/tools/gold_converter.lua @@ -1,8 +1,4 @@ -local config = { - [ITEM_GOLD_COIN] = {changeTo = ITEM_PLATINUM_COIN}, - [ITEM_PLATINUM_COIN] = {changeBack = ITEM_GOLD_COIN, changeTo = ITEM_CRYSTAL_COIN}, - [ITEM_CRYSTAL_COIN] = {changeBack = ITEM_PLATINUM_COIN} -} +local config = {} local goldConverter = Action() @@ -32,5 +28,12 @@ function goldConverter.onUse(player, item, fromPosition, target, toPosition, isH return true end +local currencyItems = Game.getCurrencyItems() +for index, currency in pairs(currencyItems) do + local back, to = currencyItems[index-1], currencyItems[index+1] + local currencyId = currency:getId() + config[currencyId] = { changeBack = back and back:getId(), changeTo = to and to:getId() } +end + goldConverter:id(26378) goldConverter:register() diff --git a/src/game.cpp b/src/game.cpp index ac3b5f16..d3c1129e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1592,39 +1592,26 @@ void Game::addMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/) return; } - uint32_t crystalCoins = money / 10000; - money -= crystalCoins * 10000; - while (crystalCoins > 0) { - const uint16_t count = std::min(100, crystalCoins); + for (const auto& it : Item::items.currencyItems) { + const uint64_t worth = it.first; - Item* remaindItem = Item::CreateItem(ITEM_CRYSTAL_COIN, count); - - ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags); - if (ret != RETURNVALUE_NOERROR) { - internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT); + uint32_t currencyCoins = money / worth; + if (currencyCoins <= 0) { + continue; } - crystalCoins -= count; - } + money -= currencyCoins * worth; + while (currencyCoins > 0) { + const uint16_t count = std::min(100, currencyCoins); - uint16_t platinumCoins = money / 100; - if (platinumCoins != 0) { - Item* remaindItem = Item::CreateItem(ITEM_PLATINUM_COIN, platinumCoins); + Item* remaindItem = Item::CreateItem(it.second, count); - ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags); - if (ret != RETURNVALUE_NOERROR) { - internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT); - } - - money -= platinumCoins * 100; - } - - if (money != 0) { - Item* remaindItem = Item::CreateItem(ITEM_GOLD_COIN, money); + ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags); + if (ret != RETURNVALUE_NOERROR) { + internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT); + } - ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags); - if (ret != RETURNVALUE_NOERROR) { - internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT); + currencyCoins -= count; } } } diff --git a/src/item.cpp b/src/item.cpp index f2e68606..3df42cf8 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1457,19 +1457,7 @@ bool Item::canDecay() const uint32_t Item::getWorth() const { - switch (id) { - case ITEM_GOLD_COIN: - return count; - - case ITEM_PLATINUM_COIN: - return count * 100; - - case ITEM_CRYSTAL_COIN: - return count * 10000; - - default: - return 0; - } + return items[id].worth * count; } LightInfo Item::getLightInfo() const diff --git a/src/items.cpp b/src/items.cpp index bb45d136..186d972a 100644 --- a/src/items.cpp +++ b/src/items.cpp @@ -185,6 +185,7 @@ const std::unordered_map ItemParseAttributes {"allowdistread", ITEM_PARSE_ALLOWDISTREAD}, {"storeitem", ITEM_PARSE_STOREITEM}, {"imbuementslots", ITEM_PARSE_IMBUEMENT_SLOT}, + {"worth", ITEM_PARSE_WORTH}, }; const std::unordered_map ItemTypesMap = { @@ -263,6 +264,7 @@ void Items::clear() items.clear(); clientIdToServerIdMap.clear(); nameToItems.clear(); + currencyItems.clear(); inventory.clear(); } @@ -1672,6 +1674,17 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id) break; } + case ITEM_PARSE_WORTH: { + uint64_t worth = pugi::cast(valueAttribute.value()); + if (currencyItems.find(worth) != currencyItems.end()) { + std::cout << "[Warning - Items::parseItemNode] Duplicated currency worth. Item " << id << " redefines worth " << worth << std::endl; + } else { + currencyItems.insert(CurrencyMap::value_type(worth, id)); + it.worth = worth; + } + break; + } + default: { // It should not ever get to here, only if you add a new key to the map and don't configure a case for it. std::cout << "[Warning - Items::parseItemNode] Not configured key value: " << keyAttribute.as_string() << std::endl; diff --git a/src/items.h b/src/items.h index fc370071..d92ea0f7 100644 --- a/src/items.h +++ b/src/items.h @@ -200,6 +200,7 @@ enum ItemParseAttributes_t { ITEM_PARSE_ALLOWDISTREAD, ITEM_PARSE_STOREITEM, ITEM_PARSE_IMBUEMENT_SLOT, + ITEM_PARSE_WORTH, }; struct Abilities { @@ -371,6 +372,7 @@ class ItemType uint16_t rotateTo = 0; int32_t runeMagLevel = 0; int32_t runeLevel = 0; + uint64_t worth = 0; CombatType_t combatType = COMBAT_NONE; @@ -438,6 +440,8 @@ class Items using NameMap = std::unordered_multimap; using InventoryVector = std::vector; + using CurrencyMap = std::map>; + Items(); // non-copyable @@ -475,6 +479,7 @@ class Items } NameMap nameToItems; + CurrencyMap currencyItems; private: std::vector items; diff --git a/src/luascript.cpp b/src/luascript.cpp index 17f62f8a..40e65003 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -2136,6 +2136,7 @@ void LuaScriptInterface::registerFunctions() registerMethod("Game", "getPlayerCount", LuaScriptInterface::luaGameGetPlayerCount); registerMethod("Game", "getNpcCount", LuaScriptInterface::luaGameGetNpcCount); registerMethod("Game", "getMonsterTypes", LuaScriptInterface::luaGameGetMonsterTypes); + registerMethod("Game", "getCurrencyItems", LuaScriptInterface::luaGameGetCurrencyItems); registerMethod("Game", "getTowns", LuaScriptInterface::luaGameGetTowns); registerMethod("Game", "getHouses", LuaScriptInterface::luaGameGetHouses); @@ -2318,6 +2319,7 @@ void LuaScriptInterface::registerFunctions() registerMethod("Item", "getCharges", LuaScriptInterface::luaItemGetCharges); registerMethod("Item", "getFluidType", LuaScriptInterface::luaItemGetFluidType); registerMethod("Item", "getWeight", LuaScriptInterface::luaItemGetWeight); + registerMethod("Item", "getWorth", LuaScriptInterface::luaItemGetWorth); registerMethod("Item", "getSubType", LuaScriptInterface::luaItemGetSubType); @@ -2865,6 +2867,7 @@ void LuaScriptInterface::registerFunctions() registerMethod("ItemType", "getFluidSource", LuaScriptInterface::luaItemTypeGetFluidSource); registerMethod("ItemType", "getCapacity", LuaScriptInterface::luaItemTypeGetCapacity); registerMethod("ItemType", "getWeight", LuaScriptInterface::luaItemTypeGetWeight); + registerMethod("ItemType", "getWorth", LuaScriptInterface::luaItemTypeGetWorth); registerMethod("ItemType", "getHitChance", LuaScriptInterface::luaItemTypeGetHitChance); registerMethod("ItemType", "getShootRange", LuaScriptInterface::luaItemTypeGetShootRange); @@ -4565,6 +4568,22 @@ int LuaScriptInterface::luaGameGetMonsterTypes(lua_State* L) return 1; } +int LuaScriptInterface::luaGameGetCurrencyItems(lua_State* L) +{ + // Game.getCurrencyItems() + const auto& currencyItems = Item::items.currencyItems; + size_t size = currencyItems.size(); + lua_createtable(L, size, 0); + + for (const auto& it : currencyItems) { + const ItemType& itemType = Item::items[it.second]; + pushUserdata(L, &itemType); + setMetatable(L, -1, "ItemType"); + lua_rawseti(L, -2, size--); + } + return 1; +} + int LuaScriptInterface::luaGameGetTowns(lua_State* L) { // Game.getTowns() @@ -6769,6 +6788,18 @@ int LuaScriptInterface::luaItemGetWeight(lua_State* L) return 1; } +int LuaScriptInterface::luaItemGetWorth(lua_State* L) +{ + // item:getWorth() + Item* item = getUserdata(L, 1); + if (item) { + lua_pushnumber(L, item->getWorth()); + } else { + lua_pushnil(L); + } + return 1; +} + int LuaScriptInterface::luaItemGetSubType(lua_State* L) { // item:getSubType() @@ -13132,6 +13163,19 @@ int LuaScriptInterface::luaItemTypeGetWeight(lua_State* L) return 1; } +int LuaScriptInterface::luaItemTypeGetWorth(lua_State* L) +{ + // itemType:getWorth() + const ItemType* itemType = getUserdata(L, 1); + if (!itemType) { + lua_pushnil(L); + return 1; + } + + lua_pushnumber(L, itemType->worth); + return 1; +} + int LuaScriptInterface::luaItemTypeGetHitChance(lua_State* L) { // itemType:getHitChance() diff --git a/src/luascript.h b/src/luascript.h index f511fdc2..17ec47fd 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -563,6 +563,7 @@ class LuaScriptInterface static int luaGameGetPlayerCount(lua_State* L); static int luaGameGetNpcCount(lua_State* L); static int luaGameGetMonsterTypes(lua_State* L); + static int luaGameGetCurrencyItems(lua_State* L); static int luaGameGetTowns(lua_State* L); static int luaGameGetHouses(lua_State* L); @@ -739,6 +740,7 @@ class LuaScriptInterface static int luaItemGetCharges(lua_State* L); static int luaItemGetFluidType(lua_State* L); static int luaItemGetWeight(lua_State* L); + static int luaItemGetWorth(lua_State* L); static int luaItemGetSubType(lua_State* L); @@ -1277,6 +1279,7 @@ class LuaScriptInterface static int luaItemTypeGetFluidSource(lua_State* L); static int luaItemTypeGetCapacity(lua_State* L); static int luaItemTypeGetWeight(lua_State* L); + static int luaItemTypeGetWorth(lua_State* L); static int luaItemTypeGetHitChance(lua_State* L); static int luaItemTypeGetShootRange(lua_State* L); diff --git a/src/player.cpp b/src/player.cpp index 58ebaa1e..46dfe2f8 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -3281,7 +3281,15 @@ void Player::postRemoveNotification(Thing* thing, const Cylinder* newParent, int bool Player::updateSaleShopList(const Item* item) { uint16_t itemId = item->getID(); - if (itemId != ITEM_GOLD_COIN && itemId != ITEM_PLATINUM_COIN && itemId != ITEM_CRYSTAL_COIN) { + bool isCurrency = false; + for (const auto& it : Item::items.currencyItems) { + if (it.second == itemId) { + isCurrency = true; + break; + } + } + + if (!isCurrency) { auto it = std::find_if(shopItemList.begin(), shopItemList.end(), [itemId](const ShopInfo& shopInfo) { return shopInfo.itemId == itemId && shopInfo.sellPrice != 0; }); if (it == shopItemList.end()) { const Container* container = item->getContainer();