• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua Snavy & Levi - Free Scripting Service - TFS 1.3

Status
Not open for further replies.

Snavy

Bakasta
Senator
Joined
Apr 1, 2012
Messages
1,249
Solutions
71
Reaction score
621
Location
Hell
@Levi999x and I will be providing scripting service for free.
The thread will be locked after a while but might be unlocked again later.



[ REQUIREMENTS ]

TFS
: 1.3(+) ( github.com/otland/forgottenserver )

SCRIPTS: Actions, Creaturescripts, Globalevents, Movements, Talkactions

INFO: Give a detailed explanation of what you want.
If we fail to understand what you're saying your request will probably be ignored.



[ SUPPORT ]
If you have any problems with the scripts, feel free to open a new thread in the
support board and make sure you follow the rules.



[⚠️ WARNING ⚠️]
Your post will be deleted if you ask for help in this thread.
You may not PM either of us for script requests.
Requests which require source modifications will be ignored.

Requests for the following engines will be ignored.
  • OTBR,
  • OTX,
  • TFS 1.2(or lower)



If either of us reacts like (👍) on your request, that means it is accepted.
 
Last edited:
I want a script that when executing a command like for example: /mytalk
then a snake mode spiral appears starting from your character's location outwards, executing a firing effect for each tile along the way
I forgot to mention that the maximum distance is 7x7
an example of what I expect is the following:

GIF 03-04-2021 11-50-11 a. m..gif
Thank you for this!
 
Last edited:
Event -> Player vs Monster Arena

At X time of day, Event will auto-start.
Y amount of players join the Arena via talkaction. (can only join whilst in a PZ zone)
Z amount of waves of monsters spawn
Each wave that is completed gives all remaining players in the event an experience gift
Final wave spawns a Boss monster when majority of creatures in that wave are destroyed
Remaining players in event after the final wave is completed are teleported to a reward room
Reward room chest when used successfully, will teleport players out of the Event to their temple.

--------------
-> random monsters
-> random rewards

Arena has a difficulty scaling feature based on how many players are in the event.
(Difficulty scales downwards as players are removed from the event after reaching 0 health)

-> -> Monsters get more..
-> Health
-> Damage
-> Life
-> Monster Amount per Wave

Each Difficulty also
-> Spawns different sets of Monsters & final Boss
-> Gives different rewards
-> Gives a scaling experience reward per wave completed

Hope that's clear enough. :)
 
I am trying to use a talkaction that should show the items that a certain player is using, delete that and also find out which player has that item in the body by ID. The biggest problem is, it only works for a player that has only one word nickname, if for example "/ p check, nameone nametwo" the script does not recognize it.

Here is the code:
Lua:
function getItemsInContainer(cont, sep)
    local text = ""
    local tsep = ""
    local count = ""
    for i=1, sep do
        tsep = tsep.."-"
    end
    tsep = tsep..">"
    for i=0, Container(cont.uid):getSize() - 1 do
        local item = pushThing(Container(cont.uid):getItem(i))
        if not Container(item.uid) then
            if item.type > 1 then
                count = " ("..item.type.."x)"
            end
            text = text.."\n"..tsep..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
        else
            if Container(item.uid):getSize() > 0 then
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
                text = text..getItemsInContainer(item, sep+2)..""
            else
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
            end
        end
    end
    return text
end

function onSay(player, words, param)
    if not player:getGroup():getAccess() then
        return true
    end
    
    if player:getAccountType() < ACCOUNT_TYPE_GOD then
        return false
    end
    
    if(param == '') then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Command param required.")
        return false
    end
    
    local slotName = {"Head", "Amulet", "Backpack", "Armor", "Right Hand", "Left Hand", "Legs", "Feet", "Ring", "Ammo Slot"}
    local t = param:split(', ')
    if(t[1] == 'check') then
        local p = Player(t[2])
        if p then
            local text = p:getName().."'s Equipment: "
            for i=1, 10 do
                text = text.."\n\n"
                local item = pushThing(Player(p:getName()):getSlotItem(i))
                if item.itemid > 0 then
                    count = ''
                    if item.type > 1 then
                        count = " ("..item.type.."x)"
                    end
                    if Container(item.uid) then
                        text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..") "..getItemsInContainer(item, 1)
                    else
                        text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
                    end
                else
                    text = text..slotName[i]..": Empty"
                end
            end
            player:showTextDialog(6579, text)
        else
            player:sendCancelMessage("This player is not online or not exist.")
        end
    elseif(t[1] == 'delete') then
        local p = Player(t[2])
        if p then
            count = t[4]
            if(not t[4]) then
                count = 1
            end
            if Player(p:getName()):getItemCount(t[3]) > 0 then
                if Player(p:getId()):removeItem(t[3], count) then
                    player:sendCancelMessage("Deleted Item.")
                else
                    player:sendCancelMessage("This player does not have this amount of item.")
                end
            else
                player:sendCancelMessage("This player does not have the item.")
            end
        else
            player:sendCancelMessage("This player is not online or not exist.")
        end
    else
        local id = ItemType(t[1]):getId()
        if id == 0 then
            return player:sendCancelMessage("The "..t[1].." not exist. ")
        end
        local query = db.storeQuery("SELECT name FROM players WHERE id IN (SELECT player_id FROM player_items WHERE itemtype = ".. id ..");")
        local msg = "Search results by item ".. ItemType(id):getName() .." in your database:\n\n"
        if (query ~= false) then
            while true do
                local name = result.getString(query, "name")
                msg = msg .. name .."\n"
                if not result.next(query) then
                    break
                end
            end
        else
            msg = msg .. "The item was not found in any player."
        end
        player:showTextDialog(id, msg)
    end
    return false
