• 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 Runes with Talkactions [TFS 1.2]

Ramirow

Veteran OT User
Joined
Aug 22, 2009
Messages
584
Solutions
15
Reaction score
301
Location
Argentina
YouTube
ramirogrant
I'm facing a weird problem now and I don't know how to address it.
The script is supposed to do the following:
Check if player is knight/elite knight and terminates execution.
Check then if player is Sorcerer and can conjure the rune.
Check if it is Druid and can conjure the rune.
And check if it is Paladin and can conjure the rune.

No problems with Sorcerer or Druid's checks, they work flawlessly.
The issue arises with Paladin's, they can cast all spells marked with the var 'usable = 3' which is only used for Druid/Sorcerer spells they share.
But I don't see how it's possible, it may be a dumb error, but I can't seem to find it..

I know this script could be written better, I was just experimenting!

Code:
local exhaust = Condition(CONDITION_SPELLCOOLDOWN)
exhaust:setParameter(CONDITION_PARAM_TICKS, (configManager.getNumber(configKeys.EX_ACTIONS_DELAY_INTERVAL) + 500))

-- Runes Table.
-- 'Usable' var. stands for: 1 - sorcerer only, 2 - druid only, 3 - sor/druid, 4 - paladin only and 5 -- stands for sor/druid/pala
local runes = {
{name = "adura gran", runeID = 2265, runeAmount = 1, manaCost = 120, levelReq = 15, soul = 2, usable = 2},
{name = "adori min vis", runeID = 2287, runeAmount = 10, manaCost = 120, levelReq = 15, soul = 1, usable = 3},
{name = "adori mas flam", runeID = 2304, runeAmount = 4, manaCost = 530, levelReq = 30, soul = 3, usable = 1},
{name = "adito grav", runeID = 2261, runeAmount = 3, manaCost = 120, levelReq = 17, soul = 2, usable = 5},
{name = "adori san", runeID = 2295, runeAmount = 5, manaCost = 350, levelReq = 27, soul = 3, usable = 4}
}

local noSoul = "You do not have enough soul points."
local noBlank = "You need a blank rune to cast this spell."
local noMana = "You do not have enough mana."
local noVoc = "Your vocation cannot use this spell."

function onSay(player, words, param)
local voc = player:getVocation():getId()

if player:getCondition(CONDITION_SPELLCOOLDOWN) then
   player:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_YOUAREEXHAUSTED))
   player:getPosition():sendMagicEffect(CONST_ME_POFF)
   return false
end

if isInArray({4, 8}, voc) then
   player:sendTextMessage(MESSAGE_STATUS_SMALL, noVoc)
   player:getPosition():sendMagicEffect(CONST_ME_POFF)
   return true
end

for i=1,#runes,1 do
   if runes[i].name == string.lower((words.." "..param)) then
   local noLvl = "You need level " .. (runes[i].levelReq) .. " to conjure this rune."
     if isInArray({1,5}, voc) and runes[i].usable == 1 or runes[i].usable == 3 or runes[i].usable == 5 then
       if player:getLevel() >= runes[i].levelReq then
         if player:getMana() >= runes[i].manaCost then
           if player:getSoul() >= runes[i].soul then
             if player:removeItem(2260, 1) then
               player:addMana(-(runes[i].manaCost))
               player:addManaSpent(runes[i].manaCost)
               player:addSoul(-(runes[i].soul))
               player:addItem(runes[i].runeID, runes[i].runeAmount)
               player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
               player:addCondition(exhaust)
               player:say(runes[i].name, TALKTYPE_MONSTER_SAY)
               return false
             else
               player:sendTextMessage(MESSAGE_STATUS_SMALL, noBlank)
               player:getPosition():sendMagicEffect(CONST_ME_POFF)
               return
             end
           else
             player:sendTextMessage(MESSAGE_STATUS_SMALL, noSoul)
             player:getPosition():sendMagicEffect(CONST_ME_POFF)
             return
           end
         else
           player:sendTextMessage(MESSAGE_STATUS_SMALL, noMana)
           player:getPosition():sendMagicEffect(CONST_ME_POFF)
           return
         end
       else
         player:sendTextMessage(MESSAGE_STATUS_SMALL, noLvl)
         player:getPosition():sendMagicEffect(CONST_ME_POFF)
         return
   end
