• 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 Error while loading actions

Exoltes

Novia OTserv Developer
Joined
Jul 2, 2009
Messages
563
Reaction score
47
Location
Belgium
I'm working on a 8.54 Open Tibia Server using The Forgotten Server - Version 0.2.7 (Mystic Spirit).

Code:
[31/07/2015 17:31:56] Warning: [Event::checkScript] Can not load script. /scripts/quests/Ice Change.lua
[31/07/2015 17:31:56] data/actions/scripts/quests/Ice Change.lua:3349: control structure too long near 'end'

I'm guessing my script is too long for the server to load so maybe someone knows a way to fix this? :)

Thanks in advance.
 
I see.. I can shorten it up a bit, but i have to leave for work and can fix it after work unless someone does it for you in the mean time.
 
Yeah. It's pretty much too large, but the vast majority of the lines could be reduced to a single for, changing the values.

Now what I know about this control structure too big problem is that you have a too long jumpable section of code, and I'm pretty sure it is the very first if. You might invert it and jump right out of the script. Replace:
Code:
if itemEx.itemid == 1945 and item.actionid == 65535 then
by:
Code:
if itemEx.itemid ~= 1945 or item.actionid ~= 65535 then
  return false
end
Then remove the corresponding end.

The problem is that, when you do not enter the if, you must do a very huge jump right to the end of the script, and the Lua VM can not accomplish that. With this change, there are no huge jump needed and it might do the trick.

Try and tell me what happens.
 
Yeah. It's pretty much too large, but the vast majority of the lines could be reduced to a single for, changing the values.

Now what I know about this control structure too big problem is that you have a too long jumpable section of code, and I'm pretty sure it is the very first if. You might invert it and jump right out of the script. Replace:
Code:
if itemEx.itemid == 1945 and item.actionid == 65535 then
by:
Code:
if itemEx.itemid ~= 1945 or item.actionid ~= 65535 then
  return false
end
Then remove the corresponding end.

The problem is that, when you do not enter the if, you must do a very huge jump right to the end of the script, and the Lua VM can not accomplish that. With this change, there are no huge jump needed and it might do the trick.

Try and tell me what happens.

Yeey, this works! now I can add and test the rest of the lines for my castle :)

@Codex NG
It would still be nice if you could show me how to shorten the script.
 
@Lordfire
Just had a major crash in my server when I used the item with the correct action id while the change was active (so while the item.id was changed)

Due to the change you suggested. Maybe you know how to fix it? :)
 
The reason your server is or will crash with this script is because when you call addEvent you're creating a separate process for the function to execute, so when you have 3k addEvents waiting to execute and then they all execute at once relatively speaking it overwhelms the server.

So I will give you an example of how you could shorten this up a bit, I didn't rewrite your entire script but the method I am showing you could cut this thing down to a 3rd of its size.

Code:
local function doTransformBack(Position, itemid, transformid)
return doTransformItem(getTileItemById(Position, transformid).uid, itemid)
end

function onUse(cid, item, fromPosition, itemEx, toPosition)

if itemEx.itemid ~= 1945 and item.actionid ~= 65535 then
     return false
end
doSendMagicEffect(toPosition,CONST_ME_ICEAREA)
doTargetCombatHealth(0, cid, COMBAT_ICEDAMAGE, -500, -1000, CONST_ME_ICEAREA)
addEvent(doTransformBack, 1*60*1000, toPosition, itemEx.itemid, 7021)
doTransformItem(itemEx.uid, 7021)

function doSomething(time_, t, itemid, effect)
    addEvent(doTransformBack, time_, {x = t[1], y = t[2], z = t[3]}, itemid[2], itemid[1])
    if effect then
        doSendMagicEffect({x = t[1], y = t[2], z = t[3]}, CONST_ME_ICEAREA)
    end  
    doTransformItem(getTileItemById({x = t[1], y = t[2], z = t[3]}, itemid[1]).uid, itemid[2])
end

function executeFunction(t, itemid, effect)
    for k, v in ipairs(t) do
        doSomething((k * 1000), v, itemid, effect)
    end
end