end

The respective functions would be:
/p check, (PNAME) - He checks the items that the player has.
/p del, (ID), (PNAME), (COUNT) - It deletes the item of particular player.
/p (ID) - It checks how many players have this item.

Thanks
 
I want a script that when executing a command like for example: /mytalk
then a snake mode spiral appears starting from your character's location outwards, executing a firing effect for each tile along the way
I forgot to mention that the maximum distance is 7x7
an example of what I expect is the following:

View attachment 57256
Thank you for this!

Lua:
local config = {
    spiralSpeed = 100,
    maxRadius   = 7
}

local function directionCheck(startPosition, position, topEdge, bottomEdge, leftEdge, rightEdge, dirX, dirY)
    if startPosition.y == position.y and ((position.x == leftEdge) or (position.x == rightEdge)) then
        dirX = dirX * -1
    end

    if startPosition.x == position.x and ((position.y == topEdge) or (position.y == bottomEdge)) then
        dirY = dirY * -1
    end

    position.x = position.x + dirX
    position.y = position.y + dirY
    return dirX, dirY
end

local function startSpiral(radius, round_n, position, startPosition, dirX, dirY, n_count, isFirst)
    if radius >= config.maxRadius then return end
    position:sendMagicEffect(CONST_ME_FIREAREA)

    if isFirst then
        position.x = position.x + dirX
        position.y = position.y + dirY
        addEvent(
            startSpiral, config.spiralSpeed, radius, round_n,
            position, startPosition, dirX, dirY, n_count+1, false
        )
        return
    end

    local topEdge    = (startPosition.y - radius)
    local bottomEdge = (startPosition.y + radius)
    local leftEdge   = (startPosition.x - radius)
    local rightEdge  = (startPosition.x + radius)

    if n_count == math.pow(round_n, 2) then
        position.x = position.x + dirX
        position.y = position.y + dirY

        local dX = math.abs(startPosition.x - position.x)
        local dY = math.abs(startPosition.y - position.y)

        if dX > dY then 
            dirX = dirX * -1
        elseif dY > dX then
            dirY = dirY * -1
        end

        addEvent(
            startSpiral, config.spiralSpeed, radius + 2, round_n + 2,
            position, startPosition, dirX, dirY, n_count+1, false
        )
        return
    end

    dirX, dirY = directionCheck(startPosition, position, topEdge, bottomEdge, leftEdge, rightEdge, dirX, dirY)
    addEvent(
        startSpiral, config.spiralSpeed, radius, round_n,
        position, startPosition, dirX, dirY, n_count+1, false
    )
end

local talkaction = TalkAction('!spiral')
function talkaction.onSay(player, words, param)
    local playerPos = player:getPosition()
    local startPosition = Position(playerPos.x, playerPos.y, playerPos.z)
    playerPos:getNextPosition(player:getDirection())
    local position = Position(playerPos.x, playerPos.y, playerPos.z)
    local radius = 1
    local dirX = (position.x < startPosition.x and 1) or -1
    local dirY = (position.y < startPosition.y and 1) or -1
    startSpiral(radius, 2, position, startPosition, dirX, dirY, 0, true)
    return false
end

talkaction:separator(" ")
talkaction:register()
--[[
        4 16 36 64
        16 -  4 = 12
        36 - 16 = 20
        64 - 36 = 28
]]

ezgif.com-gif-maker(4).gif
 
ezgif-com-gif-maker-4-gif.57271

Amazing! This looks sick for an action/creatureevent in case you enter to a boss room or after finishing a large challenge 😵
Never thought it was going to look like that, keep up the good work!
 
I want a boss every 10 seconds to transform and return to its correct form with the hp they have taken away

the boss's name is : Ghulosh
the name of its transformation is : Ghulosh' Deathgaze

Note: every 10 seconds it transforms and every 10 seconds it returns to its correct form
 
I am trying to use a talkaction that should show the items that a certain player is using, delete that and also find out which player has that item in the body by ID. The biggest problem is, it only works for a player that has only one word nickname, if for example "/ p check, nameone nametwo" the script does not recognize it.

Here is the code:
Lua:
function getItemsInContainer(cont, sep)
    local text = ""
    local tsep = ""
    local count = ""
    for i=1, sep do
        tsep = tsep.."-"
    end
    tsep = tsep..">"
    for i=0, Container(cont.uid):getSize() - 1 do
        local item = pushThing(Container(cont.uid):getItem(i))
        if not Container(item.uid) then
            if item.type > 1 then
                count = " ("..item.type.."x)"
            end
            text = text.."\n"..tsep..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
        else
            if Container(item.uid):getSize() > 0 then
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
                text = text..getItemsInContainer(item, sep+2)..""
            else
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
            end
        end
    end
    return text
end

