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

[Mod] Random Item Stats

TFS 0.4 CLIENT 8.71
WORK! but spam on my server and verry lagger
Code:
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, DISTANCE) and f.weaponType == WEAPON_DIST and f.ammoType ~= 0 ) or
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, ARMOR) and f.armor ~= 0 and f.wieldPosition ~= CONST_SLOT_NECKLACE ) or
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, SHIELD) and f.defense ~= 0 and f.weaponType == WEAPON_SHIELD ) or
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, WAND) and f.weaponType == WEAPON_WAND ) or
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, DURATION_RING) and f.wieldPosition == CONST_SLOT_RING and f.transformEquip                                                                                                                               To ~= 0 ) or
[12:40:48.191]                                                  ( table.find(n.t                                                                                                                               ypes, CHARGES) and table.find({CONST_SLOT_RING, CONST_SLOT_NECKLACE}, f.wieldPos                                                                                                                               ition) and f.charges ~= 0 )
[12:40:48.191]                                          ) )then
[12:40:48.191]                                                  table.insert(cur                                                                                                                               , m)
[12:40:48.191]                                          end
[12:40:48.191]                                  end
[12:40:48.192]
[12:40:48.192]                                  if( #cur ~= 0 )then
[12:40:48.192]                                          local n = cur[math.rando                                                                                                                               m(#cur)]
[12:40:48.192]                                          table.insert(used, n)
[12:40:48.192]
[12:40:48.192]                                          n = attr[n]
[12:40:48.192]                                          local percent, new, tmp                                                                                                                                = math.random(n.percent[1] + (v.extra[1] or 0), n.percent[2] + (v.extra[2] or 0)                                                                                                                               )
[12:40:48.192]                                          -- hacks
[12:40:48.192]                                          if( n.attr == 'duration'                                                                                                                                )then
[12:40:48.192]                                                  tmp = getItemInf                                                                                                                               o(f.transformEquipTo)
[12:40:48.192]                                                  if tmp.transform                                                                                                                               DeEquipTo ~= item then
[12:40:48.192]                                                          break
[12:40:48.192]                                                  end
[12:40:48.192]                                                  new = round( tmp                                                                                                                               .decayTime * (1 + percent / 100) * 1000 )
[12:40:48.192]                                          elseif( n.attr == 'attac                                                                                                                               kSpeed' )then
[12:40:48.192]                                                  new = round( voc                                                                                                                               ation_base_attackspeed / (1 + percent / 100) )
[12:40:48.192]                                          elseif( n.attr == 'hitCh                                                                                                                               ance' ) then
[12:40:48.192]                                                  new = round(
[12:40:48.192]                                                          f.hitCha                                                                                                                               nce == -1 and
[12:40:48.192]                                                                 p                                                                                                                               ercent
[12:40:48.192]                                                          or
[12:40:48.192]                                                                 f                                                                                                                               .hitChance * (1 + percent / 100)
[12:40:48.192]                                                  )
[12:40:48.192]                                          else
[12:40:48.192]                                                  new = round(
[12:40:48.192]                                                          n.base a                                                                                                                               nd
[12:40:48.192]                                                                 f                                                                                                                               [n['attr']] + f[n['base']] * (percent / 100)
[12:40:48.192]                                                          or
[12:40:48.192]                                                                 f                                                                                                                               [n['attr']] * (1 + percent / 100)
[12:40:48.192]                                                  )
[12:40:48.192]
[12:40:48.192]                                                  if( new == f[n[n                                                                                                                               .base and 'base' or 'attr']] )then -- no improvement
[12:40:48.192]                                                          break
[12:40:48.192]                                                  end
[12:40:48.192]                                          end
[12:40:48.192]
[12:40:48.192]                                          doItemSetAttribute(tmpIt                                                                                                                               em, n.attr:lower(), new)
[12:40:48.192]
[12:40:48.192]                                          local name = getItemAttr                                                                                                                               ibute(tmpItem, 'name')
[12:40:48.192]                                          if( v.attrNames or not n                                                                                                                               ame )then
[12:40:48.192]                                                  local name = (v.                                                                                                                               attrNames and used[#used] or k) .. ' ' .. (name or f.name)
[12:40:48.192]                                                  doItemSetAttribu                                                                                                                               te(tmpItem, 'name', name)
[12:40:48.192]
[12:40:48.192]                                                  if( f.article ~=                                                                                                                                '' )then
[12:40:48.192]                                                          local ar                                                                                                                               ticle = getArticle(name)
[12:40:48.192]                                                          if( arti                                                                                                                               cle ~= f.article )then
[12:40:48.192]                                                                 d                                                                                                                               oItemSetAttribute(tmpItem, 'article', article)
[12:40:48.192]                                                          end
[12:40:48.192]                                                  end
[12:40:48.192]                                          end
[12:40:48.192]
[12:40:48.192]                                          local desc = getItemAttr                                                                                                                               ibute(tmpItem, 'description') or f.description
[12:40:48.192]                                          doItemSetAttribute(tmpIt                                                                                                                               em, 'description', '[' .. n.name .. ': +' .. percent .. '%]' .. (desc == '' and                                                                                                                                '' or '\n' .. desc))
[12:40:48.192]
[12:40:48.192]                                          ret = k
[12:40:48.192]                                  end
[12:40:48.192]                                  cur = {}
[12:40:48.192]                                  if( #v.chance == i )then
[12:40:48.192]                                          done = true
[12:40:48.192]                                  end
[12:40:48.192]                          end
[12:40:48.192]                  else
[12:40:48.192]                          done = i ~= 1
[12:40:48.192]                          break
[12:40:48.192]                  end
[12:40:48.192]          end
[12:40:48.192]          if( done )then
[12:40:48.192]                  break
[12:40:48.192]          end
[12:40:48.192]  end
[12:40:48.192]
[12:40:48.192]  return tmpItem, ret
[12:40:48.192] end
[12:40:48.192]
[12:40:48.192] local function createChildLoot(parent, i, ext, pos)
[12:40:48.192]  if( not i or #i == 0 )then
[12:40:48.192]          return true
[12:40:48.192]  end
[12:40:48.192]
[12:40:48.192]  local size, cap = 0, getContainerCap(parent)
[12:40:48.192]  for k = 1, #i do
[12:40:48.192]          if( size == cap )then
[12:40:48.192]                  break
[12:40:48.192]          end
[12:40:48.192]          local tmp, ret = createLoot(i[k], ext)
[12:40:48.192]          if( tmp )then
[12:40:48.192]                  if( isContainer(tmp) )then
[12:40:48.192]                          if( createChildLoot(tmp, i[k].child, ext                                                                                                                               , pos) )then
[12:40:48.192]                                  doAddContainerItemEx(parent, tmp                                                                                                                               )
[12:40:48.192]                                  size = size + 1
[12:40:48.192]                          else
[12:40:48.193]                                  doRemoveItem(tmp)
[12:40:48.193]                          end
[12:40:48.193]                  else
[12:40:48.193]                          if( ret )then
[12:40:48.193]                                  doSendMagicEffect(pos, CONST_ME_                                                                                                                               MAGIC_GREEN)
[12:40:48.193]                                  doSendAnimatedText(pos, ret:uppe                                                                                                                               r(), tiers[ret].color)
[12:40:48.193]                          end
[12:40:48.193]                          doAddContainerItemEx(parent, tmp)
[12:40:48.193]                          size = size + 1
[12:40:48.193]                  end
[12:40:48.193]          end
[12:40:48.193]  end
[12:40:48.193]
[12:40:48.193]  return size > 0
[12:40:48.193] end
[12:40:48.193]
[12:40:48.193] local function dropLoot(pos, v, ext, master, cid, target)
[12:40:48.193]  local corpse
[12:40:48.193]  if( not master or master == target )then -- 0.3/4
[12:40:48.193]          corpse = getTileItemById(pos, v.lookCorpse).uid
[12:40:48.193]          if( isContainer(corpse) )then
[12:40:48.193]                  for i = 1, getContainerSize(corpse) do
[12:40:48.193]                          doRemoveItem(getContainerItem(corpse, 0)                                                                                                                               .uid)
[12:40:48.193]                  end
[12:40:48.193]                  local size, cap = 0, getContainerCap(corpse)
[12:40:48.193]                  for i = 1, #v.loot do
[12:40:48.193]                          if( size == cap )then
[12:40:48.193]                                  break
[12:40:48.193]                          end
[12:40:48.193]                          local tmp, ret = createLoot(v.loot[i], e                                                                                                                               xt)
[12:40:48.193]                          if( tmp )then
[12:40:48.193]                                  if( isContainer(tmp) )then
[12:40:48.193]                                          if( createChildLoot(tmp,                                                                                                                                v.loot[i].child, ext, pos) )then
[12:40:48.193]                                                  doAddContainerIt                                                                                                                               emEx(corpse, tmp)
[12:40:48.193]                                                  size = size + 1
[12:40:48.193]                                          else
[12:40:48.193]                                                  doRemoveItem(tmp                                                                                                                               )
[12:40:48.193]                                          end
[12:40:48.193]                                  else
[12:40:48.193]                                          if( ret )then
[12:40:48.193]                                                  doSendMagicEffec                                                                                                                               t(pos, CONST_ME_MAGIC_GREEN)
[12:40:48.193]                                                  doSendAnimatedTe                                                                                                                               xt(pos, ret:upper(), tiers[ret].color)
[12:40:48.193]                                          end
[12:40:48.193]                                          doAddContainerItemEx(cor                                                                                                                               pse, tmp)
[12:40:48.193]                                          size = size + 1
[12:40:48.193]                                  end
[12:40:48.193]                          end
[12:40:48.193]                  end
[12:40:48.193]          end
[12:40:48.193]  end
[12:40:48.193]  send(cid, corpse, v.description)
[12:40:48.193] end
[12:40:48.193]
[12:40:48.193] function onKill(cid, target, damage, flags)
[12:40:48.193]  if( (damage == true or bit.band(flags, 1) == 1) and isMonster(ta                                                                                                                               rget) )then -- 0.3/4
[12:40:48.193]          local v = getMonsterInfo(getCreatureName(target))
[12:40:48.193]          if( v and v.lookCorpse ~= 0 )then
[12:40:48.193]                  local s = getCreatureStorage(cid, extra_loot_key                                                                                                                               )
[12:40:48.193]                  addEvent(dropLoot, 0, getThingPos(target), v, s                                                                                                                                == -1 and rate or s, getCreatureMaster(target), cid, target)
[12:40:48.193]          end
[12:40:48.193]  end
[12:40:48.193]  return true
[12:40:48.193] end
[12:40:48.193] :onKill
[12:40:48.193] Description:
[12:40:48.193] (luaGetThing) Thing not found


its problem with functon
Lua:
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

it cant find Thing at getThingPos(target) idk how to fix it
 
Sorry my english, im from Brasil. This works just fine for me. I put into my server and i had no problems except for the double message from loot wich one i solved. Im using TFS 0.4 Client 8.6. Thank you very much.
 
attempting to create boosted weapons as loot in stronger monsters only.
I'm not a pro in c++/lua programming and i can't test it right now. Could someone test it?
I've marked changes in code.

1. enable mod from code below(disable for a while cykotitan's original one)
2. start ot
3. test amazons, rotworms, undead dragons - they should drop normal loot and shouldn't drop boosted items.
4. test nightmares, hellspawns, ferumbras' - they should drop boosted items(you may set higher stat change rate to check how it works)
5. post here

- does it works for creatures in table?
- is that setting random stats for eg. mace from rotworm(if yes - it's bug)?
- any errors in console caused by switching original mod into this one?
- please post full answers and don't write liars here. I really want to improve this one script.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<mod name="Random Item Stats" enabled="1">
<config name="itemstats_conf"><![CDATA[
-- //
	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 = true, -- show attribute names instead of rare
	chance = {
		[1] = 10000,
		[2] = 5000 -- chance for 2nd stat
	}
}
tiers['epic'] = {
	color = 35,
	extra = {7, 20}, -- additional percent bonus
	chance = {
		[1] = 3333,
		[2] = 25000
	}
}
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['quick'] = {
	attr = 'attackSpeed',
	name = 'Attack Speed',
	percent = {6, 20},
	types = {MELEE, DISTANCE, WAND}
}
attr['fortified'] = {
	attr = 'extraDefense',
	base = 'defense',
	name = 'Defense',
	percent = {7, 25},
	types = {MELEE, SHIELD}
}
attr['deadly'] = {
	attr = 'extraAttack',
	base = 'attack',
	name = 'Attack',
	types = {MELEE},
	percent = {7, 25}
}
attr['strong'] = {
	attr = 'armor',
	name = 'Armor',
	percent = {7, 20},
	types = {ARMOR}
}
attr['hawkeye\'s'] = {
	attr = 'hitChance',
	name = 'Hit Chance',
	percent = {10, 25},
	types = {DISTANCE}
}
--[[ // not available without source edit
attr['farsight'] = {
	attr = 'shootRange',
	name = 'Shoot Range',
	percent = {17, 34},
	types = {DISTANCE, WAND}
}
]]
attr['charged'] = {
	attr = 'charges',
	name = 'Charges',
	percent = {30, 45},
	types = {CHARGES}
}
attr['divine'] = {
	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
]]></config>
 
<event type="kill" name="itemstats" event="script"><![CDATA[
domodlib('itemstats_conf')
 
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 = 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, CONST_ME_MAGIC_GREEN)
					doSendAnimatedText(pos, ret:upper(), tiers[ret].color)
				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, CONST_ME_MAGIC_GREEN)
							doSendAnimatedText(pos, ret:upper(), tiers[ret].color)
						end
						doAddContainerItemEx(corpse, tmp)
						size = size + 1
					end
				end
			end
		end
	end
	send(cid, corpse, v.description)
end
 
function onKill(cid, target, damage, flags)
[B][COLOR="#0000FF"]local RAR_BRINGER = {"Demon", "Plaguesmith", "Nightmare", "Juggernaut", "Hellhound", "Diabolic Imp", "Grim Reaper", "Hellspawn", "Ushuriel", "Madareth", "Annihilon", "Latrivan", "Gorgoldan", "Zugurosh", "Hellgorak", "Apocalypse", "Verminor", "Infernatil", "Bazir", "Tarafiel", "Pumin", "Ashfalor", "Orshabaal", "Ferumbras", "Zoralurk", "Ghazbaran", "Morgaroth", "Massacre", "Mr. Punish", "Handmaiden", "Dracola", "The Plasmother", "The Imperor", "Coutness Sorrow"} 
local checktrg = getCreatureName(target)[/COLOR][/B]
	if( (damage == true or bit.band(flags, 1) == 1) and isMonster(target) [B][COLOR="#0000FF"]and (isInArray(RAR_BRINGER, checktrg))[/COLOR][/B] )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
]]></event>
 
<event type="login" name="itemstats_login" event="buffer"><![CDATA[
	registerCreatureEvent(cid, 'itemstats')
]]></event>
 
</mod>
 
attempting to create boosted weapons as loot in stronger monsters only.
I'm not a pro in c++/lua programming and i can't test it right now. Could someone test it?
I've marked changes in code.

1. enable mod from code below(disable for a while cykotitan's original one)
2. start ot
3. test amazons, rotworms, undead dragons - they should drop normal loot and shouldn't drop boosted items.
4. test nightmares, hellspawns, ferumbras' - they should drop boosted items(you may set higher stat change rate to check how it works)
5. post here

- does it works for creatures in table?
- is that setting random stats for eg. mace from rotworm(if yes - it's bug)?
- any errors in console caused by switching original mod into this one?
- please post full answers and don't write liars here. I really want to improve this one script.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<mod name="Random Item Stats" enabled="1">
<config name="itemstats_conf"><=!=[=C=D=A=T=A=[
-- //
	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 = true, -- show attribute names instead of rare
	chance = {
		[1] = 10000,
		[2] = 5000 -- chance for 2nd stat
	}
}
tiers['epic'] = {
	color = 35,
	extra = {7, 20}, -- additional percent bonus
	chance = {
		[1] = 3333,
		[2] = 25000
	}
}
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['quick'] = {
	attr = 'attackSpeed',
	name = 'Attack Speed',
	percent = {6, 20},
	types = {MELEE, DISTANCE, WAND}
}
attr['fortified'] = {
	attr = 'extraDefense',
	base = 'defense',
	name = 'Defense',
	percent = {7, 25},
	types = {MELEE, SHIELD}
}
attr['deadly'] = {
	attr = 'extraAttack',
	base = 'attack',
	name = 'Attack',
	types = {MELEE},
	percent = {7, 25}
}
attr['strong'] = {
	attr = 'armor',
	name = 'Armor',
	percent = {7, 20},
	types = {ARMOR}
}
attr['hawkeye\'s'] = {
	attr = 'hitChance',
	name = 'Hit Chance',
	percent = {10, 25},
	types = {DISTANCE}
}
--[[ // not available without source edit
attr['farsight'] = {
	attr = 'shootRange',
	name = 'Shoot Range',
	percent = {17, 34},
	types = {DISTANCE, WAND}
}
]]
attr['charged'] = {
	attr = 'charges',
	name = 'Charges',
	percent = {30, 45},
	types = {CHARGES}
}
attr['divine'] = {
	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
]=]=></config>
 
<event type="kill" name="itemstats" event="script"><=!=[=C=D=A=T=A=[
domodlib('itemstats_conf')
 
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 = 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, CONST_ME_MAGIC_GREEN)
					doSendAnimatedText(pos, ret:upper(), tiers[ret].color)
				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, CONST_ME_MAGIC_GREEN)
							doSendAnimatedText(pos, ret:upper(), tiers[ret].color)
						end
						doAddContainerItemEx(corpse, tmp)
						size = size + 1
					end
				end
			end
		end
	end
	send(cid, corpse, v.description)
end
 
function onKill(cid, target, damage, flags)
[B][COLOR="#0000FF"]local RAR_BRINGER = {"Demon", "Plaguesmith", "Nightmare", "Juggernaut", "Hellhound", "Diabolic Imp", "Grim Reaper", "Hellspawn", "Ushuriel", "Madareth", "Annihilon", "Latrivan", "Gorgoldan", "Zugurosh", "Hellgorak", "Apocalypse", "Verminor", "Infernatil", "Bazir", "Tarafiel", "Pumin", "Ashfalor", "Orshabaal", "Ferumbras", "Zoralurk", "Ghazbaran", "Morgaroth", "Massacre", "Mr. Punish", "Handmaiden", "Dracola", "The Plasmother", "The Imperor", "Coutness Sorrow"} 
local checktrg = getCreatureName(target)[/COLOR][/B]
	if( (damage == true or bit.band(flags, 1) == 1) and isMonster(target) [B][COLOR="#0000FF"]and (isInArray(RAR_BRINGER, checktrg))[/COLOR][/B] )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
]=]=></event>
 
<event type="login" name="itemstats_login" event="buffer"><=!=[=C=D=A=T=A=[
	registerCreatureEvent(cid, 'itemstats')
]=]=></event>
 
</mod>

Dont work, gives a runtime error (0.4)
 
Really? Hands down for you Cyko! No wonder you have that huge green reputation! Keep up the good work bro!
 
Cytko, I am having the same problem as Apocalypse, It is returning all the script in my server console and in the bottom it says:
:eek:nKill
Description
(luaGetThing) Thing not found

I did say it was working but i change to 0.4 and it is not working anymore! Could anyone help me?
Thanks

REP++ and if you need money we can talk!
 
Last edited:
what monsters is it happening with? summons? try editing send() function
Code:
local function send(cid, corpse, monster)
	if( isPlayer(cid) )then
		local ret = [B][COLOR="#FF0000"]corpse and [/COLOR][/B]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
 
Cytko,
I dont know if your last post was for me, but as far as I know that isn't my problem!
Can you please check it?

Thank you!
 
Cytko,
I dont know if your last post was for me, but as far as I know that isn't my problem!
Can you please check it?

Thank you!
it was? isContainer uses getThing in 0.4 and throws error if it's not found:p
 
humm, It seems that it is not working... Although, It did stop spamming the message! Ill try to solve this, Thanks very much, If I get anything ill post it!
obs: how do I give rep++?
Ty, Cyko
 
this error was only supposed to show up when killing summons. you had it for all monsters :p?
 
In my ot the talkaction /attr doesnt work... can it have anything to do with my problem?
Maybe, the function to change the properties is not working porperly?
Ty
 
@ cyko: yes, it is not working with all monsters... it is dropping normal item and loot says nothing!
 
[23:43:22.634] > Loading highscorebook.xml... done.
[23:43:22.650] > Loading random_item_stats.xml...[Warning - CreatureEvent::configureEvent] : You havn't register event 'itemstats'
[23:43:22.665] done.
 
Back
Top