• 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!

TFS 1.X+ [TFS 1.3] INQ Teleporter

Cloow

Active Member
Joined
May 10, 2010
Messages
1,086
Reaction score
35
Hello,

So I've spent the whole day and the day before that and perhaps the day even before that trying to make a inq teleport script, mostly because i'm trying to learn myself how to script.

I know theres a few posts already about this subject but I couldn't find one that I was looking that gives storage for all those that participated in the fight, so I have taken abit of code from each and everyone and wrote some myself..

But now i'm so tired of this script and really want to move on to something else and im stuck because its not working and it does not give me any errors either so I dont know what to do..

help is greatly appreciated

So here it comes:

creaturescripts.xml
XML:
<event type="kill" name="InqBoss" script="inq/ushuriel.lua" />

creaturescripts/scripts/login.lua
Lua:
    player:registerEvent("InqBoss")

creaturescripts/scripts/inq/ushuriel.lua
Lua:
local config = {
    {boss = {'ushuriel'}, storage = 8000, pos = Position(1260, 1504, 12), destination = Position(1308, 1576, 12)},
    {boss = {'zugurosh'}, storage = 8001, pos = Position(1263, 1542, 12), destination = Position(1234, 1576, 12)}
}

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(cid, target, damage, flags, corpse)
    if(isMonster(target)) then
        if(string.lower(getCreatureName(target)) == config.boss) then
            for attackerUid, damage in pairs(target:getDamageMap()) do
                local player = Player(attackerUid)
                if player and player:getStorageValue(config.storage) < 1 then
                    player:setStorageValue(config.storage, 1)
                end
            end
            local position = target:getPosition()
            position:sendMagicEffect(CONST_ME_TELEPORT)
            local item = Game.createItem(1387, 1, config.pos)
            if item:isTeleport() then
                item:setDestination(config.destination)
            end
            target:say('Congratulations on killing You have 3 minutes to enter the Crystal Caves.', TALKTYPE_MONSTER_SAY, 0, 0, position)
            addEvent(removeTeleport, 3 * 60 * 1000, config.pos)
            return true
        end
        end
    end
 
Solution
Tested and works.

Lua:
local bosses = {
    {name = 'ushuriel', storage = 8000, pos = Position(1260, 1504, 12), destination = Position(1308, 1576, 12)},
    {name = 'zugurosh', storage = 8001, pos = Position(1263, 1542, 12), destination = Position(1234, 1576, 12)}
}

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end

function onKill(creature, target)
    if not target:isMonster() then
        return true
    end

    for _, boss in pairs(bosses) do
        if(target:getName():lower() == boss.name) then
            for attackerUid, damage in pairs(target:getDamageMap()) do...
Tested and works.

Lua:
local bosses = {
    {name = 'ushuriel', storage = 8000, pos = Position(1260, 1504, 12), destination = Position(1308, 1576, 12)},
    {name = 'zugurosh', storage = 8001, pos = Position(1263, 1542, 12), destination = Position(1234, 1576, 12)}
}

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end

function onKill(creature, target)
    if not target:isMonster() then
        return true
    end

    for _, boss in pairs(bosses) do
        if(target:getName():lower() == boss.name) then
            for attackerUid, damage in pairs(target:getDamageMap()) do
                local player = Player(attackerUid)
                if player and player:getStorageValue(boss.storage) < 1 then
                    player:setStorageValue(boss.storage, 1)
                end
            end

            local position = target:getPosition()
            position:sendMagicEffect(CONST_ME_TELEPORT)
            local item = Game.createItem(1387, 1, boss.pos)
            if item:isTeleport() then
                item:setDestination(boss.destination)
            end

            target:say('Congratulations on killing ' .. target:getName() .. '. You have 3 minutes to enter the Crystal Caves.', TALKTYPE_MONSTER_SAY, 0, 0, position)
            addEvent(removeTeleport, 3 * 60 * 1000, boss.pos)
        end
    end
end
 
Solution
LOve you! Thanks alot it works

I'm trying to study the code and see where I did go wrong and for instance I see that you added this line that I dont quite get how it works:
Code:
for _, boss in pairs(bosses) do

so in the lua book theres an example, which I quite get:
Code:
   a = {"one", "two", "three"}
    for i, v in ipairs(a) do
      print(i, v)
    end
this will print "One, two, three"

but in your code its "_," instead of "i, v" and I dont understand

You don't have to explain it for me tho, if you dont want to :)
 
Last edited:
LOve you! Thanks alot it works :D

I'm trying to study the code and see where I did go wrong and for instance I see that you added this line that I dont quite get how it works:
Code:
for _, boss in pairs(bosses) do

so in the lua book theres an example, which I quite get:
Code:
   a = {"one", "two", "three"}
    for i, v in ipairs(a) do
      print(i, v)
    end
this will print "One, two, three"

but in your code its "_," instead of "i, v" and I dont understand :(

You don't have to explain it for me tho, if you dont want to :)
the underscore _ indicates the key of each element (I wrote _ because it's not used in the code, it is ignored)

for k, v is same as for _, v - both will work but the second means key of element is not used/required.

kv.png
us.png

I see that you added this line that I dont quite get how it works:
I renamed local config to local bosses to indicate that it is a configuration table for just bosses.

The following line can be read as "for each element in bosses, assign to variable boss.
Lua:
for _, boss in pairs(bosses) do

For example; The first element in bosses table is (another table)
Lua:
{name = 'ushuriel', storage = 8000, pos = Position(1260, 1504, 12), destination = Position(1308, 1576, 12)}

.. now while the computer is iterating, this table is gonna be accessible from the variable boss which is defined in the for-loop _, boss.
This means that we can access boss name by typing boss.name.

The original code had:
Lua:
if(string.lower(getCreatureName(target)) == config.boss) then
but that didnt make sense because the config table had no such thing as boss in it, only more tables and thats why I made a few changes.
 
Wow such in depth explanation I feel so grateful, thank you!
So if I got this right we could explain the
Code:
for _, boss in pairs(bosses) do
its like making a storage inside the storage and being able to call out any information from the storage within the variable boss?

So to put this lesson into practice I was gonna try to use the same method for this script
Lua:
local bosses = {
    ['YourBossName1'] = 555,
    ['YourBossName2'] = 555
}

local teleportPos = Position(1024, 1024, 7) -- position where tp will be created /to edit
local teleportDestination = Position(1024, 1026, 7) -- teleport destination /to edit
local teleportRemoveTime = 1 * 60 * 1000 -- remove teleport: TIME 1=1min /to edit

local timeMsg = teleportRemoveTime /1000

local function removeTeleport()
    local teleportItem = Tile(teleportPos):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        teleportPos:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(player, target)
    local targetMonster = target:getMonster()
    if not targetMonster then
        return true
    end
    local targetName = targetMonster:getName():lower()
    local bossStorage = bosses[targetName]
    if not bossStorage then
        return true
    end
    local newValue = 2
    if targetName == 'YourBossName1' or targetName == 'YourBossName2' then -- add here yours bosses names! /to edit
        newValue = math.max(0, Game.getStorageValue(bossStorage)) + 1
    end
    Game.setStorageValue(bossStorage, newValue)
    if newValue == 2 then
        player:say('You have '..timeMsg..' seconds to enter the teleport!', TALKTYPE_MONSTER_SAY) -- Msg, u can use another msg function /broadcast etc
        addEvent(Game.setStorageValue, teleportRemoveTime, bossStorage, 0)
        teleportPos:sendMagicEffect(CONST_ME_TELEPORT)
        Game.createItem(1387, 1, teleportPos)
    end
    local teleport = Tile(teleportPos):getItemById(1387)
    if teleport then
        teleport:setDestination(teleportDestination)
        addEvent(removeTeleport, teleportRemoveTime, teleportPos)
    end
    return true
end

And I almost got it to work, when I killed the bosses the teleport appeard but didnt have destinations so I tried to solve it but now nothing heppens when I kill them and I dont get any errors either kinda frustrating..

Lua:
local bosses = {
    {name = 'latrivan', storage = 8003},
    {name = 'golgordan', storage = 8003} 
}

local teleportPos = Position(1221, 1530, 12) -- I left these local teleports here because I dont want 2 teleports to appear, so I thought it was easier to just leave them here instead of moving them to "local bosses"
local teleportDestination = Position(1115, 1620, 12)
local teleportRemoveTime = 1 * 60 * 1000 

local timeMsg = teleportRemoveTime /1000

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(player, target)
    if not target:isMonster() then
        return true
    end
    local newValue = 2
    for attackerUid, damage in pairs(target:getDamageMap()) do -- I want everyone who participated in the fight to get storage
        local player = Player(attackerUid)
        for _, boss in pairs(bosses) do -- Making it avaible to get variables from the "local bosses"
            if(target:getName():lower() == boss.name) then
                newValue = math.max(0, player:getStorageValue(boss.storage)) + 1 -- Set storage for each kill +1?
                player:setStorageValue(boss.storage, newValue)
                if newValue == 2 then -- If player have storage = 2, ie killed both bosses then create portal and give new storage = 800 which will be used later for shortcut teleport to next room.
                    player:say('You have '..timeMsg..' seconds to enter the teleport!', TALKTYPE_MONSTER_SAY)
                    addEvent(Game.setStorageValue, teleportRemoveTime, boss.storage, 1) -- Here im lost, because I want to have player:setStorage but its an addEvent and im not sure if it works?
                    teleportPos:sendMagicEffect(CONST_ME_TELEPORT)
                    Game.createItem(1387, 1, teleportPos)
                end
            end
        end
        return true
    end
    local teleport = Tile(teleportPos):getItemById(1387)
    if teleport:isTeleport() then
        teleport:setDestination(teleportDestination)
        addEvent(removeTeleport, teleportRemoveTime, teleportPos)
    end
    return true
end

Im sorry asking all these questions, hopefully you dont mind but if you do dont feel obligated to help. Im already so grateful for your help
 
Wow such in depth explanation I feel so grateful, thank you!
So if I got this right we could explain the
Code:
for _, boss in pairs(bosses) do
its like making a storage inside the storage and being able to call out any information from the storage within the variable boss?

So to put this lesson into practice I was gonna try to use the same method for this script
Lua:
local bosses = {
    ['YourBossName1'] = 555,
    ['YourBossName2'] = 555
}

local teleportPos = Position(1024, 1024, 7) -- position where tp will be created /to edit
local teleportDestination = Position(1024, 1026, 7) -- teleport destination /to edit
local teleportRemoveTime = 1 * 60 * 1000 -- remove teleport: TIME 1=1min /to edit

local timeMsg = teleportRemoveTime /1000

local function removeTeleport()
    local teleportItem = Tile(teleportPos):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        teleportPos:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(player, target)
    local targetMonster = target:getMonster()
    if not targetMonster then
        return true
    end
    local targetName = targetMonster:getName():lower()
    local bossStorage = bosses[targetName]
    if not bossStorage then
        return true
    end
    local newValue = 2
    if targetName == 'YourBossName1' or targetName == 'YourBossName2' then -- add here yours bosses names! /to edit
        newValue = math.max(0, Game.getStorageValue(bossStorage)) + 1
    end
    Game.setStorageValue(bossStorage, newValue)
    if newValue == 2 then
        player:say('You have '..timeMsg..' seconds to enter the teleport!', TALKTYPE_MONSTER_SAY) -- Msg, u can use another msg function /broadcast etc
        addEvent(Game.setStorageValue, teleportRemoveTime, bossStorage, 0)
        teleportPos:sendMagicEffect(CONST_ME_TELEPORT)
        Game.createItem(1387, 1, teleportPos)
    end
    local teleport = Tile(teleportPos):getItemById(1387)
    if teleport then
        teleport:setDestination(teleportDestination)
        addEvent(removeTeleport, teleportRemoveTime, teleportPos)
    end
    return true
end

And I almost got it to work, when I killed the bosses the teleport appeard but didnt have destinations so I tried to solve it but now nothing heppens when I kill them and I dont get any errors either kinda frustrating..

Lua:
local bosses = {
    {name = 'latrivan', storage = 8003},
    {name = 'golgordan', storage = 8003}
}

local teleportPos = Position(1221, 1530, 12) -- I left these local teleports here because I dont want 2 teleports to appear, so I thought it was easier to just leave them here instead of moving them to "local bosses"
local teleportDestination = Position(1115, 1620, 12)
local teleportRemoveTime = 1 * 60 * 1000

local timeMsg = teleportRemoveTime /1000

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(player, target)
    if not target:isMonster() then
        return true
    end
    local newValue = 2
    for attackerUid, damage in pairs(target:getDamageMap()) do -- I want everyone who participated in the fight to get storage
        local player = Player(attackerUid)
        for _, boss in pairs(bosses) do -- Making it avaible to get variables from the "local bosses"
            if(target:getName():lower() == boss.name) then
                newValue = math.max(0, player:getStorageValue(boss.storage)) + 1 -- Set storage for each kill +1?
                player:setStorageValue(boss.storage, newValue)
                if newValue == 2 then -- If player have storage = 2, ie killed both bosses then create portal and give new storage = 800 which will be used later for shortcut teleport to next room.
                    player:say('You have '..timeMsg..' seconds to enter the teleport!', TALKTYPE_MONSTER_SAY)
                    addEvent(Game.setStorageValue, teleportRemoveTime, boss.storage, 1) -- Here im lost, because I want to have player:setStorage but its an addEvent and im not sure if it works?
                    teleportPos:sendMagicEffect(CONST_ME_TELEPORT)
                    Game.createItem(1387, 1, teleportPos)
                end
            end
        end
        return true
    end
    local teleport = Tile(teleportPos):getItemById(1387)
    if teleport:isTeleport() then
        teleport:setDestination(teleportDestination)
        addEvent(removeTeleport, teleportRemoveTime, teleportPos)
    end
    return true
end

Im sorry asking all these questions, hopefully you dont mind but if you do dont feel obligated to help. Im already so grateful for your help

The devil is hiding in the shadows
Skärmavbild 2021-03-19 kl. 18.15.31.png

as soon as the inner for loop is finished, return true will exit the main function onKill and therefore prevent the teleport from ever being created

Edit:

The following line is not error-safe because player:getStorageValue(boss.storage)) can return nil and since math.max function requires both parameters to be numbers it will throw an error when nil is passed.
Lua:
newValue = math.max(0, player:getStorageValue(boss.storage)) + 1 -- Set storage for each kill +1?
Instead you could have
Lua:
newValue = (player:getStorageValue(boss.storage) or 0) + 1

Lua:
addEvent(Game.setStorageValue, teleportRemoveTime, boss.storage, 1)
Game.setStorageValue is not meant for players.
Not sure why you are doing that in addEvent tho 🤔
.. but if you insist on using the addEvent, then you could have:
Lua:
addEvent(function(player, storage, amount)
    if not player then
        return
    end
    player:setStorageValue(storage, amount)
end, teleportRemoveTime, player, boss.storage, 1)
 
Last edited:
Oh yeah, I got confused about Game.setStorage instead of player:setStorage, so Game.setStorage is for other than players ie monsters then?

The script should work like, if you kill both latrivan and golgordan there will be a teleporter and you will recieve storage 8003 aswell but not if you only kill one of them. I guess for the script to count that you killed latrivan or golgordan they need to be assigned a storage so the server know if one of them already been killed before execute rest of the script?

The base of the script comes from here, which I should had mentioned before perhaps:
You need to kill 2 monsters to create teleport (https://otland.net/threads/you-need-to-kill-2-monsters-to-create-teleport.250550/)

I removed the return true and adjusted the script but still nothing happens, I think the script are getting bit confused about the different storages, since I changed Game.Storage to player:storage where it perhaps should be vice versa. But at the same time I want the teleporter to appear w/e you already have the storage or not haha. Im lost
Lua:
local bosses = {
    {name = 'latrivan', storage = 8003},
    {name = 'golgordan', storage = 8003}
}

local teleportPos = Position(1221, 1530, 12) -- position where tp will be created /to edit
local teleportDestination = Position(1115, 1620, 12) -- teleport destination /to edit
local teleportRemoveTime = 1 * 60 * 1000 -- remove teleport: TIME 1=1min /to edit

local timeMsg = teleportRemoveTime /1000

local function removeTeleport(position)
    local teleportItem = Tile(position):getItemById(1387)
    if teleportItem then
        teleportItem:remove()
        position:sendMagicEffect(CONST_ME_POFF)
    end
end
function onKill(player, target)
    if not target:isMonster() then
        return true
    end
    local newValue = 2
    for attackerUid, damage in pairs(target:getDamageMap()) do
        local player = Player(attackerUid)
        for _, boss in pairs(bosses) do
            if(target:getName():lower() == boss.name) then
                newValue = (player:getStorageValue(boss.storage) or 0) + 1
                player:setStorageValue(boss.storage, newValue)
                if newValue == 2 then
                    player:say('You have '..timeMsg..' seconds to enter the teleport!', TALKTYPE_MONSTER_SAY) -- Msg, u can use another msg function /broadcast etc
                    addEvent(function(player, storage, amount)
                        if not player then
                            return
                        end
                        player:setStorageValue(storage, amount)
                    end, teleportRemoveTime, player, boss.storage, 1)
                    teleportPos:sendMagicEffect(CONST_ME_TELEPORT)
                    Game.createItem(1387, 1, teleportPos)
                end
            end
        end
        return true
    end
    local teleport = Tile(teleportPos):getItemById(1387)
    if teleport:isTeleport() then
        teleport:setDestination(teleportDestination)
        addEvent(removeTeleport, teleportRemoveTime, teleportPos)
    end
end

btw i'am so grateful for you taking your time with explaining things for me and helping me out! your the real champ :D
 
Last edited:
Oh yeah, I got confused about Game.setStorage instead of player:setStorage, so Game.setStorage is for other than players ie monsters then?

The script should work like, if you kill both latrivan and golgordan there will be a teleporter and you will recieve storage 8003 aswell but not if you only kill one of them. I guess for the script to count that you killed latrivan or golgordan they need to be assigned a storage so the server know if one of them already been killed before execute rest of the script?

The base of the script comes from here, which I should had mentioned before perhaps:
You need to kill 2 monsters to create teleport (https://otland.net/threads/you-need-to-kill-2-monsters-to-create-teleport.250550/)

I removed the return true and adjusted the script but still nothing happens, I think the script are getting bit confused about the different storages, since I changed Game.Storage to player:storage where it perhaps should be vice versa. But at the same time I want the teleporter to appear w/e you already have the storage or not haha. Im lost

Now I'm confused aswell. 🤔

There are 2 bosses. [ OK ]
If both are killed in a certain amount of time a teleport is created. [ OK ]

It doesn't matter who kills the bosses [ ? ]
- 2 different players may kill the boss and still the tp will be created?
or
- 1 player kills both bosses and TP is created?


EDIT:
You should probably use onDeath registered on the bosses instead of registering onKill for player since it will execute for anything a player kills, not sure how efficient TFS is but it might cause performance issues this way.
 
Last edited:
Now I'm confused aswell. 🤔

There are 2 bosses. [ OK ]
If both are killed in a certain amount of time a teleport is created. [ OK ]

It doesn't matter who kills the bosses [ ? ]
- 2 different players may kill the boss and still the tp will be created?
or
- 1 player kills both bosses and TP is created?


EDIT:
You should probably use onDeath registered on the bosses instead of registering onKill for player since it will execute for anything a player kills, not sure how efficient TFS is but it might cause performance issues this way.


Haha yeah its confusing :s

Hmm, 2 different players could aswell cause problems, since if one player kill one of the bosses and then dies and like 5 hours later another player comes and kill the other the teleport shouldn't appear, they need to kill both bosses in the same "instance" for the teleport to appear I guess.

It works like this, players comes into the boss room and theres two bosses there (latrivan and golgordan) which both need to be killed before a teleport appears that will get them to the next room and give all storageID (8003) that participated in the fight.

That storageID will make them able to just walk into a teleport to get into the room after the two bosses later on so they dsnt have to kill them again for reaching that room again, like a shortcut.

Im thinking perhaps theres an easier way out, like if I made the setStorage=8003 in movements so that when players killed the bosses and teleports to next room all that enters the tile for the teleport gets storage 8003

It's this boss room, after he kills the bosses he walks into teleport and gets to the next room. But instead he walks back to the portal room to refill, and then he can just walk into the shortcut teleport to get to that room that comes after the bosses, which he couldnt before he killed them.
 
Back
Top