function onSay(player, words, param)
    if not player:getGroup():getAccess() then
        return true
    end
   
    if player:getAccountType() < ACCOUNT_TYPE_GOD then
        return false
    end
   
    if(param == '') then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Command param required.")
        return false
    end
   
    local slotName = {"Head", "Amulet", "Backpack", "Armor", "Right Hand", "Left Hand", "Legs", "Feet", "Ring", "Ammo Slot"}
    local t = param:split(', ')
    if(t[1] == 'check') then
        local p = Player(t[2])
        if p then
            local text = p:getName().."'s Equipment: "
            for i=1, 10 do
                text = text.."\n\n"
                local item = pushThing(Player(p:getName()):getSlotItem(i))
                if item.itemid > 0 then
                    count = ''
                    if item.type > 1 then
                        count = " ("..item.type.."x)"
                    end
                    if Container(item.uid) then
                        text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..") "..getItemsInContainer(item, 1)
                    else
                        text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
                    end
                else
                    text = text..slotName[i]..": Empty"
                end
            end
            player:showTextDialog(6579, text)
        else
            player:sendCancelMessage("This player is not online or not exist.")
        end
    elseif(t[1] == 'delete') then
        local p = Player(t[2])
        if p then
            count = t[4]
            if(not t[4]) then
                count = 1
            end
            if Player(p:getName()):getItemCount(t[3]) > 0 then
                if Player(p:getId()):removeItem(t[3], count) then
                    player:sendCancelMessage("Deleted Item.")
                else
                    player:sendCancelMessage("This player does not have this amount of item.")
                end
            else
                player:sendCancelMessage("This player does not have the item.")
            end
        else
            player:sendCancelMessage("This player is not online or not exist.")
        end
    else
        local id = ItemType(t[1]):getId()
        if id == 0 then
            return player:sendCancelMessage("The "..t[1].." not exist. ")
        end
        local query = db.storeQuery("SELECT name FROM players WHERE id IN (SELECT player_id FROM player_items WHERE itemtype = ".. id ..");")
        local msg = "Search results by item ".. ItemType(id):getName() .." in your database:\n\n"
        if (query ~= false) then
            while true do
                local name = result.getString(query, "name")
                msg = msg .. name .."\n"
                if not result.next(query) then
                    break
                end
            end
        else
            msg = msg .. "The item was not found in any player."
        end
        player:showTextDialog(id, msg)
    end
    return false
end

The respective functions would be:
/p check, (PNAME) - He checks the items that the player has.
/p del, (ID), (PNAME), (COUNT) - It deletes the item of particular player.
/p (ID) - It checks how many players have this item.

Thanks

You should've posted this in support since it's not quite a request but merely something which needs a fix.
Let this be the last time.
Code:
/p check,<player name>
/p del,<player name>,<itemid>,count
/p findAll,<itemid>

Lua:
local function getItemsInContainer(cont, sep)
    local text = ""
    local tsep = ""
    local count = ""
    for i=1, sep do
        tsep = tsep.."-"
    end
    tsep = tsep..">"
    for i=0, Container(cont.uid):getSize() - 1 do
        local item = pushThing(Container(cont.uid):getItem(i))
        if not Container(item.uid) then
            if item.type > 1 then
                count = " ("..item.type.."x)"
            end
            text = text.."\n"..tsep..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
        else
            if Container(item.uid):getSize() > 0 then
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
                text = text..getItemsInContainer(item, sep+2)..""
            else
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
            end
        end
    end
    return text
end

local COMMAND_CHECK = 'check'
local COMMAND_DELETE = 'del'
local COMMAND_FINDALL = 'findall'

local talk = TalkAction('/p')
function talk.onSay(player, words, param)
    param = string.split(param, ',')
    local command = param[1]:lower()
    local slotName = {"Head", "Amulet", "Backpack", "Armor", "Right Hand", "Left Hand", "Legs", "Feet", "Ring", "Ammo Slot"}
    if command == COMMAND_CHECK then
        local name = param[2]
        local text = name.."'s Equipment: "
        for i = 1, 10 do
            text = text .. "\n\n"
            local item = pushThing(Player(name):getSlotItem(i))
            if item.itemid > 0 then
                local count = ''
                if item.type > 1 then
                    count = " (".. item.type .."x)"
                end
                if Container(item.uid) then
                    text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..") "..getItemsInContainer(item, 1)
                else
                    text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
                end
            else
                text = text..slotName[i]..": Empty"
            end
        end
        player:showTextDialog(6579, text)
    elseif command == COMMAND_DELETE then
        local name   = param[2]:lower()
        local itemid = tonumber(param[3])
        if not itemid then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, '3rd param must be itemid')
            return false
        end
        local count  = tonumber(param[4]) or 1
        local p = Player(name)
        if not p then
            player:sendCancelMessage("This player is not online or not exist.")
            return false
        end
        if p:getItemCount(itemid) == 0 then
            player:sendCancelMessage("This player does not have the item.")
            return false
        end
        if not p:removeItem(itemid, count) then
            player:sendCancelMessage("This player does not have this amount of item.")
            return false
        end
        player:sendCancelMessage("Deleted Item.")
    elseif command == COMMAND_FINDALL then
        local itemid = tonumber(param[2])
        if not itemid then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, '2nd param must be itemid')
        end
        local it = ItemType(itemid)
        if not it then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, 'ItemType('.. itemid ..') unknown')
            return false
        end
        local query = db.storeQuery("SELECT name FROM players WHERE id IN (SELECT player_id FROM player_items WHERE itemtype = ".. itemid ..");")
        local msg = "Search results by item ".. it:getName() .." in your database:\n\n"
        if (query ~= false) then
            while true do
                local name = result.getString(query, "name")
                msg = msg .. name .."\n"
                if not result.next(query) then
                    break
                end
            end
        else
            msg = msg .. "The item was not found in any player."
        end
        player:showTextDialog(itemid, msg)
    else
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'Unknown command: ' .. command)
    end
    return false
end

talk:separator(' ')
talk:register()
 
Lua:
local config = {
    spiralSpeed = 100,
    maxRadius   = 7
}