end
     if isInArray({2,6}, voc) and runes[i].usable == 2 or runes[i].usable == 3 or runes[i].usable == 5 then
       if player:getLevel() >= runes[i].levelReq then
         if player:getMana() >= runes[i].manaCost then
           if player:getSoul() >= runes[i].soul then
             if player:removeItem(2260, 1) then
               player:addMana(-(runes[i].manaCost))
               player:addManaSpent(runes[i].manaCost)
               player:addSoul(-(runes[i].soul))
               player:addItem(runes[i].runeID, runes[i].runeAmount)
               player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
               player:addCondition(exhaust)
               player:say(runes[i].name, TALKTYPE_MONSTER_SAY)
               return false
             else
               player:sendTextMessage(MESSAGE_STATUS_SMALL, noBlank)
               player:getPosition():sendMagicEffect(CONST_ME_POFF)
               return
             end
           else
             player:sendTextMessage(MESSAGE_STATUS_SMALL, noSoul)
             player:getPosition():sendMagicEffect(CONST_ME_POFF)
             return
           end
         else
           player:sendTextMessage(MESSAGE_STATUS_SMALL, noMana)
           player:getPosition():sendMagicEffect(CONST_ME_POFF)
           return
         end
       else
         player:sendTextMessage(MESSAGE_STATUS_SMALL, noLvl)
         player:getPosition():sendMagicEffect(CONST_ME_POFF)
         return
   end
       end
   if isInArray({3,7}, voc) and runes[i].usable == 4 or runes[i].usable == 5 then
       if player:getLevel() >= runes[i].levelReq then
         if player:getMana() >= runes[i].manaCost then
           if player:getSoul() >= runes[i].soul then
             if player:removeItem(2260, 1) then
               player:addMana(-(runes[i].manaCost))
               player:addManaSpent(runes[i].manaCost)
               player:addSoul(-(runes[i].soul))
               player:addItem(runes[i].runeID, runes[i].runeAmount)
               player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
               player:addCondition(exhaust)
               player:say(runes[i].name, TALKTYPE_MONSTER_SAY)
               return false
             else
               player:sendTextMessage(MESSAGE_STATUS_SMALL, noBlank)
               player:getPosition():sendMagicEffect(CONST_ME_POFF)
               return
             end
           else
             player:sendTextMessage(MESSAGE_STATUS_SMALL, noSoul)
             player:getPosition():sendMagicEffect(CONST_ME_POFF)
             return
           end
         else
           player:sendTextMessage(MESSAGE_STATUS_SMALL, noMana)
           player:getPosition():sendMagicEffect(CONST_ME_POFF)
           return
         end
       else
         player:sendTextMessage(MESSAGE_STATUS_SMALL, noLvl)
         player:getPosition():sendMagicEffect(CONST_ME_POFF)
         return
   end
       end
   else
     return true
   end
   end
   return true
end
 
if you want i can rewrite the one i wrote for 0.4 to 1.2 instead of trying to fix this script since it turned out a bit messy (and the runes table setup is worse performance)
:)
edit: since thats easier for me to do than trying to go through this spaghetti :p
 
yeah 0.4 > 1.2 isnt really that much of a difference
and your way of handling vocations here is completely unnecessary, just have a vocation = {1,2,3...} in the rune data, and isInArray(vocation, playervoc), no need to split up 3 functions for diff voc conditions
 
yeah 0.4 > 1.2 isnt really that much of a difference
and your way of handling vocations here is completely unnecessary, just have a vocation = {1,2,3...} in the rune data, and isInArray(vocation, playervoc), no need to split up 3 functions for diff voc conditions
ur wrong cus 1.2 > 0.4 and everyone knows that, if you say that 0.4 is better means that u dont know shit
 
Code:
local exhaustTime = 1000
local blank = 2260

local exhaust = Condition(CONDITION_EXHAUST)
exhaust:setParameter(CONDITION_PARAM_TICKS, exhaustTime)

