mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
190 lines
7.7 KiB
Lua
190 lines
7.7 KiB
Lua
|
|
--[[
|
||
|
|
| This file was obtained through the combined efforts
|
||
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
||
|
|
|
|
||
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
||
|
|
|
|
||
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
|
||
|
|
local PLUGIN = PLUGIN
|
||
|
|
|
||
|
|
function ix.weapons:CalcCritChance(attackerChar, victim, range, hitBox, weaponClass)
|
||
|
|
local attacker = attackerChar:GetPlayer()
|
||
|
|
|
||
|
|
if (!self.hitBoxList[hitBox]) then
|
||
|
|
return 0, 0, 0
|
||
|
|
end
|
||
|
|
|
||
|
|
local weaponCat = self.weaponList[weaponClass]
|
||
|
|
if (!self.weaponCatList[weaponCat]) then
|
||
|
|
return 0, 0, 0
|
||
|
|
end
|
||
|
|
|
||
|
|
local hitBoxCrit = self:RemapClamp(range, self.hitBoxList[hitBox])
|
||
|
|
local armorMod = (victim:IsPlayer() and victim:Armor() > 0 and self:GetArmorPen(weaponClass)) or 1
|
||
|
|
local weaponSkillMod = self:GetWeaponSkillMod(attackerChar, weaponClass)
|
||
|
|
local rangeSkillMod = self:GetRangeSkillMod(attackerChar, range)
|
||
|
|
local effRangeMod = self:GetWeaponEffRangeMod(weaponClass, range)
|
||
|
|
local aimPenalty = self:GetWeaponAimPenalty(weaponClass)
|
||
|
|
local dodgeMod = 1
|
||
|
|
if (victim:IsPlayer() and ix.fights and victim:GetFight() and victim:GetCharacter().fightInfoTable) then
|
||
|
|
dodgeMod = (1 - 0.03 *
|
||
|
|
(attackerChar:GetSkillScale("guns_moving_target_penalty")) * (victim:GetCharacter().fightInfoTable.movePointsSpend or 0) *
|
||
|
|
(1 + victim:GetCharacter():GetSkillScale("speed_dodge_mod")))
|
||
|
|
end
|
||
|
|
|
||
|
|
ix.log.Add(attacker, "weaponBalanceDebugOutput", hitBoxCrit, armorMod, weaponSkillMod, rangeSkillMod, effRangeMod, dodgeMod)
|
||
|
|
local penalties, bonus = 0, 0
|
||
|
|
if (hitBoxCrit < 0.60) then penalties = bit.bor(penalties, 1) elseif (hitBoxCrit >= 0.65) then bonus = bit.bor(bonus, 1) end
|
||
|
|
if (armorMod < 0.85) then penalties = bit.bor(penalties, 2) end
|
||
|
|
if (weaponSkillMod < 1) then penalties = bit.bor(penalties, 4) elseif (weaponSkillMod >= 1.1) then bonus = bit.bor(bonus, 4) end
|
||
|
|
if (rangeSkillMod < 1) then penalties = bit.bor(penalties, 8) elseif (rangeSkillMod >= 1.1) then bonus = bit.bor(bonus, 8) end
|
||
|
|
if (effRangeMod < 0.85) then penalties = bit.bor(penalties, 16) end
|
||
|
|
if (aimPenalty < 1) then penalties = bit.bor(penalties, 32) end
|
||
|
|
if (dodgeMod < 0.85) then penalties = bit.bor(penalties, 64) end
|
||
|
|
|
||
|
|
return hitBoxCrit * armorMod * weaponSkillMod * rangeSkillMod * effRangeMod * aimPenalty * dodgeMod, penalties, bonus
|
||
|
|
end
|
||
|
|
|
||
|
|
function ix.weapons:CalcMeleeCritChance(attackerChar, victim, weaponClass)
|
||
|
|
local attacker = attackerChar:GetPlayer()
|
||
|
|
local baseCrit = self:GetMeleeWeaponBaseHitChance(attackerChar, weaponClass)
|
||
|
|
local armorMod = (victim:IsPlayer() and victim:Armor() > 0 and self:GetMeleeArmorPen(weaponClass)) or 1
|
||
|
|
local dodgeMod = 1
|
||
|
|
if (victim:IsPlayer() and ix.fights and victim:GetFight() and victim:GetCharacter().fightInfoTable) then
|
||
|
|
local movePoints = victim:GetCharacter().fightInfoTable.movePointsSpend or 0
|
||
|
|
if (movePoints >= 8) then
|
||
|
|
dodgeMod = 0.5
|
||
|
|
elseif (movePoints >= 4) then
|
||
|
|
dodgeMod = 0.75
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
ix.log.Add(attacker, "weaponMeleeBalanceDebugOutput", baseCrit, armorMod, dodgeMod)
|
||
|
|
local penalties, bonus = 0, 0
|
||
|
|
if (baseCrit < 0.1) then penalties = bit.bor(penalties, 128) elseif (baseCrit >= 0.3) then bonus = bit.bor(bonus, 128) end
|
||
|
|
if (armorMod < 0.85) then penalties = bit.bor(penalties, 2) end
|
||
|
|
if (dodgeMod < 0.85) then penalties = bit.bor(penalties, 64) end
|
||
|
|
|
||
|
|
return baseCrit * armorMod * dodgeMod, penalties, bonus
|
||
|
|
end
|
||
|
|
|
||
|
|
function ix.weapons:BalanceDamage(victim, damage, attacker, hitgroup)
|
||
|
|
local inflictor = damage:GetInflictor()
|
||
|
|
if (!IsValid(inflictor)) then return end
|
||
|
|
|
||
|
|
if (inflictor.IsTFAWeapon and !inflictor.noDoubleDamageFix) then
|
||
|
|
if (!attacker.ixCanDoDamage) then
|
||
|
|
damage:SetDamage(0)
|
||
|
|
return false
|
||
|
|
else
|
||
|
|
attacker.ixCanDoDamage = attacker.ixCanDoDamage - 1
|
||
|
|
if (attacker.ixCanDoDamage == 0) then
|
||
|
|
attacker.ixCanDoDamage = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (inflictor:IsPlayer()) then
|
||
|
|
inflictor = inflictor:GetActiveWeapon()
|
||
|
|
end
|
||
|
|
|
||
|
|
local weaponClass = inflictor:GetClass()
|
||
|
|
if (IsValid(attacker:GetActiveWeapon()) and self:IsMelee(attacker:GetActiveWeapon():GetClass())) then
|
||
|
|
weaponClass = attacker:GetActiveWeapon():GetClass()
|
||
|
|
end
|
||
|
|
|
||
|
|
local range = -1
|
||
|
|
local critChance, penalties, bonus, finalDamage, result
|
||
|
|
local critRoll = math.random()
|
||
|
|
if (!self:IsMelee(weaponClass)) then
|
||
|
|
range = attacker:GetPos():Distance(victim:GetPos()) * 0.30 / 16
|
||
|
|
critChance, penalties, bonus = self:CalcCritChance(attacker:GetCharacter(), victim, range, hitgroup, weaponClass)
|
||
|
|
if (!critChance) then return end
|
||
|
|
|
||
|
|
result = critRoll < critChance and "crit" or "hit"
|
||
|
|
local adjust = self.hitBoxDamageList[hitgroup] and self.hitBoxDamageList[hitgroup][result] or 0.9
|
||
|
|
finalDamage = math.floor((self:GetWeaponBaseDamage(weaponClass) or damage:GetDamage()) * adjust)
|
||
|
|
|
||
|
|
if (victim:IsNPC() or victim:IsPlayer()) then
|
||
|
|
if (result == "hit") then
|
||
|
|
attacker:GetCharacter():DoAction("guns_hit")
|
||
|
|
else
|
||
|
|
attacker:GetCharacter():DoAction("guns_crit")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
critChance, penalties, bonus = self:CalcMeleeCritChance(attacker:GetCharacter(), victim, weaponClass)
|
||
|
|
if (!critChance) then return end
|
||
|
|
|
||
|
|
result = critRoll < critChance and "crit" or "hit"
|
||
|
|
finalDamage = math.floor(self:GetMeleeWeaponBaseDamage(weaponClass, attacker:GetActiveWeapon().ixAttackType) * (result == "crit" and 1 or self:GetMeleeWeaponHitAdjsut(weaponClass)))
|
||
|
|
|
||
|
|
if (victim:IsNPC() or victim:IsPlayer()) then
|
||
|
|
if (result == "hit") then
|
||
|
|
attacker:GetCharacter():DoAction("melee_hit")
|
||
|
|
else
|
||
|
|
attacker:GetCharacter():DoAction("melee_crit")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
ix.log.Add(attacker, "weaponBalanceDebugRolls", critChance, critRoll, string.utf8upper(result))
|
||
|
|
|
||
|
|
damage:SetDamage(finalDamage)
|
||
|
|
|
||
|
|
hook.Run("PostCalculatePlayerDamage", victim, damage, hitgroup)
|
||
|
|
|
||
|
|
if (victim:IsNPC() or victim:IsPlayer()) then
|
||
|
|
ix.log.Add(attacker, "weaponBalanceResult", result, victim, hitgroup, math.Round(damage:GetDamage()), critChance)
|
||
|
|
end
|
||
|
|
|
||
|
|
return true, result, range, critChance, penalties, bonus
|
||
|
|
end
|
||
|
|
|
||
|
|
function ix.weapons:QueueDamageMessage(attacker, data)
|
||
|
|
if (!self.dmgMessageQueue or !istable(self.dmgMessageQueue)) then
|
||
|
|
self.dmgMessageQueue = {}
|
||
|
|
end
|
||
|
|
|
||
|
|
local idx = tonumber(attacker:SteamID64())
|
||
|
|
if (!self.dmgMessageQueue[idx]) then
|
||
|
|
self.dmgMessageQueue[idx] = {}
|
||
|
|
self.dmgMessageQueue[idx].lastIndex = 0
|
||
|
|
self.dmgMessageQueue[idx].ply = attacker
|
||
|
|
self.dmgMessageQueue[idx].stack = {}
|
||
|
|
end
|
||
|
|
|
||
|
|
self.dmgMessageQueue[idx].stack[table.Count(self.dmgMessageQueue[idx].stack) + 1] = data
|
||
|
|
end
|
||
|
|
|
||
|
|
timer.Create("ixDamageMessageStackConsumer", 0.25, 0, function()
|
||
|
|
if (!ix.weapons.dmgMessageQueue or !istable(ix.weapons.dmgMessageQueue)) then return end
|
||
|
|
|
||
|
|
for i, queue in pairs(ix.weapons.dmgMessageQueue) do
|
||
|
|
if (!queue.stack[queue.lastIndex + 1] or !IsValid(queue.ply)) then
|
||
|
|
-- queue is drained
|
||
|
|
ix.weapons.dmgMessageQueue[i] = nil
|
||
|
|
continue
|
||
|
|
end
|
||
|
|
|
||
|
|
local data = queue.stack[queue.lastIndex + 1]
|
||
|
|
ix.chat.Send(queue.ply, "weapon_damage", "", false, queue.ply, {
|
||
|
|
bCrit = data.bCrit,
|
||
|
|
target = data.target,
|
||
|
|
hitBox = data.hitBox,
|
||
|
|
range = data.range,
|
||
|
|
damage = data.damage,
|
||
|
|
calcCrit = data.calcCrit,
|
||
|
|
penalties = data.penalties,
|
||
|
|
bonus = data.bonus,
|
||
|
|
messageType = data.messageType
|
||
|
|
})
|
||
|
|
|
||
|
|
queue.lastIndex = queue.lastIndex + 1
|
||
|
|
end
|
||
|
|
end)
|