• 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+ Problem with extra loot in ring

damian00912

Member
Joined
Sep 11, 2009
Messages
90
Reaction score
6
Hei, i have problem, if someone has exta loot in ring, thats working fine, is information about extra drop, and in monster this item is like extra drop but every this drop make error in logs, and if this ring have a lot of players, thats sometime make crash server :/ someone know what is wrong?


Here is error from console:

Code:
Lua Script Error: [Main Interface]
in a timer event called from:
(Unknown scriptfile)
data/stats.lua:2080: attempt to index a nil value
stack traceback:
    [C]: in function '__index'
    data/stats.lua:2080: in function 'improveChance'
    data/stats.lua:2156: in function <data/stats.lua:2131>

And this is the script:


Lua:
function improveChance(c, monsterName, extraPercent, killer)
    local m = MonsterType(monsterName):getLoot()
    if math.random(1, 100) <= extraPercent then
        local t = {}
        for i = 1, #m do
            t[i] = {itemId = m[i].itemId, chance = m[i].chance}
        end
        
        local min = 1
        local t_s = {}
        local low5 = #t-5
        while #t > low5 do
            min = 1
            for i = 1, #t do
                if math.min(t[i].chance, t[min].chance) == t[i].chance then
                    min = i
                end
            end
            t_s[#t_s + 1] = {itemId = t[min].itemId, chance = t[min].chance}
            table.remove(t, min)
        end
        
        local chosenId = math.random(1, #t_s)
        
        local h = c:getItemHoldingCount()
        if h > 0 then
            local extra = true
            for i = 1, h do
                if ItemType(c:getItem(i - 1):getId()) == t_s[chosenId].itemId then
                    extra = false
                    break
                end
            end
            
            if extra then
                if math.random(1, 100000) <= (t_s[chosenId].chance + (t_s[chosenId].chance * extraPercent / 100)) * configManager.getNumber(configKeys.RATE_LOOT) then
                    c:addItem(m[chosenId].itemId, 1)
                    if killer then
                        local iid = ItemType(m[chosenId].itemId)
                        Player(killer):sendTextMessage(MESSAGE_EVENT_ADVANCE, "Extra loot: " .. (iid:getArticle() ~= "" and iid:getArticle() .. " " or "") .. iid:getName())
                    end
                end
            end
        end
    end                 
    return true
end

Please help if someone know where is problem
 
(Unknown scriptfile)
More information needed here. Could you post your data/stats.lua file, maybe not all of it but parts related to improveChance ?
 
The code itself is poorly designed, but leaving aside the design and elegance, the error you mention is related to the __index metamethod, this is because it is trying to obtain the index of something that does not even have indexes

I'm sure the tables you use don't have all the indexes that are handled in the function: improveChance
 
yes, here is this:


Ok line 2080 was
Lua:
t_s[#t_s + 1] = {itemId = t[min].itemId, chance = t[min].chance}
After executing the following code along with some prints..
Lua:
local m = {
    {itemId = 123, chance = 123}
}
print("#m == " .. #m)
local t = {}
for i = 1, #m do
    t[i] = {itemId = m[i].itemId, chance = m[i].chance}
end
print("#t == ".. #t)

local min = 1
local t_s = {}
local low5 = #t-5
print("#t - 5 == " .. (low5))

while #t > low5 do -- while 1 > (-4)
    min = 1
    for i = 1, #t do
        if math.min(t[i].chance, t[min].chance) == t[i].chance then
            min = i
        end
    end
    print("min == " .. min)

    print("Elements of T : " .. #t)
    t_s[#t_s + 1] = {
      itemId = t[min].itemId, -- error here
      chance = t[min].chance
    }
    table.remove(t, min)
end
.. I noticed that it was trying to access elements when #t == 0

So try adding this
Lua:
if #t == 0 then
    break
end

before
Lua:
t_s[#t_s + 1] = {itemId = t[min].itemId, chance = t[min].chance}
 
thanks you, its working pefect, but i have another problem, ofc drop is in corpse like is writing:

18:03 Loot of a bony sea devil: jaws, a rod, a rainbow quartz, an onyx chip, a green crystal fragment, a wand of voodoo, a northwind rod, a gold ingot, a giant shimmering pearl, a giant shimmering pearl, 3 ultimate health potions, 21 platinum coins
18:03 Extra loot: a giant shimmering pearl

But all time after this drop, in console i have


Lua:
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.
[Warning] DropLoot:    Could not add loot item to corpse.

Can you help also with this?

My data/events/script/monsters.lua is:

Lua:
function Monster:onDropLoot(corpse)
    if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
        return
    end

    local mType = self:getType()
    if mType:isRewardBoss() then
        corpse:registerReward()
        return
    end

    local player = Player(corpse:getCorpseOwner())
    local mType = self:getType()
    if not player or player:getStamina() > 840 then
        local monsterLoot = mType:getLoot()
        for i = 1, #monsterLoot do
            local boolCharm = false
            if player then
                local charmType = player:getCharmMonsterType(CHARM_GUT)
                if charmType and charmType:raceId() == mType:raceId() then
                    boolCharm = true
                end
            end
        
            local item = corpse:createLootItem(monsterLoot[i], boolCharm)
            if self:getName():lower() == (Game.getBoostedCreature()):lower() then
                local itemBoosted = corpse:createLootItem(monsterLoot[i], boolCharm)
            end
            if not item then
                print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
            end
        end

        if player then
            local text = {}
            if self:getName():lower() == (Game.getBoostedCreature()):lower() then
                 text = ("Loot of %s: %s (boosted loot)"):format(mType:getNameDescription(), corpse:getContentDescription())
            else
                 text = ("Loot of %s: %s"):format(mType:getNameDescription(), corpse:getContentDescription())            
            end
            local party = player:getParty()
            if party then
                party:broadcastPartyLoot(text)
            else
                player:sendTextMessage(MESSAGE_LOOT, text)
            end
            player:updateKillTracker(self, corpse)
        end
    else
        local text = ("Loot of %s: nothing (due to low stamina)"):format(mType:getNameDescription())
        local party = player:getParty()
        if party then
            party:broadcastPartyLoot(text)
        else
            player:sendTextMessage(MESSAGE_LOOT, text)
        end
    end
end

function Monster:onSpawn(position)
    if self:getType():isRewardBoss() then
        self:setReward(true)
    end

    if self:getName():lower() == "cobra scout" or 
        self:getName():lower() == "cobra vizier" or 
        self:getName():lower() == "cobra assassin" then
        if getGlobalStorageValue(GlobalStorage.CobraBastionFlask) >= os.time() then
            self:setHealth(self:getMaxHealth() * 0.75)
        end
    end

    if not self:getType():canSpawn(position) then
        self:remove()
    else
        local spec = Game.getSpectators(position, false, false)
        for _, pid in pairs(spec) do
            local monster = Monster(pid)
            if monster and not monster:getType():canSpawn(position) then
                monster:remove()
            end
        end

        if self:getName():lower() == 'iron servant replica' then
            local chance = math.random(100)
            if Game.getStorageValue(GlobalStorage.ForgottenKnowledge.MechanismDiamond) >= 1
            and Game.getStorageValue(GlobalStorage.ForgottenKnowledge.MechanismGolden) >= 1 then
                if chance > 30 then
                    local chance2 = math.random(2)
                    if chance2 == 1 then
                        Game.createMonster('diamond servant replica', self:getPosition(), false, true)
                    elseif chance2 == 2 then
                        Game.createMonster('golden servant replica', self:getPosition(), false, true)
                    end
                    self:remove()
                end
                return true
            end
            if Game.getStorageValue(GlobalStorage.ForgottenKnowledge.MechanismDiamond) >= 1 then
                if chance > 30 then
                    Game.createMonster('diamond servant replica', self:getPosition(), false, true)
                    self:remove()
                end
            end
            if Game.getStorageValue(GlobalStorage.ForgottenKnowledge.MechanismGolden) >= 1 then
                if chance > 30 then
                    Game.createMonster('golden servant replica', self:getPosition(), false, true)
                    self:remove()
                end
            end
            return true
        end
    end
end
 
Some solution?
nice spam 👍

The message is printed when item has a non-true value.
Lua:
if not item then
    print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
end

Post your data/lib/core/container.lua -> function Container.createLootItem(self, item, ... )

EDIT: Assuming you're using OTServBr..

add some prints before each return and check where it stops.
example:
Lua:
if not lootBlockType then
    print("lootBlockType") -- here
    return
end
 
Last edited:
I don't understand very well,

I added this:

Lua:
if not lootBlockType then
    print("lootBlockType") -- here
    return
end

to data/lib/core/container.lua and now every item in loot monster out show this warning :p


my data/lib/core/container.lua

Code:
function Container.isContainer(self)
    return true
end

function Container.createLootItem(self, item, boolCharm)
    if self:getEmptySlots() == 0 then
        return true
    end
    
       local itemCount = 0
    local randvalue = getLootRandom()
    if randvalue < item.chance then
        if ItemType(item.itemId):isStackable() then
            itemCount = randvalue % item.maxCount + 1
        else
            itemCount = 1
        end
    end

    if itemCount > 0 then
        local tmpItem = self:addItem(item.itemId, math.min(itemCount, 100))
        if not tmpItem then
            return true
        end

        if tmpItem:isContainer() then
            for i = 1, #item.childLoot do
                if not tmpItem:createLootItem(item.childLoot[i]) then
                    tmpItem:remove()
                    return true
                end
            end

        if item.subType ~= -1 then
            tmpItem:setAttribute(ITEM_ATTRIBUTE_CHARGES, item.subType)
        end

        if item.actionId ~= -1 then
            tmpItem:setActionId(item.actionId)
        end

        if item.text and item.text ~= "" then
            tmpItem:setText(item.text)
        end
        return tmpItem
    end
    return nil
end

    local itemCount = 0
    local randvalue = getLootRandom()
    local lootBlockType = ItemType(item.itemId)
    local chanceTo = item.chance

    if not lootBlockType then
        return
    end

    if boolCharm and lootBlockType:getType() == ITEM_TYPE_CREATUREPRODUCT then
        chanceTo = (chanceTo * (GLOBAL_CHARM_GUT + 100))/100
    end

    if randvalue < chanceTo then
        if lootBlockType:isStackable() then
            local maxc, minc = item.maxCount or 1, item.minCount or 1
            itemCount = math.max(0, randvalue % (maxc - minc + 1)) + minc           
        else
            itemCount = 1
        end
    end
    
    while (itemCount > 0) do
        local n = math.min(itemCount, 100)
        itemCount = itemCount - n
        
        local tmpItem = self:addItem(item.itemId, n)
        if not tmpItem then
            return false
        end

        if tmpItem:isContainer() then
            for i = 1, #item.childLoot do
                if not tmpItem:createLootItem(item.childLoot[i]) then
                    tmpItem:remove()
                    return false
                end
            end
        end

        if item.subType ~= -1 then
            tmpItem:transform(item.itemId, item.subType)
        elseif lootBlockType:isFluidContainer() then
            tmpItem:transform(item.itemId, 0)
        end

        if item.actionId ~= -1 then
            tmpItem:setActionId(item.actionId)
        end

        if item.text and item.text ~= "" then
            tmpItem:setText(item.text)
        end
    end
    return true
end
 
Back
Top