myspace / Data /ChanceToHitModifier.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
29.2 kB
-- ========== GENERATED BY ChanceToHitModifier Editor DO NOT EDIT MANUALLY! ==========
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
local num = aim
local min_bonus = self:ResolveValue("MinBonus")
local min_dex = self:ResolveValue("MinDex")
local dex_scale = self:ResolveValue("DexScale")
local dex = attacker.Dexterity
if IsKindOfClasses(weapon1, "FirearmProperties", "MeleeWeaponProperties") then
min_bonus = weapon1.AimAccuracy
end
local modifyVal, compDef
local metaText = {}
-- Light Stock
modifyVal, compDef = GetComponentEffectValue(weapon1, "ReduceAimAccuracy", "cth_penalty")
if modifyVal then
min_bonus = Max(1, MulDivRound(min_bonus, 100 - modifyVal, 100))
metaText[#metaText + 1] = compDef.DisplayName
end
local bonus = num * min_bonus + MulDivRound(Max(0, dex - min_dex) * num, dex_scale, 100)
-- target camo
if IsKindOf(target, "Unit") then
local armor = target:GetItemInSlot("Torso", "Armor")
if armor and armor.Camouflage then
bonus = MulDivRound(bonus, Max(0, 100 - const.Combat.CamoAimPenalty), 100)
metaText[#metaText + 1] = T(396692757033, "Camouflaged - aiming is less effective")
end
end
-- Forward Grip
modifyVal, compDef = GetComponentEffectValue(weapon1, "FirstAimBonusModifier", "first_aim_bonus")
if modifyVal then
bonus = bonus + MulDivRound(min_bonus, modifyVal, 100)
metaText[#metaText + 1] = compDef.DisplayName
end
-- Quick prism
modifyVal, compDef = GetComponentEffectValue(weapon1, "FirstShotIncreasedAim", "min_aim")
if modifyVal then
local reaction = table.find_value(WeaponComponentEffects.FirstShotIncreasedAim.unit_reactions, "Event", "OnCalcMinAimActions")
reaction = reaction and reaction.Handler
if reaction then
local result = reaction(weapon1, target, 0, attacker, target, action, weapon1)
if result and result == num then
metaText[#metaText + 1] = compDef.DisplayName
end
end
end
-- Heavy Stock
if IsFullyAimedAttack(num) then
modifyVal, compDef = GetComponentEffectValue(weapon1, "BonusAccuracyWhenFullyAimed", "bonus_cth")
if modifyVal then
bonus = bonus + modifyVal
metaText[#metaText + 1] = compDef.DisplayName
end
end
-- Improved Sight
modifyVal, compDef = GetComponentEffectValue(weapon1, "AccuracyBonusWhenAimed", "bonus_cth")
if modifyVal then
bonus = bonus + modifyVal
metaText[#metaText + 1] = compDef.DisplayName
end
return num > 0, bonus, T{762331260877, "Aiming (x<aim_mod>)", aim_mod = num}, #metaText ~= 0 and metaText
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "MinBonus",
'Value', 2,
'Tag', "<MinBonus>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MinDex",
'Value', 40,
'Tag', "<MinDex>",
}),
PlaceObj('PresetParamPercent', {
'Name', "DexScale",
'Value', 10,
'Tag', "<DexScale>%",
}),
},
display_name = T(154175220541, --[[ChanceToHitModifier Default Aim display_name]] "Aiming"),
group = "Default",
id = "Aim",
param_bindings = {},
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not attacker or not target then
return false, 0
end
local param
local metaText = {}
local extra = 0
if action.id == "BurstFire" then
param = "burst_max_penalty"
elseif action.id == "AutoFire" then
param = "auto_max_penalty"
elseif action.id == "MGBurstFire" then
if g_Overwatch[attacker] and g_Overwatch[attacker].permanent then
param = "mg_burst_max_penalty"
else
param = "mg_burst_max_held_penalty"
if weapon1 and weapon1:IsCumbersome() then
extra = self:ResolveValue("mg_burst_cumbersome_penalty")
end
end
elseif action.id == "GrizzlyPerk" then
param = "mg_burst_max_penalty"
metaText[#metaText + 1] = GrizzlyPerk.DisplayName
else
return false, 0
end
local penalty = self:ResolveValue("base_penalty")
local pb_dist = const.Weapons.PointBlankRange * const.SlabSizeX
local dist = attacker_pos:Dist(target_pos)
if dist > pb_dist then
-- scale in the distance after point-blank range to max penalty
local max_dist = self:ResolveValue("max_dist") * const.SlabSizeX
local max_penalty = self:ResolveValue(param) + extra
dist = Min(dist, max_dist) - pb_dist
max_dist = max_dist - pb_dist
penalty = penalty + Min(-1, MulDivRound(dist, max_penalty - penalty, max_dist))
end
if penalty == 0 then
return false, 0
end
if action.id == "BurstFire" then
return true, penalty, T(913932180355, "Burst Fire"), #metaText ~= 0 and metaText
end
return true, penalty, false, #metaText ~= 0 and metaText
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "max_dist",
'Value', 14,
'Tag', "<max_dist>",
}),
PlaceObj('PresetParamPercent', {
'Name', "base_penalty",
'Tag', "<base_penalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "auto_max_penalty",
'Value', -50,
'Tag', "<auto_max_penalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "burst_max_penalty",
'Value', -20,
'Tag', "<burst_max_penalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "mg_burst_max_penalty",
'Value', -50,
'Tag', "<mg_burst_max_penalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "mg_burst_max_held_penalty",
'Value', -60,
'Tag', "<mg_burst_max_held_penalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "mg_burst_cumbersome_penalty",
'Value', -20,
'Tag', "<mg_burst_cumbersome_penalty>%",
}),
},
display_name = T(520853928478, --[[ChanceToHitModifier Default Autofire display_name]] "Autofire"),
group = "Default",
id = "Autofire",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if attacker.stance ~= "Prone" or not weapon1 then
return false, 0
end
local value = GetComponentEffectValue(weapon1, "AccuracyBonusProne", "bonus_cth")
return not not value, value
end,
display_name = T(168185551132, --[[ChanceToHitModifier Default Bipod display_name]] "Bipod"),
group = "Default",
id = "Bipod",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
return true, self:ResolveValue("penalty")
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "penalty",
'Value', -10,
'Tag', "<penalty>%",
}),
},
RequireActionType = "Brutalize",
RequireTarget = true,
display_name = T(644064070045, --[[ChanceToHitModifier Default Brutalize display_name]] "Brutalize"),
group = "Default",
id = "Brutalize",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if attacker ~= target and attacker:IsPointBlankRange(target) then
return false, 0
end
if IsIlluminated(target) then
return false, 0
end
local penalty = const.EnvEffects.DarknessCTHPenalty
if IsKindOf(attacker, "Unit") and attacker:HasNightVision() then
local reductionPercent = CharacterEffectDefs.NightOps:ResolveValue("night_acc_penalty_reduction")
penalty = MulDivRound(penalty, Max(0, 100 - reductionPercent), 100)
return true, penalty, nil, T(311005929977, "Night Vision")
end
return true, penalty
end,
Comment = "Penalty when it's Night or in Underground; aim UI indication for Thermal Scope",
RequireActionType = "Any Ranged Attack",
display_name = T(686385477123, --[[ChanceToHitModifier Default Darkness display_name]] "In the dark"),
group = "Default",
id = "Darkness",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
-- temporary disable
if true then return false, 0 end
if not IsKindOf(target, "Unit") then return false, 0 end
--[[ local movement = target.last_turn_movement
if not movement or weapon1 and weapon1:HasC/o\mponent("ReflexSight") then
return false, 0
end]]
local dist = movement:Len2D()
if dist == 0 then
return false, 0
end
local move_dir = SetLen(movement, guim)
local dir = target:GetVisualPos() - attacker_pos
local dp = dir:Equal2D(point20) and guim or abs(Dot2D(SetLen(dir:SetZ(0), guim), move_dir) / guim)
-- scale by dot
local mod = MulDivRound(self:ResolveValue("MaxPenalty"), guim - dp, guim)
-- scale by distance (up to param1 tiles)
local max_dist = self:ResolveValue("MaxDistTiles") * const.SlabSizeX
mod = MulDivRound(mod, Min(dist, max_dist), max_dist)
return mod < self:ResolveValue("MinPenalty"), mod
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "MaxDistTiles",
'Value', 10,
'Tag', "<MaxDistTiles>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MaxPenalty",
'Value', -25,
'Tag', "<MaxPenalty>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MinPenalty",
'Value', -5,
'Tag', "<MinPenalty>",
}),
},
RequireTarget = true,
display_name = T(330773997382, --[[ChanceToHitModifier Default EvasiveMovement display_name]] "Evasive Movement"),
group = "Default",
id = "EvasiveMovement",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not IsGameRuleActive("HeavyWounds") then
return false, 0
end
local wounds = attacker:GetStatusEffect("Wounded")
if not wounds or wounds.stacks<=0 then
return false, 0
end
local max_wounds = GameRuleDefs.HeavyWounds:ResolveValue("MaxWoundsEffect")
local per_wound_percent = GameRuleDefs.HeavyWounds:ResolveValue("AccuracyPenalty")
local total_percent = Min(wounds.stacks,max_wounds) *per_wound_percent
return true, -total_percent
end,
display_name = T(738595150432, --[[ChanceToHitModifier Default GameRuleHeavyWounds display_name]] "Heavy Wounds"),
group = "Default",
id = "GameRuleHeavyWounds",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not weapon1 then
return false, 0
end
local min_diff = self:ResolveValue(IsKindOf(weapon1, "MeleeWeapon") and "MeleeThreshold" or "RangeThreshold")
min_diff = MulDivRound(min_diff, const.SlabSizeZ, 100)
local max_diff = const.SlabSizeZ * 20
local ax, ay, az = attacker_pos:xyz()
az = az or terrain.GetHeight(ax, ay)
local tx, ty, tz
if IsValid(target) then
tx, ty, tz = target:GetPosXYZ()
else
tx, ty, tz = target:xyz()
end
tz = tz or terrain.GetHeight(tx, ty)
local maxMod = self:ResolveValue("MaxModifier")
local minMod = self:ResolveValue("MinModifier")
local modifierCap = maxMod - minMod
local diff = az - tz
local higher = diff < 0
diff = abs(diff)
if diff < min_diff then return false, 0 end
local interp = MulDivRound(diff - min_diff, 1000, max_diff)
local modifierInterp = minMod + MulDivRound(interp, modifierCap, 1000)
if not higher then
return true, modifierInterp
end
--return true, -modifierInterp, T{"Low Ground"}
return false, 0
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "MaxModifier",
'Value', 20,
'Tag', "<MaxModifier>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MinModifier",
'Value', 10,
'Tag', "<MinModifier>",
}),
PlaceObj('PresetParamPercent', {
'Name', "RangeThreshold",
'Value', 300,
'Tag', "<RangeThreshold>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "MeleeThreshold",
'Value', 50,
'Tag', "<MeleeThreshold>%",
}),
},
StoreAsTable = true,
display_name = T(652956687180, --[[ChanceToHitModifier Default GroundDifference display_name]] "High Ground"),
group = "Default",
id = "GroundDifference",
param_bindings = {},
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if IsKindOf(weapon1, "Firearm") and target.species == "Crocodile" then
local modValue = self:ResolveValue("LowProfilePenalty")
return true, modValue
end
return false, 0
end,
Comment = "target is Crocodile",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "LowProfilePenalty",
'Value', -12,
'Tag', "<LowProfilePenalty>",
}),
},
RequireActionType = "Any Ranged Attack",
RequireTarget = true,
display_name = T(172166647737, --[[ChanceToHitModifier Default LowProfile display_name]] "Low Profile"),
group = "Default",
id = "LowProfile",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not IsKindOf(weapon1, "MeleeWeapon") or not IsKindOf(target, "Unit") then
return false, 0
end
local target_stance = target:GetHitStance()
local bonus = self:ResolveValue(target_stance .. "MeleeModifier")
return not not bonus, bonus
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "CrouchMeleeModifier",
'Value', 15,
'Tag', "<CrouchMeleeModifier>",
}),
PlaceObj('PresetParamNumber', {
'Name', "ProneMeleeModifier",
'Value', 20,
'Tag', "<ProneMeleeModifier>",
}),
},
RequireActionType = "Any Melee Attack",
RequireTarget = true,
display_name = T(413332276489, --[[ChanceToHitModifier Default MeleeAttackTargetStance display_name]] "Enemy Stance"),
group = "Default",
id = "MeleeAttackTargetStance",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if action.id ~= "MarkTarget" and action.ActionType ~= "Melee Attack" then return false, 0 end
if IsKindOf(target, "Unit") then
local w1, w2, wl = target:GetActiveWeapons()
local has_melee
for _, w in ipairs(wl) do
has_melee = has_melee or IsKindOf(w, "MeleeWeapon")
end
if w1 and not has_melee then -- if not w1 the target is unarmed, which is considered as a melee weapon for this modifier
return true, self:ResolveValue("bonus")
end
end
return false, 0
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "bonus",
'Value', 10,
'Tag', "<bonus>%",
}),
},
RequireTarget = true,
display_name = T(883060605104, --[[ChanceToHitModifier Default MeleeRangedEnemy display_name]] "Ranged Enemy"),
group = "Default",
id = "MeleeRangedEnemy",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if action.id ~= "MarkTarget" and action.ActionType ~= "Melee Attack" then return false, 0 end
if not attacker:HasStatusEffect("Hidden") or not IsKindOf(target, "Unit") or target:IsAware() then return false, 0 end
return true, self:ResolveValue("bonus")
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "bonus",
'Value', 15,
'Tag', "<bonus>%",
}),
},
RequireTarget = true,
display_name = T(272537328286, --[[ChanceToHitModifier Default MeleeStealthStrike display_name]] "Stealth Strike"),
group = "Default",
id = "MeleeStealthStrike",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if HasVisibilityTo(attacker.team or attacker, target) then
return false, 0
end
if not IsKindOf(weapon1, "Firearm") or not attacker or not target then
return false, 0
end
return true, self:ResolveValue("Penalty")
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Penalty",
'Value', -50,
'Tag', "<Penalty>",
}),
},
RequireTarget = true,
display_name = T(373728214326, --[[ChanceToHitModifier Default NoLineOfSight display_name]] "No Line of Sight"),
group = "Default",
id = "NoLineOfSight",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not opportunity_attack then
return false, 0
end
local max = self:ResolveValue("MaxPenalty")
local min = self:ResolveValue("MinPenalty")
local value = max + MulDivRound(min - max, attacker.Dexterity, 100)
local metaText = false
local bonus, compDef = GetComponentEffectValue(weapon1, "OpportunityAttackBonusCth", "bonus_cth")
if bonus then
value = value + bonus
metaText = compDef.DisplayName
end
return true, value, false, metaText
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "MaxPenalty",
'Value', -20,
'Tag', "<MaxPenalty>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MinPenalty",
'Value', 10,
'Tag', "<MinPenalty>",
}),
},
display_name = T(148987105999, --[[ChanceToHitModifier Default OpportunityAttack display_name]] "Opportunity Attack"),
group = "Default",
id = "OpportunityAttack",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if attacker and IsKindOf(weapon1, "FirearmProperties") and weapon1:HasPointBlankBonus() and attacker:IsPointBlankRange(target) then
return true, self:ResolveValue("bonus")
end
return false, 0
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "bonus",
'Value', 15,
'Tag', "<bonus>%",
}),
},
display_name = T(843386513579, --[[ChanceToHitModifier Default PointBlank display_name]] "Point-Blank Range"),
group = "Default",
id = "PointBlank",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if opportunity_attack or not IsKindOf(weapon1, "Firearm") or not IsKindOf(target, "Unit") then
return false, 0
end
local target_stance = target:GetHitStance()
if target_stance == "Prone" then
local value = self:ResolveValue("PronePenalty")
return true, value, T(904752344471, "Target Prone")
end
local cover, any, coverage
if weapon1 then
local ignoreCth = weapon1:HasComponent("IgnoreCoverCtHWhenFullyAimed") and IsFullyAimedAttack(aim)
if not ignoreCth and (opportunity_attack or target:IsAware()) and not target:HasStatusEffect("Exposed") then
cover, any, coverage = target:GetCoverPercentage(attacker_pos, target_pos)
end
end
-- force exposed when aiming/shooting
local melee_attack = action and action.ActionType == "Melee Attack"
cover = not target.aim_action_id and not melee_attack and cover
if cover then
local name = false
local exposed_value = self:ResolveValue("ExposedCover")
local full_value = self:ResolveValue("Cover")
if CheckSightCondition(attacker, target, const.usObscured) then
exposed_value = exposed_value + const.EnvEffects.DustStormCoverCTHPenalty
full_value = full_value + const.EnvEffects.DustStormCoverCTHPenalty
name = T(548829641491, "Behind Cover (Dust Storm)")
end
local value = InterpolateCoverEffect(coverage, full_value, exposed_value)
local metaText = false
if value < exposed_value then
return true, value, name, metaText, "Cover"
end
end
if target_stance == "Crouch" then
local value = self:ResolveValue("CrouchPenalty")
return true, value, T(309253003316, "Target Crouched")
end
return false, 0
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Cover",
'Value', -20,
'Tag', "<Cover>",
}),
PlaceObj('PresetParamNumber', {
'Name', "ExposedCover",
'Value', -5,
'Tag', "<ExposedCover>",
}),
PlaceObj('PresetParamNumber', {
'Name', "CrouchPenalty",
'Value', -5,
'Tag', "<CrouchPenalty>",
}),
PlaceObj('PresetParamNumber', {
'Name', "PronePenalty",
'Value', -10,
'Tag', "<PronePenalty>",
}),
},
RequireTarget = true,
display_name = T(879243129261, --[[ChanceToHitModifier Default RangeAttackTargetStanceCover display_name]] "Behind Cover"),
group = "Default",
id = "RangeAttackTargetStanceCover",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if action.id ~= "RunAndGun" then
return false, 0
end
return true, -self:ResolveValue("Penalty")
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Penalty",
'Value', 25,
'Tag', "<Penalty>",
}),
},
display_name = T(933407442617, --[[ChanceToHitModifier Default RunAndGun display_name]] "Run and Gun"),
group = "Default",
id = "RunAndGun",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if attacker:GetLastAttack() ~= target then
return false, 0
end
local value = self:ResolveValue("Bonus")
local name = self.display_name
if IsKindOf(weapon1, "MeleeWeapon") then
return true, value, T{382638810853, "<name> (Melee)", name = name}
end
if IsKindOf(weapon1, "Firearm") then
local metaText = false
local modifyVal, compDef = GetComponentEffectValue(weapon1, "AccuracyBonusSameTarget", "bonus_cth")
if modifyVal then
value = value + modifyVal
metaText = compDef.DisplayName
end
return true, value, name, metaText
end
return false, 0
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Bonus",
'Value', 10,
'Tag', "<Bonus>",
}),
},
RequireTarget = true,
display_name = T(726263349116, --[[ChanceToHitModifier Default SameTarget display_name]] "Same Target"),
group = "Default",
id = "SameTarget",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
-- the attacker must not have normal sight to the target (los + sight radius)
if not attacker or not target or VisibilityCheckAll(attacker, target, nil, const.uvVisible) then
return false, 0
end
-- perks that negate the effect
if not IsKindOf(weapon1, "Firearm") then
return false, 0
end
-- check if any teammate has normal sight to distinguish between Blind Fire and Seen by Spotter
if not attacker.team or not VisibilityCheckAll(attacker.team, target, nil, const.uvVisible) then
return true, self:ResolveValue("BlindFirePenalty")
end
return true, self:ResolveValue("SpotterPenalty"), T(431888134623, "Seen by Spotter")
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "SpotterPenalty",
'Value', -20,
'Tag', "<SpotterPenalty>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "BlindFirePenalty",
'Value', -20,
'Tag', "<BlindFirePenalty>%",
}),
},
RequireActionType = "Any Ranged Attack",
RequireTarget = true,
display_name = T(213459983213, --[[ChanceToHitModifier Default SeenBySpotter display_name]] "Blind fire"),
group = "Default",
id = "SeenBySpotter",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if not IsKindOf(target, "Trap") then return false end
return true, self:ResolveValue("Bonus")
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Bonus",
'Value', 20,
'Tag', "<Bonus>",
}),
},
display_name = T(498687848389, --[[ChanceToHitModifier Default SmallTarget display_name]] "Stationary Target"),
group = "Default",
id = "SmallTarget",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
local mod = body_part_def and body_part_def.tohit_mod or 0
if IsKindOfClasses(weapon1, "Pistol", "Revolver", "SniperRifle") then
mod = MulDivRound(mod, self:ResolveValue("pistol_effect"), 100)
end
return mod ~= 0, mod, T{357357827656, "<display_name> Shot", body_part_def}
end,
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "pistol_effect",
'Value', 66,
'Tag', "<pistol_effect>%",
}),
},
RequireTarget = true,
display_name = T(857397449322, --[[ChanceToHitModifier Default TargetedShot display_name]] "Targeted Shot"),
group = "Default",
id = "TargetedShot",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if IsKindOf(attacker, "Unit") and IsKindOf(target, "Unit") then
local attackerLevel = attacker:GetLevel()
local targetLevel = target:GetLevel()
local hasAdvantage = (attackerLevel - targetLevel) >= self:ResolveValue("levelDiff")
if hasAdvantage then
return true, self:ResolveValue("bonus")
end
end
end,
Comment = "More accurate attacks against lower level targets",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "bonus",
'Value', 10,
'Tag', "<bonus>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "levelDiff",
'Value', 2,
'Tag', "<levelDiff>",
}),
},
RequireTarget = true,
display_name = T(713286242287, --[[ChanceToHitModifier Default TrainingAdvantage display_name]] "More experienced"),
group = "Default",
id = "TrainingAdvantage",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if IsKindOf(attacker, "Unit") and IsKindOf(target, "Unit") then
local attackerLevel = attacker:GetLevel()
local targetLevel = target:GetLevel()
local hasDisadvantage = (targetLevel - attackerLevel) >= self:ResolveValue("levelDiff")
if hasDisadvantage then
return true, -self:ResolveValue("penalty")
end
end
end,
Comment = "Less accurate attacks against higher level targets",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "penalty",
'Value', 10,
'Tag', "<penalty>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "levelDiff",
'Value', 2,
'Tag', "<levelDiff>",
}),
},
RequireTarget = true,
display_name = T(133256021230, --[[ChanceToHitModifier Default TrainingDisadvantage display_name]] "Less Experienced"),
group = "Default",
id = "TrainingDisadvantage",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if action.id ~= "DualShot" then
return false, 0
end
local value = self:ResolveValue("Penalty")
return true, value
end,
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "Penalty",
'Value', -30,
'Tag', "<Penalty>",
}),
},
display_name = T(632609411805, --[[ChanceToHitModifier Default TwoWeaponFire display_name]] "Two Weapon Fire"),
group = "Default",
id = "TwoWeaponFire",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
local min_condition = Min(weapon1 and weapon1:GetConditionPercent() or 100, weapon2 and weapon2:GetConditionPercent() or 100)
local chance = GetWeaponConditionPenalty(min_condition)
return chance > 0, -chance
end,
display_name = T(485217354080, --[[ChanceToHitModifier Default WeaponCondition display_name]] "Weapon Condition"),
group = "Default",
id = "WeaponCondition",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
if action and action.id ~= "SingleShot" then
return false
end
local extraCth, component = GetComponentEffectValue(weapon1, "IncreasedSingleShotAccuracy", "bonus_cth")
return not not extraCth, extraCth, component and component.DisplayName
end,
display_name = T(539719873893, --[[ChanceToHitModifier WeaponMod IncreasedSingleShotAccuracy display_name]] "Weapon Mod"),
group = "WeaponMod",
id = "IncreasedSingleShotAccuracy",
})
PlaceObj('ChanceToHitModifier', {
CalcValue = function (self, attacker, target, body_part_def, action, weapon1, weapon2, lof, aim, opportunity_attack, attacker_pos, target_pos)
local extraCth, component = GetComponentEffectValue(weapon1, "MinorAccuracyBonus", "bonus_cth")
return not not extraCth, extraCth, component and component.DisplayName
end,
display_name = T(846343426094, --[[ChanceToHitModifier WeaponMod MinorAccuracyBonus display_name]] "Weapon Mod"),
group = "WeaponMod",
id = "MinorAccuracyBonus",
})