local runes = {
    ["adori blank"] = {runeID = 2260, runeAmount = 1, blankAmount = 0, manaCost = 20, levelReq = 8, soul = 0, vocations = {1,2,3,4,5,6,7,8}},
    ["adori vita vis"] = {runeID = 2268, runeAmount = 3, blankAmount = 1, manaCost = 200, levelReq = 200, soul = 0, vocations = {1, 2, 3}}, 
    ["adori vis"] = {runeID = 2311, runeAmount = 15, blankAmount = 1, manaCost = 200, levelReq = 200, soul = 0, vocations = {1, 2, 3}}
}

local function conjuration(player, t, word)

end

function onSay(player, words, param)
    if(player:getCondition(CONDITION_EXHAUST)) then
        doPlayerSendDefaultCancel(player, RETURNVALUE_YOUAREEXHAUSTED)
        return false
    end
   
    local cast = string.lower(words.." "..param)
    local voc = getPlayerVocation(player)
    local errorMessage = nil
   
    if runes[cast] then
        if isInArray(runes[cast].vocations, voc) then
            if player:getLevel() >= runes[cast].levelReq then
                if player:getMana() >= runes[cast].manaCost then
                    if player:getSoul() > runes[cast].soul then
                        if doPlayerRemoveItem(player, blank, runes[cast].blankAmount)then
                            doPlayerAddMana(player, -(runes[cast].manaCost))
                            doPlayerAddItem(player, runes[cast].runeID, runes[cast].runeAmount)
                            doPlayerAddManaSpent(player, runes[cast].manaCost)
                            doPlayerAddSoul(player, runes[cast].soul)
                            doCreatureSay(played, cast, TALKTYPE_ORANGE_1)
                            doSendMagicEffect(getCreaturePosition(player), CONST_ME_MAGIC_BLUE)
                            doPlayerSendTextMessage(player, MESSAGE_STATUS_CONSOLE_BLUE, "You conjured "..(runes[cast].runeAmount).." "..(getItemName(runes[cast].runeID)).." runes.")
                        else
                            errorMessage = "You do not have enough blank runes.."
                        end
                    else
                        errorMessage = "You do not have enough soul."
                    end
                else
                    errorMessage = "You do not have enough mana."
                end
            else
                errorMessage = "You do not have the required level for this. You need level "..(runes[cast].levelReq).."."
            end
        else
            errorMessage = "Your vocation cannot cast that spell."
        end   
    else
        errorMessage = "That conjuration spell does not exist."
    end
    if errorMessage then
        errorMessage = errorMessage.."\n--- Valid conjuration spells for you are ---"   
        for pos,val in pairs(runes) do
            if isInArray(runes[pos].vocations, voc) then
                errorMessage = errorMessage.."\n"..pos.." --- which costs "..(runes[pos].manaCost).." mana, "..(runes[pos].soul).." soul and gives you "..(runes[pos].runeAmount).." "..(getItemName(runes[pos].runeID))..""
                if runes[pos].runeAmount > 1 then
                    errorMessage = errorMessage.."s."
                else
                    errorMessage = errorMessage.."."
                end
            end
        end
        doSendMagicEffect(getCreaturePosition(player), CONST_ME_POFF)
        doPlayerSendTextMessage(player, MESSAGE_STATUS_CONSOLE_BLUE, errorMessage)
    end
    player:addCondition(exhaust)   
    return false
end
that works for me in 1.1
i dont have a 1.2 rev on computer but there shouldnt be any different, tell me if you get an error :)

