Module:Sandbox/User:Sfoxrs/animatedead
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Sandbox/User:Sfoxrs/animatedead/doc
-- <pre>
local p = {}
local yesno = require ("Module:Yesno")
local chart = require( 'Module:Chart data' )
local lang = mw.getContentLanguage()
local min = math.min
local max = math.max
local floor = math.floor
local ceil = math.ceil
function p.main(frame)
local invokeArgs = frame.args
local args = frame:getParent().args
return p._main( invokeArgs, args )
end
function p._main( invokeArgs, args )
--arguments
local defenceLevel = tonumber(args.defenceLevel) or 0
local headSlot = yesno(args.headSlot) or false
local headSlotTier = tonumber(args.headSlotTier) or 0
local bodySlot = yesno(args.bodySlot) or false
local bodySlotTier = tonumber(args.bodySlotTier) or 0
local legsSlot = yesno(args.legsSlot) or false
local legsSlotTier = tonumber(args.legsSlotTier) or 0
local glovesSlot = yesno(args.glovesSlot) or false
local glovesSlotTier = tonumber(args.glovesSlotTier) or 0
local bootsSlot = yesno(args.bootsSlot) or false
local bootsSlotTier = tonumber(args.bootsSlotTier) or 0
local shieldSlot = yesno(args.shieldSlot) or false
local shieldSlotType = args.shieldSlotType
local shieldSlotTier = tonumber(args.shieldSlotTier) or 0
local capeSlot = yesno(args.capeSlot) or false
local capeSlotTier = tonumber(args.capeSlotTier) or 0
local damagetoggle = args.damagetoggle
local damage = tonumber(args.damage) or 0
local damageLow = tonumber(args.damageLow) or 0
local damageHigh = tonumber(args.damageHigh) or 0
local outputType = args.outputType
local scale = args.scale
if(damageLow>damageHigh) then
return "<div style=\"font-weight:bold\">The lower bound must not be higher than upper bound.</div>"
end
--calculate Animate Dead value on buff bar
local animateDeadValue = calculateAnimateDeadValue(defenceLevel,headSlot,headSlotTier,bodySlot,bodySlotTier,legsSlot,legsSlotTier,glovesSlot,glovesSlotTier,bootsSlot,bootsSlotTier,shieldSlot,shieldSlotType,shieldSlotTier,capeSlot,capeSlotTier)
--calculate damage reduction for specific value of base damage taken
local damageReduction = calculateDamageReduction(animateDeadValue,damage)
local damageReductionLow = calculateDamageReduction(animateDeadValue,damageLow)
local damageReductionHigh = calculateDamageReduction(animateDeadValue,damageHigh)
--crate plot of damage reduction (%) vs base damage taken
local damageReductionArr = { {x=0, y=100} }
local damageReductionBoundsArr = { {x=damageLow, y=(1-damageReductionLow/damageLow)*100} }
local lifepointsSubtractedArr = { {x=0, y=0} }
local lifepointsSubtractedBoundsArr = { {x=damageLow, y=damageReductionLow} }
local arrLen = 1
local arrLenBounds = 1
local damageBoundsSum = 0
local damageReductionBoundsSum = 0
local stepSize = max(1,ceil(max(damage,damageHigh)/15000))
local plot = chart.newChart{ type='scatter' }
:setDimensions( '40vw', '40vh', '400px', '400px', true )
:setXLabel( 'Base damage taken' )
:showLegend( false )
if(scale=='Logarithmic') then plot:setYAxisType( 'logarithmic' ) end
--calculate damageReductionValues and store
local damageMax = max(damage,(damageLow+damageHigh)/2)
for i = 1, 2*damageMax, stepSize do
local DamageValueStep = calculateDamageReduction(animateDeadValue,i)
local damageReductionValueStep = (1-DamageValueStep/i)*100
damageReductionArr[arrLen + 1] = { x=i, y=damageReductionValueStep }
lifepointsSubtractedArr[arrLen + 1] = { x=i, y=DamageValueStep }
if(damagetoggle=="Range" and i>=damageLow and i<=damageHigh) then
damageReductionBoundsArr[arrLenBounds + 1] = { x=i, y=damageReductionValueStep }
damageBoundsSum = damageBoundsSum + i
damageReductionBoundsSum = damageReductionBoundsSum + DamageValueStep
lifepointsSubtractedBoundsArr[arrLenBounds + 1] = { x=i, y=DamageValueStep }
arrLenBounds = arrLenBounds + 1
end
arrLen = arrLen + 1
end
if(outputType=="Percent damage reduction") then
plot:setTitle( 'Damage reduction (%) vs Base damage taken' )
:setYLabel( 'Damage reduction (%)' )
if (damagetoggle=="Single") then
plot:newDataSet{
data = { {x=0, y=(1-damageReduction/damage)*100}, {x=damage, y=(1-damageReduction/damage)*100}, {x=damage, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = '- - -'
}
plot:newDataSet{
data = damageReductionArr,
pointRadius = 0,
label = 'Damage reduction (%)'
}
elseif (damagetoggle=="Range") then
plot.options.colorPallet = {
chart.rgba.new( 31,120,180 ),
chart.rgba.new( 166,206,227 ),
chart.rgba.new( 31,120,180 ),
chart.rgba.new( 166,206,227 ),
}
plot:newDataSet{
data = damageReductionArr,
pointRadius = 0,
label = 'Damage reduction (%)'
}
:done()
:newDataSet{
data = { {x=0, y=(1-damageReductionLow/damageLow)*100}, {x=damageLow, y=(1-damageReductionLow/damageLow)*100}, {x=damageLow, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = 'Lower bound'
}
:done()
:newDataSet{
data = damageReductionBoundsArr,
pointRadius = 0,
label = 'Bounded region',
fill = true
}
:done()
:newDataSet{
data = { {x=0, y=(1-damageReductionHigh/damageHigh)*100}, {x=damageHigh, y=(1-damageReductionHigh/damageHigh)*100}, {x=damageHigh, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = 'Upper bound'
}
end
elseif(outputType=="Life points subtracted") then
plot:setTitle( 'Life points subtracted vs Base damage taken' )
:setYLabel( 'Life points subtracted' )
if (damagetoggle=="Single") then
plot:newDataSet{
data = { {x=0, y=damageReduction}, {x=damage, y=damageReduction}, {x=damage, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = '- - -'
}
plot:newDataSet{
data = lifepointsSubtractedArr,
pointRadius = 0,
label = 'Life points subtracted'
}
elseif (damagetoggle=="Range") then
plot.options.colorPallet = {
chart.rgba.new( 31,120,180 ),
chart.rgba.new( 166,206,227 ),
chart.rgba.new( 31,120,180 ),
chart.rgba.new( 166,206,227 ),
}
plot:newDataSet{
data = lifepointsSubtractedArr,
pointRadius = 0,
label = 'Life points subtracted'
}
:done()
:newDataSet{
data = { {x=0, y=damageReductionLow}, {x=damageLow, y=damageReductionLow}, {x=damageLow, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = 'Lower bound'
}
:done()
:newDataSet{
data = lifepointsSubtractedBoundsArr,
pointRadius = 0,
label = 'Bounded region',
fill = true
}
:done()
:newDataSet{
data = { {x=0, y=damageReductionHigh}, {x=damageHigh, y=damageReductionHigh}, {x=damageHigh, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = 'Upper bound'
}
end
end
--return results
local res = ""
res = res .. "Damage reduction value on buff bar: (" .. animateDeadValue ..")<br>"
if(damagetoggle=="Single") then
res = res .. "Damage taken: " .. string.format("%s", lang:formatNum(damageReduction)) .. "<br>"
res = res .. "<br>"
res = res .. "Percent damage reduction: " .. string.format("%.1f",(1-damageReduction/damage)*100) .. "%" .. "<br>"
elseif(damagetoggle=="Range") then
res = res .. "Damage taken between: " .. string.format("%s", lang:formatNum(damageReductionLow)) .. " and " .. string.format("%s", lang:formatNum(damageReductionHigh)) .."<br>"
res = res .. "<br>"
res = res .. "Percent damage reduction between: " .. string.format("%.1f",(1-damageReductionHigh/damageHigh)*100) .. "% and " .. string.format("%.1f",(1-damageReductionLow/damageLow)*100) .. "%<br>"
res = res .. "Average percent damage reduction: " .. string.format("%.1f",(1-damageReductionBoundsSum/damageBoundsSum)*100) .. "%<br>"
end
res = res .. "<br>"
if(animateDeadValue>0) then
res = res .. "75%+ damage reduction for base damage under or equal to " .. string.format("%s", lang:formatNum(floor(animateDeadValue/0.75))) .. "<br>"
res = res .. "50%+ damage reduction for base damage under or equal to " .. string.format("%s", lang:formatNum(floor(animateDeadValue/0.50))) .. "<br>"
res = res .. "10%+ damage reduction for base damage under or equal to " .. string.format("%s", lang:formatNum(floor(animateDeadValue/0.10))) .. "<br>"
res = res .. tostring( plot )
end
return res
end
--base defence value
function calculateBaseValue(gearTier,shieldType)
--Armour#Calculating_Armour_bonus
local base = ( gearTier^3/500 + 10*gearTier + 100 )
if (shieldType=="Rebounder") then base = base / 2 end
return base
end
--armor piece defence value
function calculateArmourPieceValue(modifier,armourPieceBaseValue)
--return to 1 decimal
return floor( modifier*armourPieceBaseValue*10 ) / 10
end
--check if piece of tank gear is equipped
function equippedGear(value)
return value and 1 or 0
end
function calculateAnimateDeadValue(defenceLevel,headSlot,headSlotTier,bodySlot,bodySlotTier,legsSlot,legsSlotTier,glovesSlot,glovesSlotTier,bootsSlot,bootsSlotTier,shieldSlot,shieldSlotType,shieldSlotTier,capeSlot,capeSlotTier)
--calculate base defensive value for each slot
local headBaseValue = calculateBaseValue(headSlotTier)
local bodyBaseValue = calculateBaseValue(bodySlotTier)
local legsBaseValue = calculateBaseValue(legsSlotTier)
local glovesBaseValue = calculateBaseValue(glovesSlotTier)
local bootsBaseValue = calculateBaseValue(bootsSlotTier)
local shieldBaseValue = calculateBaseValue(shieldSlotTier,shieldSlotType)
local capeBaseValue = calculateBaseValue(capeSlotTier)
--calculate armour bonus of each slot
local headArmourValue = calculateArmourPieceValue(0.2,headBaseValue)
local bodyArmourValue = calculateArmourPieceValue(0.23,bodyBaseValue)
local legsArmourValue = calculateArmourPieceValue(0.22,legsBaseValue)
local glovesArmourValue = calculateArmourPieceValue(0.05,glovesBaseValue)
local bootsArmourValue = calculateArmourPieceValue(0.05,bootsBaseValue)
local shieldArmourValue = calculateArmourPieceValue(0.2,shieldBaseValue)
local capeArmourValue = calculateArmourPieceValue(0.03,capeBaseValue)
--calculate 10% of armour value towards damage reduction
local headArmourValueDamageReduction = 0.1*headArmourValue
local bodyArmourValueDamageReduction = 0.1*bodyArmourValue
local legsArmourValueDamageReduction = 0.1*legsArmourValue
local glovesArmourValueDamageReduction = 0.1*glovesArmourValue
local bootsArmourValueDamageReduction = 0.1*bootsArmourValue
local shieldArmourValueDamageReduction = 0.1*shieldArmourValue
local capeArmourValueDamageReduction = 0.1*capeArmourValue
--calculate 33% of defence level toward damage reduction (it appears that 1/3 gives correct values)
local defenceLevelDamageReduction = floor(defenceLevel/3)
--calculate combination of armour value damage reduction and defence level damage reduction for each equipped piece of magic tank gear
local headDamageReduction = headArmourValueDamageReduction + defenceLevelDamageReduction
local bodyDamageReduction = bodyArmourValueDamageReduction + defenceLevelDamageReduction
local legsDamageReduction = legsArmourValueDamageReduction + defenceLevelDamageReduction
local glovesDamageReduction = glovesArmourValueDamageReduction + defenceLevelDamageReduction
local bootsDamageReduction = bootsArmourValueDamageReduction + defenceLevelDamageReduction
local shieldDamageReduction = shieldArmourValueDamageReduction + defenceLevelDamageReduction
local capeDamageReduction = capeArmourValueDamageReduction + defenceLevelDamageReduction
--sum the values and return sum
return floor(equippedGear(headSlot)*headDamageReduction + equippedGear(bodySlot)*bodyDamageReduction + equippedGear(legsSlot)*legsDamageReduction + equippedGear(glovesSlot)*glovesDamageReduction + equippedGear(bootsSlot)*bootsDamageReduction + equippedGear(shieldSlot)*shieldDamageReduction + equippedGear(capeSlot)*capeDamageReduction)
end
function calculateDamageReduction(animateDeadValue,damage)
--calculate damage reduction
return max(damage-animateDeadValue,floor(0.25*damage))
end
return p