--stairs at end
local table1 = {
    [1] = {774, 1014, 7},
    [2] = {774, 1015, 7},
    [3] = {773, 1014, 7},
    [4] = {773, 1015, 7}
}
--[[
    Explanation of the functions:
    addEvent is called and put on the waiting list so to speak, for 1 minute it patiently waits to call executeFunction
    executeFunction then cycles through the 1st argument (e.g. table1) passing the index of the 1st argument (e.g. {774, 1014, 7})
    to doSomething as its 2nd argument, the 2nd argument of executeFunction is then also passed to doSomething as its 3rd argument
    since doSomething also uses an addEvent to execute its internal function we use the index value ( k ) of executeFunction's 1st argument
    and multiply it by 1000 to tell addEvent we would like this function to execute at 1 second times the value of k for the amount of
    elements in the table

    The 3rd argument of executeFunction and 4th of doSomething will execute the magic effect, if ommited or set to false it will
    not add a magic effect

    Explanation of the indexes:
    I explicitly use numerical indexes and ipairs for the for loop incase each coordinate needed to execute in that order
    If execution of each coordinate doesn't matter you don't need to include the index and ipairs will do its thing regardless,
    as long as the index of each element of the table is a non-text based index.. if you don't know what this means don't worry :)

--]]
addEvent(executeFunction, 60*1000, table1, {1388, 6909}, true)


--first dirt after stairs
local table2 = {
    [1] = {745, 1012, 7},
    [2] = {745, 1011, 7},
    [3] = {745, 1013, 7},
    [4] = {746, 1011, 7},
    [5] = {746, 1012, 7},
    [6] = {746, 1013, 7},
    [7] = {746, 1014, 7},
    [8] = {747, 1013, 7},
    [9] = {747, 1012, 7},
    [10] = {748, 1012, 7}
}
addEvent(executeFunction, 60*1000, table2, {103, 671}, true)

--second dirt after stairs
local table3 = {
    [1] = {748, 1013, 7},
    [2] = {748, 1014, 7},
    [3] = {749, 1014, 7},
    [4] = {749, 1013, 7},
    [5] = {747, 1012, 7},
    [6] = {749, 1012, 7},
    [7] = {750, 1012, 7},
    [8] = {750, 1013, 7},
    [9] = {750, 1014, 7}
}
addEvent(executeFunction, 60*1000, table3, {103, 671}, true)

end
 
Last edited:
The earlier one I did while i was just waking up I can't know for sure if it works or not so rather than deleting it i'll just leave this version below, try both out and see which one works best for you.

Edit: corrected the code
Code:
function doSomething(t, itemid, effect)
    doTransformItem(getTileItemById({x = t[1], y = t[2], z = t[3]}, itemid[1]).uid, itemid[2])
    if effect then
        doSendMagicEffect({x = t[1], y = t[2], z = t[3]}, CONST_ME_ICEAREA)
    end
    doTransformItem(getTileItemById({x = t[1], y = t[2], z = t[3]}, itemid[2]).uid, itemid[1])
end

function executeFunction(t, itemid, effect)
    for k, v in ipairs(t) do
        doSomething(v, itemid, effect)
    end
end

--stairs at end
local table1 = {
    [1] = {774, 1014, 7},
    [2] = {774, 1015, 7},
    [3] = {773, 1014, 7},
    [4] = {773, 1015, 7}
}

--first dirt after stairs
local table2 = {
    [1] = {745, 1012, 7},
    [2] = {745, 1011, 7},
    [3] = {745, 1013, 7},
    [4] = {746, 1011, 7},
    [5] = {746, 1012, 7},
    [6] = {746, 1013, 7},
    [7] = {746, 1014, 7},
    [8] = {747, 1013, 7},
    [9] = {747, 1012, 7},
    [10] = {748, 1012, 7}
}

--second dirt after stairs
local table3 = {
    [1] = {748, 1013, 7},
    [2] = {748, 1014, 7},
    [3] = {749, 1014, 7},
    [4] = {749, 1013, 7},
    [5] = {747, 1012, 7},
    [6] = {749, 1012, 7},
    [7] = {750, 1012, 7},
    [8] = {750, 1013, 7},
    [9] = {750, 1014, 7}
}

local all = {
    [1] = { table1, {1388, 6909} },
    [2] = { table2, {103, 671} },
    [3] = { table3, {103, 671} }
}

function onUse(cid, item, fromPosition, itemEx, toPosition)

    if itemEx.itemid ~= 1945 and item.actionid ~= 65535 then
         return false
    end

    doSendMagicEffect(toPosition,CONST_ME_ICEAREA)
    doTargetCombatHealth(0, cid, COMBAT_ICEDAMAGE, -500, -1000, CONST_ME_ICEAREA)
    doTransformItem(getTileItemById(toPosition, 7021).uid, itemEx.itemid)
    doTransformItem(itemEx.uid, 7021)


    for k, v in ipairs(all) do
        addEvent(executeFunction, (60 + k ) * 1000, v[1], v[2], true)
    end

end
 
Last edited:

Similar threads

Replies
0
Views
144
Back
Top