I think it is easy to abuse and cause crash. You are checking![]()
Lua - Xikini's Free Scripting Service TFS 1.4.2
Request whatever you want, within reason. Please do not request for things that require source editing or database queries. ------------------------------------ If I've reacted to your post, it means I've read it. 👍😍🤣😲🙁😡🤔😉 ------------------------------------ Completed Requests A boss that...otland.net
In the 4th.or 5th post merge I do what you're trying to do.
They use the item, then choose a reward with modal window, and then it removes the item that was used.
not usedItem
but its not gonna work, if you for example throw that usedItem
into into lava/bin after using the item it will still hold userdata so that not usedItem
won't be true
. Test it to be sure if it is gonna crash or just throw some Lua error.yo, I was thinking something similar, just trade the item and accept before using it will cause some problem imoI think it is easy to abuse and cause crash. You are checkingnot usedItem
but its not gonna work, if you for example throw thatusedItem
into into lava/bin after using the item it will still hold userdata so thatnot usedItem
won't betrue
. Test it to be sure if it is gonna crash or just throw some Lua error.
I think it is easy to abuse and cause crash. You are checkingnot usedItem
but its not gonna work, if you for example throw thatusedItem
into into lava/bin after using the item it will still hold userdata so thatnot usedItem
won't betrue
. Test it to be sure if it is gonna crash or just throw some Lua error.
View attachment bandicam 2024-04-29 20-31-41-284.mp4yo, I was thinking something similar, just trade the item and accept before using it will cause some problem imo
I think trash bin is a container so the item still exists. Trading is also moving the item not recreating it. Try with lava.
View attachment bandicam 2024-04-29 21-27-18-895.mp4I think trash bin is a container so the item still exists. Trading is also moving the item not recreating it. Try with lava.
Edit: Nvm.
This is weird behavior tho. How is the item returning something with getTopParent if the item doesn't exist anymore?
if not usedItem then
if not usedItem or not Item(usedItem.uid) then
Your code causes undefined behaviour, you cant store userdata like that. It may be deleted or not, if it is, it doesn't necessarily mean it will crash, its ub.![]()
Lua - Xikini's Free Scripting Service TFS 1.4.2
Request whatever you want, within reason. Please do not request for things that require source editing or database queries. ------------------------------------ If I've reacted to your post, it means I've read it. 👍😍🤣😲🙁😡🤔😉 ------------------------------------ Completed Requests A boss that...otland.net
In the 4th.or 5th post merge I do what you're trying to do.
They use the item, then choose a reward with modal window, and then it removes the item that was used.
local rewardBagItemId = 1950
local config = {
modalWindow = {
id = 1001, -- needs to be unique number?
title = "Reward Bag",
message = "Choose a reward from the list!",
eventText = "ModalWindow_Reward_Bag",
buttons = {
{text = "Choose", defaultEnterButton = true},
{text = "Cancel", defaultEscapeButton = true},
}
},
rewards = {
{itemId = 2160, amount = 1},
{itemId = 2160, amount = 3}, -- add as many as you want.
{itemId = 2160, amount = 10}
}
}
-- END OF CONFIG
local usedItems = {
-- [playerId] = item
}
local function getItemNameString(item)
return item:getNameDescription(item:getSubType(), true)
end
local function createRewardBagWindow(playerId)
local player = Player(playerId)
if not player then
return
end
player:unregisterEvent(config.modalWindow.eventText)
player:registerEvent(config.modalWindow.eventText)
local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
for id, button in ipairs(config.modalWindow.buttons) do
modalWindow:addButton(id, button.text)
if button.defaultEscapeButton then
modalWindow:setDefaultEscapeButton(id)
elseif button.defaultEnterButton then
modalWindow:setDefaultEnterButton(id)
end
end
for id, v in ipairs(config.rewards) do
local item = Game.createItem(v.itemId, v.amount)
local text = getItemNameString(item)
modalWindow:addChoice(id, text)
end
modalWindow:hasPriority()
modalWindow:sendToPlayer(player)
end
local action = Action()
function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
local _player = Player(item:getTopParent())
if not _player then
player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
return true
end
item:setCustomAttribute("onUse_chooseItemReward", true)
usedItems[player:getId()] = item
createRewardBagWindow(player:getId())
return true
end
action:id(rewardBagItemId)
action:register()
local creatureevent = CreatureEvent(config.modalWindow.eventText)
function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
player:unregisterEvent(config.modalWindow.eventText)
if modalWindowId == config.modalWindow.id then
local buttonChoice = config.modalWindow.buttons[buttonId].text
local playerId = player:getId()
if buttonChoice == "Choose" then
local usedItem = usedItems[playerId]
if not usedItem or not Item(usedItem.uid) then
player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag no longer exists.")
player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
usedItems[playerId] = nil
return true
end
local _player = Player(usedItem:getTopParent())
if not _player or _player:getId() ~= playerId then
player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
usedItems[playerId] = nil
return true
end
local item = Game.createItem(config.rewards[choiceId].itemId, config.rewards[choiceId].amount)
if not player:addItemEx(item, false) then
player:sendTextMessage(MESSAGE_STATUS_SMALL, "You do not have the room or capacity to receive this item.")
player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
usedItems[playerId] = nil
return true
end
player:say("You received " .. getItemNameString(item), TALKTYPE_MONSTER_SAY, nil, player)
player:getPosition():sendMagicEffect(CONST_ME_HEARTS)
usedItem:remove(1)
usedItems[playerId] = nil
else
-- "Cancel" button
usedItems[playerId] = nil
return true
end
end
return true
end
creatureevent:register()
local event = EventCallback
function event.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
if item:getCustomAttribute("onUse_chooseItemReward") then
item:removeCustomAttribute("onUse_chooseItemReward")
usedItems[player:getId()] = nil
end
return RETURNVALUE_NOERROR
end
event:register()
Same issue, don't store the item in table. Store item id, then get item by that id from player and validate it and then remove.Anyway, here I leave a modification of the script that is much safer and should not cause errors in 99.9% of the cases
LUA:local rewardBagItemId = 1950 local config = { modalWindow = { id = 1001, -- needs to be unique number? title = "Reward Bag", message = "Choose a reward from the list!", eventText = "ModalWindow_Reward_Bag", buttons = { {text = "Choose", defaultEnterButton = true}, {text = "Cancel", defaultEscapeButton = true}, } }, rewards = { {itemId = 2160, amount = 1}, {itemId = 2160, amount = 3}, -- add as many as you want. {itemId = 2160, amount = 10} } } -- END OF CONFIG local usedItems = { -- [playerId] = item } local function getItemNameString(item) return item:getNameDescription(item:getSubType(), true) end local function createRewardBagWindow(playerId) local player = Player(playerId) if not player then return end player:unregisterEvent(config.modalWindow.eventText) player:registerEvent(config.modalWindow.eventText) local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message) for id, button in ipairs(config.modalWindow.buttons) do modalWindow:addButton(id, button.text) if button.defaultEscapeButton then modalWindow:setDefaultEscapeButton(id) elseif button.defaultEnterButton then modalWindow:setDefaultEnterButton(id) end end for id, v in ipairs(config.rewards) do local item = Game.createItem(v.itemId, v.amount) local text = getItemNameString(item) modalWindow:addChoice(id, text) end modalWindow:hasPriority() modalWindow:sendToPlayer(player) end local action = Action() function action.onUse(player, item, fromPosition, target, toPosition, isHotkey) local _player = Player(item:getTopParent()) if not _player then player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.") player:getPosition():sendMagicEffect(CONST_ME_POFF, player) return true end item:setCustomAttribute("onUse_chooseItemReward", true) usedItems[player:getId()] = item createRewardBagWindow(player:getId()) return true end action:id(rewardBagItemId) action:register() local creatureevent = CreatureEvent(config.modalWindow.eventText) function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId) player:unregisterEvent(config.modalWindow.eventText) if modalWindowId == config.modalWindow.id then local buttonChoice = config.modalWindow.buttons[buttonId].text local playerId = player:getId() if buttonChoice == "Choose" then local usedItem = usedItems[playerId] if not usedItem or not Item(usedItem.uid) then player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag no longer exists.") player:getPosition():sendMagicEffect(CONST_ME_POFF, player) usedItems[playerId] = nil return true end local _player = Player(usedItem:getTopParent()) if not _player or _player:getId() ~= playerId then player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.") player:getPosition():sendMagicEffect(CONST_ME_POFF, player) usedItems[playerId] = nil return true end local item = Game.createItem(config.rewards[choiceId].itemId, config.rewards[choiceId].amount) if not player:addItemEx(item, false) then player:sendTextMessage(MESSAGE_STATUS_SMALL, "You do not have the room or capacity to receive this item.") player:getPosition():sendMagicEffect(CONST_ME_POFF, player) usedItems[playerId] = nil return true end player:say("You received " .. getItemNameString(item), TALKTYPE_MONSTER_SAY, nil, player) player:getPosition():sendMagicEffect(CONST_ME_HEARTS) usedItem:remove(1) usedItems[playerId] = nil else -- "Cancel" button usedItems[playerId] = nil return true end end return true end creatureevent:register() local event = EventCallback function event.onMoveItem(player, item, count, fromPosition, toPosition, fromCylinder, toCylinder) if item:getCustomAttribute("onUse_chooseItemReward") then item:removeCustomAttribute("onUse_chooseItemReward") usedItems[player:getId()] = nil end return RETURNVALUE_NOERROR end event:register()
That's just removing a random item instead of the item that was used, tho?Same issue, don't store the item in table. Store item id, then get item by that id from player and validate it and then remove.
What's the difference in Tibia? ItemType is ItemType, what does it matter if its in slot 2 of 4 or in bp 1 or bp 5?That's just removing a random item instead of the item that was used, tho?
Player experience.What's the difference in Tibia? ItemType is ItemType, what does it matter if its in slot 2 of 4 or in bp 1 or bp 5?