local function directionCheck(startPosition, position, topEdge, bottomEdge, leftEdge, rightEdge, dirX, dirY)
    if startPosition.y == position.y and ((position.x == leftEdge) or (position.x == rightEdge)) then
        dirX = dirX * -1
    end

    if startPosition.x == position.x and ((position.y == topEdge) or (position.y == bottomEdge)) then
        dirY = dirY * -1
    end

    position.x = position.x + dirX
    position.y = position.y + dirY
    return dirX, dirY
end

local function startSpiral(radius, round_n, position, startPosition, dirX, dirY, n_count, isFirst)
    if radius >= config.maxRadius then return end
    position:sendMagicEffect(CONST_ME_FIREAREA)

    if isFirst then
        position.x = position.x + dirX
        position.y = position.y + dirY
        addEvent(
            startSpiral, config.spiralSpeed, radius, round_n,
            position, startPosition, dirX, dirY, n_count+1, false
        )
        return
    end

    local topEdge    = (startPosition.y - radius)
    local bottomEdge = (startPosition.y + radius)
    local leftEdge   = (startPosition.x - radius)
    local rightEdge  = (startPosition.x + radius)

    if n_count == math.pow(round_n, 2) then
        position.x = position.x + dirX
        position.y = position.y + dirY

        local dX = math.abs(startPosition.x - position.x)
        local dY = math.abs(startPosition.y - position.y)

        if dX > dY then
            dirX = dirX * -1
        elseif dY > dX then
            dirY = dirY * -1
        end

        addEvent(
            startSpiral, config.spiralSpeed, radius + 2, round_n + 2,
            position, startPosition, dirX, dirY, n_count+1, false
        )
        return
    end

    dirX, dirY = directionCheck(startPosition, position, topEdge, bottomEdge, leftEdge, rightEdge, dirX, dirY)
    addEvent(
        startSpiral, config.spiralSpeed, radius, round_n,
        position, startPosition, dirX, dirY, n_count+1, false
    )
end

local talkaction = TalkAction('!spiral')
function talkaction.onSay(player, words, param)
    local playerPos = player:getPosition()
    local startPosition = Position(playerPos.x, playerPos.y, playerPos.z)
    playerPos:getNextPosition(player:getDirection())
    local position = Position(playerPos.x, playerPos.y, playerPos.z)
    local radius = 1
    local dirX = (position.x < startPosition.x and 1) or -1
    local dirY = (position.y < startPosition.y and 1) or -1
    startSpiral(radius, 2, position, startPosition, dirX, dirY, 0, true)
    return false
end

talkaction:separator(" ")
talkaction:register()
--[[
        4 16 36 64
        16 -  4 = 12
        36 - 16 = 20
        64 - 36 = 28
]]

View attachment 57271
Excellent, thanks for doing the script <3
 
You should've posted this in support since it's not quite a request but merely something which needs a fix.
Let this be the last time.
Code:
/p check,<player name>
/p del,<player name>,<itemid>,count
/p findAll,<itemid>

Lua:
local function getItemsInContainer(cont, sep)
    local text = ""
    local tsep = ""
    local count = ""
    for i=1, sep do
        tsep = tsep.."-"
    end
    tsep = tsep..">"
    for i=0, Container(cont.uid):getSize() - 1 do
        local item = pushThing(Container(cont.uid):getItem(i))
        if not Container(item.uid) then
            if item.type > 1 then
                count = " ("..item.type.."x)"
            end
            text = text.."\n"..tsep..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
        else
            if Container(item.uid):getSize() > 0 then
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
                text = text..getItemsInContainer(item, sep+2)..""
            else
                text = text.."\n"..tsep..ItemType(item.itemid):getName().." ("..item.itemid..")"
            end
        end
    end
    return text
end

local COMMAND_CHECK = 'check'
local COMMAND_DELETE = 'del'
local COMMAND_FINDALL = 'findall'

local talk = TalkAction('/p')
function talk.onSay(player, words, param)
    param = string.split(param, ',')
    local command = param[1]:lower()
    local slotName = {"Head", "Amulet", "Backpack", "Armor", "Right Hand", "Left Hand", "Legs", "Feet", "Ring", "Ammo Slot"}
    if command == COMMAND_CHECK then
        local name = param[2]
        local text = name.."'s Equipment: "
        for i = 1, 10 do
            text = text .. "\n\n"
            local item = pushThing(Player(name):getSlotItem(i))
            if item.itemid > 0 then
                local count = ''
                if item.type > 1 then
                    count = " (".. item.type .."x)"
                end
                if Container(item.uid) then
                    text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..") "..getItemsInContainer(item, 1)
                else
                    text = text..slotName[i]..": "..ItemType(item.itemid):getName()..""..count.." ("..item.itemid..")"
                end
            else
                text = text..slotName[i]..": Empty"
            end
        end
        player:showTextDialog(6579, text)
    elseif command == COMMAND_DELETE then
        local name   = param[2]:lower()
        local itemid = tonumber(param[3])
        if not itemid then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, '3rd param must be itemid')
            return false
        end
        local count  = tonumber(param[4]) or 1
        local p = Player(name)
        if not p then
            player:sendCancelMessage("This player is not online or not exist.")
            return false
        end
        if p:getItemCount(itemid) == 0 then
            player:sendCancelMessage("This player does not have the item.")
            return false
        end
        if not p:removeItem(itemid, count) then
            player:sendCancelMessage("This player does not have this amount of item.")
            return false
        end
        player:sendCancelMessage("Deleted Item.")
    elseif command == COMMAND_FINDALL then
        local itemid = tonumber(param[2])
        if not itemid then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, '2nd param must be itemid')
        end
        local it = ItemType(itemid)
        if not it then
            player:sendTextMessage(MESSAGE_STATUS_SMALL, 'ItemType('.. itemid ..') unknown')
            return false
        end
        local query = db.storeQuery("SELECT name FROM players WHERE id IN (SELECT player_id FROM player_items WHERE itemtype = ".. itemid ..");")
        local msg = "Search results by item ".. it:getName() .." in your database:\n\n"
        if (query ~= false) then
            while true do
                local name = result.getString(query, "name")
                msg = msg .. name .."\n"
                if not result.next(query) then
                    break
                end
            end
        else
            msg = msg .. "The item was not found in any player."
        end
        player:showTextDialog(itemid, msg)
    else
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'Unknown command: ' .. command)
    end
    return false
