Skip to content

Instantly share code, notes, and snippets.

@Elmuti
Created January 27, 2021 15:01
Show Gist options
  • Save Elmuti/48e9912fcee32b0b6d9df029cb651327 to your computer and use it in GitHub Desktop.
Save Elmuti/48e9912fcee32b0b6d9df029cb651327 to your computer and use it in GitHub Desktop.
local Orakel = require(game.ReplicatedStorage.Orakel.Main)
local mathLib = Orakel.LoadModule("MathLib")
local Die = require(game.ReplicatedStorage.Die)
local Combat = {}
local UnitCombatDieSides = require(game.ReplicatedStorage.Enums.UnitCombatDieSides)
local DamageSchool = require(game.ReplicatedStorage.Enums.DamageSchool)
local EquipmentSlot = require(game.ReplicatedStorage.Enums.EquipmentSlot)
local UNARMED_DAMAGE = NumberRange.new(1, 3)
function Combat.CalculateArmorReduction(attacker, victimArmor)
local tmpvalue = 0.1 * victimArmor / (8.5 * attacker:GetLevel() + 40) --what the fuck?
return math.clamp(tmpvalue / (1 + tmpvalue), 0, 0.75)
end
function Combat.CalculateMeleeAP(unit)
local class = unit:GetClass()
local ap = 0 -- + ap from items and talents
local str = unit:GetStat("Strength")
local dex = unit:GetStat("Dexterity")
if class == "Hunter" or unit:GetForm() == "Cat" or class == "Rogue" then
ap = ap + dex
end
if class == "Druid" or class == "Paladin" or class == "Shaman" or class == "Warrior" then
ap = ap + (str * 2)
else
ap = ap + str
end
return ap
end
function Combat.CalculateRangedAP(unit)
local class = unit:GetClass()
local ap = 0 -- + ap from items and talents
local dex = unit:GetStat("Dexterity")
if class == "Hunter" then
ap = ap + (dex * 2)
end
return ap
end
function Combat.CalculateCritChance(unit)
local class = unit:GetClass()
local dex = unit:GetStat("Dexterity")
local crit = 5 -- + crit from items, talents and auras
if class == "Hunter" then
crit = crit + (dex / 45)
elseif class == "Rogue" then
crit = crit + (dex / 31)
elseif class == "Druid" or class == "Paladin" or class == "Shaman" or class == "Warrior" then
crit = crit + (dex / 23)
end
return crit
end
function IsCritical(critChance)
if math.random() <= (critChance / 100) then
return true
end
return false
end
--unit:GetAPMultiplier(attType, normalised)
function Combat.CalculateMinMaxDamage(plr, attType, normalised)
local attSpeed = plr:GetAPMultiplier(attType, normalised)
local addedFlat = 10 --= ADED FLAT DAMAGE (sundays: idfk i made this 10 because it was nil help)
local baseValue = addedFlat
print(string.format("attacking with %s basevalue from %s attack power", baseValue, plr:GetStat("AttackPower")))
-- If unarmed then this will be nil
local mainHandItem = plr:GetItem(EquipmentSlot.MainHand)
local min = mainHandItem and mainHandItem.Damage.Min or UNARMED_DAMAGE.Min
local max = mainHandItem and mainHandItem.Damage.Max or UNARMED_DAMAGE.Max
local wepname = mainHandItem and mainHandItem.DisplayName or "Unarmed"
baseValue += mathLib.RandomFloat(min, max)
baseValue += (plr:GetStat("AttackPower") / 14 * attSpeed)
print(string.format("min:%s, max:%s", min, max))
if plr:GetForm() == "Cat" or plr:GetForm() == "Bear" then
local lvl = plr:GetLevel()
if lvl > 60 then
lvl = 60
end
min = lvl * 0.85 * attSpeed
max = lvl * 1.25 * attSpeed
else
if attType == "RangedAttack" then
--TODO: increase "min" by ammunition DPS
--TODO: increase "max" by ammunition DPS
end
min = baseValue * (plr:GetStat("DamageMultiplier") or 1)
max = baseValue * (plr:GetStat("DamageMultiplier") or 1)
end
local dmgRoll = mathLib.RandomFloat(min, max)
print(string.format("attacking with %s for %s damage from (%s min, %s max)", wepname, dmgRoll, min, max))
return dmgRoll
end
--Block% = 5% base chance + contribution from Block Rating + contribution from talents + ((Defense skill - attacker's weapon skill) * 0.04)
--shieldblockvalue = (shieldblockvalue + strength/2) * addedBlock
--Unit::CalculateSpellDamage
--MeleeDamageBonusDone, MeleeDamageBonusTaken, RollMeleeOutcomeAgainst, GetShieldBlockValue, CalculateGlanceAmount
--Crushing is 150%
--[[
CalculateEffectiveGlanceChance
CalculateEffectiveBlockChance
CalculateEffectiveParryChance
CalculateEffectiveDodgeChance
CalculateEffectiveCritChance
CalculateEffectiveCrushChance
CalculateEffectiveMissChance
]]
function Combat.CalculateEffectiveMissChance(attacker, target)
local chance = 0
local hit = target:GetStat("Hit")
local attSkill = 300
local defense = 300
--if not isAbility and isOffhand then
--chance += 19
--end
local difference = defense - attSkill
local factor = 0.04
if not attacker:IsPlayerOrPet() and difference > 0 then
if difference > 10 then
chance += 1
difference -= 10
factor = 0.4
chance += difference * 0.2
else
factor = 0.1
end
end
chance += difference * factor
chance -= target:GetStat("Hit")
-- chance -= (ability ? GetHitChance(ability, SPELL_SCHOOL_MASK_NORMAL) : GetHitChance(attType));
local minimum = difference > 10 and 1 or 0
return math.clamp(chance, 0, 100)
end
function Combat.CalculateEffectiveDodgeChance(attacker, target)
local chance = target:GetStat("Dodge")
local attSkill = 300
local defense = 300
local skilldiff = defense - attSkill
local factor = 0.04
if not target:IsPlayerOrPet() then
factor = 0.1
end
chance += skilldiff * factor
return chance
end
function Combat.CalculateEffectiveParryChance(attacker, target)
local chance = target:GetStat("Parry")
local attSkill = 300
local defense = 300
local skilldiff = defense - attSkill
local factor = 0.04
if not target:IsPlayerOrPet() then
if skilldiff > 10 then
factor = 0.6
else
factor = 0.1
end
end
chance += skilldiff * factor
chance = (skilldiff >= 15) and 0.14 or chance
return chance
end
function Combat.CalculateEffectiveBlockChance(attacker, target)
local chance = target:GetStat("Block")
local attSkill = 300
local defense = 300
local skilldiff = defense - attSkill
local factor = 0.04
if not target:IsPlayerOrPet() then
factor = 0
end
chance += skilldiff * factor
return chance
end
function Combat.CalculateEffectiveCrushChance(attacker, target)
local chance = 0
local attSkill = 300
local defense = 300
local deficit = attSkill - defense
if deficit >= 15 then
chance +=((2 * deficit) - 15)
end
return chance
end
function Combat.CalculateEffectiveGlanceChance(attacker, target)
local chance = 0
local attSkill = 300
local defense = 300
local level = target:GetLevel()
if attacker:GetClass() == "Mage" or attacker:GetClass() == "Warlock" or attacker:GetClass() == "Priest" then
chance += (level < 30) and (level + ((defense - attSkill) * 2)) or (30 + ((defense - attSkill) * 2))
else
chance += (10 + ((defense - attSkill) * 2))
end
return chance
end
--returns damage multiplier
function Combat.CalculateGlanceAmount(attacker, target)
local attSkill = 300
local defense = 300
local skilldiff = defense - attSkill
local caster = attacker:IsCaster()
local baseHighEnd = (caster and 0.9 or 1.2)
local baseLowEnd = (caster and 0.6 or 1.3)
local maxLowEnd = (caster and 0.6 or 0.91)
local highEnd = baseHighEnd - (0.03 * skilldiff)
local lowEnd = baseLowEnd - (0.05 * skilldiff)
highEnd = math.min(math.max(highEnd, 0.2), 0.99)
lowEnd = math.min(math.max(lowEnd, 0.01), math.min(maxLowEnd, highEnd))
return mathLib.RandomFloat(lowEnd, highEnd)
end
function Combat.CalculateEffectiveCritChance(attacker, target)
local attSkill = 300
local defense = 300
local chance = Combat.CalculateCritChance(attacker)
local skilldiff = defense - attSkill
local factor = 0.04
if not target:IsPlayerOrPet() then
factor = 0.2
end
chance += skilldiff * factor
return math.clamp(chance, 0, 100)
end
--(Dodge, Parry, Miss, Glancing, Crushing, Crit, Normal, Evade)
function Combat.CalculateMeleeOutcome(attacker, target, attType)
local die = Die:new(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_HIT"), #UnitCombatDieSides)
--if target:Sitting() then
--die:Set(Orakel.TGetIndex(UnitCombatDieSides, "UNIT_COMBAT_DIE_CRIT"), 1000)
--end
if target:CanAct() then
if target:CanDodge() and not attType == "RangedAttack" then
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_DODGE"), Combat.CalculateEffectiveDodgeChance(attacker, target))
end
if target:CanParry() and not attType == "RangedAttack" then
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_PARRY"), Combat.CalculateEffectiveParryChance(attacker, target))
end
if target:CanBlock() and not attType == "RangedAttack" then
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_BLOCK"), Combat.CalculateEffectiveBlockChance(attacker, target))
end
end
if attacker:CanGlance(target) and not attType == "RangedAttack" then
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_GLANCE"), Combat.CalculateEffectiveGlanceChance(attacker, target))
end
if attacker:CanCrush(target) and not target:IsPlayerOrPet() and not attType == "RangedAttack" then
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_CRUSH"), Combat.CalculateEffectiveCrushChance(attacker, target))
end
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_MISS"), Combat.CalculateEffectiveMissChance(attacker, target))
die:Set(Orakel.TGetIndexFromValue(UnitCombatDieSides, "UNIT_COMBAT_DIE_CRIT"), Combat.CalculateEffectiveCritChance(attacker, target))
local random = math.random(1, 10000)
local side = UnitCombatDieSides[die:Roll(random)]
print("COMBAT ROLL RESULT: "..side)
return side
end
--(Glancing, Crushing, Crit, Normal) > Reduction > Armor > Block > Absorb
function Combat.CalculateMeleeDamage(attacker, target, attType)
local outcome = Combat.CalculateMeleeOutcome(attacker, target)
local dmg = Combat.CalculateMinMaxDamage(attacker, attType, true)
if outcome == "UNIT_COMBAT_DIE_CRUSH" then
dmg *= 1.5
elseif outcome == "UNIT_COMBAT_DIE_GLANCE" then
dmg *= Combat.CalculateGlanceAmount(attacker, target)
elseif outcome == "UNIT_COMBAT_DIE_CRIT" then
dmg *= (attacker:GetStat("CritMultiplier") + 1) or 2
--if target:Sitting() then
--target:StandUp()
--end
end
--Damage reduction
dmg *= (target:GetStat("DamageReduction") + target:GetStat("DamageReductionPhysical"))
print(string.format("%s dmg before armor", dmg))
--Armor reduction
local armorMult = 1 - Combat.CalculateArmorReduction(attacker, target:GetStat("Armor"))
dmg *= armorMult
print(string.format("%s dmg after armor", dmg))
--Block reduction
if outcome == "UNIT_COMBAT_DIE_BLOCK" then
local blockValue = (target:GetStat("BlockValue") + target:GetStat("Strength") / 2) * 1
blockValue = 1 - blockValue
dmg *= blockValue
end
--Damage absorb
-- NOTE: Handled by the Absorb aura effect, no longer needed here!
--dmg -= target:GetStat("PhysicalAbsorb")
--target:SetStat("PhysicalAbsorb", math.clamp(target:GetStat("PhysicalAbsorb") - dmg, 0, math.huge))
return math.clamp(math.ceil(dmg), 0, math.huge), outcome
end
--Returns damage multiplier
function Combat.CalculateSpellResistanceReduction(caster, target, spellId)
--TODO: Implement me
return 1
end
--DamageSchool
function Combat.CalculateSpellDamage(caster, target, spellId)
local spellDB = require(game.ReplicatedStorage.SpellDatabase)
local spell = spellDB.GetById(spellId)
assert(spell, string.format("spellId:%s doesnt exist u mongoloid", spellId))
--Get total spell power and spell power for specific schools
local sp = caster:GetStat("SpellPower") + caster:GetStat(spell.DamageSchool.."SpellPower")
--Increase by spell power and modify by coefficient
local dmg = mathLib.RandomFloat(spell.Damage.Min, spell.Damage.Max) + sp * spell.Coefficient
--Reduce by resistances
dmg = dmg * Combat.CalculateSpellResistanceReduction(caster, target, spellId)
return math.ceil(dmg)
end
return Combat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment