local openShop_With_ActionID = nil
local openShop_With_ItemID = nil
local openShop_StorageID = nil
local openShop_StorageValue = nil
local openShop_MessageFailStorage = "nil"
local mOdAlWiNdOw_iD = 99999 -- Try to keep this ID unique for this window
local shop = {}
local modalWindow = ModalWindow(mOdAlWiNdOw_iD, "~ Shop Item List ~", "List of items available in the shop.")
modalWindow:addButton(1, "Buy")
modalWindow:addButton(2, "Sell")
modalWindow:addButton(3, "Close")
modalWindow:setDefaultEscapeButton(3)
modalWindow:setDefaultEnterButton(3)
local function getMoneyString(gp)
if gp < 1000 then
return string.format("%dgp", gp)
elseif gp < 1000000 then
local k = gp / 1000
gp = gp % 1000
return string.format("%dk%s", k, (gp > 0 and string.format(" %dgp", gp) or ""))
end
local kk = gp / 1000000
gp = gp % 1000000
local k = gp / 1000
gp = gp % 1000
return string.format("%dkk%s", kk, (k > 0 and string.format(" %dk%s", k, (gp > 0 and string.format(" %dgp", gp) or "")) or (gp > 0 and string.format(" %dgp", gp) or "")))
end
local index = 1
for name, item in pairs({
-- The names are converted to lowercase letters automatically, don't worry.
-- Note: for stackable items the maximum quantity is 100, and for non-stackable items the maximum quantity is 1
-- Examples:
["Demon Helmet"] = { id=2493, price=3000000, sell=1500000 },
["Demon Armor"] = { id=2494, price=3000000, sell=1500000 },
["Demon Legs"] = { id=2495, price=3000000, sell=1500000 },
["Banana"] = { id=2676, price=3000000, sell=1500000, count=100 },
["Pear"] = { id=2673, price=20, sell=15, count=25, currency=2674 },
["Blood Herb"] = { id=2798, price=80, sell=40, count=6, storagePay=78545, moneyName="$dollar" }
}) do
local lowerCaseName = name:lower()
if index <= 255 then -- This is due to the client's limitations, in the future I may improve this system so that it has pages, but for now that is all
modalWindow:addChoice(index, string.format("%d %s %s %s", math.min(item.count and item.count or 1, 100), lowerCaseName, string.char(215), (item.storagePay and string.format("%d %s", item.price, item.moneyName) or (item.currency and string.format("%d %s(s)", item.price, ItemType(item.currency):getName()) or getMoneyString(item.price))) ))
shop[index] = lowerCaseName -- for help to modalWindow
index = index +1
end
shop[lowerCaseName] = item
end
local function buyItem(player, param)
local item = shop[param:lower()]
if not item then
player:sendCancelMessage(string.format("Item with name %s not found!", param))
return false
end
local money = 0
if item.storagePay then
money = player:getStorageValue(item.storagePay)
if money < item.price then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("You don't have enough %s, You need %d %s.", item.moneyName, item.price, item.moneyName))
return false
end
elseif item.currency then
money = player:getItemCount(item.currency)
if money < item.price then
local moneyName = ItemType(item.currency):getName()
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("You don't have enough %s, You need %d %s.", moneyName, item.price, moneyName))
return false
end
else
money = player:getMoney()
local bankBalance = player:getBankBalance()
local totalMoney = money + bankBalance
if totalMoney < item.price then
player:sendCancelMessage(string.format("You don't have enough gold coins, You need %s", getMoneyString(item.price)))
return false
end
end
local buyedItem = Game.createItem(item.id, math.min((item.count and item.count or 1), 100))
if not buyedItem or not buyedItem:getType():isMovable() then
print(string.format("Warning: The shop item with ID: %d is invalid.\n%s", item.id, debug.traceback()))
Item.remove(buyedItem) -- in case the buyedItem is nil, no problem will occur
return false
end
if player:addItemEx(buyedItem) ~= RETURNVALUE_NOERROR then
player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
buyedItem:remove()
return false
end
if item.storagePay then
player:setStorageValue(item.storagePay, money - item.price)
elseif item.currency then
player:removeItem(item.currency, item.price)
else
local resultMoney = money - item.price
if resultMoney < 0 then
bankBalance = player:getBankBalance()
player:removeMoney(money)
player:setBankBalance(bankBalance + resultMoney)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("You now have %d zennis, Bank Balance:(%d zennis).", money, player:getBankBalance()))
else
player:removeMoney(item.price)
end
end
--player:getPosition():sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("Your purchase was successful! (%d %s).\n%s", math.min(item.count and item.count or 1, 100), buyedItem:getName(), (item.storagePay and string.format("You pay with %d %s.", item.price, item.moneyName) or (item.currency and string.format("You pay with %d %s.", item.price, ItemType(item.currency):getName()) or string.format("You pay with %s.", getMoneyString(item.price))))))
return false
end
local function sellItem(player, itemName)
if not itemName then
return false
end
local item = shop[itemName:lower()]
if not item then
player:sendCancelMessage(string.format("Item with name %s not found!", itemName))
return false
end
local itemCount = item.count or 1
if not player:removeItem(item.id, itemCount) then
player:sendCancelMessage(string.format("You do not have %d %s in your inventory.", itemCount, itemName))
return false
end
if item.storagePay then
player:setStorageValue(item.storagePay, player:getStorageValue(item.storagePay) + item.sell)
elseif item.currency then
player:addItem(item.currency, item.sell)
else
player:setBankBalance(player:getBankBalance() + item.sell)
end
--player:getPosition():sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("Your sale was successful! (%d %s).\n%s", math.min(item.count and item.count or 1, 100), itemName, (item.storagePay and string.format("You receive %d %s.", item.sell, item.moneyName) or (item.currency and string.format("You receive %d %s.", item.sell, ItemType(item.currency):getName()) or string.format("You receive %s to your bank balance.", getMoneyString(item.sell))))))
return false
end
local talkAction = TalkAction("!shop")
function talkAction.onSay(player, words, param, type)
if param == "list" then
if openShop_StorageID then
if player:getStorageValue(openShop_StorageID) ~= openShop_StorageValue then
player:sendCancelMessage(openShop_MessageFailStorage)
return false
end
end
modalWindow:sendToPlayer(player)
return false
elseif param == "sell" then
return sellItem(player, param:splitTrimmed(",")[2])
end
return buyItem(player, param)
end
talkAction:separator(" ")
talkAction:register()
if openShop_With_ActionID or openShop_With_ItemID then
local action = Action()
function action.onUse(player, item, fromPos, target, toPos, isHotkey)
if openShop_StorageID then
if player:getStorageValue(openShop_StorageID) ~= openShop_StorageValue then
player:sendCancelMessage(openShop_MessageFailStorage)
return false
end
end
modalWindow:sendToPlayer(player)
return true
end
if openShop_With_ItemID then action:id(openShop_With_ItemID) end
if openShop_With_ActionID then action:aid(openShop_With_ActionID) end
action:register()
end
local creatureEvent = CreatureEvent("shopModalWindow")
function creatureEvent.onModalWindow(player, modalWindowId, buttonId, choiceId)
if modalWindowId == mOdAlWiNdOw_iD then
if buttonId == 1 then
local param = shop[choiceId]
if not param then
return true
end
buyItem(player, param)
return true
elseif buttonId == 2 then
local param = shop[choiceId]
if not param then
return true
end
sellItem(player, param)
return true
end
end
return true
end
creatureEvent:register()
local creatureEvent = CreatureEvent("shopRegister")
function creatureEvent.onLogin(player)
player:registerEvent("shopModalWindow")
return true
end
creatureEvent:register()