end

talk:separator(' ')
talk:register()
First of all, thank you for your attention and great work.
Sorry for the misplaced request.

Only if it is possible, I don't want to upset you, can you tell me what could be happening here? Again, thank you very much.
Lua Script Error: [Test Interface]
data/talkactions/scripts/playercheck.lua
data/talkactions/scripts/playercheck.lua:32: attempt to call global 'TalkAction'
(a nil value)
stack traceback:
[C]: in function 'TalkAction'
data/talkactions/scripts/playercheck.lua:32: in main chunk
[Warning - Event::checkScript] Can not load script: scripts/playercheck.lua
 
Hello, I don’t know if what I’m going to ask for is any of these script bases, but I’ll try. I wanted a chest that each server save had the chance to appear at some random point on the map, but as it could just appear in the middle of the water and become almost impossible to find, it could be on premeditated points, and his prize, in addition to a random item (yes, i like randomness xd) the player won a storage.
My idea is that this storage would be like a points system, so when the game accumulated a total of those points, it could pass through some tile that required a number of points from that storage (as an access, as a reward for the person to have gone after and got the chest x times). One detail is that the player can only open the chest and earn this 1 point of storage once a day.
 
Last edited by a moderator:
Hey bro, I would like a talkaction that I could mute players on any channel by specifying this way:

/pmute, (player name), (channel name or id), (muted time hours), (reason)

And unmute with:

/punmute, (player name)

Thank you Sir!
 
Hello fellas!

I would love a Daily Task chest option, not the NPC version but so a chest that can be looted at x hours every day like 10.00.

Type of Reward:

1: Items/exp or both in one day.
2: Max hp/mana boost.
3: Regeneration boos.
4: Higher exp rate in %. (like 5% extra exp the whole day) - If this is overkill then dump nr 4.



Example below on daily's:

Monday = 1 gold
Tuesday = 1 gold
Wednesday
= 1 gold
Thursday
= 1 gold
Friday
= 1 gold
Saturday
= 1 gold
Sunday = 1 gold.



Keep up the good work!

Thanks you!
 
my request for the 8.6 tfs 1.3 users:

mana leech/life leech based on customAttributes (one for chance% and one for damage%)

we already got a plenty of critical scripts, but I don't remember seeing anything for leech
Well, there is this one, but might not be what you're looking for.
 
Event -> Player vs Monster Arena

At X time of day, Event will auto-start.
Y amount of players join the Arena via talkaction. (can only join whilst in a PZ zone)
Z amount of waves of monsters spawn
Each wave that is completed gives all remaining players in the event an experience gift
Final wave spawns a Boss monster when majority of creatures in that wave are destroyed
Remaining players in event after the final wave is completed are teleported to a reward room
Reward room chest when used successfully, will teleport players out of the Event to their temple.

--------------
-> random monsters
-> random rewards

Arena has a difficulty scaling feature based on how many players are in the event.
(Difficulty scales downwards as players are removed from the event after reaching 0 health)

-> -> Monsters get more..
-> Health
-> Damage
-> Life
-> Monster Amount per Wave

Each Difficulty also
-> Spawns different sets of Monsters & final Boss
-> Gives different rewards
-> Gives a scaling experience reward per wave completed

Hope that's clear enough. :)

Note: reward chest must have actionid (10129)
login.lua
Lua:
player:registerEvent("WaveEventMonsterDeath")
player:registerEvent("WaveEventPrepareDeath")
player:registerEvent("WaveEventPHC")
player:registerEvent("WaveEventPMC")
data/scripts/xikini.lua
Lua:
--------------------------------------------------------------------------------
---------------------------------- # CONFIG # ----------------------------------
--------------------------------------------------------------------------------
local WaveEvent = {
    MAX_WAVES           = 3,
    ----------------------------
    STATE_CLOSED        = -1,
    STATE_STARTED       =  1,
    STATE_WAITING       =  2,
    ----------------------------
    STATE_STORAGE       = 101192,
    WAVE_ROUND_STORAGE  = 101193,
    PLAYERS_JOINED      = 101194,
    DMG_OVERFLOW        = 101195,
    REWARD_CHEST_USED   = 101196,
    REWARD_DIFFICULTY   = 101197,
    -----------------------------
    WAITING_TIME        = 1 * 10 * 1000,
    MIN_REQ_PLAYERS     = 1,
    ----------------------------
    NEXT_WAVE_DELAY     = 10 * 1000,
    BOSS_SPAWN_DELAY    = 5  * 1000,
    BOSS_SPAWN_TRIES    = 5,
    ----------------------------
    FINAL_BOSS          = 'Zugurosh',
    mobsPerPlayer       =  2,
    ----------------------------
    EXP_REWARD_FACTOR   = 1.05, -- 5%
    REWARD_CHEST_AID    = 10129,
    REWARDS = {
        [1] = { -- easy
        --  {itemid, count, chance}
            {2160, 10, 100},
            {2159,  5,   5}
        },
        [2] = { -- medium
            {2392,  1,  25},
            {2645,  1,  32}
        },
        [3] = { -- hard
            {2520,  1, 100},
            {2470,  1, 100}
        }
    },
    MONSTERS = {
        HP_INCREMENT  = 1.05, -- +5%
        DMG_INCREMENT = 1.05, -- +5%
        INITIAL_COUNT = 3,
        monsterList = {
            'armenius','barbaria','thalas'
            --'orc warrior'
            -- 'rat','snake','orc','rotworm','troll','slime','skeleton','orc warrior','wyvern',
            -- 'carrion worm','cyclops','cyclops drone','orc shaman','orc spearman','vampire',
            -- 'orc warlord','orc berserker','dragon','fire elemental','energy elemental','wyrm',
            -- 'cyclops smith','plaguesmith'
        }
    },
    Arena = {
        TOP_LEFT     = Position(47, 399, 7),
        BOTTOM_RIGHT = Position(61, 409, 7),
        monsters     = {} -- leave this empty
    },
    WaitingRoom = {
        TOP_LEFT     = Position(52, 395, 7),
        BOTTOM_RIGHT = Position(55, 397, 7)
    },
    RewardRoom = Position(58, 397, 7)
}
local function countMonstersInEvent()
    local counter = 0
    for cid, monster in pairs(WaveEvent.Arena.monsters) do
        if monster then
            counter = counter + 1
        end
    end
    return counter
end
local function getRandomPosition(conf)
    return Position(
        math.random(conf.TOP_LEFT.x, conf.BOTTOM_RIGHT.x),
        math.random(conf.TOP_LEFT.y, conf.BOTTOM_RIGHT.y),
        conf.TOP_LEFT.z
    )
end
local function secondsToReadable(s)
    local minutes = math.floor(math.mod(s, 3600)/60)
    local seconds = math.floor(math.mod(s, 60))
    return (minutes > 0 and (minutes .. ' minutes ') or '') ..
           (seconds > 0 and (seconds .. ' seconds ') or '')
end
local function ordinal_number(n)
    -- https://stackoverflow.com/a/20726654
    last_digit = n % 10
    if last_digit == 1 and n ~= 11
        then return 'st'
    elseif last_digit == 2 and n ~= 12
        then return 'nd'
    elseif last_digit == 3 and n ~= 13
        then return 'rd'
    else
        return 'th'
    end
end
--------------------------------------------------------------------------------
-------------------------------- # TALKACTION # --------------------------------
--------------------------------------------------------------------------------
local ta = TalkAction('!joinwave')
function ta.onSay(player, words, param)
    local waveEventState = Game.getStorageValue(WaveEvent.STATE_STORAGE)
    if not waveEventState or waveEventState == WaveEvent.STATE_CLOSED then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'The event hasn\'t started.')
        return false
    end
    if waveEventState == WaveEvent.STATE_STARTED then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You are late. Catch the train next time.')
        return false
    end
    if player:getZone() ~= ZONE_PROTECTION then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'Go to a safe zone first.')
        return false
    end
    player:setStorageValue(WaveEvent.REWARD_CHEST_USED, 0)
    player:teleportTo(getRandomPosition(WaveEvent.WaitingRoom))
    local playersJoined = (Game.getStorageValue(WaveEvent.PLAYERS_JOINED) or 0) + 1
    Game.broadcastMessage(
        player:getName() .. ' has joined the wave event. ('.. playersJoined ..'/'.. WaveEvent.MIN_REQ_PLAYERS ..')',
        MESSAGE_STATUS_CONSOLE_BLUE
    )
    Game.setStorageValue(WaveEvent.PLAYERS_JOINED, playersJoined)
    return false
end
ta:separator(' ')
ta:register()
--------------------------------------------------------------------------------
-------------------------------- # GLOBALEVENT # -------------------------------
--------------------------------------------------------------------------------
local function closeEvent()
    Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
    Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, 0)
    Game.setStorageValue(WaveEvent.PLAYERS_JOINED,     0)
    for cid, creature in pairs(WaveEvent.Arena.monsters) do
        creature:remove()
    end
    WaveEvent.Arena.monsters = {}
end
local function isInEvent(player)
    local playerPos = player:getPosition()
    if  (playerPos.x >= WaveEvent.Arena.TOP_LEFT.x and playerPos.x <= WaveEvent.Arena.BOTTOM_RIGHT.x)
    and (playerPos.y >= WaveEvent.Arena.TOP_LEFT.y and playerPos.y <= WaveEvent.Arena.BOTTOM_RIGHT.y) then
        return true
    end
    return false
end
local function getPlayersInEvent()
    local onlinePlayers = Game.getPlayers()
    local playersInEvent = {}
    for i, player in pairs(onlinePlayers) do
        if isInEvent(player) then
            table.insert(playersInEvent, i, player)
        end
    end
    return playersInEvent
end
local function spawnBoss(effect_rounds)
    if not effect_rounds then
        addEvent(spawnBoss, 1000, WaveEvent.BOSS_SPAWN_TRIES)
        return
    end
    local pos = getRandomPosition(WaveEvent.Arena)
    if effect_rounds == 0 then
        local m = Game.createMonster(WaveEvent.FINAL_BOSS, getRandomPosition(WaveEvent.Arena), false, true)
        m:say('GROOAAAAAR! <dramatic msg here>', TALKTYPE_MONSTER_SAY)
        pos:sendMagicEffect(CONST_ME_TELEPORT)
        return
    end
    pos:sendMagicEffect(CONST_ME_TELEPORT)
    pos:sendMagicEffect(CONST_ME_POFF)
    addEvent(spawnBoss, 1000, effect_rounds - 1)
