FeLiPe-Eduardo

data\scripts\creaturescripts\others\attributes.lua

May 25th, 2021
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 28.73 KB | None | 0 0
  1. --[[ --------------------------------------------------------------------------------------------------------------------------------------
  2.         Author: Leo32
  3.         File: creatureevents/scripts/attributes.lua
  4.        
  5.         This pulls attributes from items that affect combat, and applies the damage changes.
  6.         (!) Be aware that primaryType and secondaryType has been swapped for elemental visual clarity.
  7.         (!) This system has CONDITION_STUN (can add it to your sources from here: https://otland.net/threads/tfs-1-x-shield-bash.268433/ and uncomment the code in (stunTarget))
  8.        
  9.         Your creaturescripts.xml should have these, for this to work:
  10.         <event type="healthchange" name="CombatModifiers" script="combatmodifiers.lua"/>
  11.         <event type="manachange" name="CombatModifiersMana" script="combatmodifiers.lua"/>
  12. --]] --------------------------------------------------------------------------------------------------------------------------------------
  13.  
  14. -- Crits
  15. local critmodifier = 2 -- Critical hits do 200% damage
  16. local criteffect = CONST_ME_EXPLOSIONAREA
  17.  
  18. -- This is for batching manaleech gains, so you get mana in a lump sum
  19. local manaleechBatched = {}
  20. local lifeleechBatched = {}
  21.  
  22. -- What slots should be checked for elemental damage, crit, multi shot, mana leech, spelldamage etc
  23. local checkweaponslots = {
  24.     CONST_SLOT_LEFT,
  25.     CONST_SLOT_RIGHT,
  26.     CONST_SLOT_NECKLACE,
  27.     CONST_SLOT_HEAD,
  28.     CONST_SLOT_RING
  29. }
  30.  
  31. -- What slots should be checked for resistances (basically all of them, as shields can be in either hand)
  32. local checkallslots = {
  33.     CONST_SLOT_LEFT,
  34.     CONST_SLOT_RIGHT,
  35.     CONST_SLOT_HEAD,
  36.     CONST_SLOT_NECKLACE,
  37.     CONST_SLOT_ARMOR,
  38.     CONST_SLOT_LEGS,
  39.     CONST_SLOT_FEET,
  40.     CONST_SLOT_RING
  41. }
  42.  
  43. -- Match the animation to the ammunation type
  44. local animation = {
  45.     [2543] = CONST_ANI_BOLT,
  46.     [2547] = CONST_ANI_POWERBOLT,
  47.     [6529] = CONST_ANI_INFERNALBOLT,
  48.     [7363] = CONST_ANI_PIERCINGBOLT,
  49.     [15649] = CONST_ANI_VORTEXBOLT,
  50.     [18435] = CONST_ANI_PRISMATICBOLT,
  51.     [18436] = CONST_ANI_DRILLBOLT,
  52.  
  53.     [2544] = CONST_ANI_ARROW,
  54.     [2545] = CONST_ANI_POISONARROW,
  55.     [2546] = CONST_ANI_BURSTARROW,
  56.     [7365] = CONST_ANI_ONYXARROW,
  57.     [7364] = CONST_ANI_SNIPERARROW,
  58.     [7838] = CONST_ANI_FLASHARROW,
  59.     [7840] = CONST_ANI_FLAMMINGARROW,
  60.     [7839] = CONST_ANI_SHIVERARROW,
  61.     [7850] = CONST_ANI_EARTHARROW,
  62.     [15648] = CONST_ANI_TARSALARROW,
  63.     [18437] = CONST_ANI_ENVENOMEDARROW,
  64.     [18304] = CONST_ANI_CRYSTALLINEARROW,
  65.  
  66.     [2111] = CONST_ANI_SNOWBALL,
  67.     [2389] = CONST_ANI_SPEAR,
  68.     [3965] = CONST_ANI_HUNTINGSPEAR,
  69.     [7367] = CONST_ANI_ENCHANTEDSPEAR,
  70.     [7378] = CONST_ANI_ROYALSPEAR,
  71.     [2399] = CONST_ANI_THROWINGSTAR,
  72.     [7368] = CONST_ANI_REDSTAR,
  73.     [7366] = CONST_ANI_GREENSTAR,
  74.     [2410] = CONST_ANI_THROWINGKNIFE
  75. }
  76.  
  77. -- Used for shuffling targets, so random ones are chosen
  78. function shuffle(t)
  79.     local rand = math.random
  80.     assert(t, "table.shuffle() expected a table, got nil")
  81.     local iterations = #t
  82.     local j
  83.     for i = iterations, 2, -1 do
  84.         j = rand(i)
  85.         t[i], t[j] = t[j], t[i]
  86.     end
  87. end
  88.  
  89. -- Mana leech (individual amounts)
  90. function manaLeechConcat(attackerid, manatoadd)
  91.     -- Create player table if it doesn't exist
  92.     if not manaleechBatched[attackerid] then
  93.         manaleechBatched[attackerid] = {}
  94.     end
  95.     -- Run processManaleechBatch after 5ms
  96.     if not manaleechBatched[attackerid].ReadyToCommit then
  97.         addEvent(processManaleechBatch, 5, attackerid)
  98.         manaleechBatched[attackerid].ReadyToCommit = true
  99.     end
  100.     -- Sum manaleech amounts together (10% for additional targets)
  101.     manaleechBatched[attackerid].Mana = (manaleechBatched[attackerid].Mana or manatoadd) + ((10 / 100) * math.floor(manatoadd))
  102. end
  103.  
  104. -- Mana leech (batched, makes AOE spells give single bulk amount)
  105. function processManaleechBatch(attackerid)
  106.     -- Check if player is still in-game
  107.     if Creature(attackerid) then
  108.         local player = Creature(attackerid)
  109.         local attackerpos = player:getPosition()
  110.         local actualmanadd = math.floor(manaleechBatched[attackerid].Mana)
  111.         -- Consume batched manaleech
  112.         player:addMana(manaleechBatched[attackerid].Mana)
  113.         --player:sendTextMessage(MESSAGE_HEALED, "You leech ".. actualmanadd .. " mana.")
  114.     end
  115.     -- Reset player table
  116.     manaleechBatched[attackerid] = nil
  117. end
  118.  
  119. -- Life leech (individual amounts)
  120. function lifeLeechConcat(attackerid, lifetoadd)
  121.     -- Create player table if it doesn't exist
  122.     if not lifeleechBatched[attackerid] then
  123.         lifeleechBatched[attackerid] = {}
  124.     end
  125.     -- Run processlifeleechBatch after 5ms
  126.     if not lifeleechBatched[attackerid].ReadyToCommit then
  127.         addEvent(processLifeleechBatch, 5, attackerid)
  128.         lifeleechBatched[attackerid].ReadyToCommit = true
  129.     end
  130.     -- Sum lifeleech amounts together (10% for additional targets)
  131.     lifeleechBatched[attackerid].Life = (lifeleechBatched[attackerid].Life or lifetoadd) + ((10 / 100) * math.floor(lifetoadd))
  132. end
  133.  
  134. -- Life leech (batched, makes AOE spells give single bulk amount)
  135. function processLifeleechBatch(attackerid)
  136.     -- Check if player is still in-game
  137.     if Creature(attackerid) then
  138.         local player = Creature(attackerid)
  139.         local attackerpos = player:getPosition()
  140.         local actualLifeAdd = math.floor(lifeleechBatched[attackerid].Life)
  141.         -- Consume batched manaleech
  142.         player:addHealth(lifeleechBatched[attackerid].Life)
  143.         --player:sendTextMessage(MESSAGE_HEALED, "You leech ".. actualLifeAdd .. " life.")
  144.     end
  145.     -- Reset player table
  146.     lifeleechBatched[attackerid] = nil
  147. end
  148.  
  149. -- Check player slots and get resistence information   
  150. function getResistences(resistanceitemdesc, resistances, attackerisplayer)
  151.     for k,v in pairs(resistances) do
  152.         -- Get custom roll resistances
  153.         if string.match(resistanceitemdesc, "%[" .. v.String .. " Resistance") then
  154.             v.Custom = v.Custom + (string.match(resistanceitemdesc, '%[' .. v.String .. ' Resistance: %+(%d+)%%%]') or 0)
  155.         end
  156.         -- If attacker is player roll native rolls so custom elemental rolls are reduced by that as-well
  157.         if attackerisplayer then
  158.             -- Get natural item resistances, can't do it through native TFS functions properly (so it's pulled from description)
  159.             local nativeResist = v.String:lower()
  160.             if string.match(resistanceitemdesc, nativeResist .. " ([+-]%d+)%%") then
  161.                 local nativePercent = string.match(resistanceitemdesc, nativeResist .. " ([+-]%d+)%%")
  162.                 v.Native = v.Native + nativePercent
  163.             end
  164.         end
  165.     end
  166. end
  167.  
  168. -- Stun animation loop
  169. function stunanimation(stunnedcreature, stunnedpos, counter)
  170.     if counter ~= 0 and Creature(stunnedcreature) then
  171.         stunnedpos:sendMagicEffect(CONST_ME_STUN)
  172.         counter = counter - 1
  173.         stunnedcreature = Creature(stunnedcreature).uid
  174.         addEvent(stunanimation, 500, stunnedcreature, stunnedpos, counter)
  175.     end
  176. end
  177.  
  178. -- Stun condition
  179. function stunTarget(itemdesc, stunduration)
  180.     if not Creature(stuncreature) then
  181.         return false
  182.     end
  183.    
  184.     -- Convert back to userdata
  185.     local stuncreature = Creature(stuncreature)
  186.     if stuncreature:isPlayer() then
  187.         stunduration = stunduration / 2
  188.     end
  189.     -- Stun
  190.     --local stun = Condition(CONDITION_STUN)
  191.     --stun:setParameter(CONDITION_PARAM_TICKS, stunduration)
  192.    
  193.     -- Mute
  194.     local mute = Condition(CONDITION_MUTED)
  195.     mute:setParameter(CONDITION_PARAM_TICKS, stunduration)
  196.    
  197.     -- Apply conditions
  198.     --stuncreature:addCondition(stun)
  199.     stuncreature:addCondition(mute)
  200.    
  201.     -- Run animation
  202.     addEvent(stunAnimation, 0, stuncreature.uid, stuncreature:getPosition(), (stunduration / 1000) * 2)
  203. end
  204.  
  205. -- Input damage, it's type and creature immunites/resistances - output reduced damage
  206. function filterResistance(damage, damageType, immunity, resistance)
  207.     -- adjust by monster resistance
  208.     if resistance[damageType] then
  209.         local resistancePercent = (100 - resistance[damageType])
  210.         damage = (resistancePercent / 100) * damage
  211.     end
  212.     -- set it to 0 if monster is immune
  213.     if bit.band(immunity, damageType) == damageType then
  214.         damage = 0
  215.     end
  216.     return math.floor(damage)
  217. end
  218.  
  219. -- Roll elemental damage
  220. function elementalDmg(weaponDescription, elementType, extraAnimation, creature, resistances, primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll)
  221.    
  222.     -- Get damage from item
  223.     local dmgmin, dmgmax = string.match(weaponDescription, '%[Enhanced ' .. resistances[elementType].String .. ' Damage: (%d+)%-(%d+)%]')
  224.     local eleDmg = (math.random(dmgmin, dmgmax))
  225.  
  226.     -- Damage reduction
  227.     if creature:isMonster() then -- If monster is resistant to elementType, adjust the added elemental damage
  228.         local resistance = creature:getType():getElementList()
  229.         local immunity = creature:getType():getCombatImmunities()
  230.         eleDmg = filterResistance(eleDmg, elementType, immunity, resistance)
  231.     elseif creature:isPlayer() then -- PVP
  232.         -- If player, halve the damage
  233.         eleDmg = eleDmg / 2
  234.         -- If about to add elemental damage, check custom and vanilla resistence and adjust
  235.         if (resistances[elementType].Native + resistances[elementType].Custom ~= 0) then
  236.             local resistancePercent = (100 - (resistances[elementType].Custom + resistances[elementType].Native))
  237.             eleDmg = (resistancePercent / 100) * eleDmg
  238.         end
  239.     end
  240.    
  241.     -- Apply damage
  242.     if eleDmg ~= 0 then -- only do this if damage is actually applied
  243.         -- Animation
  244.         if extraAnimation == true then
  245.             local pos = creature:getPosition()
  246.             local EFFECT_TYPE = 0
  247.             if elementType == COMBAT_FIREDAMAGE then
  248.                 EFFECT_TYPE = CONST_ME_FIREATTACK
  249.             elseif elementType == COMBAT_ENERGYDAMAGE then
  250.                 EFFECT_TYPE = CONST_ME_ENERGYAREA
  251.             end
  252.             pos:sendMagicEffect(EFFECT_TYPE)
  253.         end
  254.        
  255.         -- Previous elemental damage
  256.         if elementalroll then
  257.             if primaryType == elementType then -- 'secondary' damage is the same, just add to it
  258.                 primaryDamage = primaryDamage + eleDmg
  259.             else -- add to 'main' damage and overwrite its type
  260.                 if primaryType == 0 then -- is this  wand?
  261.                     if secondaryType == elementType then -- is the wand damage the same type?
  262.                         secondaryDamage = secondaryDamage + eleDmg
  263.                     else -- no it's not, make use of empty primaryValues
  264.                         primaryDamage = eleDmg
  265.                         primaryType = elementType
  266.                     end
  267.                 else -- not a wand, add eleDmg and change from physical to elementType
  268.                     secondaryDamage = secondaryDamage + eleDmg
  269.                     secondaryType = elementType
  270.                 end
  271.             end
  272.         else -- This is the first elemental roll on this weapon
  273.             local originalDamage = primaryDamage
  274.             local originalType = primaryType
  275.            
  276.             -- Swap primary & secondary types
  277.             primaryDamage = secondaryDamage + eleDmg
  278.             primaryType = elementType
  279.             secondaryDamage = originalDamage
  280.             secondaryType = originalType
  281.            
  282.             -- damageTypes have been swapped, flag it
  283.             elementalroll = true
  284.         end
  285.     end
  286.     return primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll
  287. end
  288.                                            
  289. function statChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  290.  
  291.     -- Defaults
  292.     local chance = 0 -- Crit Chance
  293.     local spellmodifier = 0 -- Spell Damage
  294.     local manaleech = 0
  295.     local lifeleech = 0
  296.     local stunDuration = 2000
  297.     local sourceDamage = primaryDamage -- Used for multi-shot when secondary targets are immune
  298.     local elementalroll = false -- Flag for if weapon has an element on it
  299.     local doubleroll = false -- Flag for if the weapon has two elements on it
  300.     --local dawnbreaker = false
  301.     --local rainbowshield = false
  302.    
  303.     -- What elements should be checked when calculating resistances
  304.     local resistances = {
  305.         [COMBAT_PHYSICALDAMAGE] = {Native = 0, Custom = 0, String = "Physical"},
  306.         [COMBAT_FIREDAMAGE] = {Native = 0, Custom = 0, String = "Fire"},
  307.         [COMBAT_ICEDAMAGE] = {Native = 0, Custom = 0, String = "Ice"},
  308.         [COMBAT_ENERGYDAMAGE] = {Native = 0, Custom = 0, String = "Energy"},
  309.         [COMBAT_EARTHDAMAGE] = {Native = 0, Custom = 0, String = "Earth"},
  310.         [COMBAT_DEATHDAMAGE] = {Native = 0, Custom = 0, String = "Death"}
  311.     }
  312.    
  313.     -- Check resistences if victim is a player before applying extra elemental damage below
  314.     if creature:isPlayer() then
  315.         for i = 1,#checkallslots do
  316.             if creature:getSlotItem(checkallslots[i]) ~= nil then
  317.                 local resistanceitem = creature:getSlotItem(checkallslots[i])
  318.                 local resistanceitemdesc = resistanceitem:getDescription()
  319.                 getResistences(resistanceitemdesc, resistances, true)
  320.                 --[[
  321.                 -- if rainbow shield
  322.                 if resistanceitem.itemid == 8905 then
  323.                     if checkallslots[i] == CONST_SLOT_LEFT or checkallslots[i] == CONST_SLOT_RIGHT then -- Only if equipped
  324.                         rainbowshield = resistanceitem
  325.                     end
  326.                 end
  327.                 --]]
  328.             end
  329.         end
  330.        
  331.          -- Reduce main damage on custom resistance rolls before applying extra elemental damage below
  332.         if primaryType ~= 0 then
  333.             if resistances[primaryType] then
  334.                 if resistances[primaryType].Custom ~= 0 then
  335.                     local resistancePercent = (100 - resistances[primaryType].Custom)
  336.                     primaryDamage = (resistancePercent / 100) * primaryDamage
  337.                 end
  338.             end
  339.         end
  340.         if secondaryType ~= 0 then
  341.             if resistances[secondaryType] then
  342.                 if resistances[secondaryType].Custom ~= 0 then
  343.                     local resistancePercent = (100 - resistances[secondaryType].Custom)
  344.                     secondaryDamage = (resistancePercent / 100) * secondaryDamage
  345.                 end
  346.             end
  347.         end
  348.     end
  349.  
  350.     if attacker then -- Ignore HP changes from healing fountains, terrain elemental fields (neutral sources basically)
  351.         if attacker:isPlayer() then
  352.             if origin == ORIGIN_RANGED or origin == ORIGIN_MELEE then -- Skip if player is using spells
  353.                 -- Natural elemental damage (wand, fire sword, flaming arrow etc) swap Types around for better visuals and set flags
  354.                 if secondaryType ~= 0 or primaryType ~= COMBAT_PHYSICALDAMAGE then
  355.                     -- Cache original physical damage
  356.                     local originalDamage = primaryDamage
  357.                     local originalType = primaryType
  358.                    
  359.                     -- Swap primary & secondary
  360.                     primaryDamage = secondaryDamage
  361.                     primaryType = secondaryType
  362.                     secondaryDamage = originalDamage
  363.                     secondaryType = originalType
  364.                    
  365.                     -- damageTypes have been swapped, flag it
  366.                     elementalroll = true
  367.                 end
  368.                
  369.                 -- Check weapons for crit/elemental damage
  370.                 for i = 1,#checkweaponslots do -- Roll for each slot
  371.                     if attacker:getSlotItem(checkweaponslots[i]) ~= nil then
  372.                         local slotitem = attacker:getSlotItem(checkweaponslots[i])
  373.                         local slotitemdesc = slotitem:getDescription()
  374.                
  375.                         --[[
  376.                         -- If dawnbreaker
  377.                         if slotitem.itemid == 7744 or slotitem.itemid == 7751 or slotitem.itemid == 7756 then
  378.                             dawnbreaker = slotitem
  379.                         end
  380.                         --]]
  381.                        
  382.                         --[[ if wand or rod reduce damage on custom elemental resistences
  383.                         if primaryType ~= 0 and ItemType(slotitem.itemid):getWeaponType() == WEAPON_WAND then
  384.                             if resistances[primaryType] and resistances[primaryType].Custom ~= 0 then
  385.                                 local resistancePercent = (100 - resistances[primaryType].Custom)
  386.                                 primaryDamage = (resistancePercent / 100) * primaryDamage
  387.                             end
  388.                         end
  389.                         --]]
  390.                        
  391.                         -- Check elemental damage
  392.                         if slotitemdesc:find "%[Enhanced Fire Damage" then
  393.                             primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll = elementalDmg(slotitemdesc, COMBAT_FIREDAMAGE, true, creature, resistances, primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll)
  394.                             if math.random(1,3) == 3 then -- 33% chance to apply burn
  395.                                 local condition = createConditionObject(CONDITION_FIRE)
  396.                                 local burnDamage = 20
  397.                                 if creature:isPlayer() then
  398.                                     if resistances[COMBAT_FIREDAMAGE].Custom ~= 0 or resistances[COMBAT_FIREDAMAGE].Native ~= 0 then
  399.                                         local resistancePercent = (100 - (resistances[COMBAT_FIREDAMAGE].Custom + resistances[COMBAT_FIREDAMAGE].Native))
  400.                                         burnDamage = (resistancePercent / 100) * burnDamage
  401.                                     end
  402.                                 elseif creature:isMonster() then
  403.                                     local resistance = creature:getType():getElementList()
  404.                                     local immunity = creature:getType():getCombatImmunities()
  405.                                     if resistance[COMBAT_FIREDAMAGE] then
  406.                                         local resistancePercent = (100 - resistance[COMBAT_FIREDAMAGE])
  407.                                         burnDamage = (resistancePercent / 100) * burnDamage
  408.                                     end
  409.                                     if bit.band(immunity, COMBAT_FIREDAMAGE) == COMBAT_FIREDAMAGE then
  410.                                         burnDamage = 0
  411.                                     end
  412.                                 end
  413.                                 if burnDamage ~= 0 then
  414.                                     addDamageCondition(condition, 10, 2000, burnDamage)
  415.                                     setConditionParam(condition, CONDITION_PARAM_DELAYED, true)
  416.                                     doTargetCombatCondition(attacker, creature, condition, CONST_ME_FIRE)
  417.                                 end
  418.                             end
  419.                         end
  420.                         if slotitemdesc:find "%[Enhanced Ice Damage" then
  421.                             primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll = elementalDmg(slotitemdesc, COMBAT_ICEDAMAGE, false, creature, resistances, primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll)
  422.                             if math.random(1,5) == 5 then -- 20% to paralyze/slow
  423.                                 local condition = createConditionObject(CONDITION_PARALYZE)
  424.                                 setConditionParam(condition, CONDITION_PARAM_TICKS, 3000)
  425.                                 setConditionParam(condition, CONDITION_PARAM_SPEED, -300)
  426.                                 doTargetCombatCondition(attacker, creature, condition, CONST_ME_MAGIC_ICEAREA)
  427.                             end
  428.                         end
  429.                         if slotitemdesc:find "%[Enhanced Energy Damage" then
  430.                             primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll = elementalDmg(slotitemdesc, COMBAT_ENERGYDAMAGE, true, creature, resistances, primaryDamage, primaryType, secondaryDamage, secondaryType, elementalroll)
  431.                         end
  432.                        
  433.                         -- Check crit chance of slots and add together
  434.                         if slotitemdesc:find "%[Crit Chance" then
  435.                             local crit = string.match(slotitemdesc, "Crit Chance: [+-](%d+)%%")
  436.                             chance = chance + crit
  437.                         end
  438.                        
  439.                         -- Mana leech gather %
  440.                         if slotitemdesc:find "%[Mana Leech" then
  441.                             manaleech = string.match(slotitemdesc, '%[Mana Leech: %+(%d+)%%%]') or 0
  442.                         end
  443.                        
  444.                         -- Life leech gather %
  445.                         if slotitemdesc:find "%[Life Leech" then
  446.                             lifeleech = string.match(slotitemdesc, '%[Life Leech: %+(%d+)%%%]') or 0
  447.                         end
  448.                        
  449.                         -- Stun Chance
  450.                         if slotitemdesc:find "%[Stun Chance" then
  451.                             local stunchance = tonumber(string.match(slotitemdesc, '%[Stun Chance: %+(%d+)%%%]')) or 0
  452.                             local rollchance = math.random(1,100)
  453.                             if stunchance >= rollchance and attacker ~= creature then
  454.                                 stunTarget(creature.uid, stunDuration)
  455.                             end
  456.                         end
  457.                            
  458.                         -- Multi-shot
  459.                         if slotitemdesc:find "%[Multi Shot" then
  460.                             if attacker:getSlotItem(CONST_SLOT_AMMO) ~= nil then -- Does player have ammo
  461.                                 local multishot = tonumber(string.match(slotitemdesc, "%[Multi Shot: %+(%d+)%]"))
  462.                                 local ammoSlot = attacker:getSlotItem(CONST_SLOT_AMMO).itemid
  463.                                 local validammo = false
  464.                                 for k,v in pairs(animation) do
  465.                                     if k == ammoSlot then
  466.                                         validammo = true -- Ammo they're using exists in animation table
  467.                                         break
  468.                                     end
  469.                                 end
  470.                                 if validammo then -- (!) You may need to add more CONST_ANI_XXXX animations to the animation table
  471.                                     local targetpos = creature:getPosition()
  472.                                     local targets = getSpectators(targetpos, 2, 2) -- get possible multi-shot targets
  473.                                     local victims = {}
  474.                                     if targets ~= nil then
  475.                                         -- do the shuffle
  476.                                         shuffle(targets)
  477.                                         for i = 1,#targets do
  478.                                             local target = Creature(targets[i])
  479.                                             if target:isMonster() then -- only target monsters
  480.                                                 if isSightClear(attacker:getPosition(), target:getPosition()) then -- that are in sight
  481.                                                     if target:getPosition() ~= targetpos then -- ignore the original target
  482.                                                         local victimcount = #victims or 0
  483.                                                         if victimcount < multishot then
  484.                                                             table.insert(victims, target) -- collate valid targets into victims table
  485.                                                         else
  486.                                                             break -- exit the for loop, have enough targets
  487.                                                         end
  488.                                                     end
  489.                                                 end
  490.                                             end
  491.                                         end
  492.                                     end
  493.                                     -- this a rats nest due to swapping primaryType/secondaryType above for visuals
  494.                                     if victims ~= nil then
  495.                                         for i = 1,#victims do
  496.                                             -- defaults
  497.                                             local damage = 0
  498.                                             local elementalDamage = 0
  499.                                             local backupDamage = 0
  500.                                             local mainType = primaryType
  501.                                             local altType = secondaryType
  502.                                             local resistance = victims[i]:getType():getElementList()
  503.                                             local immunity = victims[i]:getType():getCombatImmunities()
  504.                                             local distanceEffect = animation[ammoSlot]
  505.                                             -- animation
  506.                                             attacker:getPosition():sendDistanceEffect(victims[i]:getPosition(), animation[ammoSlot])
  507.                                             -- damage
  508.                                             if elementalroll then -- check if types are swapped
  509.                                                 mainType = secondaryType
  510.                                                 altType = primaryType
  511.                                                 damage = filterResistance(secondaryDamage, secondaryType, immunity, resistance)
  512.                                                 elementalDamage = filterResistance(primaryDamage, primaryType, immunity, resistance)
  513.                                             else -- types haven't been swapped
  514.                                                 damage = filterResistance(primaryDamage, primaryType, immunity, resistance)
  515.                                                 elementalDamage = filterResistance(secondaryDamage, secondaryType, immunity, resistance)
  516.                                             end
  517.                                             -- apply secondary if damage
  518.                                             if elementalDamage ~= 0 then
  519.                                                 doTargetCombatHealth(attacker, victims[i], altType, math.ceil((80 / 100) * elementalDamage), elementalDamage)
  520.                                             end
  521.                                             -- apply main if damage
  522.                                             if damage ~= 0 then
  523.                                                 doTargetCombatHealth(attacker, victims[i], mainType, math.ceil((80 / 100) * damage), damage)
  524.                                             else -- no damage, monster is immune fallback to original physical damage
  525.                                                 backupDamage = filterResistance(sourceDamage, COMBAT_PHYSICALDAMAGE, immunity, resistance)
  526.                                                 if backupDamage ~= 0 then -- try rolling back to base physical damage
  527.                                                     doTargetCombatHealth(attacker, victims[i], COMBAT_PHYSICALDAMAGE, math.ceil((80 / 100) * sourceDamage), sourceDamage)
  528.                                                 else -- monster immune to physical damage too or w/e
  529.                                                     victims[i]:getPosition():sendMagicEffect(CONST_ME_BLOCKHIT)
  530.                                                 end
  531.                                             end
  532.                                         end
  533.                                     end
  534.                                 end
  535.                             end
  536.                         end
  537.                     end
  538.                 end
  539.                
  540.                 -- Roll crit chance and apply if critical strike
  541.                 if chance > 0 then
  542.                     if math.random(100) <= chance then
  543.                         local pos = creature:getPosition()
  544.                         pos:sendMagicEffect(criteffect)
  545.                          -- if elemental roll flag, crit the swapped secondaryDamage instead of primaryDamage
  546.                         if elementalroll then
  547.                             secondaryDamage = secondaryDamage * critmodifier
  548.                         else
  549.                             primaryDamage = primaryDamage * critmodifier
  550.                         end
  551.                         --[[
  552.                         if dawnbreaker then
  553.                             if dawnbreaker.itemid == 7744 then
  554.                                 dawnbreaker:transform(7763)
  555.                             elseif dawnbreaker.itemid == 7751 then
  556.                                 dawnbreaker:transform(7770)
  557.                             elseif dawnbreaker.itemid == 7756 then
  558.                                 dawnbreaker:transform(7775)
  559.                             end
  560.                             dawnbreaker:decay()
  561.                             if attacker:getStorageValue(30033) == 1 then
  562.                                 attacker:setStorageValue(30033, 2)
  563.                             end
  564.                         end
  565.                         --]]
  566.                     end
  567.                 end
  568.                
  569.                 -- Apply mana leech
  570.                 if manaleech ~= 0 then
  571.                     local manatoadd = math.floor((manaleech / 100) * (primaryDamage + secondaryDamage))
  572.                     local attackerpos = attacker:getPosition()
  573.                     addEvent(manaLeechConcat, 5, attacker.uid, manatoadd)
  574.                 end
  575.                
  576.                 -- Apply life leech
  577.                 if lifeleech ~= 0 then
  578.                     local lifetoadd = math.floor((lifeleech / 100) * (primaryDamage + secondaryDamage))
  579.                     local attackerpos = attacker:getPosition()
  580.                     addEvent(lifeLeechConcat, 5, attacker.uid, lifetoadd)
  581.                 end
  582.             elseif origin == ORIGIN_SPELL then 
  583.                 -- Reduce spell damage based on custom resistances
  584.                 if resistances[primaryType] then
  585.                     if resistances[primaryType].Custom ~= 0 then
  586.                         local resistancePercent = (100 - resistances[primaryType].Custom)
  587.                         primaryDamage = (resistancePercent / 100) * primaryDamage
  588.                     end
  589.                 end
  590.                
  591.                 -- Check slots that can roll the following attributes
  592.                 for i = 1,#checkweaponslots do
  593.                     if attacker:getSlotItem(checkweaponslots[i]) ~= nil then
  594.                         local slotitem = attacker:getSlotItem(checkweaponslots[i])
  595.                         local slotitemdesc = slotitem:getDescription()
  596.                        
  597.                         -- Check crit chance of slots and add together
  598.                         if slotitemdesc:find "%[Spell Damage" then
  599.                             local spellDamage = string.match(slotitemdesc, "Spell Damage: [+-](%d+)%%")
  600.                             spellmodifier = spellmodifier + spellDamage
  601.                         end
  602.                        
  603.                         -- Mana leech gather %
  604.                         if slotitemdesc:find "%[Mana Leech" then
  605.                             manaleech = string.match(slotitemdesc, '%[Mana Leech: %+(%d+)%%%]') or 0
  606.                         end
  607.                        
  608.                         -- Life leech gather %
  609.                         if slotitemdesc:find "%[Life Leech" then
  610.                             lifeleech = string.match(slotitemdesc, '%[Life Leech: %+(%d+)%%%]') or 0
  611.                         end
  612.                        
  613.                         -- Stun Chance
  614.                         if slotitemdesc:find "%[Stun Chance" then
  615.                             local stunchance = tonumber(string.match(slotitemdesc, '%[Stun Chance: %+(%d+)%%%]')) or 0
  616.                             local rollchance = math.random(1,100)
  617.                             if stunchance >= rollchance and attacker ~= creature then
  618.                                 stunTarget(creature.uid, stunDuration)
  619.                             end
  620.                         end
  621.                     end
  622.                 end
  623.                
  624.                 -- if using a +%spelldamage wand, adjust damage
  625.                 if spellmodifier > 0 then
  626.                     local extraDamage = (spellmodifier / 100) * primaryDamage
  627.                     primaryDamage = primaryDamage + extraDamage
  628.                 end
  629.                
  630.                 -- Apply mana leech
  631.                 if manaleech ~= 0 and primaryType ~= COMBAT_HEALING and secondaryType ~= COMBAT_HEALING then
  632.                     local manatoadd = math.floor((manaleech / 100) * (primaryDamage + secondaryDamage))
  633.                     manaLeechConcat(attacker.uid, manatoadd)
  634.                 end
  635.                
  636.                 -- Apply life leech
  637.                 if lifeleech ~= 0 and primaryType ~= COMBAT_HEALING and secondaryType ~= COMBAT_HEALING then
  638.                     local lifetoadd = math.floor((lifeleech / 100) * (primaryDamage + secondaryDamage))
  639.                     lifeLeechConcat(attacker.uid, lifetoadd)
  640.                 end
  641.             end
  642.         end
  643.     end
  644.    
  645.     --[[
  646.     -- If rainbow shield
  647.     if rainbowshield then
  648.         local rainbowTransformation = 0
  649.         local rainbowTransformations = {
  650.             [COMBAT_FIREDAMAGE] = 8906,
  651.             [COMBAT_ICEDAMAGE] = 8907,
  652.             [COMBAT_ENERGYDAMAGE] = 8908,
  653.             [COMBAT_EARTHDAMAGE] = 8909
  654.         }
  655.        
  656.         -- Check primary first
  657.         if primaryType ~= 0 then
  658.             if rainbowTransformations[primaryType] then
  659.                 rainbowTransformation = rainbowTransformations[primaryType]
  660.             end
  661.         end
  662.        
  663.         -- Check secondary second (This prioritizes secondaryType which is what we want)
  664.         if secondaryType ~= 0 then
  665.             if rainbowTransformations[secondaryType] then
  666.                 rainbowTransformation = rainbowTransformations[secondaryType]
  667.             end
  668.         end
  669.         -- Transform rainbow shield
  670.         if rainbowTransformation ~= 0 then
  671.             rainbowshield:transform(rainbowTransformation)
  672.             rainbowshield:decay()
  673.         end
  674.     end
  675.     --]]
  676.    
  677.     return primaryDamage, primaryType, secondaryDamage, secondaryType, origin
  678. end
  679. local rollHealth = CreatureEvent("rollHealth")
  680. function rollHealth.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  681.  
  682.     if primaryType ~= 128 then -- Ignore health potions
  683.         primaryDamage, primaryType, secondaryDamage, secondaryType, origin = statChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) -- This is for feeding both onHealthChange and onManaChange through the same damage/buff formula
  684.     end
  685.    
  686.     return primaryDamage, primaryType, secondaryDamage, secondaryType, origin
  687. end
  688. rollHealth:register()
  689.  
  690. local rollMana = CreatureEvent("rollMana")
  691. function onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  692.  
  693.     if primaryType ~= 64 then -- Ignore mana potions
  694.         primaryDamage, primaryType, secondaryDamage, secondaryType, origin = statChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) -- This is for feeding both onHealthChange and onManaChange through the same damage/buff formula
  695.        
  696.         -- Apply magic shield bonus, even if neutral source
  697.         if creature:isPlayer() then
  698.             local manashield = 0
  699.             for i = 1,#checkweaponslots do
  700.                 if creature:getSlotItem(checkweaponslots[i]) ~= nil then
  701.                     local slotitem = creature:getSlotItem(checkweaponslots[i])
  702.                     local slotitemdesc = slotitem:getDescription()
  703.                     if slotitemdesc:find "%[Mana Shield" then
  704.                         manashield = manashield + tonumber(string.match(slotitemdesc, '%[Mana Shield: %+(%d+)%%%]'))
  705.                     end
  706.                 end
  707.             end
  708.             if manashield ~= 0 then
  709.                 local shieldPercent = (100 - manashield)
  710.                 primaryDamage = (shieldPercent / 100) * primaryDamage
  711.                 secondaryDamage = (shieldPercent / 100) * secondaryDamage
  712.             end
  713.         end
  714.        
  715.     end
  716.    
  717.     return primaryDamage, primaryType, secondaryDamage, secondaryType, origin
  718. end
  719. rollMana:register()
  720.  
  721. local loginEvents = CreatureEvent("LoginEventsAttribute")
  722. function loginEvents.onLogin(player)
  723.     player:registerEvent("rollHealth")
  724.     player:registerEvent("rollMana")
  725.     return true
  726. end
  727. loginEvents:register()
  728.  
Add Comment
Please, Sign In to add comment