Random items loot

heba

Veteran OT User
Joined
Aug 5, 2011
Messages
1,361
Reaction score
171
hello
i use this random loot script and everything work good but when need to add some thing like
Code:
attr['good'] = {
    attr = 'skillsword',
    name = 'Sword',
    percent = {6, 20},
    types = {MELEE}
}
get this error 37590
im use tfs 0.4 anyone can tell me how to add some thing like
  • skillsword, skillaxe, skillclub, skilldist, skillfish, skillshield, skillfist, maxhealthpoints, maxmanapoints, magiclevel
Code:
-- //
   extra_loot_key = 123 --: optional storage for higher loot rate
   vocation_base_attackspeed = getVocationInfo(1).attackSpeed --: used for attackSpeed stat
-- //
tiers, attr = {}, {}
tiers['rare'] = {
   color = 66, -- color of 'RARE' text
   extra = {0, 0},
   attrNames = false, -- show attribute names instead of rare
   chance = {
     [1] = 4000,
     [2] = 25000 -- chance for 2nd stat
   }
}
tiers['special'] = {
   color = 35,
   extra = {7, 20}, -- additional percent bonus
   chance = {
     [1] = 2000,
     [2] = 45000
   }
}
tiers['legendary'] = {
   color = 149,
   extra = {20, 35},
   chance = {
     [1] = 1000,
     [2] = 100000 -- 2 bonuses always
   }
}
MELEE = 0
DISTANCE = 1
ARMOR = 2
SHIELD = 3
WAND = 4
DURATION_RING = 5
CHARGES = 6
--! attributes
attr['light'] = {
   attr = 'attackSpeed',
   name = 'Attack Speed',
   percent = {2, 8},
   types = {MELEE, DISTANCE, WAND}
}
attr['armoured'] = {
   attr = 'defense',
   name = 'Defense',
   percent = {2, 15},
   types = {MELEE, SHIELD}
}
attr['sharpened'] = {
   attr = 'attack',
   name = 'Attack',
   types = {MELEE},
   percent = {2, 15}
}
attr['hard'] = {
   attr = 'armor',
   name = 'Armor',
   percent = {2, 15},
   types = {ARMOR}
}
attr['eagle'] = {
   attr = 'hitChance',
   name = 'Hit Chance',
   percent = {2, 10},
   types = {DISTANCE}
}
attr['farsight'] = {
   attr = 'shootRange',
   name = 'Shoot Range',
   percent = {10, 30},
   types = {DISTANCE, WAND}
}
attr['unique'] = {
   attr = 'charges',
   name = 'Charges',
   percent = {8, 20},
   types = {CHARGES}
}
attr['extended'] = {
   attr = 'duration',
   name = 'Duration',
   percent = {35, 50},
   types = {DURATION_RING}
}
--/ attributes
rate = getConfigInfo('rateLoot')
if( getConfigInfo('monsterLootMessage') ~= 0 )then
   print('[Notice] Set monsterLootMessage = 0 to prevent duplicate loot messages')
end
 
function round(n, s)
   return tonumber(('%.' .. (s or 0) .. 'f'):format(n))
end
function getContentDescription(uid, sep)
   local ret, i, containers = '', 0, {}
   while( i < getContainerSize(uid) )do
     local v, s = getContainerItem(uid, i), ''
     local k = getItemInfo(v.itemid)
     k.name = getItemAttribute(v.uid, 'name') or k.name
     if( k.name ~= '' )then
       if( v.type > 1 and k.stackable and k.showCount )then
         s = v.type .. ' ' .. k.plural
       else
         local article = getItemAttribute(v.uid, 'article') or k.article
         s = (article == '' and '' or article .. ' ') .. k.name
       end
       ret = ret .. (i == 0 and not sep and '' or ', ') .. s
       if( isContainer(v.uid) and getContainerSize(v.uid) ~= 0 )then
         table.insert(containers, v.uid)
       end
     else
       ret = ret .. (i == 0 and not sep and '' or ', ') .. 'an item of type ' .. v.itemid .. ', please report it to gamemaster'
     end
     i = i + 1
   end
   for i = 1, #containers do
     ret = ret .. getContentDescription(containers[i], true)
   end
   return ret