@StreamSide i meant 0.4 -> 1.2 as in converting a script from 0.4 to 1.2 isnt much difference, i know 1.2 is far superior (although i use 1.1 cus im 2 lazy to get 1.2 :()
 
Last edited:
Code:
local exhaustTime = 1000

local exhaust = Condition(CONDITION_EXHAUST)
exhaust:setParameter(CONDITION_PARAM_TICKS, 1000)

local function conjuration(player, t, word)
    doPlayerAddMana(player, -(t[word].manaCost))
    doPlayerAddItem(player, t[word].runeID, t[word].runeAmount)
    doPlayerAddManaSpent(player, t[word].manaCost)
    doPlayerAddSoul(player, t[word].soul)
    doSendMagicEffect(getCreaturePosition(player), CONST_ME_MAGIC_BLUE)
    doPlayerSendTextMessage(player, MESSAGE_STATUS_CONSOLE_BLUE, "You conjured "..(t[word].runeAmount).." "..(getItemName(t[word].runeID)).." runes.")
    player:addCondition(exhaust)
end

function onSay(player, words, param)
    if(player:getCondition(CONDITION_EXHAUST)) then
        doPlayerSendDefaultCancel(player, RETURNVALUE_YOUAREEXHAUSTED)
        return true
    end
    local vocations = {"Sorcerer", "Druid", "Paladin", "Knight", "Master sorcerer", "Elder druid", "Royal paladin", "Elite knight"}
    local cast = string.lower(words.." "..param)
    local voc = getPlayerVocation(player)
    local lvl = getPlayerLevel(player)
    local mana = getPlayerMana(player)
    local errorMessage = ""
    local invalidSpell = "--- Valid conjuration spells for you are ---"
    local runes = {["adori blank"] = {runeID = 2260, runeAmount = 1, manaCost = 20, levelReq = 8, soul = 0, vocations = {1,2,3,4,5,6,7,8}},["adori vita vis"] = {runeID = 2268, runeAmount = 3, manaCost = 200, levelReq = 200, soul = 0, vocations = {1, 2, 3}}, ["adori vis"] = {runeID = 2311, runeAmount = 15, manaCost = 200, levelReq = 200, soul = 0, vocations = {1, 2, 3}}}
    if runes[cast] then
        if isInArray(runes[cast].vocations, voc) then
            if lvl >= runes[cast].levelReq then
                if mana >= runes[cast].manaCost then
                    if (getPlayerSoul(player) > runes[cast].soul) then
                        if (cast ~= "adori blank") and (doPlayerRemoveItem(player, 2260, runes[cast].runeAmount))then
                            conjuration(player, runes, cast)
                            return true
                        elseif cast == "adori blank" then
                            conjuration(player, runes, cast)
                            return true
                        else
                            errorMessage = "You do not have enough blank runes. You need "..(runes[cast].runeAmount).."."
                        end
                    else
                        errorMessage = "You do not have enough soul. You need "..(runes[cast].soul).." and you have "..getPlayerSoul(player).."."
                    end
                else
                    errorMessage = "You do not have enough mana. You have "..mana.." and you need "..(runes[cast].manaCost).."."
                end
            else
                errorMessage = "You do not have the required level for this. You need level "..(runes[cast].levelReq).."."
            end
        else
            errorMessage = "That spell can only be used by:\n"
            for i=1,#(runes[cast].vocations),1 do
                if i == #(runes[cast].vocations) then
                    errorMessage = errorMessage..vocations[i].."."
                else
                    errorMessage = errorMessage..vocations[i]..", "
                end
            end
        end
    else
        errorMessage = "That conjuration spell does not exist."
    end
    for pos,val in pairs(runes) do
        if isInArray(runes[pos].vocations, voc) then
            invalidSpell = invalidSpell.."\n"..pos.." --- which costs "..(runes[pos].manaCost).." mana, "..(runes[pos].soul).." soul and gives you "..(runes[pos].runeAmount).." "..(getItemName(runes[pos].runeID))..""
            if runes[pos].runeAmount > 1 then
                invalidSpell = invalidSpell.."s."
            else
                invalidSpell = invalidSpell.."."
            end
        end
    end
    invalidSpell = errorMessage.."\n"..invalidSpell
    doPlayerSendTextMessage(player, MESSAGE_STATUS_CONSOLE_BLUE, invalidSpell)
    player:addCondition(exhaust)
    return false
end
that works for me in 1.1
i dont have a 1.2 rev on computer but there shouldnt be any different, tell me if you get an error :)