end
local function handleMonsterCreation(m, wave_n, playerAmount)
    local mType = MonsterType(m)
    if not mType then
        return print('[Warning - WaveEvent::spawnMonsters] Unknown monster type ' .. m)
    end
    local mPos = getRandomPosition(WaveEvent.Arena)
    local monster = Game.createMonster(m, mPos, false, true)
    if not monster then
        return print('[Warning - WaveEvent::spawnMonsters] Could not create monster ' .. m)
    end
    monster:setMaxHealth(math.floor((monster:getMaxHealth() * (playerAmount + 1) * WaveEvent.MONSTERS.HP_INCREMENT) / 2))
    monster:setHealth(monster:getMaxHealth())
    mPos:sendMagicEffect(CONST_ME_TELEPORT)
    WaveEvent.Arena.monsters[monster:getId()] = monster
end
local function initWave(wave_n, playerAmount)
    if wave_n > WaveEvent.MAX_WAVES then
        local mType = MonsterType(WaveEvent.FINAL_BOSS)
        if not mType then
            print('[Error - WaveEvent::initWave] Could not create final boss. Unknown monster type ('.. WaveEvent.FINAL_BOSS ..')')
            -- kick players
            return
        end
        spawnBoss()
        return
    end
    local monsterCount = (wave_n * 2) + WaveEvent.MONSTERS.INITIAL_COUNT
    for i = 1, monsterCount do
        local m = WaveEvent.MONSTERS.monsterList[math.random(1, #WaveEvent.MONSTERS.monsterList)]
        handleMonsterCreation(m, wave_n, playerAmount)
    end
end
local function teleportPlayersToArena()
    local playersFound = 0
    local z = WaveEvent.WaitingRoom.TOP_LEFT.z
    for x = WaveEvent.WaitingRoom.TOP_LEFT.x, WaveEvent.WaitingRoom.BOTTOM_RIGHT.x do
        for y = WaveEvent.WaitingRoom.TOP_LEFT.y, WaveEvent.WaitingRoom.BOTTOM_RIGHT.y do
            local tile = Tile(x, y, z)
            local tileCreatures = tile:getCreatures()
            if tileCreatures then
                for _, creature in pairs(tileCreatures) do
                    creature:teleportTo(getRandomPosition(WaveEvent.Arena))
                    playersFound = playersFound + 1
                end
            end
        end
    end
    if playersFound == 0 then
        Game.broadcastMessage('[WaveEvent] Nobody joined the wave event. Closing.', MESSAGE_STATUS_CONSOLE_BLUE)
        Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
        return
    end
    if playersFound < WaveEvent.MIN_REQ_PLAYERS then
        Game.broadcastMessage('[WaveEvent] Not enough players. Closing.', MESSAGE_STATUS_CONSOLE_BLUE)
        Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
        return
    end
    Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_STARTED)
    Game.broadcastMessage(
        '[WaveEvent] Starting with ' .. playersFound .. ' player'
            .. (playersFound > 1 and 's' or '')
            .. '. Good luck!',
            MESSAGE_STATUS_CONSOLE_BLUE
    )
    Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, 1)
    initWave(1, playersFound)
end
local ge = GlobalEvent('WaveEvent')
function ge.onTime(interval)
    local eventState = Game.getStorageValue(WaveEvent.STATE_STORAGE)
    if eventState == WaveEvent.STATE_STARTED
    or eventState == WaveEvent.STATE_WAITING then
        print('[Error - WaveEvent::onTime] Event state not closed. StorageKey -> '.. WaveEvent.STATE_STORAGE)
        return true
    end
    Game.broadcastMessage(
        'WaveEvent has started. You have '
            .. secondsToReadable(WaveEvent.WAITING_TIME / 1000)
            .. ' to join. !joinwave',
        MESSAGE_STATUS_CONSOLE_BLUE
    )
    Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_WAITING)
    addEvent(teleportPlayersToArena, WaveEvent.WAITING_TIME)
end
ge:time('03:49:30')
ge:register()
--------------------------------------------------------------------------------
-------------------------------- # CREATURESCRIPT # ----------------------------
--------------------------------------------------------------------------------
local cs = CreatureEvent('WaveEventPrepareDeath')
function cs.onPrepareDeath(player, killer)
    if Game.getStorageValue(WaveEvent.STATE_STORAGE) == WaveEvent.STATE_CLOSED then
        return true
    end
    if isInEvent(player) then
        player:teleportTo(player:getTown():getTemplePosition())
        player:setHealth(player:getMaxHealth())
        player:setMana(player:getMaxMana())
        Game.broadcastMessage('[WaveEvent] ' .. player:getName() .. ' was killed by a monster.')
    end
    local isEventClosed = Game.getStorageValue(WaveEvent.STATE_STORAGE) ~= WaveEvent.STATE_CLOSED
    if #getPlayersInEvent() == 0 and not isEventClosed then
        Game.broadcastMessage('[WaveEvent] Nobody has completed the wave event. Closing ...')
        closeEvent()
    end
    return true
