-- ========== 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 = num}, #metaText ~= 0 and metaText end, Parameters = { PlaceObj('PresetParamNumber', { 'Name', "MinBonus", 'Value', 2, 'Tag', "", }), PlaceObj('PresetParamNumber', { 'Name', "MinDex", 'Value', 40, 'Tag', "", }), PlaceObj('PresetParamPercent', { 'Name', "DexScale", 'Value', 10, 'Tag', "%", }), }, 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', "", }), PlaceObj('PresetParamPercent', { 'Name', "base_penalty", 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "auto_max_penalty", 'Value', -50, 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "burst_max_penalty", 'Value', -20, 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "mg_burst_max_penalty", 'Value', -50, 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "mg_burst_max_held_penalty", 'Value', -60, 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "mg_burst_cumbersome_penalty", 'Value', -20, 'Tag', "%", }), }, 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', "%", }), }, 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', "", }), PlaceObj('PresetParamNumber', { 'Name', "MaxPenalty", 'Value', -25, 'Tag', "", }), PlaceObj('PresetParamNumber', { 'Name', "MinPenalty", 'Value', -5, 'Tag', "", }), }, 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', "", }), PlaceObj('PresetParamNumber', { 'Name', "MinModifier", 'Value', 10, 'Tag', "", }), PlaceObj('PresetParamPercent', { 'Name', "RangeThreshold", 'Value', 300, 'Tag', "%", }), PlaceObj('PresetParamPercent', { 'Name', "MeleeThreshold", 'Value', 50, 'Tag', "%", }), }, 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', "", }), }, 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', "", }), PlaceObj('PresetParamNumber', { 'Name', "ProneMeleeModifier", 'Value', 20, 'Tag', "", }), }, 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', "%", }), }, 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', "%", }), }, 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', "", }), }, 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', "", }), PlaceObj('PresetParamNumber', { 'Name', "MinPenalty", 'Value', 10, 'Tag', "", }), }, 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', "%", }), }, 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', "", }), PlaceObj('PresetParamNumber', { 'Name', "ExposedCover", 'Value', -5, 'Tag', "", }), PlaceObj('PresetParamNumber', { 'Name', "CrouchPenalty", 'Value', -5, 'Tag', "", }), PlaceObj('PresetParamNumber', { 'Name', "PronePenalty", 'Value', -10, 'Tag', "", }), }, 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', "", }), }, 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, " (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', "", }), }, 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', "%", }), PlaceObj('PresetParamPercent', { 'Name', "BlindFirePenalty", 'Value', -20, 'Tag', "%", }), }, 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', "", }), }, 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, " Shot", body_part_def} end, Parameters = { PlaceObj('PresetParamPercent', { 'Name', "pistol_effect", 'Value', 66, 'Tag', "%", }), }, 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', "%", }), PlaceObj('PresetParamNumber', { 'Name', "levelDiff", 'Value', 2, 'Tag', "", }), }, 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', "%", }), PlaceObj('PresetParamNumber', { 'Name', "levelDiff", 'Value', 2, 'Tag', "", }), }, 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', "", }), }, 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", })