Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Random Stats
- local rare_popup = true
- local rare_effect = true
- local rare_effect_id = CONST_ME_STUN
- -- Tiers
- local tiers = {
- [1] = {
- prefix = 'rare',
- chance = {
- [1] = 10000, -- chance for basic stat
- [2] = 5000 -- chance for second stat
- }
- },
- [2] = {
- prefix = 'epic',
- chance = {
- [1] = 3333,
- [2] = 25000
- }
- },
- [3] = {
- prefix = 'legendary',
- chance = {
- [1] = 1000,
- [2] = 100000 -- Legendary rolls always have two affixes.
- }
- },
- }
- -- Attributes
- local attr = {
- atk = {
- name = 'Attack',
- rare = {1, 3}, -- Customize roll numbers here
- epic = {4, 6},
- legendary = {7, 10},
- },
- def = {
- name = 'Defense',
- rare = {1, 2},
- epic = {3, 4},
- legendary = {5, 6},
- },
- extradef = {
- name = 'Extra Defense',
- rare = {1, 1},
- epic = {2, 3},
- legendary = {4, 5},
- },
- arm = {
- name = 'Armor',
- rare = {1, 1},
- epic = {2, 3},
- legendary = {4, 5},
- },
- hitchance = {
- name = 'Accuracy',
- rare = {1, 5},
- epic = {6, 10},
- legendary = {11, 15},
- },
- shootrange = {
- name = 'Range',
- rare = {1, 1},
- epic = {2, 2},
- legendary = {3, 3},
- },
- charges = {
- name = 'Charges',
- rare = {10, 20},
- },
- duration = {
- name = 'Time',
- rare = {10, 20},
- },
- -- Not available in 1.X
- -- attackSpeed = {},
- -- extraAttack = {},
- }
- local stats = {
- [1] = {ITEM_ATTRIBUTE_ATTACK, attr.atk},
- [2] = {ITEM_ATTRIBUTE_DEFENSE, attr.def},
- [3] = {ITEM_ATTRIBUTE_EXTRADEFENSE, attr.extradef},
- [4] = {ITEM_ATTRIBUTE_ARMOR, attr.arm},
- [5] = {ITEM_ATTRIBUTE_HITCHANCE, attr.hitchance},
- [6] = {ITEM_ATTRIBUTE_SHOOTRANGE, attr.shootrange},
- [7] = {ITEM_ATTRIBUTE_CHARGES, attr.charges},
- [8] = {ITEM_ATTRIBUTE_DURATION, attr.duration},
- -- Not available in 1.X
- -- [9] = {ITEM_ATTRIBUTE_ATTACKSPEED, attr.attackSpeed},
- -- [10] = {ITEM_ATTRIBUTE_EXTRAATTACK, attr.extraAttack},
- }
- function stat_getItemDuration(item)
- local it_id = item:getId()
- local tid = ItemType(it_id):getTransformEquipId()
- if tid > 0 then
- item:transform(tid)
- local vx = item:getAttribute(ITEM_ATTRIBUTE_DURATION)
- item:transform(it_id)
- item:removeAttribute(ITEM_ATTRIBUTE_DURATION)
- return vx
- end
- return 0
- end
- function loot_attrToVal(item, attr)
- local id = ItemType(item:getId())
- local v = {
- [ITEM_ATTRIBUTE_ATTACK] = id:getAttack(),
- [ITEM_ATTRIBUTE_DEFENSE] = id:getDefense(),
- [ITEM_ATTRIBUTE_EXTRADEFENSE] = id:getExtraDefense(),
- [ITEM_ATTRIBUTE_ARMOR] = id:getArmor(),
- [ITEM_ATTRIBUTE_HITCHANCE] = id:getHitChance(),
- [ITEM_ATTRIBUTE_SHOOTRANGE] = id:getShootRange(),
- [ITEM_ATTRIBUTE_CHARGES] = id:getCharges(),
- [ITEM_ATTRIBUTE_DURATION] = stat_getItemDuration(item),
- -- Not available in 1.X
- -- [ITEM_ATTRIBUTE_ATTACKSPEED] = item:getAttackSpeed(),
- -- [ITEM_ATTRIBUTE_EXTRAATTACK] = item:getExtraAttack(),
- }
- return v[attr]
- end
- function assign_loot_Stat(c)
- local rares = 0
- local h = c:getItemHoldingCount()
- if h > 0 then
- for i = 1, h do
- local available_stats = {}
- it_u = c:getItem(i - 1)
- it_id = ItemType(it_u:getId())
- if it_u:isContainer() then
- local crares = assign_loot_Stat(it_u)
- rares = rares + crares
- else
- if not it_id:isStackable() then
- local wp = it_id:getWeaponType()
- if wp > 0 then
- if wp == WEAPON_SHIELD then
- table.insert(available_stats, stats[2])
- elseif wp == WEAPON_DISTANCE then -- type bow
- table.insert(available_stats, stats[1])
- table.insert(available_stats, stats[5])
- table.insert(available_stats, stats[6])
- -- Not available in 1.1
- -- table.insert(available_stats, stats[9])
- -- elseif wp == WEAPON_WAND then -- type wand
- -- SHOOTRANGE doesn't seem to be working for wands
- -- table.insert(available_stats, stats[6])
- -- table.insert(available_stats, stats[9])
- elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, wp) then -- melee weapon
- if it_id:getAttack() > 0 then
- table.insert(available_stats, stats[1])
- end
- if it_id:getDefense() > 0 then
- table.insert(available_stats, stats[2])
- end
- if it_id:getExtraDefense() ~= 0 then
- table.insert(available_stats, stats[3])
- end
- -- Not available in 1.1
- -- table.insert(available_stats, stats[10])
- end
- else -- Armors, Amulets, Runes and Rings
- if it_id:getArmor() > 0 then -- Ignore clothing
- table.insert(available_stats, stats[4])
- end
- -- Rather not roll on consumables
- -- if it_id:getCharges() > 0 then
- -- table.insert(available_stats, stats[7])
- -- end
- -- Not working
- -- local eq_id = it_id:getTransformEquipId()
- -- if eq_id > 0 then
- -- table.insert(available_stats, stats[8])
- -- end
- end
- end
- end
- if #available_stats > 0 then
- -- Skips it all if it's empty
- local tier = math.random(1, #tiers)
- if #tiers[tier].chance > 0 then
- local statsStored = 0
- local stats_used = {}
- for stat = 1, #tiers[tier].chance do
- if #available_stats > 0 then
- -- Stops if no more stats available
- if stat - 1 == statsStored then
- -- Checks when it's time to stop adding stats
- if math.random(1, 100000) <= tiers[tier].chance[stat] then
- statsStored = statsStored + 1
- local selected_stat = math.random(1, #available_stats)
- table.insert(stats_used, available_stats[selected_stat])
- table.remove(available_stats, selected_stat)
- end
- end
- end
- end
- if #stats_used > 0 then
- rares = rares + 1
- local stat_desc = {}
- for stat = 1, #stats_used do
- if tiers[tier].prefix == tiers[3].prefix then
- statmin = stats_used[stat][2].legendary[1]
- statmax = stats_used[stat][2].legendary[2]
- elseif tiers[tier].prefix == tiers[2].prefix then
- statmin = stats_used[stat][2].epic[1]
- statmax = stats_used[stat][2].epic[2]
- else
- statmin = stats_used[stat][2].rare[1]
- statmax = stats_used[stat][2].rare[2]
- end
- local v = math.random(
- statmin,
- statmax
- )
- local basestat = loot_attrToVal(it_u, stats_used[stat][1])
- it_u:setAttribute(stats_used[stat][1], basestat + v) -- Converted to static bonus
- table.insert(stat_desc, '[' .. stats_used[stat][2].name .. ': +' .. v .. ']') -- Put roll results into a table
- end
- -- Replace article if item rolls as epic
- if tiers[tier].prefix == "epic" then
- it_u:setAttribute(ITEM_ATTRIBUTE_ARTICLE, "an")
- end
- -- Add rarity prefix to item name
- it_u:setAttribute(ITEM_ATTRIBUTE_NAME, tiers[tier].prefix .. " " .. it_id:getName())
- -- It item has a description, retain it instead of over-writing it
- if it_id:getDescription() == "" then
- it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n"))
- else
- it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n") .. "\n" .. it_id:getDescription())
- end
- -- Capitalize tier.prefix to be used for the animated text above corpses
- rare_text = (tiers[tier].prefix:gsub("^%l", string.upper) .. "!")
- end
- end
- end
- end
- end
- return rares
- end
- function find_loot_Container(pos)
- local rares = 0
- local c = Tile(pos):getTopDownItem()
- if c ~= nil then
- if c:isContainer() then
- rares = rares + assign_loot_Stat(c)
- if rares > 0 then -- If a rare item was rolled, play animation
- if rare_popup then
- local spectators = Game.getSpectators(pos, false, true, 7, 7, 5, 5)
- for i = 1, #spectators do
- spectators[i]:say(rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], pos)
- end
- end
- if rare_effect then
- pos:sendMagicEffect(rare_effect_id)
- end
- end
- return true
- end
- end
- end
- function MonsterType.createLoot(self, corpse, modifier)
- if not corpse then
- return
- end
- -- Take lootrate into consideration
- if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
- return
- end
- local owner = Player(corpse:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER))
- if not owner or owner:getStamina() > 840 then
- -- The code below caused loot to be added to corpses in the wrong order (gold at the end, items at the start)
- --
- -- for _, v in pairs(self:getLoot()) do
- -- itemList = self:createLootItem(v, modifier)
- -- if itemList then
- -- for _, item in ipairs(itemList) do
- -- print(item:getName())
- -- if item:isContainer() then
- -- local lootContainer = self:createLootContainer(item, v, modifier)
- -- if lootContainer then
- -- corpse:addItemEx(item)
- -- end
- -- else
- -- corpse:addItemEx(item, 1)
- -- end
- -- end
- -- end
- --end
- -- Insert Loot into corpse, rewritten as per above.
- itemIndex = {}
- for _, v in pairs(self:getLoot()) do
- itemList = self:createLootItem(v, modifier)
- if itemList then
- for _, item in ipairs(itemList) do
- table.insert(itemIndex, item)
- end
- end
- end
- for i = #itemIndex, 1, -1 do
- if itemIndex[i]:isContainer() then
- local lootContainer = self:createLootContainer(itemIndex[i], v, modifier)
- if lootContainer then
- corpse:addItemEx(itemIndex[i])
- end
- else
- corpse:addItemEx(itemIndex[i], 1)
- end
- end
- -- Apply rarity chance to corpse contents
- find_loot_Container(corpse:getPosition())
- -- Print loot list to Server Log
- if owner then
- local loot_msg = "Loot of " .. self:getNameDescription() .. ": " .. corpse:getContentDescription()
- if owner:getParty() then
- owner:getParty():broadcastLoot(loot_msg)
- owner:getParty():broadcastChannelLoot(loot_msg)
- else
- owner:sendTextMessage(MESSAGE_INFO_DESCR, loot_msg)
- -- Loot channel un-used on my server.
- -- owner:channelSay(nil, TALKTYPE_CHANNEL_O, loot_msg, 10)
- end
- end
- else
- local loot_msg = "Loot of " .. self:getNameDescription() .. ": nothing (due to low stamina)"
- if owner:getParty() then
- owner:getParty():broadcastLoot(loot_msg)
- owner:getParty():broadcastChannelLoot(loot_msg)
- else
- owner:sendTextMessage(MESSAGE_INFO_DESCR, loot_msg)
- end
- end
- corpse:decay()
- end
- function MonsterType.createLootItem(self, lootBlock, modifier)
- local lootTable = {}
- local itemCount = 0
- local randvalue = math.random(0, 100000) / (configManager.getNumber(configKeys.RATE_LOOT) * modifier);
- if randvalue < lootBlock.chance then
- if (ItemType(lootBlock.itemId):isStackable()) then
- itemCount = randvalue % lootBlock.maxCount + 1;
- else
- itemCount = 1;
- end
- end
- while (itemCount > 0) do
- local n = math.min(itemCount, 100)
- itemCount = itemCount - n
- local item = Game.createItem(lootBlock.itemId, n)
- if item then
- if lootBlock.subType ~= -1 then
- item:transform(lootBlock.itemId, lootBlock.subType)
- end
- if lootBlock.actionId ~= -1 then
- item:setActionId(lootBlock.actionId)
- end
- if lootBlock.text and lootBlock.text ~= "" then
- item:setAttribute(ITEM_ATTRIBUTE_TEXT, lootBlock.text)
- end
- table.insert(lootTable, item)
- end
- end
- return #lootTable == 0 and nil or lootTable
- end
- function MonsterType.createLootContainer(self, parent, lootBlock, modifier)
- if #lootBlock.childLoot == 0 then
- return true
- end
- for _, v in pairs(lootBlock.childLoot) do
- if parent:getSize() < parent:getCapacity() then
- local itemList = self:createLootItem(v, modifier)
- if itemList then
- for _, item in ipairs(itemList) do
- if item:isContainer() then
- local lootContainer = self:createLootContainer(item, v, modifier)
- if lootContainer then
- parent:addItemEx(item)
- end
- else
- parent:addItem(item, 1)
- end
- end
- end
- end
- end
- return #parent > 0
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement