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();