Files
wnsrc/gamemodes/darkrp/plugins/weaponbalance/sv_plugin.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

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)