@StreamSide i meant 0.4 -> 1.2 as in converting a script from 0.4 to 1.2 isnt much difference, i know 1.2 is far superior (although i use 1.1 cus im 2 lazy to get 1.2 :()
oh wasnt even reading, im so stupido sorry my bro, can I invite you a joint?
 
@StreamSide dont worry i still love you :rolleyes:

@Ramirow if i had to fix ur script though, i would just remove 2 of the 3 identical ifs~ that check vocations, and add vocations to the runes table, and use isInArray(runes[...].vocation, playervoc) to remove the need for 3 identical functions :)
with that way any extra variables for who can use it is unnecessary, since having a vocation = {} in the rune table will contain all allowed vocs anyway
also if you want to learn check the way my rune tables are currently
having them in the form of
Code:
["name"] = {...}
you can just use [words.." "..param] (words from talkaction) to get the specific rune table, and if it doesnt exist it will be nil and the first check in my code is for that and skip the big function
the way urs is, is how i did it at first, but then the big runes table is in the form of runes[1].name, runes[2].name etc, which means you have to loop through the entire table to find the right one, while this way you can just go straight to the index of the table

also from what i can see you took one of the first versions of the function i wrote, which didnt have tables that way or vocation checks yet, cause i forgot them at first :oops:
 
also ur original error was in the
Code:
if isInArray({1,5}, voc) and runes[i].usable == 1 or runes[i].usable == 3 or runes[i].usable == 5 then
or same one for {2,6}
i think lua evaluates that like this
Code:
if (isInArray({1,5}, voc) and runes[i].usable == 1) or (runes[i].usable == 3) or (runes[i].usable == 5)
and if either of those 3 are true it will execute that part
if im wrong someone educate me :)
this also means that if you didnt have a check to not allow knights, they would also be able to do these, to fix it you can have
Code:
isInArray({1,5}, voc) and (runes[i].usable == 1 or runes[i].usable == 3 or runes[i].usable == 5)
 
Your's worked like a charm! I'm very happy with the code, I'm reading it step by step to learn what's happening and where I made my mistakes. It's amazing, it's half the lenght of what I've coded and works! I see what you did there, HUGE thanks mate! This gave me even more ideas D:
 
Your's worked like a charm! I'm very happy with the code, I'm reading it step by step to learn what's happening and where I made my mistakes. It's amazing, it's half the lenght of what I've coded and works! I see what you did there, HUGE thanks mate! This gave me even more ideas D:
if you removed 2 of the duplicate functions yours would be shorter, since my error messages back to the user is over half the onSay(...) function :p
always nice when people actually try to understand scripts instead of just copy pasting them :)
 
if you removed 2 of the duplicate functions yours would be shorter, since my error messages back to the user is over half the onSay(...) function :p
always nice when people actually try to understand scripts instead of just copy pasting them :)
But perfomance wise it would not be better than yours, like you said, mine would loop trough the runes table, your script is 'wiser' :)
 
Why make it a talk action when you can make it as a spell in 1.2 atleast?
Spells don't require you to define the cool down in the script, you can do that in the xml.
 
Why make it a talk action when you can make it as a spell in 1.2 atleast?
Spells don't require you to define the cool down in the script, you can do that in the xml.
I don't remember TFS 1.2 having the words said in the variant tho is it?
 
Why make it a talk action when you can make it as a spell in 1.2 atleast?
Spells don't require you to define the cool down in the script, you can do that in the xml.
i didnt know you could fetch the words from the variant in 1.2, that makes it a bit easier :)
when i was trying it out in 0.3.6 it didnt pass the words in any way though
this is what print_r(var) for a spell gives me in 0.3.6
Code:
[10/05/2016 15:24:07] table: 1265B678 {
[10/05/2016 15:24:07]   [pos] => table: 1265B678 {
[10/05/2016 15:24:07]              [y] => 996
[10/05/2016 15:24:07]              [x] => 1001
[10/05/2016 15:24:07]              [stackpos] => 0
[10/05/2016 15:24:07]              [z] => 7
[10/05/2016 15:24:07]            }
[10/05/2016 15:24:07]   [type] => 2
[10/05/2016 15:24:07] }
 
i didnt know you could fetch the words from the variant in 1.2, that makes it a bit easier :)
when i was trying it out in 0.3.6 it didnt pass the words in any way though
It does not pass the words only spell params.
You have to set params="1" in the XML.

Then casting words "param

var.text = "param"
 
Back
Top