end
cs:register()
local csx = CreatureEvent('WaveEventMonsterDeath')
function csx.onKill(player, target)
    if Game.getStorageValue(WaveEvent.STATE_STORAGE) == WaveEvent.STATE_CLOSED
    or not isInEvent(player)
    or target:getMaster() then
        return true
    end
    if target:getName():lower() == WaveEvent.FINAL_BOSS:lower() then
        Game.broadcastMessage('[WaveEvent] The final boss has been killed. Congratulations!')
        Game.setStorageValue(WaveEvent.STATE_STORAGE, WaveEvent.STATE_CLOSED)
        local pie = getPlayersInEvent()
        -- What was the difficulty ?
        local joined = Game.getStorageValue(WaveEvent.PLAYERS_JOINED)
        local diff = math.abs(#pie - joined)
        if     diff <= math.floor(joined * 0.33) then diff = 1
        elseif diff <= math.floor(joined * 0.66) then diff = 2
        else   diff = 3 end
        Game.setStorageValue(WaveEvent.REWARD_DIFFICULTY, diff)
        for _, p in pairs(pie) do
            p:teleportTo(WaveEvent.RewardRoom)
        end
        closeEvent()
        return true
    end
    WaveEvent.Arena.monsters[target:getId()] = nil
    if countMonstersInEvent() > 0 then
        return true
    end
    local n = Game.getStorageValue(WaveEvent.WAVE_ROUND_STORAGE) or 1
    local bcMsg = ordinal_number(n) ..' wave has been cleared.'
    if n < WaveEvent.MAX_WAVES then
        bcMsg = bcMsg .. ' Prepare for the next wave. ('.. secondsToReadable(WaveEvent.NEXT_WAVE_DELAY / 1000).. ')'
    else
        bcMsg = bcMsg .. ' Prepare for the final boss!'
    end
    local playersInEvent = getPlayersInEvent()
    for _, player in pairs(playersInEvent) do
        player:say('+EXP', TALKTYPE_MONSTER_SAY)
        player:addExperience(4200 * player:getLevel() * WaveEvent.EXP_REWARD_FACTOR) -- meh
    end
    Game.broadcastMessage(bcMsg)
    Game.setStorageValue(WaveEvent.WAVE_ROUND_STORAGE, n + 1)
    addEvent(initWave, WaveEvent.NEXT_WAVE_DELAY, n + 1, #playersInEvent)
    return true
end
csx:register()
local csy = CreatureEvent('WaveEventPHC')
function csy.onHealthChange(player, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if (primaryType == COMBAT_HEALING)
    or (not isInEvent(player))
    or (player:getStorageValue(WaveEvent.DMG_OVERFLOW) == 1) then
        player:setStorageValue(WaveEvent.DMG_OVERFLOW, -1)
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
    return  primaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
            primaryType,
            secondaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
            secondaryType
end
csy:register()
local csz = CreatureEvent('WaveEventPMC')
function csz.onManaChange(player, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if (primaryType == COMBAT_HEALING) or (not isInEvent(player)) then
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
    local dmgTotal = primaryDamage + secondaryDamage
    if dmgTotal > player:getMana() then
        player:setStorageValue(WaveEvent.DMG_OVERFLOW, 1)
    end
    return  primaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
            primaryType,
            secondaryDamage * WaveEvent.MONSTERS.DMG_INCREMENT,
            secondaryType
end
csz:register()
--------------------------------------------------------------------------------
------------------------------------ # ACTION # --------------------------------
--------------------------------------------------------------------------------
local action = Action()
function action.onUse(player, item, fromPosition, itemEx, toPosition, isHotkey)
    local hasUsed = player:getStorageValue(WaveEvent.REWARD_CHEST_USED)
    if hasUsed == 1 then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, 'You have already obtained the reward.')
        player:getPosition():sendMagicEffect(CONST_ME_POFF)
        return true
    end
    local diff = Game.getStorageValue(WaveEvent.REWARD_DIFFICULTY)
    local rewards = WaveEvent.REWARDS[diff]
    local items = ''
    for _, rewardItem in pairs(rewards) do
        local chance = rewardItem[3]
        if math.random(1, 100) <= chance then
            items = items .. (#items > 0 and ', ' or '')
            local itemId = rewardItem[1]
            local count  = rewardItem[2]
            local itemX = Game.createItem(itemId, count)
            local depot = player:getDepotChest(player:getTown():getId(), true)
            depot:addItemEx(itemX, INDEX_WHEREEVER, FLAG_NOLIMIT)
            items = items .. '('.. count ..'x ' .. itemX:getName() .. (count > 1 and 's' or '') .. ')'
        end
    end
    items = items .. '.'
    player:setStorageValue(WaveEvent.REWARD_CHEST_USED, 1)
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, '[WaveEvent] You have received ' .. items)
    player:teleportTo(player:getTown():getTemplePosition())
    return true
end
action:aid(WaveEvent.REWARD_CHEST_AID)
action:register()
 
Last edited:
1.3 tfs doesn't have special skills (critical, leech etc) on source, so they need to be done in OnHealth/ManaChange :(
It definitely exists. xP
Lua:
    ["critical hit chance"] = {CONDITION_PARAM_SPECIALSKILL_CRITICALHITCHANCE},
    ["critical hit damage"] = {CONDITION_PARAM_SPECIALSKILL_CRITICALHITAMOUNT},
    ["life leech chance"] = {CONDITION_PARAM_SPECIALSKILL_LIFELEECHCHANCE},
    ["life leech amount"] = {CONDITION_PARAM_SPECIALSKILL_LIFELEECHAMOUNT},
    ["mana leech chance"] = {CONDITION_PARAM_SPECIALSKILL_MANALEECHCHANCE},
    ["mana leech amount"] = {CONDITION_PARAM_SPECIALSKILL_MANALEECHAMOUNT},
 
Status
Not open for further replies.
Back
Top