end
local function send(cid, corpse, monster)
   if( isPlayer(cid) )then
     local ret = corpse and isContainer(corpse) and getContentDescription(corpse)
     doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, 'Loot of ' .. monster .. ': ' .. (ret ~= '' and ret or 'nothing'))
     local party = getPlayerParty(cid)
     if( party )then
       for _, pid in ipairs(getPartyMembers(party)) do
         doPlayerSendChannelMessage(pid, '', 'Loot of ' .. monster .. ': ' .. (ret ~= '' and ret or 'nothing'), TALKTYPE_CHANNEL_W, CHANNEL_PARTY)
       end
     end
   end
end
local function createLoot(i, ext)
   local item = type(i.id) == 'table' and i.id[math.random(#i.id)] or i.id
   local random = math.ceil(math.random(100000) / ext)
   local tmpItem, f
   if( random < i.chance )then
     if i.subType == -1 then
       f = getItemInfo(item)
     end
     tmpItem = doCreateItemEx(item,
       i.subType ~= -1 and i.subType or
       f.stackable and random % i.count + 1 or
       f.charges ~= 0 and f.charges or
       1
     )
   end
   if( not tmpItem )then
     return
   end
   if( i.actionId ~= -1 )then
     doItemSetAttribute(tmpItem, 'aid', i.actionId)
   end
   if( i.uniqueId ~= -1 )then
     doItemSetAttribute(tmpItem, 'uid', i.uniqueId)
   end
   if( i.text ~= '' )then
     doItemSetAttribute(tmpItem, 'text', i.text)
   end
   local ret, done
   for k, v in pairs(tiers) do
     local cur, used = {}, {}
     for i = 1, #v.chance do
       if( math.random(100000) <= v.chance[i] )then
         if( f )then
           f = getItemInfo(item)
         end
         if( not f.stackable )then
           for m, n in pairs(attr) do
             if( not table.find(used, m) and
             (
               ( table.find(n.types, MELEE) and table.find({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, f.weaponType) ) or
               ( table.find(n.types, DISTANCE) and f.weaponType == WEAPON_DIST and f.ammoType ~= 0 ) or
               ( table.find(n.types, ARMOR) and f.armor ~= 0 and f.wieldPosition ~= CONST_SLOT_NECKLACE ) or
               ( table.find(n.types, SHIELD) and f.defense ~= 0 and f.weaponType == WEAPON_SHIELD ) or
               ( table.find(n.types, WAND) and f.weaponType == WEAPON_WAND ) or
               ( table.find(n.types, DURATION_RING) and f.wieldPosition == CONST_SLOT_RING and f.transformEquipTo ~= 0 ) or
               ( table.find(n.types, CHARGES) and table.find({CONST_SLOT_RING, CONST_SLOT_NECKLACE}, f.wieldPosition) and f.charges ~= 0 )
             ) )then
               table.insert(cur, m)
             end
           end
           if( #cur ~= 0 )then
             local n = cur[math.random(#cur)]
             table.insert(used, n)
             n = attr[n]
             local percent, new, tmp = math.random(n.percent[1] + (v.extra[1] or 0), n.percent[2] + (v.extra[2] or 0))
             -- hacks
             if( n.attr == 'duration' )then
               tmp = getItemInfo(f.transformEquipTo)
               if tmp.transformDeEquipTo ~= item then
                 break
               end
               new = round( tmp.decayTime * (1 + percent / 100) * 1000 )
             elseif( n.attr == 'attackSpeed' )then
               new = round( vocation_base_attackspeed / (1 + percent / 100) )
             elseif( n.attr == 'hitChance' ) then
               new = round(
                 f.hitChance == -1 and
                   percent
                 or
                   f.hitChance * (1 + percent / 100)
               )
             else
               new = round(
                 n.base and
                   f[n['attr']] + f[n['base']] * (percent / 100)
                 or
                   f[n['attr']] * (1 + percent / 100)
               )
               if( new == f[n[n.base and 'base' or 'attr']] )then -- no improvement
                 break
               end
             end
             doItemSetAttribute(tmpItem, n.attr:lower(), new)
             local name = getItemAttribute(tmpItem, 'name')
             if( v.attrNames or not name )then
               local name = (v.attrNames and used[#used] or k) .. ' ' .. (name or f.name)
               doItemSetAttribute(tmpItem, 'name', name)
               if( f.article ~= '' )then
                 local article = getArticle(name)
                 if( article ~= f.article )then
                   doItemSetAttribute(tmpItem, 'article', article)
                 end
               end
             end

             local desc = getItemAttribute(tmpItem, 'description') or f.description
             doItemSetAttribute(tmpItem, 'description', '[' .. n.name .. ': +' .. percent .. '%]' .. (desc == '' and '' or '\n' .. desc))
             ret = k
           end
           cur = {}
           if( #v.chance == i )then
             done = true
           end
         end
       else
         done = i ~= 1
         break
       end
     end
     if( done )then
       break
     end
   end
   return tmpItem, ret
end
local function createChildLoot(parent, i, ext, pos)
   if( not i or #i == 0 )then
     return true
   end
   local size, cap = 0, getContainerCap(parent)
   for k = 1, #i do
     if( size == cap )then
       break
     end
     local tmp, ret = createLoot(i[k], ext)
     if( tmp )then
       if( isContainer(tmp) )then
         if( createChildLoot(tmp, i[k].child, ext, pos) )then
           doAddContainerItemEx(parent, tmp)
           size = size + 1
         else
           doRemoveItem(tmp)
         end
       else
         if( ret )then
           doSendMagicEffect(pos, 55)
         end
         doAddContainerItemEx(parent, tmp)
         size = size + 1
       end
     end
   end
   return size > 0
end
local function dropLoot(pos, v, ext, master, cid, target)
   local corpse
   if( not master or master == target )then -- 0.3/4
     corpse = getTileItemById(pos, v.lookCorpse).uid
     if( isContainer(corpse) )then
       for i = 1, getContainerSize(corpse) do
         doRemoveItem(getContainerItem(corpse, 0).uid)
       end
       local size, cap = 0, getContainerCap(corpse)
       for i = 1, #v.loot do
         if( size == cap )then
           break
         end
         local tmp, ret = createLoot(v.loot[i], ext)
         if( tmp )then
           if( isContainer(tmp) )then
             if( createChildLoot(tmp, v.loot[i].child, ext, pos) )then
               doAddContainerItemEx(corpse, tmp)
               size = size + 1
             else
               doRemoveItem(tmp)
             end
           else
             if( ret )then
               doSendMagicEffect(pos, 55)
             end
             doAddContainerItemEx(corpse, tmp)
             size = size + 1
           end
         end
       end
     end
   end
   send(cid, corpse, v.description)
end
function onKill(cid, target, damage, flags)
   if( (damage == true or bit.band(flags, 1) == 1) and isMonster(target) )then -- 0.3/4
     local v = getMonsterInfo(getCreatureName(target))
     if( v and v.lookCorpse ~= 0 )then
       local s = getCreatureStorage(cid, extra_loot_key)
       addEvent(dropLoot, 0, getThingPos(target), v, s == -1 and rate or s, getCreatureMaster(target), cid, target)
     end
   end
   return true
end
 
OP
heba

heba

Veteran OT User
Joined
Aug 5, 2011
Messages
1,361
Reaction score
171
anyone can tell me how ?
 

belal112

Basic Lua scripter
Joined
Dec 20, 2012
Messages
96
Reaction score
11
Can you explain more what you're trying to achieve? what's the code supposed to do? and which files are you posting? and please post the entire code of the file because if you don't post it all, the line numbers in the error message will not be accurate
 
OP
heba

heba

Veteran OT User
Joined
Aug 5, 2011
Messages
1,361
Reaction score
171
Can you explain more what you're trying to achieve? what's the code supposed to do? and which files are you posting? and please post the entire code of the file because if you don't post it all, the line numbers in the error message will not be accurate
i want add some thing like this in my script
attr['good'] = {
attr = 'skillsword',
name = 'Sword',
percent = {6, 20},
types = {MELEE}
}
 

kuhi

Intermediate OT User
Joined
Aug 26, 2012
Messages
123
Reaction score
30
I'm not sure about this... but...

Changing this line
Lua:
doItemSetAttribute(tmpItem, n.attr:lower(), new)
Into this one
Lua:
doItemSetAttribute(tmpItem, string.lower(n.attr), new)
I didn't even check what is "n.attr" but idk I think it's getting null value and I think it's just trying to convert a string into lowercase... at least with my change it won't get null
 
OP
heba

heba

Veteran OT User
Joined
Aug 5, 2011
Messages
1,361
Reaction score
171
I'm not sure about this... but...

Changing this line
Lua:
doItemSetAttribute(tmpItem, n.attr:lower(), new)
Into this one
Lua:
doItemSetAttribute(tmpItem, string.lower(n.attr), new)
I didn't even check what is "n.attr" but idk I think it's getting null value and I think it's just trying to convert a string into lowercase... at least with my change it won't get null
not work and n.attr = name of attr like this attr = 'armor',
n.attr = armor
 

kuhi

Intermediate OT User
Joined
Aug 26, 2012
Messages
123
Reaction score
30
You could "debug" a bit by adding some prints:

Lua:
print("A"..tostring(tmpItem))
print("B"..tostring(n.attr:lower()))
print("C"..tostring(new))
Just between lines 216 and 217

This way you will see in console which values are holding that variables so we can trace the null one
 

oen432

Intermediate OT User
Joined
Oct 3, 2014
Messages
374
Reaction score
347
Location
Poland
Lua:
print("A"..tostring(tmpItem))
print("B"..tostring(n.attr:lower()))
print("C"..tostring(new))
Can be cleaner.
Lua:
print("tmpItem", tmpItem)
print("n.attr", n.attr:lower())
print("new", new)
 
OP
heba

heba

Veteran OT User
Joined
Aug 5, 2011
Messages
1,361
Reaction score
171
when use print get this
37680

and in game
Code:
12:06 You see a rare mace (Atk:16, Def:11).
It weighs 28.00 oz.
[speed: +0]
and for skillsword just give me the first error :S
 

kuhi

Intermediate OT User
Joined
Aug 26, 2012
Messages
123
Reaction score
30
Can be cleaner.
Lua:
print("tmpItem", tmpItem)
print("n.attr", n.attr:lower())
print("new", new)
print won't give problems by casting an integer as string? it converts automatically?
 

oen432

Intermediate OT User
Joined
Oct 3, 2014
Messages
374
Reaction score
347
Location
Poland
print won't give problems by casting an integer as string? it converts automatically?
Yup. You can even put boolean there and it will return true or false as a string. By using commas, you can separate parameters, by default it's using tabs as separators where heba has it printed line by line, which is odd. Even if you go to https://www.lua.org/cgi-bin/demo and put there
Lua:
local integer = 123
local string = "string"
local boolean = true
print("integer", integer)
print("string", string)
print("boolean", boolean)
Which results in
Code:
integer    123
string    string
boolean    true
 

kuhi

Intermediate OT User
Joined
Aug 26, 2012
Messages
123
Reaction score
30
Yup. You can even put boolean there and it will return true or false as a string. By using commas, you can separate parameters, by default it's using tabs as separators where heba has it printed line by line, which is odd. Even if you go to https://www.lua.org/cgi-bin/demo and put there
Lua:
local integer = 123
local string = "string"
local boolean = true
print("integer", integer)
print("string", string)
print("boolean", boolean)
Which results in
Code:
integer    123
string    string
boolean    true
Thank you bro, very useful link btw
 
Top