myspace / Data /CombatAction.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
Raw History Blame Contribute Delete
331 kB
-- ========== GENERATED BY CombatAction Editor DO NOT EDIT MANUALLY! ==========
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = 2000,
ActionPoints = 2000,
ActionType = "Ranged Attack",
AimType = "line",
Comment = "-> AttackDual FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(208869050611, --[[CombatAction DualShot Description]] "The Dual Shot attack produces a Basic Attack from each gun."),
DisplayName = T(712971913349, --[[CombatAction DualShot DisplayName]] "Dual Shot"),
DisplayNameShort = T(811622228569, --[[CombatAction DualShot DisplayNameShort]] "Dual"),
FiringModeMember = "AttackDual",
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if not weapon1 or not weapon2 then
return -1
end
local aim = args and args.aim or 0
-- pass self.ActionPointDelta to both to allow the RainHeavy check to work correctly
return Max(unit:GetAttackAPCost(self, weapon1, false, aim, self.ActionPointDelta), unit:GetAttackAPCost(self, weapon2, false, aim, self.ActionPointDelta))
end,
GetActionDamage = function (self, unit, target, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if not weapon1 or not weapon2 then return 0 end
local aim = args and args.aim
if not aim then
local dlg = GetInGameInterfaceModeDlg()
if IsKindOf(dlg, "IModeCombatAttackBase") and dlg.crosshair then
aim = dlg.crosshair.aim
end
end
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
assert(weapon1 and weapon2)
local w1Attack = weapon1:GetBaseAttack(unit)
w1Attack = w1Attack and CombatActions[w1Attack]
local w2Attack = weapon2:GetBaseAttack(unit)
w2Attack = w2Attack and CombatActions[w2Attack]
-- Demote attacks to single shot if attacks dont match.
-- This prevents discrepencies in cth between attacks and such.
if w1Attack ~= w2Attack then
w1Attack = CombatActions.SingleShot
w2Attack = CombatActions.SingleShot
end
args = args or {}
args.weapon = weapon1
local dmg1, base1 = w1Attack:GetActionDamage(unit, target, args)
args.weapon = weapon2
args.lof = false
local dmg2, base2 = w2Attack:GetActionDamage(unit, target, args)
args.weapon = false
args.lof = false
local damage = dmg1 + dmg2
local baseCombo = base1 + base2
return damage, base1, 0, {
min = Min(base1, base2),
max = damage,
wep1_damage = dmg1,
wep2_damage = dmg2,
wep1_base = base1,
wep2_base = base2
}
end,
GetActionDescription = function (self, units)
local unit = units[1]
local damage = self:GetActionDamage(unit)
return T{self.Description, damage = damage}
end,
GetActionResults = function (self, unit, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
args = args or {}
args.used_action_id = self.id
args.weapon = weapon1
local attack1, args1 = w1Attack:GetActionResults(unit, args)
args.weapon = weapon2
args.lof = false -- GetActionResults mutates our table lol
local attack2, args2 = w2Attack:GetActionResults(unit, args)
args.weapon = false
args.lof = false
return MergeAttacks({ attack1, attack2 }, { args1, args2 })
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetActiveWeapons("Firearm", "strict")
end,
GetUIState = function (self, units, args)
local unit = units[1]
if not unit then return "hidden" end
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
local enable, reason = unit:CanUseWeapon(weapon1)
if not enable then
return "disabled", reason
end
enable, reason = unit:CanUseWeapon(weapon2)
if not enable then
return "disabled", reason
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/dual_shot",
IconFiringMode = "UI/Hud/fm_dual_shot",
IdDefault = "DualShotdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = -1,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "DualShot",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPoints = 3000,
ActionType = "Ranged Attack",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(863161981262, --[[CombatAction MGBurstFire Description]] "Make a burst attack<coneDescription>. Lower accuracy against distant enemies, and further reduced accuracy if fired without being Set.<interrupts_info>"),
DisplayName = T(706547341778, --[[CombatAction MGBurstFire DisplayName]] "Long Burst"),
Execute = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
args.num_shots = weapon:GetAutofireShots(self)
args.multishot = true
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return -1 end
-- GetAttackAPCost returns aim cost as second value, while GetAPCost's second return value has a different semantic (display cost)
local cost = unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0)
return cost
end,
GetActionDamage = function (self, unit, target, args)
local weapon = args and args.weapon or self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit and unit:GetBaseDamage(weapon) or weapon.Damage
local penalty = self:ResolveValue("dmg_penalty")
local num_shots = weapon:GetAutofireShots(self)
base = MulDivRound(base, Max(0, 100 + penalty), 100)
local damage = num_shots*base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
local unit = units[1]
local coneDescription = T{""}
local interrupts_info = ""
local overwatch = g_Overwatch[unit]
if overwatch and overwatch.permanent then
coneDescription = T(480046777812, " within the set cone")
interrupts_info = T{757307734445, "<newline><newline>Remaining interrupt attacks: <interrupts>", interrupts = unit:GetNumMGInterruptAttacks()}
end
return T{description, coneDescription = coneDescription, interrupts_info = interrupts_info}
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionIcon = function (self, units)
-- replace icon when using Revolver
local unit = units and units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if IsKindOf(weapon, "Revolver") then
return CombatActions.Fanning.Icon
end
end
return self.Icon
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.weapon = args.weapon or self:GetAttackWeapons(unit, args)
args.num_shots = args.num_shots or args.weapon and args.weapon:GetAutofireShots(self)
args.multishot = true
args.damage_bonus = self:ResolveValue("dmg_penalty")
--args.cth_loss_per_shot = self:ResolveValue("cth_loss_per_shot")
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
return CombatActionGetOneAttackableEnemy(self, units and units[1], nil, CombatActionTargetFilters.MGBurstFire, units)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetTargets = function (self, units)
return CombatActionGetAttackableEnemies(self, units and units[1], nil, CombatActionTargetFilters.MGBurstFire, units)
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/burst_fire",
IdDefault = "MGBurstFiredefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectHeavyAttack",
KeybindingSortId = "2372",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 8,
'Tag', "<num_shots>",
}),
PlaceObj('PresetParamPercent', {
'Name', "cth_loss_per_shot",
'Tag', "<cth_loss_per_shot>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "dmg_penalty",
'Value', -50,
'Tag', "<dmg_penalty>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "min_shots",
'Value', 1,
'Tag', "<min_shots>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "WeaponAttacks",
id = "MGBurstFire",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
Comment = "-> AttackDual FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(520163235403, --[[CombatAction RightHandShot Description]] "Cheap attack with your right-hand weapon that conserves ammo."),
DisplayName = T(282789699649, --[[CombatAction RightHandShot DisplayName]] "Right Hand Shot"),
DisplayNameShort = T(145254451163, --[[CombatAction RightHandShot DisplayNameShort]] "Right Hand"),
FiringModeMember = "AttackDual",
GetAPCost = function (self, unit, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
if not w1Attack then return -1 end
args = args and table.copy(args) or {}
args.weapon = weapon1
return w1Attack:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
args = args or {}
args.weapon = weapon1
local dmg, base, bonus, params = w1Attack:GetActionDamage(unit, target, args)
args.weapon = false
return dmg, base, bonus, params
end,
GetActionDescription = function (self, units)
local w1Attack, w2Attack = GetDualShotAttacks(units[1])
return w1Attack:GetActionDescription(units)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
args = args or {}
args.weapon = weapon1
local result, att_args = w1Attack:GetActionResults(unit, args)
args.weapon = false
return result, att_args
end,
GetAttackWeapons = function (self, unit, args)
local weapon1, weapon2 = unit:GetActiveWeapons("Firearm", "strict")
return weapon1
end,
GetUIState = function (self, units, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(units[1])
if not w1Attack then return "hidden" end
local enable, reason = units[1]:CanUseWeapon(weapon1)
if not enable then
return "disabled", reason
end
args = args or {}
args.weapon = weapon1
local uiState = w1Attack:GetUIState(units, args)
args.weapon = false
return uiState
end,
Icon = "UI/Icons/Hud/attack",
IconFiringMode = "UI/Hud/fm_right_hand_shot",
IdDefault = "RightHandShotdefault",
IsTargetableAttack = true,
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "RightHandShot",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
Comment = "-> Attack FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(298670513550, --[[CombatAction SingleShot Description]] "Cheap attack that conserves ammo."),
DisplayName = T(355970076448, --[[CombatAction SingleShot DisplayName]] "Single Shot"),
DisplayNameShort = T(392229752968, --[[CombatAction SingleShot DisplayNameShort]] "Single"),
FiringModeMember = "Attack",
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if unit:OutOfAmmo(weapon2) or unit:IsWeaponJammed(weapon2) then
weapon2 = nil
end
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0, self.ActionPointDelta) or -1
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local _, _, _, params = self:GetActionDamage(unit)
local descr = T{self.Description, damage = GetDamageRangeText(params.min, params.max), crit = params.critChance}
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon, _, list = unit:GetActiveWeapons("Firearm")
return weapon
end,
GetUIState = function (self, units, args)
local unit = units[1]
local attackWep = self:GetAttackWeapons(unit, args)
if not attackWep then return "hidden" end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/attack",
IconFiringMode = "UI/Hud/fm_single_shot",
IdDefault = "SingleShotdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "SingleShot",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
Comment = "mortar attack",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(169779903706, --[[CombatAction Bombard Description]] "<em>Spends all AP</em>\nSetup a zone bombarded at the start of your next turn. The amount of attacks depends on spent AP.\n\n<em><attacks></em> attacks."),
DisplayName = T(293721021077, --[[CombatAction Bombard DisplayName]] "Bombard"),
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
return Max(unit:GetUIActionPoints(), unit:GetAttackAPCost(self, weapon, false, 0)) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if weapon and IsKindOf(weapon.ammo, "Ordnance") then
return weapon.ammo.BaseDamage
end
return 0
end,
GetActionDescription = function (self, units)
local unit = units[1]
local attacks = unit and (unit:GetUIActionPoints() / (self:ResolveValue("ap_per_shot")*const.Scale.AP)) or 1
return T{self.Description, attacks = attacks}
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
local target = ResolveGrenadeTargetPos(args.target)
local ammos = weapon and unit:GetAvailableAmmos(weapon, nil, "unique")
if not weapon or not target or not ammos then
return {}
end
local args = table.copy(args)
local cost_ap = args.spent_ap or self:GetAPCost(unit)
args.weapon = weapon
args.target = target
args.ordnance = args.ordnance or ammos[1]
args.can_use_covers = false
args.bombard_shots = cost_ap / (self:ResolveValue("ap_per_shot")*const.Scale.AP)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("HeavyWeapon")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/heavy_weapon_attack",
IdDefault = "Bombarddefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectHeavyAttack",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "ap_per_shot",
'Value', 3,
'Tag', "<ap_per_shot>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("PrepareBombard", self.id, ap, ...)
end,
SortKey = 1,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "WeaponAttacks",
id = "Bombard",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "cone",
Comment = "-> ShotgunAttack FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(734174652599, --[[CombatAction Buckshot Description]] "All enemy targets in cover are <GameTerm('Exposed')>.\nInflicts additional status effects based on the ammo. All targets affected by the area of attack receive additional damage."),
DisplayName = T(673459341122, --[[CombatAction Buckshot DisplayName]] "Shotgun Shot"),
DisplayNameShort = T(686623207963, --[[CombatAction Buckshot DisplayNameShort]] "Single"),
FiringModeMember = "AttackShotgun",
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
local base = weapon and unit:GetBaseDamage(weapon) or 0
local aoeDamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)
return base, base, 0, { aoe_damage = aoeDamage }
end,
GetActionDescription = function (self, units)
local unit = units[1]
local damage, _, _, params = self:GetActionDamage(unit)
local descr = T{self.Description, damage = damage, aoedamage = params.aoe_damage}
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
if not args.target_spot_group then
args.num_shots = 0
end
args.aoe_action_id = self.id
args.fx_action = "WeaponBuckshot"
args.aoe_fx_action = "WeaponBuckshot"
args.single_fx = true
args.aoe_damage_type = "percent"
args.aoe_damage_value = const.Weapons.ShotgunCollateralDamage
args.buckshot_scatter_fx = 10
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return 2
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/shotgun_shot",
IconFiringMode = "UI/Hud/fm_buckshot",
IdDefault = "Buckshotdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
local dlg = GetInGameInterfaceModeDlg()
if IsKindOf(dlg, "IModeCombatAreaAim") and dlg.crosshair then
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "attack")
else
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end
end,
basicAttack = true,
group = "WeaponAttacks",
id = "Buckshot",
})
PlaceObj('CombatAction', {
ActionPointDelta = 1000,
ActionType = "Ranged Attack",
AimType = "cone",
Comment = "-> ShotgunAttack FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(112396421802, --[[CombatAction BuckshotBurst Description]] "All enemy targets in cover are <GameTerm('Exposed')>.\nShoots <em><num_shots> bullets</em> at the target. Lower accuracy vs distant enemies. All targets affected by the area of attack receive additional damage."),
DisplayName = T(750178209605, --[[CombatAction BuckshotBurst DisplayName]] "Buckshot Burst"),
DisplayNameShort = T(946188984206, --[[CombatAction BuckshotBurst DisplayNameShort]] "Burst"),
FiringModeMember = "AttackShotgun",
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit and unit:GetBaseDamage(weapon) or weapon.Damage
local aoeDamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)
local num_shots = weapon:GetAutofireShots(self)
local damage = num_shots*base
return damage, base, damage - base, { aoe_damage = aoeDamage }
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local aoedamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)
local num_shots = IsKindOf(weapon, "Firearm") and weapon:GetAutofireShots(self) or 1
local descr = T{self.Description, num_shots = num_shots, damage = base, aoedamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)}
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
local weapon = self:GetAttackWeapons(unit)
args.num_shots = weapon and weapon:GetAutofireShots(self) or 1
args.aoe_action_id = self.id
args.fx_action = "WeaponBuckshot"
args.buckshot_scatter_fx = 10
args.aoe_damage_type = "percent"
args.aoe_damage_value = const.Weapons.ShotgunCollateralDamage
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
-- make sure the fx action plays
local shots = results.attacks and results.attacks[1].shots or empty_table
if #shots == 0 then
attack_args.aoe_fx_action = "WeaponBuckshot"
end
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return 2
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/shotgun_shot",
IconFiringMode = "UI/Hud/fm_buckshot_burst",
IdDefault = "BuckshotBurstdefault",
IsTargetableAttack = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 3,
'Tag', "<num_shots>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
local dlg = GetInGameInterfaceModeDlg()
if IsKindOf(dlg, "IModeCombatAreaAim") and dlg.crosshair then
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "attack")
else
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end
end,
basicAttack = true,
group = "WeaponAttacks",
id = "BuckshotBurst",
})
PlaceObj('CombatAction', {
ActionPointDelta = 1000,
ActionPoints = 1000,
ActionType = "Ranged Attack",
AimType = "cone",
Comment = "-> ShotgunAttack FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(212508932528, --[[CombatAction DoubleBarrel Description]] "All enemy targets in cover are <GameTerm('Exposed')>.\nInflicts additional status effects based on the ammo. All targets affected by the area of attack receive additional damage."),
DisplayName = T(745680006620, --[[CombatAction DoubleBarrel DisplayName]] "Double Barrel"),
DisplayNameShort = T(425861398044, --[[CombatAction DoubleBarrel DisplayNameShort]] "Double"),
FiringModeMember = "AttackShotgun",
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
local cost = unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0)
return cost and cost + self.ActionPointDelta or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
local base = weapon and unit:GetBaseDamage(weapon) or 0
return MulDivRound(base, const.Weapons.ShotgunCollateralDamage * const.Weapons.DoubleBarrelDamageBonus, 10000)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
base = MulDivRound(base, 100+const.Weapons.DoubleBarrelDamageBonus, 100)
return T{self.Description, damage = base, aoedamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)}
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.weapon = self:GetAttackWeapons(unit, args)
if not args.target_spot_group then
args.num_shots = 0
end
args.aoe_action_id = self.id
args.fx_action = "WeaponBuckshot"
args.aoe_fx_action = "WeaponBuckshot"
args.single_fx = true
args.aoe_damage_type = "percent"
args.aoe_damage_value = const.Weapons.ShotgunCollateralDamage
args.consumed_ammo = 2
args.damage_bonus = const.Weapons.DoubleBarrelDamageBonus
args.buckshot_scatter_fx = 10
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return 2
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not weapon or not weapon.ammo or weapon.ammo.Amount < 2 then
return "disabled", AttackDisableReasons.InsufficientAmmo
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/double_barrel",
IconFiringMode = "UI/Hud/fm_double_barrel",
IdDefault = "DoubleBarreldefault",
IsTargetableAttack = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "bullets",
'Value', 2,
'Tag', "<bullets>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 1,
UIBegin = function (self, units, args)
local dlg = GetInGameInterfaceModeDlg()
if IsKindOf(dlg, "IModeCombatAreaAim") and dlg.crosshair then
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "attack")
else
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end
end,
basicAttack = true,
group = "WeaponAttacks",
id = "DoubleBarrel",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
Comment = "HeavyWeaponAttack",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(950970877551, --[[CombatAction GrenadeLauncherFire Description]] "Blasts enemies in the area of effect. Inflicts additional status effects based on grenade type."),
DisplayName = T(636102722781, --[[CombatAction GrenadeLauncherFire DisplayName]] "Launch Grenade"),
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
return unit:GetAttackAPCost(self, weapon, false, 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if weapon and IsKindOf(weapon.ammo, "Ordnance") then
return weapon.ammo.BaseDamage
end
return 0
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = unit and self:GetAttackWeapons(unit)
if weapon then
return T{self.Description, damage = weapon:GetBaseDamage()}
end
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return description
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
local target = ResolveGrenadeTargetPos(args.target)
local ammos = weapon and unit:GetAvailableAmmos(weapon, nil, "unique")
if not weapon or not target or not ammos then
return {}
end
local args = table.copy(args)
args.weapon = weapon
args.target = target
args.ordnance = args.ordnance or ammos[1]
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("HeavyWeapon")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return "hidden" end
if not weapon.ammo or weapon.ammo.Amount < 1 then
return "disabled", AttackDisableReasons.OutOfAmmo
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/heavy_weapon_attack",
IdDefault = "GrenadeLauncherFiredefault",
KeybindingFromAction = "actionRedirectHeavyAttack",
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("HeavyWeaponAttack", self.id, ap, ...)
end,
SortKey = 1,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "WeaponAttacks",
id = "GrenadeLauncherFire",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
Comment = "-> AttackDual FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(533333504738, --[[CombatAction LeftHandShot Description]] "Cheap attack with your left-hand weapon that conserves ammo."),
DisplayName = T(458191457929, --[[CombatAction LeftHandShot DisplayName]] "Left Hand Shot"),
DisplayNameShort = T(158585226110, --[[CombatAction LeftHandShot DisplayNameShort]] "Left Hand"),
FiringModeMember = "AttackDual",
GetAPCost = function (self, unit, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
if not w2Attack then return -1 end
args = args and table.copy(args) or {}
args.weapon = weapon2
return w2Attack:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
args = args or {}
args.weapon = weapon2
local dmg, base, bonus, params = w2Attack:GetActionDamage(unit, target, args)
args.weapon = false
return dmg, base, bonus, params
end,
GetActionDescription = function (self, units)
local w1Attack, w2Attack = GetDualShotAttacks(units[1])
return w2Attack:GetActionDescription(units)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(unit)
args = args or {}
args.weapon = weapon2
local result, att_args = w2Attack:GetActionResults(unit, args)
args.weapon = false
return result, att_args
end,
GetAttackWeapons = function (self, unit, args)
local weapon1, weapon2 = unit:GetActiveWeapons("Firearm", "strict")
return weapon2
end,
GetUIState = function (self, units, args)
local w1Attack, w2Attack, weapon1, weapon2 = GetDualShotAttacks(units[1])
if not w1Attack then return "hidden" end
local enable, reason = units[1]:CanUseWeapon(weapon2)
if not enable then
return "disabled", reason
end
args = args or {}
args.weapon = weapon2
local uiState = w2Attack:GetUIState(units, args)
args.weapon = false
return uiState
end,
Icon = "UI/Icons/Hud/attack",
IconFiringMode = "UI/Hud/fm_left_hand_shot",
IdDefault = "LeftHandShotdefault",
IsTargetableAttack = true,
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "LeftHandShot",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
Comment = "HeavyWeaponAttack",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(393692003865, --[[CombatAction RocketLauncherFire Description]] "Blasts enemies in the area of effect. Inflicts additional status effects based on the rocket type."),
DisplayName = T(259883670447, --[[CombatAction RocketLauncherFire DisplayName]] "Launch Rocket"),
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
return unit:GetAttackAPCost(self, weapon, false, 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if weapon and IsKindOf(weapon.ammo, "Ordnance") then
return weapon.ammo.BaseDamage
end
return 0
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = unit and self:GetAttackWeapons(unit)
if weapon then
return T{self.Description, damage = weapon:GetBaseDamage()}
end
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return description
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
local target = ResolveGrenadeTargetPos(args.target)
local ammos = weapon and unit:GetAvailableAmmos(weapon, nil, "unique")
if not weapon or not target or not ammos then
return {}
end
local args = table.copy(args)
args.weapon = weapon
args.target = args.target or target
args.ordnance = args.ordnance or ammos[1]
args.target_height_range = guim
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("HeavyWeapon")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return "hidden" end
if not weapon.ammo or weapon.ammo.Amount < 1 then
return "disabled", AttackDisableReasons.OutOfAmmo
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/heavy_weapon_attack",
IdDefault = "RocketLauncherFiredefault",
KeybindingFromAction = "actionRedirectHeavyAttack",
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("HeavyWeaponAttack", self.id, ap, ...)
end,
SortKey = 1,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "WeaponAttacks",
id = "RocketLauncherFire",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPoints = 3000,
ActionType = "Ranged Attack",
Comment = "-> Attack FiringMode",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(838141287304, --[[CombatAction BurstFire Description]] "Shoots <em><num> bullets</em> at the target. Lower accuracy against distant enemies."),
DisplayName = T(885711257338, --[[CombatAction BurstFire DisplayName]] "Burst Fire"),
DisplayNameShort = T(421007639739, --[[CombatAction BurstFire DisplayNameShort]] "Burst"),
Execute = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
args.num_shots = weapon:GetAutofireShots(self)
args.multishot = true
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
FiringModeMember = "Attack",
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and (unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0) + self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit and unit:GetBaseDamage(weapon) or weapon.Damage
local penalty = self:ResolveValue("dmg_penalty")
local num_shots = weapon:GetAutofireShots(self)
base = MulDivRound(base, Max(0, 100 + penalty), 100)
local damage = num_shots*base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local description = self.Description
local unit = units and units[1]
if not unit then
return self:GetActionDisplayName()
end
local weapon = self:GetAttackWeapons(unit)
-- replace description when using Revolver
if IsKindOf(weapon, "Revolver") then
description = CombatActions.Fanning.Description
end
local damage, base, bonus = self:GetActionDamage(unit)
local num_shots = weapon:GetAutofireShots(self)
local descr = T{description, num = num_shots, damage = base}
return CombatActionsAppendFreeAimDescription(self, unit, descr)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
-- replace name when using Revolver
local unit = units and units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if IsKindOf(weapon, "Revolver") then
name = CombatActions.Fanning.DisplayName
end
end
if (name or "") == "" then
name = Untranslated(self.id)
end
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionIcon = function (self, units)
-- replace icon when using Revolver
local unit = units and units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if IsKindOf(weapon, "Revolver") then
return CombatActions.Fanning.Icon
end
end
return self.Icon
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.weapon = self:GetAttackWeapons(unit, args)
args.num_shots = args.num_shots or args.weapon and args.weapon:GetAutofireShots(self)
args.multishot = true
args.damage_bonus = self:ResolveValue("dmg_penalty")
--args.cth_loss_per_shot = self:ResolveValue("cth_loss_per_shot")
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon, _, list = unit:GetActiveWeapons("Firearm")
return weapon
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
local num_shots = weapon:GetAutofireShots(self)
if not weapon.ammo or weapon.ammo.Amount < num_shots then
return "disabled", AttackDisableReasons.InsufficientAmmo
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/burst_fire",
IconFiringMode = "UI/Hud/fm_burst_fire",
IdDefault = "BurstFiredefault",
IsTargetableAttack = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 3,
'Tag', "<num_shots>",
}),
PlaceObj('PresetParamPercent', {
'Name', "cth_loss_per_shot",
'Tag', "<cth_loss_per_shot>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "dmg_penalty",
'Value', -50,
'Tag', "<dmg_penalty>%",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 2,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "BurstFire",
})
PlaceObj('CombatAction', {
ActionType = "Melee Attack",
AimType = "melee",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(892145930253, --[[CombatAction MeleeAttack Description]] "If the enemy is in cover, they will become <GameTerm('Exposed')>."),
DisplayName = T(318246892071, --[[CombatAction MeleeAttack DisplayName]] "Melee strike"),
EvalTarget = function (self, units, target, args)
local unit = units[1]
if (not args or not args.goto_pos) and (not IsValid(target) or not unit:GetClosestMeleeRangePos(target)) then
return 0
end
return unit:CalcChanceToHit(target, self, args)
end,
GetAPCost = function (self, unit, args)
return GetMeleeAttackAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, damage, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionDescription(units)
end
local damage, base, bonus = self:GetActionDamage(unit)
local descr
if LastLoadedOrLoadingIMode == "IModeCombatMelee" then
descr = T{652639293521, "Select a unit to attack.", damage = damage}
else
descr = T{self.Description, damage = damage, basedamage = base, bonusdamage = bonus}
end
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionDisplayName(units)
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionIcon = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionIcon(units)
end
return self.Icon
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
args.weapon = self:GetAttackWeapons(unit, args)
if IsKindOf(args.weapon, "GutHookKnife") then
args.applied_status = { "Bleeding" }
end
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
return CombatActionGetOneAttackableEnemy(self, unit, nil, CombatActionTargetFilters.MeleeAttack, unit)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("MeleeWeapon")
end,
GetDefaultTarget = function (self, unit)
local units = {unit}
local targets = self:GetTargets(units)
local weapon = self:GetAttackWeapons(unit)
local nearest, min_dist
for _, target in ipairs(targets) do
if unit:IsOnEnemySide(target) and HasVisibilityTo(unit.team, target) then
local pos = unit:GetClosestMeleeRangePos(target)
local dist
if not g_Combat or unit:CanAttack(target, weapon, self, 0, pos) then
dist = pos and unit:GetDist(pos)
end
if dist and (not min_dist or dist < min_dist) then
nearest, min_dist = target, dist
end
end
end
return nearest, min_dist
end,
GetTargets = function (self, units)
local unit = units[1]
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.MeleeAttack, unit)
end,
GetUIState = function (self, units, args)
local unit = units[1]
args = args or {}
args.ap_cost_breakdown = args.ap_cost_breakdown or {}
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost, self.id, args) then
return "disabled", AttackDisableReasons.NoAP
end
return "enabled"
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "MeleeAttackdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MoveStep = true,
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MeleeAttack", self.id, ap, ...)
end,
SortKey = 2,
StealthAttack = true,
UIBegin = function (self, units, args)
if not args or not args.free_aim then
local action = GetMeleeAttackAction(self, units[1])
if action ~= self and action:GetUIState(units) == "enabled" then
return action:UIBegin(units, args)
end
end
CombatActionAttackStart(self, units, args, "IModeCombatMelee", "attack")
end,
UseFreeMove = true,
basicAttack = true,
group = "WeaponAttacks",
id = "MeleeAttack",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Ranged Attack",
AimType = "mobile",
CostBasedOnWeapon = true,
Description = T(978968390011, --[[CombatAction MobileShot Description]] "<em>Once per turn</em>.\nMove to a new location and then shoot the closest enemy."),
DisplayName = T(755564702219, --[[CombatAction MobileShot DisplayName]] "Mobile Shot"),
GetActionDamage = function (self, unit, target, args)
local rangedAttack = unit:GetDefaultAttackAction("ranged")
return rangedAttack:GetActionDamage(unit, target, args)
end,
GetActionDescription = function (self, units)
local description = self.Description
local unit = units and units[1]
if not unit then
return self:GetActionDisplayName()
end
local damage, base, bonus = self:GetActionDamage(unit)
return T{description, damage = damage, basedamage = base, bonusdamage = bonus}
end,
GetActionResults = function (self, unit, args)
return GetMobileShotResults(self, unit, args)
end,
GetAnyTarget = function (self, units)
return self:GetTargets(units)[1]
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon = unit:GetActiveWeapons("Firearm")
return weapon -- make sure to return only 1 weapon, the attack doesn't use 2
end,
GetTargets = function (self, units)
local unit = units[1]
if unit then
return GetEnemies(unit)
end
return {}
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/mobile_shot",
IdDefault = "MobileShotdefault",
IsAimableAttack = false,
KeybindingSortId = "2371",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "mobile_move_ap",
'Value', 8,
'Tag', "<mobile_move_ap>",
}),
PlaceObj('PresetParamNumber', {
'Name', "cooldown",
'Tag', "<cooldown>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("RunAndGun", self.id, ap, ...)
end,
SortKey = 2,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatMovingAttack")
end,
group = "WeaponAttacks",
id = "MobileShot",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = 2000,
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "mobile",
CostBasedOnWeapon = true,
Description = T(986970516880, --[[CombatAction RunAndGun Description]] "<em>Once per turn</em>.\nMove to a new position. Fire up to <em><num_shots> bursts</em> during movement toward the closest enemies. Each shot suffers <em>-<percent(penalty)> Accuracy</em> penalty."),
DisplayName = T(624088050886, --[[CombatAction RunAndGun DisplayName]] "Run and Gun"),
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local damage = unit:GetBaseDamage(weapon)
local num_shots = self:ResolveValue("mobile_num_shots")
return damage, damage / num_shots, 0
end,
GetActionDescription = function (self, units)
local description = self.Description
local unit = units and units[1]
if not unit then
return self:GetActionDisplayName()
end
local damage, base, bonus = self:GetActionDamage(unit)
local num_shots = self:ResolveValue("mobile_num_shots")
local penalty = Presets.ChanceToHitModifier.Default.RunAndGun:ResolveValue("Penalty")
description = T{description, damage = damage, basedamage = base, bonusdamage = bonus, num_shots = num_shots, penalty = penalty}
if unit.stance ~= "Standing" then
description = description .. T(801805830695, "<newline>You will end up in Standing stance.")
end
return description
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit)
args.attack_id = "BurstFire"
args.num_shots = weapon and weapon:GetAutofireShots("BurstFire") or CombatActions.BurstFire:ResolveValue("num_shots")
args.multishot = true
return GetMobileShotResults(self, unit, args)
end,
GetAnyTarget = function (self, units)
return self:GetTargets(units)[1]
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon = unit:GetActiveWeapons("Firearm")
return weapon -- make sure to return only 1 weapon, the attack doesn't use 2
end,
GetTargets = function (self, units)
local unit = units[1]
if unit then
return GetEnemies(unit)
end
return {}
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/run_and_gun",
IdDefault = "RunAndGundefault",
IsAimableAttack = false,
KeybindingSortId = "2372",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "mobile_move_ap",
'Value', 8,
'Tag', "<mobile_move_ap>",
}),
PlaceObj('PresetParamNumber', {
'Name', "cooldown",
'Tag', "<cooldown>",
}),
PlaceObj('PresetParamNumber', {
'Name', "mobile_num_shots",
'Value', 3,
'Tag', "<mobile_num_shots>",
}),
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 9,
'Tag', "<num_shots>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("RunAndGun", self.id, ap, ...)
end,
SortKey = 2,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatMovingAttack")
end,
group = "WeaponAttacks",
id = "RunAndGun",
})
PlaceObj('CombatAction', {
ActionType = "Melee Attack",
AimType = "melee",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(307739610044, --[[CombatAction UnarmedAttack Description]] "If the enemy is in cover, they will become <GameTerm('Exposed')>. Enemies have a chance to be knocked <GameTerm('Prone')>."),
DisplayName = T(878149704237, --[[CombatAction UnarmedAttack DisplayName]] "Punch"),
EvalTarget = function (self, units, target, args)
return CombatActions.MeleeAttack.EvalTarget(self, units, target, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
if not args.goto_pos then
args.goto_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.stance = "Standing"
CombatActionExecuteWithMove(self, unit, args)
end,
GetAPCost = function (self, unit, args)
return GetMeleeAttackAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, damage, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionDescription(units)
end
local damage, base, bonus = self:GetActionDamage(unit)
local descr
if LastLoadedOrLoadingIMode == "IModeCombatMelee" then
descr = T{315652693177, "Select a unit to punch.", damage = damage}
else
descr = T{self.Description, damage = damage, basedamage = base, bonusdamage = bonus}
end
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionDisplayName(units)
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionIcon = function (self, units)
local unit = units[1]
local action = GetMeleeAttackAction(self, unit)
if action ~= self and action:GetUIState(units) == "enabled" then
return action:GetActionIcon(units)
end
return self.Icon
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
return CombatActions.MeleeAttack.GetAnyTarget(self, units)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetActiveWeapons("UnarmedWeapon")
end,
GetDefaultTarget = function (self, unit)
return CombatActions.MeleeAttack.GetDefaultTarget(self, unit)
end,
GetTargets = function (self, units)
return CombatActions.MeleeAttack.GetTargets(self, units)
end,
GetUIState = function (self, units, args)
local unit = units[1]
args = args or {}
args.ap_cost_breakdown = args.ap_cost_breakdown or {}
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost, self.id, args) then
return "disabled", AttackDisableReasons.NoAP
end
return "enabled"
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "UnarmedAttackdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MeleeAttack", self.id, ap, ...)
end,
SortKey = 2,
StealthAttack = true,
UIBegin = function (self, units, args)
return CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
UseFreeMove = true,
basicAttack = true,
group = "WeaponAttacks",
id = "UnarmedAttack",
})
PlaceObj('CombatAction', {
ActionPoints = 10000,
ActionType = "Ranged Attack",
AimType = "line",
Comment = "-> Attack FiringMode",
ConfigurableKeybind = false,
Description = T(393518976346, --[[CombatAction AutoFire Description]] "<em>Spends all AP</em>.\nShoots a hail of <em><bullets> bullets</em> and inflict <GameTerm('Suppressed')> even on miss when the enemy is in weapon range. Lower accuracy against distant enemies."),
DisplayName = T(847115637646, --[[CombatAction AutoFire DisplayName]] "Auto Fire"),
DisplayNameShort = T(810267106493, --[[CombatAction AutoFire DisplayNameShort]] "Auto"),
Execute = function (self, units, args)
local unit = units[1]
args.multishot = true
local weapon = self:GetAttackWeapons(unit, args)
args.num_shots = weapon:GetAutofireShots(self)
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
FiringModeMember = "Attack",
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon or not weapon:CanAutofire() then
return -1
end
return unit:GetMaxActionPoints()
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local penalty = self:ResolveValue("dmg_penalty")
local num_shots = weapon:GetAutofireShots(self)
base = MulDivRound(base, Max(0, 100 + penalty), 100)
local damage = num_shots*base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
local damage, base, bonus = self:GetActionDamage(unit)
local params = weapon:GetAreaAttackParams("AutoFire")
local descr = T{self.Description, damage = base, bullets = weapon:GetAutofireShots(self)}
return CombatActionsAppendFreeAimDescription(self, unit, descr)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.applied_status = "Suppressed"
args.multishot = true
args.weapon = self:GetAttackWeapons(unit, args)
args.num_shots = args.num_shots or args.weapon and args.weapon:GetAutofireShots(self)
--args.single_fx = true
--args.fx_action = "WeaponAutoFire"
args.damage_bonus = self:ResolveValue("dmg_penalty")
--args.cth_loss_per_shot = self:ResolveValue("cth_loss_per_shot")
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
local target = attack_args.target
if results.miss and not attack_args.stuck and IsKindOf(target, "Unit") and IsValidTarget(target) then
local target_dist = unit:GetDist(target)
local weapon = attack_args.weapon
if target_dist <= weapon.WeaponRange * const.SlabSizeX then
local flight_dist = 0
for _, shot in ipairs(results.shots) do
for _, hit in ipairs(shot.hits) do
flight_dist = Max(flight_dist, shot.attack_pos:Dist(hit.pos))
end
end
flight_dist = flight_dist / const.SlabSizeX
target_dist = target_dist / const.SlabSizeX
if flight_dist >= target_dist - 1 then
results.extra_packets = results.extra_packets or {}
table.insert(results.extra_packets, {target = target, effects = "Suppressed"})
end
end
end
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon, _, list = unit:GetActiveWeapons("Firearm")
return weapon
end,
GetUIState = function (self, units, args)
local state, err = CombatActionGenericAttackGetUIState(self, units, args)
if state ~= "enabled" then return state, err end
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
local autoFire_ammo = weapon:GetAutofireShots(self)
if not weapon.ammo or weapon.ammo.Amount < autoFire_ammo then
return "disabled", AttackDisableReasons.InsufficientAmmo
end
return "enabled"
end,
Icon = "UI/Icons/Hud/full_auto",
IconFiringMode = "UI/Hud/fm_autoshot",
IdDefault = "AutoFiredefault",
IsAimableAttack = false,
IsTargetableAttack = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "cth_loss_per_shot",
'Tag', "<cth_loss_per_shot>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "dmg_penalty",
'Value', -80,
'Tag', "<dmg_penalty>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 15,
'Tag', "<num_shots>",
}),
},
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 3,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
basicAttack = true,
group = "WeaponAttacks",
id = "AutoFire",
})
PlaceObj('CombatAction', {
ActionPointDelta = 2000,
ActionPoints = 6000,
ActionType = "Ranged Attack",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(362787141601, --[[CombatAction CancelShot Description]] "Does not provoke <GameTerm('Interrupt')> <em>attacks</em>.\nRemoves <GameTerm('Overwatch')> and <GameTerm('PinDown')> on hit."),
DisplayName = T(984858495047, --[[CombatAction CancelShot DisplayName]] "Distracting Shot"),
EvalTarget = function (self, units, target, args)
--return units[1]:CalcChanceToHit(target, self, args, "chance_only")
if not units or not units[1] then return 0 end
local unitList = g_unitOrder[units[1]]
if not unitList then return 0 end
local orderIdx = unitList[target]
local value = orderIdx and -orderIdx or 0
return value
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
local damage = unit and unit:GetBaseDamage(weapon)
return T{self.Description, damage = damage}
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.applied_status = "CancelShot"
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local w1 = unit:GetActiveWeapons("Firearm", "HeavyWeapon")
return w1
end,
GetDefaultTarget = function (self, unit)
local units = {unit}
local targets = self:GetTargets(units)
local distance_to_best = 10000*guim
local best_eval, best_target, best_prep = 0, false, false
for _, target in ipairs(targets or empty_table) do
local eval = self:EvalTarget(units, target)
local prep = target:HasPreparedAttack()
local dist = IsKindOf(target, "Unit") and unit:GetDist(target) or 0
if not best_target or (not best_prep and prep) then
best_target, best_eval, best_prep, distance_to_best = target, eval, prep, dist
elseif best_prep == prep then
if eval > best_eval or (eval == best_eval and dist < distance_to_best) then
best_target, best_eval, best_prep, distance_to_best = target, eval, prep, dist
end
end
end
return best_target, best_eval
end,
GetUIState = function (self, units, args)
local unit = units[1]
if not HasPerk(unit, "CancelShotPerk") then
return "hidden"
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/distracting_shot",
IdDefault = "CancelShotdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectCancelShot",
MultiSelectBehavior = "first",
RequireState = "any",
RequireTargets = true,
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 3,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "WeaponAttacks",
id = "CancelShot",
})
PlaceObj('CombatAction', {
ActionPointDelta = 2000,
ActionType = "Ranged Attack",
AimType = "cone",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(551145852969, --[[CombatAction CancelShotCone Description]] "Does not provoke <GameTerm('Interrupt')> <em>attacks</em>.\nRemoves <GameTerm('Overwatch')> and <GameTerm('PinDown')> on hit."),
DisplayName = T(415284687953, --[[CombatAction CancelShotCone DisplayName]] "Distracting Shot"),
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
local base = weapon and unit:GetBaseDamage(weapon) or 0
return MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local aoedamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)
local descr = T{self.Description, damage = base, aoedamage = MulDivRound(base, const.Weapons.ShotgunCollateralDamage, 100)}
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
if not args.target_spot_group then
args.num_shots = 0
end
args.fx_action = "WeaponBuckshot"
args.aoe_action_id = self.id
args.aoe_damage_type = "percent"
args.aoe_damage_value = const.Weapons.ShotgunCollateralDamage
args.buckshot_scatter_fx = 10
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
-- make sure the fx action plays
local shots = results.attacks and results.attacks[1].shots or empty_table
if #shots == 0 then
attack_args.aoe_fx_action = "WeaponBuckshot"
end
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return 2
end,
GetUIState = function (self, units, args)
local unit = units[1]
if not HasPerk(unit, "CancelShotPerk") then
return "hidden"
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/distracting_shot",
IdDefault = "CancelShotConedefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectCancelShot",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
SortKey = 3,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "WeaponAttacks",
id = "CancelShotCone",
})
PlaceObj('CombatAction', {
ActionPointDelta = 3000,
ActionPoints = 7000,
ActionType = "Melee Attack",
AimType = "melee-charge",
CostBasedOnWeapon = true,
Description = T(839516433881, --[[CombatAction Charge Description]] "Minimum Range: <em><minDistance></em>\nAll targets in cover are <GameTerm('Exposed')>.\nMove in a straight line and attack the selected target for <em><damage> damage</em>."),
DisplayName = T(997748923990, --[[CombatAction Charge DisplayName]] "Charge"),
EvalTarget = function (self, units, target, args)
local unit = units[1]
if (not args or not args.goto_pos) and (not IsValid(target) or not unit:GetClosestMeleeRangePos(target)) then
return 0
end
return unit:CalcChanceToHit(target, self, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
if not args.goto_pos then
args.goto_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.available_move_ap = self:ResolveValue("move_ap") * const.Scale.AP
CombatActionExecuteWithMove(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, damage, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local damage, base, bonus = self:GetActionDamage(unit)
if LastLoadedOrLoadingIMode == "IModeCombatMelee" then
return T{873047291313, "Select a unit to charge.", damage = damage}
end
return T{self.Description, self, damage = damage, basedamage = base, bonusdamage = bonus}
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
-- distance-based bonus damage
local max_dist = self:ResolveValue("max_damage_dist") * const.SlabSizeX
local max_bonus = self:ResolveValue("max_damage_bonus")
local dist = Min(unit:GetDist(args.target), max_dist)
args.damage_bonus = MulDivRound(max_bonus, dist, max_dist)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetOneAttackableEnemy(self, unit, nil, CombatActionTargetFilters.Charge, unit, move_ap, self.id)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("MeleeWeapon")
end,
GetDefaultTarget = function (self, unit)
local best_eval, best_target
local units = {unit}
local targets = self:GetTargets(units)
for _, target in ipairs(targets or empty_table) do
local cost = self:GetAPCost(unit, { target = target })
if unit:UIHasAP(cost) then
local eval = self:EvalTarget(units, target)
if not best_eval or eval > best_eval then
best_target, best_eval = target, eval
end
end
end
return best_target, best_eval
end,
GetTargets = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.Charge, unit, move_ap, self.id)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "hidden" end
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
if unit.stance ~= "Standing" then
return "disabled", AttackDisableReasons.OnlyStanding
end
local ap = self:GetAPCost(unit, args)
if not unit:UIHasAP(ap) then return "disabled", GetUnitNoApReason(unit) end
if not self:GetAnyTarget(units) then
return "disabled", AttackDisableReasons.NoTarget
end
return "enabled"
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "Chargedefault",
IsAimableAttack = false,
KeybindingSortId = "2380",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "move_ap",
'Value', 10,
'Tag', "<move_ap>",
}),
PlaceObj('PresetParamPercent', {
'Name', "max_damage_bonus",
'Value', 50,
'Tag', "<max_damage_bonus>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "max_damage_dist",
'Value', 6,
'Tag', "<max_damage_dist>",
}),
PlaceObj('PresetParamNumber', {
'Name', "minDistance",
'Value', 2,
'Tag', "<minDistance>",
}),
PlaceObj('PresetParamNumber', {
'Name', "minAngle",
'Value', 150,
'Tag', "<minAngle>",
}),
},
RequireState = "any",
RequireTargets = true,
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ChargeAttack", self.id, ap, ...)
end,
SortKey = 3,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatCharge")
end,
group = "WeaponAttacks",
id = "Charge",
})
PlaceObj('CombatAction', {
ActionPoints = 3000,
ActionType = "Ranged Attack",
AimType = "parabola aoe",
ConfigurableKeybind = false,
Description = T(261122276696, --[[CombatAction FireFlare Description]] "Shoot a Flare in the sky that illuminates the selected area. "),
DisplayName = T(961636210046, --[[CombatAction FireFlare DisplayName]] "Signal Flare"),
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
return unit:GetAttackAPCost(self, weapon, false, 0) or -1
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = unit and self:GetAttackWeapons(unit)
if weapon then
return T{self.Description, damage = weapon:GetBaseDamage()}
end
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return description
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
local target = ResolveGrenadeTargetPos(args.target)
local ammos = weapon and unit:GetAvailableAmmos(weapon, nil, "unique")
if not weapon or not target or not ammos then
return {}
end
local args = table.copy(args)
args.weapon = weapon
args.target = target
args.ordnance = args.ordnance or ammos[1]
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("FlareGun")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/fire_flare",
IdDefault = "FireFlaredefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FireFlare", self.id, ap, ...)
end,
SortKey = 3,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "WeaponAttacks",
id = "FireFlare",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Melee Attack",
AimType = "melee",
Comment = "Used by crocodile animal units granted by the CrocodileJaws weapon",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(107890223879, --[[CombatAction CrocodileBite DisplayName]] "Bite"),
Execute = function (self, units, args)
CombatActions.MeleeAttack.Execute(self, units, args)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "CrocodileBitedefault",
IsAimableAttack = false,
MultiSelectBehavior = "hidden",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MeleeAttack", self.id, ap, ...)
end,
SortKey = 4,
UIBegin = function (self, units, args)
CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
group = "WeaponAttacks",
id = "CrocodileBite",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Melee Attack",
AimType = "melee",
Comment = "Used by hyena animal units granted by the HyenaJaws weapon",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(107890223879, --[[CombatAction HyenaBite DisplayName]] "Bite"),
Execute = function (self, units, args)
CombatActions.MeleeAttack.Execute(self, units, args)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "HyenaBitedefault",
IsAimableAttack = false,
MultiSelectBehavior = "hidden",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MeleeAttack", self.id, ap, ...)
end,
SortKey = 4,
UIBegin = function (self, units, args)
CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
group = "WeaponAttacks",
id = "HyenaBite",
})
PlaceObj('CombatAction', {
ActionPoints = 5000,
ActionType = "Melee Attack",
AimType = "melee-charge",
Comment = "Used by hyena animal units",
ConfigurableKeybind = false,
DisplayName = T(617452697208, --[[CombatAction HyenaCharge DisplayName]] "Charge"),
Execute = function (self, units, args)
CombatActions.Charge.Execute(self, units, args)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.applied_status = "KnockDown"
args.move_ap = self:ResolveValue("move_ap") * const.Scale.AP
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetOneAttackableEnemy(self, unit, nil, CombatActionTargetFilters.HyenaCharge, unit, move_ap, false, self.id)
end,
GetTargets = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.HyenaCharge, unit, move_ap, false, self.id)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "hidden" end
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
local ap = self:GetAPCost(unit, args)
if not unit:UIHasAP(ap) then return "disabled", GetUnitNoApReason(unit) end
if not self:GetAnyTarget(units) then
return "disabled", AttackDisableReasons.NoTarget
end
return "enabled"
end,
Icon = "UI/Icons/Hud/melee",
IdDefault = "HyenaChargedefault",
IsAimableAttack = false,
MultiSelectBehavior = "hidden",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "move_ap",
'Value', 100,
'Tag', "<move_ap>",
}),
PlaceObj('PresetParamNumber', {
'Name', "minAngle",
'Value', 150,
'Tag', "<minAngle>",
}),
PlaceObj('PresetParamNumber', {
'Name', "minDistance",
'Value', 1,
'Tag', "<minDistance>",
}),
PlaceObj('PresetParamNumber', {
'Name', "maxDistance",
'Value', 2,
'Tag', "<maxDistance>",
}),
},
Run = function (self, unit, ap, ...)
unit:SetActionCommand("HyenaCharge", self.id, ap, ...)
end,
SortKey = 4,
UIBegin = function (self, units, args)
CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
group = "WeaponAttacks",
id = "HyenaCharge",
})
PlaceObj('CombatAction', {
ActionPoints = 5000,
ActionType = "Melee Attack",
AimType = "melee",
Description = T(647630380410, --[[CombatAction Brutalize Description]] "<em>Spends all AP</em>\nDeliver a series of attacks against random body parts. Cannot be targeted or aimed. These attacks are slightly less accurate than normal attacks. If the enemy is in cover, they will become <GameTerm('Exposed')>.\n\n<em><attacks></em> attacks."),
DisplayName = T(506780540915, --[[CombatAction Brutalize DisplayName]] "Brutalize"),
EvalTarget = function (self, units, target, args)
return CombatActions.MeleeAttack.EvalTarget(self, units, target, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
local ap = self:GetAPCost(unit, args)
args.num_attacks = unit:GetNumBrutalizeAttacks(args.goto_pos)
args.stance = "Standing"
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return Max(unit:GetUIActionPoints(), GetMeleeAttackAPCost(self, unit, args))
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
if unit then
local max = unit:GetNumBrutalizeAttacks()
local attacks = 3
if max > 3 then
attacks = T{516692960914, "<min>-<max>", min = 3, max = max}
end
return T{self.Description, attacks = attacks}
end
return self.Description
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.weapon = self:GetAttackWeapons(unit, args)
args.num_shots = 0
if IsKindOf(args.weapon, "GutHookKnife") then
args.applied_status = { "Bleeding" }
end
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
return CombatActions.MeleeAttack.GetAnyTarget(self, units)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon = unit:GetActiveWeapons("MeleeWeapon") or unit:GetActiveWeapons("UnarmedWeapon")
return weapon
end,
GetDefaultTarget = function (self, unit)
return CombatActions.MeleeAttack.GetDefaultTarget(self, unit)
end,
GetTargets = function (self, units)
return CombatActions.MeleeAttack.GetTargets(self, units)
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
local attacker = units[1]
local no_target = true
for _, u in ipairs(g_Units) do
if CombatActionTargetFilters.MeleeAttack(u, attacker) then
no_target = false
break
end
end
if no_target then
return "disabled", AttackDisableReasons.NoTarget
end
return CombatActions.MeleeAttack.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/brutalize_attack",
IdDefault = "Brutalizedefault",
IsAimableAttack = false,
KeybindingSortId = "2376",
MoveStep = true,
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("Brutalize", self.id, ap, ...)
end,
SortKey = 6,
UIBegin = function (self, units, args)
return CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
UseFreeMove = true,
group = "WeaponAttacks",
id = "Brutalize",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
CostBasedOnWeapon = true,
Description = T(662192145975, --[[CombatAction KnifeThrow Description]] "<em>Silent</em> ranged attack with a Knife. You can retrieve the knife afterwards."),
DisplayName = T(201038143523, --[[CombatAction KnifeThrow DisplayName]] "Throw Knife"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local weapon1= self:GetAttackWeapons(unit, args)
if not weapon1 or not weapon1.CanThrow then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local _, _, _, params = self:GetActionDamage(unit)
local descr = T{self.Description, damage = GetDamageRangeText(params.min, params.max), crit = params.critChance}
descr = CombatActionsAppendFreeAimDescription(self, unit, descr)
return descr
end,
GetActionResults = function (self, unit, args)
args = args or {}
if unit.stance == "Prone" then
args.stance = "Standing"
end
local attack_args = unit:PrepareAttackArgs(self.id, args)
if not attack_args.weapon then
return {}, attack_args
end
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
if not weapon then return {} end
local range = self:GetMaxAimRange(unit, weapon) * const.SlabSizeX
return CombatActionGetOneAttackableEnemy(self, units, nil, CombatActionTargetFilters.KnifeThrow, unit, range)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetThrowableKnife()
end,
GetMaxAimRange = function (self, unit, weapon)
local maxRange = weapon.WeaponRange
if HasPerk(unit, "Throwing") then
maxRange = maxRange + CharacterEffectDefs.Throwing:ResolveValue("RangeIncrease")
end
return maxRange
end,
GetTargets = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
if not weapon then return {} end
local range = self:GetMaxAimRange(unit, weapon) * const.SlabSizeX
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.KnifeThrow, unit, range)
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/throw_knife",
IdDefault = "KnifeThrowdefault",
IsTargetableAttack = true,
KeybindingSortId = "2375",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ThrowKnife", self.id, ap, ...)
end,
SortKey = 7,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "WeaponAttacks",
id = "KnifeThrow",
})
PlaceObj('CombatAction', {
Comment = "stub action for the Fanning attack; only texts/icon are used",
Description = T(488417500972, --[[CombatAction Fanning Description]] "Shoots <em><num> bullets</em> at slightly increased AP cost. Lower accuracy against distant enemies."),
DisplayName = T(386523063486, --[[CombatAction Fanning DisplayName]] "Fanning"),
Icon = "UI/Icons/Hud/burst_fire",
IdDefault = "Fanningdefault",
IsTargetableAttack = true,
RequireState = "any",
ShowIn = false,
group = "Default",
id = "Fanning",
})
PlaceObj('CombatAction', {
ActionPoints = 1000,
ActivePauseBehavior = "queue",
DisplayName = T(796190228832, --[[CombatAction Move DisplayName]] "Move"),
GetAPCost = function (self, unit, args)
if not g_Combat then return 0 end
if unit:HasStatusEffect("StationedMachineGun") or unit:HasStatusEffect("ManningEmplacement") then return -1 end
local stance = args and args.stance
local pos = args and args.goto_pos
if not pos then return -1 end
local startStance = args and args.stanceAtStart
local endStance = args and args.stanceAtEnd
local move_ap = args and args.available_move_ap or unit.ActionPoints
local combatPath = GetCombatPath(unit, startStance or stance, move_ap, endStance or stance)
local apCost = combatPath:GetAP(pos, endStance or stance)
if not apCost or apCost == -1 then return -1 end
return apCost
end,
GetTargets = function (self, units)
return units[1]:GetVisibleEnemies()
end,
GetUIState = function (self, units, args)
local unit = units[1]
if args then
local cost = self:GetAPCost(unit, args)
if cost < 0 then
return "hidden"
end
if not unit:UIHasAP(cost, self.id) then
return "disabled"
end
end
if g_Combat then
if unit:HasStatusEffect("StationedMachineGun") then
return "hidden"
elseif unit:HasStatusEffect("ManningEmplacement") then
return "hidden"
elseif unit:HasPreparedAttack() then
return "hidden"
end
end
if unit:GetBandageTarget() or unit:IsBeingBandaged() then
return "hidden"
end
return "enabled"
end,
Icon = "UI/Icons/Hud/placeholder",
IdDefault = "Movedefault",
InterruptInExploration = true,
IsAimableAttack = false,
MultiSelectBehavior = "hidden",
QueuedBadgeText = T(954873063444, --[[CombatAction Move QueuedBadgeText]] "MOVE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
if g_Combat then
unit:SetActionCommand("CombatGoto", self.id, ap, args.goto_pos, args.path, args.forced_run, args.stanceAtStart, args.stanceAtEnd, args.willBeTracked, args.visibleMovement)
else
unit:InterruptCommand("GotoSlab", args.goto_pos, nil, nil, args.move_type, args.follow_target)
end
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Default",
id = "Move",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(219233654993, --[[CombatAction ReloadMultiSelection Description]] "Reload ammunition for all selected mercs."),
DisplayName = T(416808859941, --[[CombatAction ReloadMultiSelection DisplayName]] "Reload Everyone"),
GetAPCost = function (self, unit, args)
return 0
end,
GetTargets = function (self, units)
-- Reload with the current ammo, if the unit has more of it, or change ammo if the mag is empty
local reloadTargets = {}
local errorReason
for i, u in ipairs(units) do
local w1, w2, weaponList = u:GetActiveWeapons("Firearm")
for i, w in ipairs(weaponList) do
if w.ammo and w.ammo.Amount == w.MagazineSize then
errorReason = errorReason or T(790275997183, "Full clip")
goto continue
end
local ammoForWeapon = u:GetAvailableAmmos(w, nil, "unique")
if #ammoForWeapon == 0 then
errorReason = T(215123596652, "No ammo")
goto continue
end
local currentAmmo = w.ammo and table.find_value(ammoForWeapon, "class", w.ammo.class)
if not currentAmmo and w.ammo and w.ammo.Amount > 0 then
errorReason = T(215123596652, "No ammo") -- No ammo of current type and magazine isn't empty
goto continue
end
reloadTargets[#reloadTargets + 1] = { u = {u}, w = w, ammo = currentAmmo or ammoForWeapon[1] }
::continue::
end
end
return reloadTargets, errorReason
end,
GetUIState = function (self, units, args)
if #units < 2 then return "hidden" end
if not self:GetAnyTarget(units) then
return "disabled"
end
return "enabled"
end,
Icon = "UI/Icons/Hud/reload",
IdDefault = "ReloadMultiSelectiondefault",
IsAimableAttack = false,
QueuedBadgeText = T(533763685831, --[[CombatAction ReloadMultiSelection QueuedBadgeText]] "RELOAD"),
RequireState = "exploration",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ReloadAction", self.id, ap, ...)
end,
SortKey = 8,
UIBegin = function (self, units, args)
local reloadProc = self:GetTargets(units)
for i, r in ipairs(reloadProc) do
self:Execute(r.u, { weapon = r.w.class, target = r.ammo.class })
end
end,
group = "Default",
id = "ReloadMultiSelection",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
ConfigurableKeybind = false,
Description = T(134458994872, --[[CombatAction StopBandaging Description]] "Cancel the bandaging action."),
DisplayName = T(856153698041, --[[CombatAction StopBandaging DisplayName]] "Stop Bandaging"),
GetActionDescription = function (self, units)
local unit = units[1]
if unit:IsBeingBandaged() then
return T(540349977342, "Cancel the bandaging action. The unit will be able to move but not regain any more HP.")
end
if not g_Combat then
return T(151546259528, "Cancel the bandaging action. The bandaged unit will not regain any more HP.")
end
return self.Description
end,
GetUIState = function (self, units, args)
local unit = units[1]
if unit:GetBandageTarget() or unit:IsBeingBandaged() then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Icons/Hud/stop_bandaging_downed",
IdDefault = "StopBandagingdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectBandage",
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
if unit:GetBandageTarget() then
unit:SetActionCommand("EndCombatBandage")
else
for _, other in ipairs(g_Units) do
if unit ~= other and other:GetBandageTarget() == unit then
other:SetActionCommand("EndCombatBandage")
end
end
end
end,
SortKey = 9,
group = "Default",
id = "StopBandaging",
})
PlaceObj('CombatAction', {
ActionPoints = 5000,
ActivePauseBehavior = "queue",
Description = T(582755603672, --[[CombatAction Unjam Description]] "Fix a jammed weapon. The weapon loses <em>Condition</em> depending on the <em><mechanical></em> skill."),
DisplayName = T(348534461674, --[[CombatAction Unjam DisplayName]] "Unjam"),
GetAPCost = function (self, unit, args)
if HasPerk(unit, "MrFixit") then
return CharacterEffectDefs.MrFixit:ResolveValue("mrfixit_ap") * const.Scale.AP
end
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
local weapon = false
if args and args.pos then
weapon = unit:GetItemAtPackedPos(args.pos)
elseif args and args.weapon then
weapon = unit:GetWeaponByDefIdOrDefault("Firearm", args and args.weapon, args and args.pos)
end
if weapon then -- from Inventory
local jammed = false
if IsKindOf(weapon, "Firearm") and weapon.jammed and not weapon:IsCondition("Broken") then
jammed = true
end
if not jammed then return "hidden" end
else
local weapon1, weapon2 = unit:GetActiveWeapons()
local weaponJammed1, weaponJammed2 = false, false
if IsKindOf(weapon1, "Firearm") and weapon1.jammed and not weapon1:IsCondition("Broken") then
weaponJammed1 = true
end
if IsKindOf(weapon2, "Firearm") and weapon2.jammed and not weapon2:IsCondition("Broken") then
weaponJammed2 = true
end
if not weaponJammed1 and not weaponJammed2 then
return "hidden"
end
end
if not unit:UIHasAP(cost) then return "disabled", GetUnitNoApReason(unit) end
return "enabled"
end,
Icon = "UI/Icons/Hud/repair_weapon",
IdDefault = "Unjamdefault",
IsAimableAttack = false,
KeybindingSortId = "2505",
MultiSelectBehavior = "first",
QueuedBadgeText = T(224178341316, --[[CombatAction Unjam QueuedBadgeText]] "UNJAM"),
RequireState = "any",
Run = function (self, unit, ap, args)
unit:SetActionCommand("UnjamWeapon", self.id, ap, args)
end,
SortKey = 10,
group = "Default",
id = "Unjam",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
ActivePauseBehavior = "queue",
AimType = "cone",
ConfigurableKeybind = false,
Description = T(780359204834, --[[CombatAction Overwatch Description]] "<em>Spends all AP</em>\nAny targets who move or shoot in the overwatch area will provoke <GameTerm('Interrupt')> <em>attacks</em>.\nAccuracy is influenced by <em><dexterity></em>."),
DisplayName = T(396308001195, --[[CombatAction Overwatch DisplayName]] "Overwatch"),
Execute = function (self, units, args)
local unit = units[1]
local attacks, aim = unit:GetOverwatchAttacksAndAim(self, args)
args.num_attacks = attacks
args.aim = aim
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
if args and args.action_cost_only then
return self.ActionPoints
end
local weapon = self:GetAttackWeapons(unit, args)
if not weapon or (weapon.PreparedAttackType ~= "Overwatch" and weapon.PreparedAttackType ~= "Both")then return -1 end
local attack = unit:GetDefaultAttackAction("ranged", "ungrouped")
local atk_cost = attack:GetAPCost(unit, args) + self.ActionPoints
return Max(unit:GetUIActionPoints(), atk_cost), atk_cost
end,
GetActionDescription = function (self, units)
local unit = units[1]
local apply, value = Presets.ChanceToHitModifier.Default.OpportunityAttack:CalcValue(unit, nil, nil, nil, nil, nil, nil, nil, true)
local total, cost = self:GetAPCost(unit)
local attacks = 1
if unit and (cost or -1) >= 0 then
attacks = unit:GetOverwatchAttacksAndAim()
end
local descr = g_Combat and self.Description or CombatActions.ExplorationOverwatch.Description
local description = descr
if g_Overwatch[unit] and (g_Overwatch[unit].num_attacks or 0) > 0 then
-- add remaining attacks text
attacks = g_Overwatch[unit].num_attacks
description = descr .. T{133054169959, "<newline><newline>Remaining attacks: <em><attacks></em>", attacks = attacks}
elseif unit:UIHasAP(cost, self.id) then
-- add max attacks text
description = descr .. T{452784485986, "<newline><newline>Max attacks: <em><attacks></em>", attacks = attacks}
end
local action = unit and unit:GetDefaultAttackAction()
if action and (action.id == "Buckshot" or action.id == "DoubleBarrel") then
description = description .. "<newline><newline>" .. T(769183913636, "Collateral damage might hit units outside the overwatch cone.")
end
return description
end,
GetActionDisplayName = function (self, units)
local name = g_Combat and self.DisplayName or CombatActions.ExplorationOverwatch.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetActionIcon = function (self, units)
if not g_Combat then
return CombatActions.ExplorationOverwatch.Icon
end
return self.Icon
end,
GetActionResults = function (self, unit, args)
local target = args.target
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return {} end
local sub_action = unit:GetDefaultAttackAction("ranged", "ungrouped")
local attack_args = unit:PrepareAttackArgs(self.id, args)
local targets = unit:GetVisibleEnemies()
local results = {}
if sub_action.AimType == "cone" then
-- check for collateral damage around exact targets
local sub_attack_args = unit:PrepareAttackArgs(sub_action.id, args)
local aoe = GetAreaAttackResults(sub_attack_args)
for i, aoeHit in ipairs(aoe) do
if IsKindOf(aoeHit.obj, "Unit") then
table.insert_unique(targets, aoeHit.obj)
results[#results + 1] = aoeHit
end
end
end
local modifiers = GetAreaAttackHitModifiers(self.id, attack_args, targets)
local sub_action_lof_params = {
can_use_covers = false,
can_stuck_on_unit = false,
}
local lof_data = GetLoFData(unit, targets, sub_action_lof_params)
for i, target in ipairs(targets) do
local mod = modifiers[i]
if mod > 0 then
sub_action_lof_params.target = target
local sub_action_results = sub_action:GetActionResults(unit, sub_action_lof_params)
if sub_action.AimType == "cone" then -- cause area action results are in different format...
sub_action_results = sub_action_results.area_hits
end
local target_hit
for i, hitData in ipairs(sub_action_results) do
if hitData.obj == target then
results[#results + 1] = hitData
target_hit = true
end
end
--if not target_hit then
local target_lof_data = lof_data[i]
if target_lof_data.clear_attacks == 0 then
results.no_lof_targets = results.no_lof_targets or {}
table.insert(results.no_lof_targets, target)
end
end
end
-- We dont want to show damage prediction, just hit prediction.
for i, result in ipairs(results) do
result.damage = 0
result.display_only = true
result.ignore_armor = true
end
return results, attack_args
end,
GetAimParams = function (self, unit, weapon)
local params = weapon:GetAreaAttackParams(self.id, unit)
params.min_range = self:GetMinAimRange(unit, weapon)
params.max_range = self:GetMaxAimRange(unit, weapon)
assert(params.max_range >= params.min_range)
return params
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
local range = weapon:GetOverwatchConeParam("MaxRange")
local sight = unit:GetSightRadius() / const.SlabSizeX
return Min(range, sight)
end,
GetMinAimRange = function (self, unit, weapon)
local range = weapon:GetOverwatchConeParam("MinRange")
local sight = unit:GetSightRadius() / const.SlabSizeX
return Min(range, sight)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled", GetUnitNoApReason(unit) end
local attack = unit:GetDefaultAttackAction()
local state, reason = attack:GetUIState(units, args)
return state, reason
end,
Icon = "UI/Icons/Hud/overwatch",
IdDefault = "Overwatchdefault",
KeybindingFromAction = "actionRedirectOverwatch",
MultiSelectBehavior = "first",
QueuedBadgeText = T(507392307526, --[[CombatAction Overwatch QueuedBadgeText]] "OVERWATCH"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local vr = IsMerc(unit) and "Overwatch" or "AIOverwatch"
PlayVoiceResponse(unit, vr)
unit:SetActionCommand("OverwatchAction", self.id, ap, ...)
end,
SortKey = 20,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "cancel")
end,
group = "Default",
id = "Overwatch",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPoints = 3000,
ActionType = "Ranged Attack",
ActivePauseBehavior = "queue",
AimType = "line",
Description = T(769278662659, --[[CombatAction PinDown Description]] "<em>Spends all AP</em>\nThe target is <em><GameTerm('Marked')></em>. At the start of next turn, shoot the target for <em><damage> damage</em> if the target is still in the line of sight.\n\nPin Down requires a clear line and sight to the target."),
DisplayName = T(964546937629, --[[CombatAction PinDown DisplayName]] "Pin Down"),
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon or (weapon.PreparedAttackType ~= "Pin Down" and weapon.PreparedAttackType ~= "Both") then
return -1
end
local ap = self.ActionPoints
if HasPerk(unit, "HawksEye") then
ap = CharacterEffectDefs.HawksEye:ResolveValue("pindownCostOverwrite") * const.Scale.AP
end
return Max(ap, unit:GetUIActionPoints()), ap
end,
GetActionDescription = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
if not weapon then return self.Description end
local damage = unit:GetBaseDamage(weapon)
return T{self.Description, damage = damage}
end,
GetActionResults = function (self, unit, args)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
return CombatActionGetOneAttackableEnemy(self, unit, nil, CombatActionTargetFilters.Pindown, unit, weapon)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon1, weapon2 = unit:GetActiveWeapons("Firearm")
if weapon1 and weapon2 then
return false
end
if not weapon1 or (weapon1.PreparedAttackType ~= "Pin Down" and weapon1.PreparedAttackType ~= "Both") then
return false
end
return weapon1
end,
GetTargets = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.Pindown, unit, weapon)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not weapon or (weapon.PreparedAttackType ~= "Pin Down" and weapon.PreparedAttackType ~= "Both") then
return "hidden"
end
if #(self:GetTargets(units) or empty_table) == 0 then
return "disabled", AttackDisableReasons.NoTarget
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/steady_does_it",
IdDefault = "PinDowndefault",
IsTargetableAttack = true,
KeybindingSortId = "2353",
MultiSelectBehavior = "first",
QueuedBadgeText = T(707708840555, --[[CombatAction PinDown QueuedBadgeText]] "PIN DOWN"),
RequireTargets = true,
RequireWeapon = true,
Run = function (self, unit, ap, ...)
local vr = IsMerc(unit) and "PinDown" or "AIPinDown"
local targetIsCiv = unit.aim_attack_args and unit.aim_attack_args.target and IsKindOf(unit.aim_attack_args.target, "Unit") and unit.aim_attack_args.target:IsCivilian()
if not targetIsCiv then
PlayVoiceResponse(unit, vr)
end
unit:SetActionCommand("PinDown", self.id, ap, ...)
end,
SortKey = 20,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "Default",
id = "PinDown",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
Comment = "exploration mode only",
ConfigurableKeybind = false,
Description = T(309141031133, --[[CombatAction CancelOverwatch Description]] "Cancel <GameTerm('Overwatch')> and move normally"),
DisplayName = T(642998606373, --[[CombatAction CancelOverwatch DisplayName]] "Cancel Overwatch"),
DisplayNameShort = T(951774623470, --[[CombatAction CancelOverwatch DisplayNameShort]] "Cancel Overwatch"),
GetUIState = function (self, units, args)
local has_overwatch
for _, unit in ipairs(Selection or units) do -- action should be visible if anyone selected has an overwatch, not just the first
has_overwatch = has_overwatch or not not g_Overwatch[unit] or (IsActivePaused() and unit.queued_action_id == "Overwatch")
end
return has_overwatch and "enabled" or "hidden"
end,
Icon = "UI/Icons/Hud/cancel_overwatch",
IdDefault = "CancelOverwatchdefault",
IsAimableAttack = false,
RequireState = "exploration",
Run = function (self, unit, ap, ...)
unit:InterruptPreparedAttack()
end,
SortKey = 21,
group = "Default",
id = "CancelOverwatch",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
ConfigurableKeybind = false,
Description = "",
DisplayName = T(118687433511, --[[CombatAction Despawn DisplayName]] "Despawn"),
GetAPCost = function (self, unit, args)
return 0
end,
Icon = "UI/Icons/Hud/placeholder",
IdDefault = "Despawndefault",
IsAimableAttack = false,
MultiSelectBehavior = "hidden",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("Despawn", self.id, ap)
end,
ShowIn = false,
SortKey = 100,
group = "Default",
id = "Despawn",
})
PlaceObj('CombatAction', {
ActionPoints = 2000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(696253281343, --[[CombatAction Hide Description]] "Toggle <GameTerm('Stealth')>. This action will force the character to be in the <em>Crouched</em> stance if they are in a <em>Standing</em> stance."),
DisplayName = T(490121255879, --[[CombatAction Hide DisplayName]] "Sneak Mode"),
DisplayNameShort = T(219222528962, --[[CombatAction Hide DisplayNameShort]] "Sneak Mode"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
PlayFX("activityButtonPress_Sneak", "start")
end,
GetAPCost = function (self, unit, args)
if not unit:CanStealth(unit:GetStanceToStealth()) then
return -1
end
return self.ActionPoints
end,
GetUIState = function (self, units, args)
units = table.ifilter(units, function(idx, unit) return not unit:HasStatusEffect("Hidden") end)
local unit = units[1]
if not unit then return "hidden" end
if not unit:CanStealth(unit:GetStanceToStealth()) then
if unit.enemy_visual_contact then
return "disabled", AttackDisableReasons.InEnemySight
elseif unit:HasStatusEffect("Revealed") then
return "disabled", AttackDisableReasons.Revealed
end
return "disabled", AttackDisableReasons.CannotSneak
end
local cost = self:GetAPCost(unit, args)
if cost < 0 or not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/stealth_off",
IdDefault = "Hidedefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(288854857786, --[[CombatAction Hide QueuedBadgeText]] "HIDE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
if not g_Combat and unit.goto_target and not IsActivePaused() then
local stance = unit:GetStanceToStealth(unit.goto_stance)
if unit:CanStealth(stance) then
unit.goto_stance = stance
unit.goto_hide = true
end
return
end
unit:SetActionCommand("Hide")
end,
ShowIn = "Special",
SimultaneousPlay = true,
SortKey = 100,
group = "Default",
id = "Hide",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
ConfigurableKeybind = false,
Description = T(393528800033, --[[CombatAction Reveal Description]] "Exit <GameTerm('Stealth')> and reveal yourself to all nearby enemies."),
DisplayName = T(812951099239, --[[CombatAction Reveal DisplayName]] "Stop Sneaking"),
DisplayNameShort = T(565305410833, --[[CombatAction Reveal DisplayNameShort]] "Stop Sneaking"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
PlayFX("activityButtonPress_UndoSneak", "start")
end,
GetAPCost = function (self, unit, args)
if not unit:CanStealth(unit:GetStanceToStealth()) then
return -1
end
return self.ActionPoints
end,
GetUIState = function (self, units, args)
for _, unit in ipairs(units) do
if not unit:HasStatusEffect("Hidden") then
return "hidden"
end
end
return "enabled"
end,
Icon = "UI/Icons/Hud/stealth_on",
IdDefault = "Revealdefault",
IsAimableAttack = false,
RequireState = "any",
Run = function (self, unit, ap, ...)
if not g_Combat and unit.goto_target then
unit:Unhide()
return
end
unit:SetActionCommand("Unhide")
end,
ShowIn = "Special",
SimultaneousPlay = true,
SortKey = 100,
group = "Default",
id = "Reveal",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActionShortcut = "J",
ActivePauseBehavior = "queue",
Description = T(492006416359, --[[CombatAction TakeCover Description]] "<em>Spends all AP</em>\nSets your stance to <em>Crouched</em>. Gain superior protection against attacks from the other side of <em>cover</em>. You will lose the benefit if you become <GameTerm('Exposed')>."),
DisplayName = T(365281729213, --[[CombatAction TakeCover DisplayName]] "Take Cover"),
DisplayNameShort = T(934207804139, --[[CombatAction TakeCover DisplayNameShort]] "Take Cover"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDescription = function (self, units)
local unit = units[1]
if unit then
local cost = self:GetAPCost(unit)
local num = Max(0, unit:GetUIActionPoints() - cost)
num = Min(num, Protected:ResolveValue("max_ap_carried")*const.Scale.AP)
if num >= const.Scale.AP then
return self.Description .. T{128220108077, "<newline><newline>This action will transfer <em><ap(num_ap)></em> to the next turn", num_ap = num}
end
end
return self.Description
end,
GetUIState = function (self, units, args)
if not units or #units < 1 then return "hidden" end
local active = true
for _, unit in ipairs(units) do
if not unit:HasStatusEffect("Protected") then
if unit:CanTakeCover() then
if not unit:HasAP(self:GetAPCost(unit)) then
return "disabled", AttackDisableReasons.NoAP
end
return "enabled"
end
active = false
end
end
if active then
return "disabled", AttackDisableReasons.AlreadyActive
end
return "disabled", AttackDisableReasons.NotInCover
end,
Icon = "UI/Icons/Hud/take_cover",
IdDefault = "TakeCoverdefault",
IsAimableAttack = false,
KeybindingSortId = "2325",
QueuedBadgeText = T(659947635353, --[[CombatAction TakeCover QueuedBadgeText]] "TAKE COVER"),
RequireState = "any",
Run = function (self, unit, ap, ...)
PlayVoiceResponse(unit, "TakeCover")
unit:SetActionCommand("TakeCover")
GetCoverShieldBonusEffect(unit)
end,
SimultaneousPlay = true,
SortKey = 101,
group = "Default",
id = "TakeCover",
})
PlaceObj('CombatAction', {
Comment = "dummy action used to facilitate Reposition queueing when needed",
ConfigurableKeybind = false,
DisplayName = T(890398580666, --[[CombatAction Reposition DisplayName]] "Reposition"),
IdDefault = "Repositiondefault",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("Reposition", ...)
end,
SimultaneousPlay = true,
group = "Hidden",
id = "Reposition",
})
PlaceObj('CombatAction', {
Comment = "dummy action used for opening attack in reposition",
ConfigurableKeybind = false,
DisplayName = T(165860894460, --[[CombatAction RepositionOpeningAttack DisplayName]] "Opening Attack"),
IdDefault = "RepositionOpeningAttackdefault",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("RepositionOpeningAttack", ...)
end,
group = "Hidden",
id = "RepositionOpeningAttack",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
ConfigurableKeybind = false,
Description = T(733401287883, --[[CombatAction CancelMark Description]] "Cancel the prepared Takedown action and allows preparing Takedown for a new target.<newline><newline>The prepared takedown will be executed if you approach the enemy undetected."),
DisplayName = T(800852469502, --[[CombatAction CancelMark DisplayName]] "Cancel Takedown"),
DisplayNameShort = T(117355578745, --[[CombatAction CancelMark DisplayNameShort]] "Cancel Takedown"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetMaxAimRange = function (self, unit, weapon)
return 150
end,
GetUIState = function (self, units, args)
local mark = false
for _, unit in ipairs(units) do
mark = mark or not not unit.marked_target_attack_args
end
if not mark then return "hidden" end
return "enabled"
end,
Icon = "UI/Icons/Hud/cancel_mark",
IdDefault = "CancelMarkdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectTakedown",
RequireState = "exploration",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("CancelMark")
end,
SimultaneousPlay = true,
SortKey = 3,
group = "Hidden",
id = "CancelMark",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
ActivePauseBehavior = "instant",
AimType = "line",
ConfigurableKeybind = false,
Description = T(688968867904, --[[CombatAction MarkTarget Description]] "Mark an enemy to perform a <em>melee attack</em> when the target is in range. The mark will be removed if combat starts. Often used while <GameTerm('Sneaking')>."),
DisableAimAnim = true,
DisplayName = T(100199336646, --[[CombatAction MarkTarget DisplayName]] "Prepare Takedown"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit, args)
args = args or {}
args.action_cost_only = true -- only used in exploration, never try to add movement cost
if IsKindOf(weapon, "UnarmedWeapon") then
return CombatActions.UnarmedAttack:GetAPCost(unit, args)
end
return CombatActions.MeleeAttack:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return CombatActionsAppendFreeAimDescription(self, units[1], description, "ignore")
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
if args.target then
args.step_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.weapon = args.weapon or self:GetAttackWeapons(unit)
return CombatActions.MeleeAttack:GetActionResults(unit, args)
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
if not weapon then return {} end
return CombatActionGetOneAttackableEnemy(self, unit)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetActiveWeapons("MeleeWeapon") or unit:GetActiveWeapons("UnarmedWeapon")
end,
GetMaxAimRange = function (self, unit, weapon)
return 150
end,
GetTargets = function (self, units)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit)
if not weapon then return {} end
return CombatActionGetAttackableEnemies(self, unit)
end,
GetUIState = function (self, units, args)
local unit = units[1]
if not unit or not self:GetAttackWeapons(unit, args) then
return "hidden"
end
if unit.marked_target_attack_args and IsValid(unit.marked_target_attack_args.target) and not unit.marked_target_attack_args.target:IsDead() then
return "hidden"
end
--if not unit:HasStatusEffect("Hidden") then
-- return "disabled", AttackDisableReasons.NotSneaking
--end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/mark_enemy",
IdDefault = "MarkTargetdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectTakedown",
MultiSelectBehavior = "first",
RequireState = "exploration",
RequireTargets = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MarkTarget", self.id, ap, ...)
end,
SortKey = 3,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "Hidden",
id = "MarkTarget",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Description = T(646737101780, --[[CombatAction Reload Description]] "<em>Reload</em> or <em>change</em> ammo."),
DisplayName = T(642187794904, --[[CombatAction Reload DisplayName]] "Reload"),
GetAPCost = function (self, unit, args)
if unit:HasStatusEffect("ManningEmplacement") then return -1 end
local weapon
if args and args.item_id then
local alt_set = (unit.current_weapon == "Handheld A") and "Handheld B" or "Handheld A"
weapon =
unit:FindWeaponInSlotById(unit.current_weapon, args.item_id) or
unit:FindWeaponInSlotById(alt_set, args.item_id) or
unit:FindWeaponInSlotById("Inventory", args.item_id)
end
if not weapon then
if args and args.pos then
weapon = unit:GetItemAtPackedPos(args.pos)
else
weapon = unit:GetWeaponByDefIdOrDefault("Firearm", args and args.weapon)
end
end
return (weapon and not weapon.jammed) and weapon.ReloadAP or -1
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
if not IsKindOf(unit, "Unit") then return end
local w1, w2, weaponList = unit:GetActiveWeapons("Firearm")
local canChange = false
for i, w in ipairs(weaponList) do
local ammoForWeapon = unit:GetAvailableAmmos(w, nil, "unique")
local noAmmo = #ammoForWeapon == 0
local onlyAmmoIsCurrent = w.ammo and #ammoForWeapon == 1 and ammoForWeapon[1].class == w.ammo.class
local fullMag = not w.ammo or w.ammo.Amount == w.MagazineSize
canChange = canChange or (onlyAmmoIsCurrent and fullMag)
end
if canChange then
return T(817996274899, "Change Ammo")
else
return self.DisplayName
end
end,
GetTargets = function (self, units)
local unit = units[1]
local weapon = unit:GetActiveWeapons()
return unit:GetAvailableAmmos(weapon)
end,
GetUIState = function (self, units, args)
if not g_Combat and #units ~= 1 then return "hidden" end
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled", GetUnitNoApReason(unit) end
local availableWeaponsToReload = 0
local errorReason
local weapon
if args and args.pos then
weapon = unit:GetItemAtPackedPos(args.pos)
elseif args and args.weapon then
weapon = unit:GetWeaponByDefIdOrDefault("Firearm", args and args.weapon, args and args.pos)
end
if weapon then
local weaponReloadOptions = GetReloadOptionsForWeapon(weapon, unit)
if #weaponReloadOptions > 0 then
availableWeaponsToReload = availableWeaponsToReload + 1
end
else
local w1, w2, weaponList = unit:GetActiveWeapons()
if not weaponList then return "enabled" end
for i, w in ipairs(weaponList) do
local canReload, err = IsWeaponAvailableForReload(w, unit:GetAvailableAmmos(w, nil, "unique"))
errorReason = err
if canReload then
availableWeaponsToReload = availableWeaponsToReload + 1
end
end
end
if availableWeaponsToReload == 0 then return "disabled", errorReason end
return "enabled"
end,
Icon = "UI/Icons/Hud/reload",
IdDefault = "Reloaddefault",
IsAimableAttack = false,
QueuedBadgeText = T(871510388525, --[[CombatAction Reload QueuedBadgeText]] "RELOAD"),
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ReloadAction", self.id, ap, ...)
end,
ShowIn = false,
SortKey = 8,
UIBegin = function (self, units, args)
local unit = units[1]
local mode_dlg = GetInGameInterfaceModeDlg()
if IsKindOf(mode_dlg, "IModeCommonUnitControl") then
-- Process weapons
local w1, w2, weaponList = unit:GetActiveWeapons("Firearm")
local processedList = {}
for i, w in ipairs(weaponList) do
local text = T{535301054415, "<weaponName>", weaponName = w.DisplayName}
local ammoForWeapon = unit:GetAvailableAmmos(w, nil, "unique")
local noAmmo = #ammoForWeapon == 0
if w.ammo == 0 then
text = text .. T(642941753004, " (Empty)")
end
local onlyAmmoIsCurrent = w.ammo and #ammoForWeapon == 1 and ammoForWeapon[1].class == w.ammo.class
local fullMag = not w.ammo or w.ammo.Amount == w.MagazineSize
local processedAmmo = {}
for _, a in ipairs(ammoForWeapon) do
local isCurrent = w.ammo and a.class == w.ammo.class
local ammoEntry = {
DisplayName = isCurrent and T{541680584484, "Current: <DisplayName>", a} or a.DisplayName,
ammo = a,
disabled = w.ammo and isCurrent and fullMag,
icon = a.Icon,
uiCtx = a,
rolloverTemplate = "RolloverInventory"
}
if isCurrent then table.insert(processedAmmo, 1, ammoEntry) else table.insert(processedAmmo, ammoEntry) end
end
processedList[#processedList + 1] = {
DisplayName = text,
weaponIdx = i,
ammo = processedAmmo,
disabled = noAmmo or (onlyAmmoIsCurrent and fullMag),
icon = w.Icon,
uiCtx = w,
rolloverTemplate = "RolloverInventory"
}
end
-- First you choose which weapon to reload, then you choose the ammo to load into it.
local weaponChoiceCallback = function(u, weaponWrapped)
local ammoChoiceCallback = function(u, ammoWrapped)
self:Execute({u}, { weapon = weaponWrapped.weaponIdx, target = ammoWrapped.ammo.class })
end
mode_dlg:ShowCombatActionTargetChoice(self, {u}, weaponWrapped.ammo, ammoChoiceCallback, "suppress_toggle")
end
mode_dlg:ShowCombatActionTargetChoice(self, units, processedList, weaponChoiceCallback)
else
self:Execute(units)
end
end,
group = "Hidden",
id = "Reload",
})
PlaceObj('CombatAction', {
ActionPoints = 1000,
ActionShortcut = "U",
ActivePauseBehavior = "queue",
Description = T(784247279587, --[[CombatAction ChangeWeapon Description]] "Swap to the alternative weapon set: <items>"),
DisplayName = T(692166142490, --[[CombatAction ChangeWeapon DisplayName]] "Change Weapon"),
GetAPCost = function (self, unit, args)
if unit:CanActivatePerk("Scoundrel") then return 0 end
local otherSet = "Handheld A"
if unit and unit.current_weapon == "Handheld A" then
otherSet = "Handheld B"
end
if unit:FindItemInSlot(otherSet, function(weapon) return weapon:IsWeapon() and weapon:HasComponent("FreeWeaponSwap") end) then
return 0
end
return self.ActionPoints
end,
GetActionDescription = function (self, units)
local otherSetItems = GetUnitWeapons(units[1], "otherSet")
local itemsConcat = {}
for i, item in ipairs(otherSetItems) do
itemsConcat[#itemsConcat + 1] = item.DisplayName
end
itemsConcat = table.concat(itemsConcat, ", ")
return T{self.Description, items = itemsConcat}
end,
GetUIState = function (self, units, args)
local unit = units[1]
if not IsKindOf(unit, "Unit") then return "hidden" end
if unit:GetBandageTarget() then
return "disabled", AttackDisableReasons.BandagingDowned
end
if unit:HasStatusEffect("ManningEmplacement") or unit:HasStatusEffect("StationedMachineGun") then
return "hidden", AttackDisableReasons.UsingMachineGun
end
if not unit:UIHasAP(self:GetAPCost(unit, args)) then return "disabled", AttackDisableReasons.NoAP end
if g_Combat and HasCombatActionInProgress(unit) then return "hidden" end
return "enabled" -- always available to allow switching to unarmed attacks
end,
Icon = "UI/Icons/Hud/change_weapon_set",
IdDefault = "ChangeWeapondefault",
IsAimableAttack = false,
KeybindingSortId = "2295",
MultiSelectBehavior = "first",
QueuedBadgeText = T(518198236082, --[[CombatAction ChangeWeapon QueuedBadgeText]] "CHANGE WEAPON"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("SwapActiveWeapon", self.id, ap)
end,
ShowIn = "Special",
SortKey = 11,
group = "Hidden",
id = "ChangeWeapon",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = "stub action for Overwatch in exploration - changed appearance (text/name/icon/etc)",
ConfigurableKeybind = false,
Description = T(365505233508, --[[CombatAction ExplorationOverwatch Description]] "Can be used out of combat to set up an ambush. Enemies do not provoke <GameTerm('Interrupt')> <em>attacks</em> until combat starts.\nMercs in <em>Overwatch</em> start combat <em>without AP</em>."),
DisplayName = T(398975828612, --[[CombatAction ExplorationOverwatch DisplayName]] "Overwatch"),
Icon = "UI/Icons/Hud/overwatch",
IdDefault = "ExplorationOverwatchdefault",
KeybindingFromAction = "actionRedirectOverwatch",
QueuedBadgeText = T(302085333903, --[[CombatAction ExplorationOverwatch QueuedBadgeText]] "OVERWATCH"),
SortKey = 20,
group = "Hidden",
id = "ExplorationOverwatch",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "instant",
ConfigurableKeybind = false,
Description = T(809105796347, --[[CombatAction Inventory Description]] "Access inventory. Some inventory actions cost <em>Action Points</em> during combat."),
DisplayName = T(846446595710, --[[CombatAction Inventory DisplayName]] "Inventory"),
EvalTarget = function (self, unit, target)
return 0
end,
Execute = function (self, units, args)
local unit = units[1]
if unit then
OpenInventory(unit)
end
end,
GetAttackWeapons = function (self, unit, args)
return false
end,
GetDefaultTarget = function (self, unit)
return false
end,
GetTargets = function (self, unit)
return false
end,
GetUIState = function (self, units, args)
local unit = units and units[1]
if not unit or not unit:CanBeControlled() then return "disabled" end
if unit:IsDowned() then
return "disabled"
end
return "enabled"
end,
Icon = "UI/Icons/Hud/inventory",
IdDefault = "Inventorydefault",
IsAimableAttack = false,
KeybindingFromAction = "idInventory",
MultiSelectBehavior = "first",
RequireState = "any",
ShowIn = "Special",
SortKey = 20,
group = "Hidden",
id = "Inventory",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(342083935157, --[[CombatAction ItemSkills Description]] "Use one of your equipped quick slot items."),
DisplayName = T(205114072648, --[[CombatAction ItemSkills DisplayName]] "Items"),
GetActionIcon = function (self, units)
return self.Icon
end,
GetDefaultTarget = function (self, unit)
return false
end,
IdDefault = "ItemSkillsdefault",
IsAimableAttack = false,
QueuedBadgeText = T(820113998923, --[[CombatAction ItemSkills QueuedBadgeText]] "USE ITEM"),
RequireState = "any",
SortKey = 98,
UIBegin = function (self, units, args)
local mode_dlg = GetInGameInterfaceModeDlg()
if not IsKindOf(mode_dlg, "IModeCommonUnitControl") then return end
local unit = units[1]
local availableSkills = { always_show = true }
for i, s in ipairs(itemCombatSkillsList) do
if unit.ui_actions[s] then
local action = CombatActions[s]
local entry = {}
entry.rolloverTemplate = "CombatActionRollover"
entry.rolloverTitle = action:GetActionDisplayName(units)
entry.text = action:GetActionDescription(units)
entry.icon = action:GetActionIcon(units)
entry.disabled = action:GetUIState(units) ~= "enabled"
entry.uiCtx = SubContext(units, { action = action })
entry.iconColumns = 3
availableSkills[#availableSkills + 1] = entry
end
end
mode_dlg:ShowCombatActionTargetChoice(self, units, availableSkills, function(u, item)
item.uiCtx.action:UIBegin({unit}, args)
end)
end,
group = "Hidden",
id = "ItemSkills",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = "(Unused)",
ConfigurableKeybind = false,
Description = T(269603568429, --[[CombatAction ChangeStance Description]] "Change the unit's stance. Stances affect the movement range and the accuracy of attacks against this unit."),
DisplayName = T(536235772160, --[[CombatAction ChangeStance DisplayName]] "Change Stance"),
GetActionIcon = function (self, units)
local unit = units[1]
local stance = unit.stance
local currentStanceAction = CombatActions["Stance" .. stance]
local image = currentStanceAction and currentStanceAction:GetActionIcon(units) or "UI/Icons/Hud/placeholder.dds"
return image
end,
GetDefaultTarget = function (self, unit)
return false
end,
IdDefault = "ChangeStancedefault",
IsAimableAttack = false,
QueuedBadgeText = T(827612796111, --[[CombatAction ChangeStance QueuedBadgeText]] "CHANGE STANCE"),
RequireState = "any",
SortKey = 99,
UIBegin = function (self, units, args)
local mode_dlg = GetInGameInterfaceModeDlg()
if not IsKindOf(mode_dlg, "IModeCommonUnitControl") then return end
local stanceChoice = function(u, stance)
MultiTargetExecute(self.MultiSelectBehavior, units, function (unit)
stance.uiCtx.action:Execute({unit})
end, args and args.target)
end
local stances = {
{
uiCtx = CombatActions.StanceStanding
},
{
uiCtx = CombatActions.StanceCrouch
},
{
uiCtx = CombatActions.StanceProne
}
}
for i, s in ipairs(stances) do
local action = s.uiCtx
s.rolloverTemplate = "CombatActionRollover"
s.rolloverTitle = action:GetActionDisplayName(units)
s.text = action:GetActionDescription(units)
s.disabled = #units == 1 and action:GetUIState(units) ~= "enabled"
s.icon = action:GetActionIcon(units)
s.uiCtx = SubContext(units, { action = action })
s.iconColumns = 3
end
mode_dlg:ShowCombatActionTargetChoice(self, units, stances, stanceChoice)
end,
group = "Hidden",
id = "ChangeStance",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = "Execute default attack on the interactable target. Implemented in UIInteractWith",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = "",
DisplayName = T(678480902214, --[[CombatAction Interact_Attack DisplayName]] "Attack"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local action = unit:GetDefaultAttackAction()
return action:GetAPCost(unit, args)
end
return self.ActionPoints
end,
GetTargets = function (self, units)
return CombatActionGetAttackableEnemies(self, units and units[1])
end,
Icon = "UI/Hud/iw_attack",
IdDefault = "Interact_Attackdefault",
MultiSelectBehavior = "first",
QueuedBadgeText = T(574905632012, --[[CombatAction Interact_Attack QueuedBadgeText]] "INTERACT"),
RequireState = "any",
ShowIn = "Special",
group = "Interactions",
id = "Interact_Attack",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(581591931905, --[[CombatAction Interact_Banter DisplayName]] "Talk with <target.DisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return GetReachableObjects(units, "Unit")
end,
GetUIState = function (self, units, args)
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
local target = args.target
if target:IsNPC() and target:GetAllBanters("findFirst", { target_units = units }) then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_speak",
IdDefault = "Interact_Banterdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(755005650995, --[[CombatAction Interact_Banter QueuedBadgeText]] "INTERACT"),
RequireState = "exploration",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
UseFreeMove = true,
group = "Interactions",
id = "Interact_Banter",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(192251955775, --[[CombatAction Interact_CustomInteractable Description]] "<target.Description>"),
DisplayName = T(783948937482, --[[CombatAction Interact_CustomInteractable DisplayName]] "<target.DisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("CustomInteractable")
end,
GetUIState = function (self, units, args)
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
return args and args.target:GetUIState(units, args) or "disabled"
end,
Icon = "UI/Hud/iw_examine",
IdDefault = "Interact_CustomInteractabledefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(695484031538, --[[CombatAction Interact_CustomInteractable QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
UseFreeMove = true,
group = "Interactions",
id = "Interact_CustomInteractable",
})
PlaceObj('CombatAction', {
ActionPoints = 3000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(805362980184, --[[CombatAction Interact_Disarm Description]] "Attempt to disarm the trap."),
DisplayName = T(628643595814, --[[CombatAction Interact_Disarm DisplayName]] "Disarm <target.GetTrapDisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetActionDisplayName = function (self, units)
local actionText = false
for i, u in ipairs(units) do
if IsKindOf(u, "BoobyTrappable") then
actionText = u:GetDisarmActionName()
break
end
end
actionText = actionText or self.DisplayName
return T{actionText, units}
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("Trap")
end,
Icon = "UI/Hud/iw_disarm",
IdDefault = "Interact_Disarmdefault",
InteractionLoadingBar = true,
InterruptInExploration = true,
IsAimableAttack = false,
LocalChoiceAction = true,
MultiSelectBehavior = "first",
QueuedBadgeText = T(845650418409, --[[CombatAction Interact_Disarm QueuedBadgeText]] "DISARM"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Interactions",
id = "Interact_Disarm",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = "Interaction for exiting a sector.",
ConfigurableKeybind = false,
Description = "",
DisplayName = T(131395799549, --[[CombatAction Interact_Exit DisplayName]] "Exit sector"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetTargets = function (self, units)
return CombatActionGetAttackableEnemies(self, units)
end,
Icon = "UI/Hud/iw_travel",
IdDefault = "Interact_Exitdefault",
InterruptInExploration = true,
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = "Special",
UseFreeMove = true,
group = "Interactions",
id = "Interact_Exit",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(775371181070, --[[CombatAction Interact_LootContainer DisplayName]] "Loot"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("ItemContainer")
end,
Icon = "UI/Hud/iw_loot",
IdDefault = "Interact_LootContainerdefault",
InterruptInExploration = true,
IsAimableAttack = false,
LocalChoiceAction = true,
QueuedBadgeText = T(869928919299, --[[CombatAction Interact_LootContainer QueuedBadgeText]] "LOOT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Interactions",
id = "Interact_LootContainer",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(844963734438, --[[CombatAction Interact_LootUnit DisplayName]] "Loot <target.DisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("Unit")
end,
GetUIState = function (self, units, args)
if not IsKindOf(args.target, "Unit") or not args.target:IsDead() then return "hidden" end
return CombatAction.GetUIState(self, units, args)
end,
Icon = "UI/Hud/iw_loot",
IdDefault = "Interact_LootUnitdefault",
InterruptInExploration = true,
IsAimableAttack = false,
LocalChoiceAction = true,
QueuedBadgeText = T(465761957076, --[[CombatAction Interact_LootUnit QueuedBadgeText]] "LOOT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Interactions",
id = "Interact_LootUnit",
})
PlaceObj('CombatAction', {
ActionPoints = 2000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(158391711834, --[[CombatAction Interact_ManEmplacement Description]] "Man Emplacement"),
DisplayName = T(666572046174, --[[CombatAction Interact_ManEmplacement DisplayName]] "Operate"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("MachineGunEmplacement")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not IsVisible(args.target) then return "hidden" end
if not unit:UIHasAP(cost, self.id, args) then
return "disabled", AttackDisableReasons.NoAP
end
return "enabled"
end,
Icon = "UI/Hud/iw_operate",
IdDefault = "Interact_ManEmplacementdefault",
InterruptInExploration = true,
IsAimableAttack = false,
LocalChoiceAction = true,
MultiSelectBehavior = "nearest",
QueuedBadgeText = T(693162081758, --[[CombatAction Interact_ManEmplacement QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Interactions",
id = "Interact_ManEmplacement",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(530290341300, --[[CombatAction Interact_NotNow Description]] "Cannot talk with NPCs in combat"),
DisplayName = T(629253239925, --[[CombatAction Interact_NotNow DisplayName]] "Talk with <target.DisplayName>"),
Execute = function (self, units, args)
local unit = units
if #unit > 0 then
unit = units[1]
end
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return self.ActionPoints
end,
GetTargets = function (self, units)
return GetReachableObjects(units, "Unit")
end,
Icon = "UI/Hud/iw_speak",
IdDefault = "Interact_NotNowdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(305159927540, --[[CombatAction Interact_NotNow QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
PlayVoiceResponse(unit, "NotNow")
end,
ShowIn = false,
SimultaneousPlay = true,
UseFreeMove = true,
group = "Interactions",
id = "Interact_NotNow",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(362512741067, --[[CombatAction Interact_Talk DisplayName]] "Talk with <target.DisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("Unit")
end,
GetUIState = function (self, units, args)
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
local target = args.target
if target:IsNPC() and FindEnabledConversation(target) then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_speak",
IdDefault = "Interact_Talkdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(865614171711, --[[CombatAction Interact_Talk QueuedBadgeText]] "INTERACT"),
RequireState = "exploration",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
UseFreeMove = true,
group = "Interactions",
id = "Interact_Talk",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(110677158472, --[[CombatAction Interact_UnitCustomInteraction DisplayName]] "Interact with <target.DisplayName>"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
local target = units[2]
if target and target.spawner and target.spawner.InteractionName then
return target.spawner.InteractionName
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetTargets = function (self, units)
return GetReachableObjects(units, "Unit")
end,
GetUIState = function (self, units, args)
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
local target = args.target
if target:IsNPC() then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_speak",
IdDefault = "Interact_UnitCustomInteractiondefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(380543262427, --[[CombatAction Interact_UnitCustomInteraction QueuedBadgeText]] "INTERACT"),
RequireState = "exploration",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
UseFreeMove = true,
group = "Interactions",
id = "Interact_UnitCustomInteraction",
})
PlaceObj('CombatAction', {
ActionPoints = 6000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(980718540270, --[[CombatAction Cut Description]] "Cut a wire fence with a <em>Wire Cutter</em>. You need to have a Wire Cutter in the character's Inventory."),
DisplayName = T(653704184125, --[[CombatAction Cut DisplayName]] "Cut"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetAnyTarget = function (self, units)
return #units > 0 and ChooseClosestFence(units[1])
end,
GetDefaultTarget = function (self, unit)
local target = ChooseClosestFence(unit)
return target, 100
end,
GetTargets = function (self, units)
if #units == 0 then return {} end
return {ChooseClosestFence(units[1])}
end,
GetUIState = function (self, units, args)
local unit
for i, u in ipairs(units) do
if GetUnitWirecutter(u) then
unit = u
break
end
end
if not unit then return "hidden", AttackDisableReasons.NoCutters end
return CombatAction.GetUIState(self, units, args)
end,
Icon = "UI/Hud/iw_wire_cut",
IdDefault = "Cutdefault",
InteractionLoadingBar = true,
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(301556646698, --[[CombatAction Cut QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("Lockpick", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
SortKey = 7,
UIBegin = function (self, units, args)
CombatActionInteractablesChoice(self, units, args)
end,
group = "Interactions",
id = "Cut",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(585037139087, --[[CombatAction Interact_DoorClose Description]] "Close the door. This may break the line of sight to and from enemies."),
DisplayName = T(124371611844, --[[CombatAction Interact_DoorClose DisplayName]] "Close"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
local totalCost, interactCost = CombatActionInteractionGetCost(self, unit, args)
local ap_mod = ((args and args.target and args.target.width or 0) >= 3) and 2 or 1
local nonInteractCost = totalCost - interactCost
return (interactCost * ap_mod) + nonInteractCost
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("SlabWallDoor")
end,
GetUIState = function (self, units, args)
local door = args and args.target
if door then
if door:IsInteracting() then
return "disabled"
end
if door.room and door.room.outside_border then
return "hidden"
end
end
local base_state, reason = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state, reason end
local u = units[1]
if not DoorOnSameLevel(u, door) then return "hidden" end
if not door:GetInteractionPos(u) then
return "disabled"
end
if door and door.pass_through_state == "open" then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_close_door",
IdDefault = "Interact_DoorClosedefault",
InterruptInExploration = true,
IsAimableAttack = false,
MultiSelectBehavior = "nearest",
QueuedBadgeText = T(690754380204, --[[CombatAction Interact_DoorClose QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target, "from ui")
end,
ShowIn = false,
SortKey = 11,
UseFreeMove = true,
group = "Interactions",
id = "Interact_DoorClose",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(677617724134, --[[CombatAction Interact_DoorOpen Description]] "Attempt to open the door. Some doors may be locked."),
DisplayName = T(445739435529, --[[CombatAction Interact_DoorOpen DisplayName]] "Open"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
local totalCost, interactCost = CombatActionInteractionGetCost(self, unit, args)
if totalCost < 0 then return totalCost end
local ap_mod = ((args and args.target and args.target.width or 0) >= 3) and 2 or 1
local nonInteractCost = totalCost - interactCost
return (interactCost * ap_mod) + nonInteractCost
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("SlabWallDoor")
end,
GetUIState = function (self, units, args)
local door = args and args.target
if door then
if door:IsInteracting() then
return "disabled"
end
if door.room and door.room.outside_border then
return "hidden"
end
end
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
local u = units[1]
if not DoorOnSameLevel(u, door) then return "hidden" end
if not door:GetInteractionPos(u) then
return "disabled"
end
if door and door.pass_through_state ~= "open" then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_open_door",
IdDefault = "Interact_DoorOpendefault",
InterruptInExploration = true,
IsAimableAttack = false,
MultiSelectBehavior = "nearest",
QueuedBadgeText = T(306356128321, --[[CombatAction Interact_DoorOpen QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target, "from ui")
end,
ShowIn = false,
SortKey = 13,
UseFreeMove = true,
group = "Interactions",
id = "Interact_DoorOpen",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(146720455225, --[[CombatAction LockImpossible Description]] "Can't be opened by skill or force, unless the door is destroyed."),
DisplayName = T(307771095785, --[[CombatAction LockImpossible DisplayName]] "Impossible to Open"),
DontShowWith = true,
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
Icon = "UI/Hud/iw_broken_lock",
IdDefault = "LockImpossibledefault",
IsAimableAttack = false,
QueuedBadgeText = T(836721737447, --[[CombatAction LockImpossible QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", GetOpenAction(args.target) or self.id, ap, args.goto_pos, args.goto_ap, args.target, "from ui")
end,
ShowIn = false,
SortKey = 14,
UIBegin = function (self, units, args)
MultiTargetExecute(self.MultiSelectBehavior, units, function (unit)
self:Execute({unit}, args)
end, args and args.target)
end,
group = "Interactions",
id = "LockImpossible",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(644731668039, --[[CombatAction Lockpick Description]] "Attempt to pick the lock (<em><mechanical></em>). Critical fail will jam the lock."),
DisplayName = T(277286761846, --[[CombatAction Lockpick DisplayName]] "Pick Lock"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetAnyTarget = function (self, units)
if #units == 0 then return end
local interactables = GetReachableObjects(units, "Lockpickable")
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
return int
end
end
end,
GetDefaultTarget = function (self, unit)
local interactables = unit:GetReachableObjects("Lockpickable")
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
return int
end
end
end,
GetTargets = function (self, units)
if #units == 0 then return {} end
local interactables = GetReachableObjects(units, "Lockpickable")
local result = {}
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
result[#result + 1] = int
end
end
return result
end,
GetUIState = function (self, units, args)
local target = args and args.target or self:GetAnyTarget(units)
if not target or not IsKindOf(target, "Lockpickable") or not target:CanUseAction(self.id) then
return "hidden"
end
local unit
for i, u in ipairs(units) do
if GetUnitLockpick(u) then
unit = u
break
end
end
if not unit then return "hidden", AttackDisableReasons.NoLockpick end
return "enabled"
end,
Icon = "UI/Hud/iw_lockpick",
IdDefault = "Lockpickdefault",
InteractionLoadingBar = true,
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(863593591904, --[[CombatAction Lockpick QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("Lockpick", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
SortKey = 15,
UIBegin = function (self, units, args)
CombatActionInteractablesChoice(self, units, args)
end,
group = "Interactions",
id = "Lockpick",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(991703344697, --[[CombatAction NoToolsLocked Description]] "You need a <em>Locksmith's Kit</em> to unlock or a <em>Crowbar</em> to break the lock."),
DisplayName = T(895045610563, --[[CombatAction NoToolsLocked DisplayName]] "Locked"),
DontShowWith = true,
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
Icon = "UI/Hud/iw_lockpick",
IdDefault = "NoToolsLockeddefault",
IsAimableAttack = false,
QueuedBadgeText = T(693029676179, --[[CombatAction NoToolsLocked QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", GetOpenAction(args.target) or self.id, ap, args.goto_pos, args.goto_ap, args.target, "from ui")
end,
ShowIn = false,
SortKey = 15,
UIBegin = function (self, units, args)
MultiTargetExecute(self.MultiSelectBehavior, units, function (unit)
self:Execute({unit}, args)
end, args and args.target)
end,
group = "Interactions",
id = "NoToolsLocked",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(148191264365, --[[CombatAction Break Description]] "Attempt to break the lock (<em><strength></em>). Items in a breached container may be damaged."),
DisplayName = T(373874832012, --[[CombatAction Break DisplayName]] "Break Lock"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetAnyTarget = function (self, units)
if #units == 0 then return end
local interactables = GetReachableObjects(units, "Lockpickable")
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
return int
end
end
end,
GetDefaultTarget = function (self, unit)
local interactables = unit:GetReachableObjects("Lockpickable")
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
return int
end
end
end,
GetTargets = function (self, units)
if #units == 0 then return {} end
local interactables = GetReachableObjects(units, "Lockpickable")
local result = {}
for i, int in ipairs(interactables) do
if int:CanUseAction(self.id) then
result[#result + 1] = int
end
end
return result
end,
GetUIState = function (self, units, args)
local target = args and args.target or self:GetAnyTarget(units)
if not target or not IsKindOf(target, "Lockpickable") or not target:CanUseAction(self.id) then
return "hidden"
end
local unit
for i, u in ipairs(units) do
if GetUnitCrowbar(u) then
unit = u
break
end
end
if not unit then return "hidden", AttackDisableReasons.NoCrowbar end
return "enabled"
end,
Icon = "UI/Hud/iw_break_lock",
IdDefault = "Breakdefault",
InteractionLoadingBar = true,
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(334542893280, --[[CombatAction Break QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("Lockpick", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
SortKey = 16,
UIBegin = function (self, units, args)
CombatActionInteractablesChoice(self, units, args)
end,
group = "Interactions",
id = "Break",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(641342518672, --[[CombatAction NoToolsBlocked Description]] "Lock jammed! You need a <em>Crowbar</em> to break the lock."),
DisplayName = T(699556305475, --[[CombatAction NoToolsBlocked DisplayName]] "Blocked"),
DontShowWith = true,
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
Icon = "UI/Hud/iw_break_lock",
IdDefault = "NoToolsBlockeddefault",
IsAimableAttack = false,
QueuedBadgeText = T(807947680083, --[[CombatAction NoToolsBlocked QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", GetOpenAction(args.target) or self.id, ap, args.goto_pos, args.goto_ap, args.target, "from ui")
end,
ShowIn = false,
SortKey = 16,
UIBegin = function (self, units, args)
MultiTargetExecute(self.MultiSelectBehavior, units, function (unit)
self:Execute({unit}, args)
end, args and args.target)
end,
group = "Interactions",
id = "NoToolsBlocked",
})
PlaceObj('CombatAction', {
ActionPoints = 1000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(131999829664, --[[CombatAction Interact_WindowBreak Description]] "Break the window."),
DisplayName = T(174179805252, --[[CombatAction Interact_WindowBreak DisplayName]] "Break"),
Execute = function (self, units, args)
CombatActionExecuteWithMove(self, units, args)
end,
GetAPCost = function (self, unit, args)
return CombatActionInteractionGetCost(self, unit, args)
end,
GetTargets = function (self, units)
return units[1]:GetReachableObjects("SlabWallWindow")
end,
GetUIState = function (self, units, args)
local base_state = CombatAction.GetUIState(self, units, args)
if base_state ~= "enabled" then return base_state end
if not args.target:ShouldShowUnitInteraction() then
return "hidden"
end
if args.target.pass_through_state ~= "broken" then
return "enabled"
end
return "hidden"
end,
Icon = "UI/Hud/iw_break_lock",
IdDefault = "Interact_WindowBreakdefault",
InterruptInExploration = true,
IsAimableAttack = false,
MultiSelectBehavior = "first",
QueuedBadgeText = T(815107486828, --[[CombatAction Interact_WindowBreak QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
unit:SetActionCommand("InteractWith", self.id, ap, args.goto_pos, args.goto_ap, args.target)
end,
ShowIn = false,
SortKey = 17,
UseFreeMove = true,
group = "Interactions",
id = "Interact_WindowBreak",
})
PlaceObj('CombatAction', {
ActionPoints = 2000,
ActivePauseBehavior = "queue",
Comment = "leave emplacement",
ConfigurableKeybind = false,
Description = T(353439501830, --[[CombatAction MGLeave Description]] "Leave the Emplacement"),
DisplayName = T(108712918403, --[[CombatAction MGLeave DisplayName]] "Leave Emplacement"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
if not unit:HasStatusEffect("ManningEmplacement") then return -1 end
return self.ActionPoints
end,
Icon = "UI/Icons/Hud/dash",
IdDefault = "MGLeavedefault",
QueuedBadgeText = T(877939170118, --[[CombatAction MGLeave QueuedBadgeText]] "LEAVE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("LeaveEmplacement")
end,
UIBegin = function (self, units, args)
self:Execute(units, args)
end,
group = "MachineGun",
id = "MGLeave",
})
PlaceObj('CombatAction', {
ActionPoints = 1000,
ActivePauseBehavior = "queue",
Description = T(197752638092, --[[CombatAction MGPack Description]] "Cancel machine gun setup and move freely."),
DisplayName = T(717760265144, --[[CombatAction MGPack DisplayName]] "Pack Up Machine Gun"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
if unit:HasStatusEffect("ManningEmplacement") then return -1 end
self.ActionPoints = unit:GetAttackAPCost(self.action, self.weapon, self.ActionPoints)
return self.ActionPoints
end,
Icon = "UI/Icons/Hud/dash",
IdDefault = "MGPackdefault",
KeybindingSortId = "2375",
QueuedBadgeText = T(841179028797, --[[CombatAction MGPack QueuedBadgeText]] "PACK UP"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MGPack", self.id, ap, ...)
end,
UIBegin = function (self, units, args)
self:Execute(units, args)
end,
group = "MachineGun",
id = "MGPack",
param_bindings = {},
})
PlaceObj('CombatAction', {
ActionPoints = 5000,
ActionType = "Ranged Attack",
ActivePauseBehavior = "queue",
AimType = "cone",
ConfigurableKeybind = false,
Description = T(404393085473, --[[CombatAction MGRotate Description]] "Rotate the machine gun's firing cone."),
DisplayName = T(515040916802, --[[CombatAction MGRotate DisplayName]] "Rotate Machine Gun"),
Execute = function (self, units, args)
return CombatActions.Overwatch.Execute(self, units, args)
end,
GetAPCost = function (self, unit, args)
if unit:HasStatusEffect("ManningEmplacement") then return -1 end
local cost = CombatActions.MGSetup:GetAPCost(unit, args) / 2
cost = Max(1, cost / const.Scale.AP) * const.Scale.AP
return cost
end,
GetActionDescription = function (self, units)
local unit = units[1]
local bonus = 0
local cost = self:GetAPCost(unit)
if unit and cost >= 0 then
local weapon = self:GetAttackWeapons(unit)
local aim = Min((unit:GetUIActionPoints() - cost) / const.Scale.AP, weapon.MaxAimActions)
local apply, value = Presets.ChanceToHitModifier.Default.Aim:CalcValue(unit, nil, nil, nil, nil, nil, nil, aim)
bonus = value
end
local attacks = 1
if unit and (cost or -1) >= 0 then
attacks = unit:GetNumMGInterruptAttacks(true)
end
local description = T{self.Description, bonus = bonus}
if unit:UIHasAP(cost, self.id) then
description = description .. T(813594976169, "<newline><newline>Max number of <em>interrupt</em> attacks is based on remaining AP.")
end
return description
end,
GetActionResults = function (self, unit, args)
return CombatActions.Overwatch.GetActionResults(self, unit, args)
end,
GetAimParams = function (self, unit, weapon)
return CombatActions.Overwatch.GetAimParams(self, unit, weapon)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return CombatActions.Overwatch.GetMaxAimRange(self, unit, weapon)
end,
GetMinAimRange = function (self, unit, weapon)
return CombatActions.Overwatch.GetMinAimRange(self, unit, weapon)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled", GetUnitNoApReason(unit) end
local in_water = terrain.IsWater(unit)
if in_water then
return "disabled", AttackDisableReasons.Water
end
return "enabled"
end,
Icon = "UI/Icons/Hud/bullet_hell",
IdDefault = "MGRotatedefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectOverwatch",
KeybindingSortId = "2371",
MultiSelectBehavior = "hidden",
QueuedBadgeText = T(361425500129, --[[CombatAction MGRotate QueuedBadgeText]] "ROTATE"),
Run = function (self, unit, ap, ...)
--PlayVoiceResponse(unit, "Overwatch")
unit:SetActionCommand("MGTarget", self.id, ap, ...)
end,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "cancel")
end,
group = "MachineGun",
id = "MGRotate",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
ActivePauseBehavior = "queue",
AimType = "cone",
ConfigurableKeybind = false,
Description = T(868121469992, --[[CombatAction MGSetup Description]] "Focus on a cone-shaped area, immobilizing yourself and going <em>prone</em>. You can only shoot enemies inside that cone. Accuracy is increased and enemies will provoke <em>interrupt</em> attacks with actions inside the cone (even if your AP are spent)."),
DisplayName = T(898083486639, --[[CombatAction MGSetup DisplayName]] "Set Machine Gun"),
Execute = function (self, units, args)
return CombatActions.Overwatch.Execute(self, units, args)
end,
GetAPCost = function (self, unit, args)
local base = self:ResolveValue("max_cost") * const.Scale.AP
local min = self:ResolveValue("min_cost") * const.Scale.AP
local min_str = self:ResolveValue("min_str")
local cost = base - MulDivRound(Max(0, unit.Strength - min_str), base - min, 100 - min_str)
cost = Max(min, (cost / const.Scale.AP) * const.Scale.AP)
return unit:GetAttackAPCost(self, self:GetAttackWeapons(unit), cost)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local bonus = 0
local cost = self:GetAPCost(unit)
if unit and cost >= 0 then
local weapon = self:GetAttackWeapons(unit)
if not weapon then return self.Description end
local aim = Min((unit:GetUIActionPoints() - cost) / const.Scale.AP, weapon.MaxAimActions)
local apply, value = Presets.ChanceToHitModifier.Default.Aim:CalcValue(unit, nil, nil, nil, nil, nil, nil, aim)
bonus = value
end
local attacks = 1
if unit and (cost or -1) >= 0 then
attacks = unit:GetNumMGInterruptAttacks(true)
end
local description = T{self.Description, bonus = bonus}
if unit:UIHasAP(cost, self.id) then
description = description .. T(813594976169, "<newline><newline>Max number of <em>interrupt</em> attacks is based on remaining AP.")
end
return description
end,
GetActionResults = function (self, unit, args)
return CombatActions.Overwatch.GetActionResults(self, unit, args)
end,
GetAimParams = function (self, unit, weapon)
return CombatActions.Overwatch.GetAimParams(self, unit, weapon)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return CombatActions.Overwatch.GetMaxAimRange(self, unit, weapon)
end,
GetMinAimRange = function (self, unit, weapon)
return CombatActions.Overwatch.GetMinAimRange(self, unit, weapon)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
local weapon = self:GetAttackWeapons(unit, args)
local ok, reason = unit:CanUseWeapon(weapon)
if not ok then return "disabled", reason end
if not unit:UIHasAP(cost) then return "disabled", GetUnitNoApReason(unit) end
local in_water = terrain.IsWater(unit)
if in_water then
return "disabled", AttackDisableReasons.Water
end
local attack = unit:GetDefaultAttackAction()
local state, reason = attack:GetUIState(units, args)
if state ~= "enabled" and (reason == AttackDisableReasons.NoWeapon or reason == AttackDisableReasons.OutOfAmmo or reason == AttackDisableReasons.WeaponJammed or reason == AttackDisableReasons.InsufficientAmmo) then
return state, reason
end
return "enabled"
end,
Icon = "UI/Icons/Hud/SetMachineGun ",
IdDefault = "MGSetupdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectOverwatch",
KeybindingSortId = "2370",
MultiSelectBehavior = "hidden",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "min_cost",
'Value', 4,
'Tag', "<min_cost>",
}),
PlaceObj('PresetParamNumber', {
'Name', "max_cost",
'Value', 10,
'Tag', "<max_cost>",
}),
PlaceObj('PresetParamNumber', {
'Name', "min_str",
'Value', 50,
'Tag', "<min_str>",
}),
},
QueuedBadgeText = T(515583344616, --[[CombatAction MGSetup QueuedBadgeText]] "SET"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("MGSetup", self.id, ap, ...)
end,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "cancel")
end,
group = "MachineGun",
id = "MGSetup",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(579959239660, --[[CombatAction Attack Description]] "Make an attack using your equipped weapon. Some weapons have alternative attack modes."),
DisplayName = T(449333187481, --[[CombatAction Attack DisplayName]] "Attack"),
Execute = function (self, units, args)
local unit = units[1]
local defAction = unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Execute(units, args)
end,
GetAPCost = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
if not defAction then
assert(false) -- This unit's action caching did something weird?
return
end
return CombatActions[defAction]:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionDamage(unit, target, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
return CombatActionsAppendFreeAimDescription(self, unit, self.Description)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionResults(unit, args)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
local weapon, _, list = unit:GetActiveWeapons("Firearm")
return weapon
end,
GetUIState = function (self, units, args)
return CombatActionFiringMetaGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/attack",
IdDefault = "Attackdefault",
InterruptInExploration = true,
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Run(unit, ap, ...)
end,
ShowIn = "Special",
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack", "attack")
end,
basicAttack = true,
group = "FiringModeMetaAction",
id = "Attack",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = -1000,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(278014409867, --[[CombatAction AttackDual Description]] "Make an attack using your equipped weapon. Some weapons have alternative attack modes."),
DisplayName = T(701092552040, --[[CombatAction AttackDual DisplayName]] "Dual Shot"),
DisplayNameShort = T(582378660435, --[[CombatAction AttackDual DisplayNameShort]] "Dual Shot"),
Execute = function (self, units, args)
local unit = units[1]
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Execute(units, args)
end,
GetAPCost = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionDamage(unit, target, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
return CombatActionsAppendFreeAimDescription(self, unit, self.Description)
end,
GetActionDisplayName = function (self, units)
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
local unit = units[1]
return CombatActionsAppendFreeAimActionName(self, unit, name)
end,
GetActionResults = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionResults(unit, args)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetActiveWeapons("Firearm")
end,
GetUIState = function (self, units, args)
return CombatActionFiringMetaGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/attack",
IdDefault = "AttackDualdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Run(unit, ap, ...)
end,
ShowIn = "Special",
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack", "attack")
end,
basicAttack = true,
group = "FiringModeMetaAction",
id = "AttackDual",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "cone",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
Description = T(406630009702, --[[CombatAction AttackShotgun Description]] "Make an attack using your equipped weapon. Targets in the attack cone take guaranteed damage. Some weapons have alternative firing modes."),
DisplayName = T(591280140960, --[[CombatAction AttackShotgun DisplayName]] "Shotgun Attack"),
Execute = function (self, units, args)
local unit = units[1]
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Execute(units, args)
end,
GetAPCost = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetAPCost(unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionDamage(unit, target, args)
end,
GetActionDescription = function (self, units)
local unit = units[1]
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionDescription(units)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionDisplayName(units)
end,
GetActionResults = function (self, unit, args)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetActionResults(unit, args)
end,
GetAimParams = function (self, unit, weapon)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetAimParams(unit, weapon)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:GetMinAimRange(unit, weapon)
end,
GetUIState = function (self, units, args)
return CombatActionFiringMetaGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/attack",
IdDefault = "AttackShotgundefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectBasicAttack",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
local defAction = unit.ui_actions and unit.ui_actions[self.IdDefault] or unit:ResolveDefaultFiringModeAction(self, true)
return CombatActions[defAction]:Run(unit, ap, ...)
end,
ShowIn = "Special",
SortKey = 1,
StealthAttack = true,
UIBegin = function (self, units, args)
local dlg = GetInGameInterfaceModeDlg()
if IsKindOf(dlg, "IModeCombatAreaAim") and dlg.crosshair then
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "attack")
else
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end
end,
basicAttack = true,
group = "FiringModeMetaAction",
id = "AttackShotgun",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(760140507992, --[[CombatAction StanceStanding Description]] "Normal movement."),
DisplayName = T(892987595505, --[[CombatAction StanceStanding DisplayName]] "Stance: Standing"),
DisplayNameShort = T(878700600627, --[[CombatAction StanceStanding DisplayNameShort]] "Standing"),
Execute = function (self, units, args)
if self:GetUIState(units, args) ~= "enabled" then
return
end
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return unit:GetStanceToStanceAP("Standing", args and args.stance_override)
end,
GetActionIcon = function (self, units)
local unit = units[1]
local cover = GetHighestCoverUI(unit)
if cover then
return cover == const.CoverHigh and "UI/Hud/stances_cover_full" or "UI/Hud/stances_up"
end
return self.Icon
end,
GetUIState = function (self, units, args)
if #units > 1 and not g_Combat then
return "enabled"
end
local unit = units[1]
local canSwitch, reason = unit:CanSwitchStance("Standing", args)
if reason == "hidden" then return reason end
return canSwitch and "enabled" or "disabled", reason
end,
Icon = "UI/Hud/stances_up",
IdDefault = "StanceStandingdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(700088630352, --[[CombatAction StanceStanding QueuedBadgeText]] "CHANGE STANCE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
if not g_Combat and unit.goto_target and not IsActivePaused() then
unit.goto_stance = "Standing"
return
end
unit:SetActionCommand("ChangeStance", self.id, ap, "Standing", ...)
end,
ShowIn = "Stances",
SortKey = 1,
UseFreeMove = true,
group = "Stances",
id = "StanceStanding",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(923499847364, --[[CombatAction StanceCrouch Description]] "Decreased movement range.\nHarder to hit with ranged attacks and resistant to explosive damage."),
DisplayName = T(849813879402, --[[CombatAction StanceCrouch DisplayName]] "Stance: Crouched"),
DisplayNameShort = T(904286738966, --[[CombatAction StanceCrouch DisplayNameShort]] "Crouched"),
Execute = function (self, units, args)
if self:GetUIState(units, args) ~= "enabled" then
return
end
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return unit:GetStanceToStanceAP("Crouch", args and args.stance_override)
end,
GetActionIcon = function (self, units)
local unit = units[1]
local cover = GetHighestCoverUI(unit)
if cover then
return (cover == const.CoverHigh or cover == const.CoverLow) and "UI/Hud/stances_cover" or "UI/Hud/stances_middle"
end
return self.Icon
end,
GetTargets = function (self, units)
return units[1]:GetVisibleEnemies()
end,
GetUIState = function (self, units, args)
if #units > 1 and not g_Combat then
return "enabled"
end
local unit = units[1]
local canSwitch, reason = unit:CanSwitchStance("Crouch", args)
if reason == "hidden" then return reason end
return canSwitch and "enabled" or "disabled", reason
end,
Icon = "UI/Hud/stances_middle",
IdDefault = "StanceCrouchdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(114028599146, --[[CombatAction StanceCrouch QueuedBadgeText]] "CHANGE STANCE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
if not g_Combat and unit.goto_target and not IsActivePaused() then
unit.goto_stance = "Crouch"
return
end
unit:SetActionCommand("ChangeStance", self.id, ap, "Crouch", ...)
end,
ShowIn = "Stances",
SortKey = 2,
UseFreeMove = true,
group = "Stances",
id = "StanceCrouch",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
Description = T(772277920996, --[[CombatAction StanceProne Description]] "Greatly decreased movement range. Can't climb or jump over obstacles.\nMuch harder to hit with ranged attacks and very resistant to explosive damage."),
DisplayName = T(775355544630, --[[CombatAction StanceProne DisplayName]] "Stance: Prone"),
DisplayNameShort = T(587848793431, --[[CombatAction StanceProne DisplayNameShort]] "Prone"),
Execute = function (self, units, args)
if self:GetUIState(units, args) ~= "enabled" then
return
end
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local ap = unit:GetStanceToStanceAP("Prone", args and args.stance_override)
return ap
end,
GetUIState = function (self, units, args)
local allowed, text
for i, unit in ipairs(units) do
local canSwitch, reason = unit:CanSwitchStance("Prone", args)
if canSwitch or reason == "hidden" then
allowed = true
break
else
allowed = "disabled"
text = reason
end
end
if allowed == "disabled" then
return allowed, text
end
if #units > 1 and not g_Combat then
return "enabled"
end
local unit = units[1]
local canSwitch, reason = unit:CanSwitchStance("Prone", args)
if reason == "hidden" then return reason end
return canSwitch and "enabled" or "disabled", reason
end,
Icon = "UI/Hud/stances_down",
IdDefault = "StancePronedefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(438930896929, --[[CombatAction StanceProne QueuedBadgeText]] "CHANGE STANCE"),
RequireState = "any",
Run = function (self, unit, ap, ...)
if not g_Combat and unit.goto_target and not IsActivePaused() then
unit.goto_stance = "Prone"
return
end
unit:SetActionCommand("ChangeStance", self.id, ap, "Prone", ...)
end,
ShowIn = "Stances",
SortKey = 3,
UseFreeMove = true,
group = "Stances",
id = "StanceProne",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = 'Placeholder action to allow controllable beasts who are in stance ""',
ConfigurableKeybind = false,
DisplayName = T(417850002799, --[[CombatAction Stance DisplayName]] "StanceStanding"),
IdDefault = "Stancedefault",
InterruptInExploration = true,
QueuedBadgeText = T(562909457289, --[[CombatAction Stance QueuedBadgeText]] "CHANGE STANCE"),
ShowIn = false,
SortKey = 99,
UseFreeMove = true,
group = "Stances",
id = "Stance",
})
PlaceObj('CombatAction', {
ActionShortcut = "1",
AimType = "line",
ConfigurableKeybind = false,
DisplayName = T(464727480495, --[[CombatAction Action1 DisplayName]] "Action 1"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action1default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(1)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 1,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action1",
})
PlaceObj('CombatAction', {
ActionShortcut = "2",
ConfigurableKeybind = false,
DisplayName = T(950327111815, --[[CombatAction Action2 DisplayName]] "Action 2"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action2default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(2)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 2,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action2",
})
PlaceObj('CombatAction', {
ActionShortcut = "3",
ConfigurableKeybind = false,
DisplayName = T(354149051865, --[[CombatAction Action3 DisplayName]] "Action 3"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action3default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(3)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 3,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action3",
})
PlaceObj('CombatAction', {
ActionShortcut = "4",
ConfigurableKeybind = false,
DisplayName = T(581763369778, --[[CombatAction Action4 DisplayName]] "Action 4"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action4default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(4)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 4,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action4",
})
PlaceObj('CombatAction', {
ActionShortcut = "5",
ConfigurableKeybind = false,
DisplayName = T(640626466336, --[[CombatAction Action5 DisplayName]] "Action 5"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action5default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(5)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 5,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action5",
})
PlaceObj('CombatAction', {
ActionShortcut = "6",
AimType = "melee",
ConfigurableKeybind = false,
DisplayName = T(131093562331, --[[CombatAction Action6 DisplayName]] "Action 6"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action6default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(6)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 6,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action6",
})
PlaceObj('CombatAction', {
ActionShortcut = "7",
ConfigurableKeybind = false,
DisplayName = T(612538760827, --[[CombatAction Action7 DisplayName]] "Action 7"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action7default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(7)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 7,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action7",
})
PlaceObj('CombatAction', {
ActionShortcut = "8",
ConfigurableKeybind = false,
DisplayName = T(346351186243, --[[CombatAction Action8 DisplayName]] "Action 8"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action8default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(8)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 8,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action8",
})
PlaceObj('CombatAction', {
ActionShortcut = "9",
ConfigurableKeybind = false,
DisplayName = T(929240688056, --[[CombatAction Action9 DisplayName]] "Action 9"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action9default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(9)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 9,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action9",
})
PlaceObj('CombatAction', {
ActionShortcut = "0",
ConfigurableKeybind = false,
DisplayName = T(884893693139, --[[CombatAction Action10 DisplayName]] "Action 10"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action10default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(10)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 10,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action10",
})
PlaceObj('CombatAction', {
ActionShortcut = "-",
ConfigurableKeybind = false,
DisplayName = T(862495147832, --[[CombatAction Action11 DisplayName]] "Action 11"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action11default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(11)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 11,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action11",
})
PlaceObj('CombatAction', {
ActionShortcut = "=",
ConfigurableKeybind = false,
DisplayName = T(550345032199, --[[CombatAction Action12 DisplayName]] "Action 12"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action12default",
IsAimableAttack = false,
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(12)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 12,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action12",
})
PlaceObj('CombatAction', {
Comment = "Signature Ability goes here.",
ConfigurableKeybind = false,
DisplayName = T(432523773389, --[[CombatAction Action13 DisplayName]] "Signature Ability"),
EvalTarget = function (self, units, target, args)
local action = self:ResolveAction(units)
if action then
return action:EvalTarget(units, target, args)
end
end,
Execute = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:Execute(units, args)
end
end,
GetAPCost = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAPCost(unit, args)
end
return -1
end,
GetActionDescription = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDescription(units)
end
return ""
end,
GetActionDisplayName = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionDisplayName(units)
end
return ""
end,
GetActionIcon = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetActionIcon(units)
end
return ""
end,
GetAnyTarget = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetAnyTarget(units)
end
end,
GetAttackWeapons = function (self, unit, args)
local action = self:ResolveAction(unit)
if action then
return action:GetAttackWeapons(unit, args)
end
end,
GetDefaultTarget = function (self, unit)
local action = self:ResolveAction(unit)
if action then
return action:GetDefaultTarget(unit)
end
end,
GetMaxAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMaxAimRange(unit, weapon)
end
return false
end,
GetMinAimRange = function (self, unit, weapon)
local action = self:ResolveAction(unit)
if action then
return action:GetMinAimRange(unit, weapon)
end
return false
end,
GetTargets = function (self, units)
local action = self:ResolveAction(units)
if action then
return action:GetTargets(units)
end
end,
GetUIState = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:GetUIState(units, args)
end
return "hidden"
end,
IdDefault = "Action13default",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
ResolveAction = function (self, context)
local obj = IsValid(context) and context or (context or empty_table)[1]
return obj and IsKindOf(obj, "Unit") and obj:ResolveUIAction(13)
end,
Run = function (self, unit, ap, ...)
local action = self:ResolveAction(unit)
if action then
return action:Run(unit, ap, ...)
end
end,
SortKey = 13,
UIBegin = function (self, units, args)
local action = self:ResolveAction(units)
if action then
return action:UIBegin(units, args)
end
end,
group = "UIActions",
id = "Action13",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
Description = T(812548786196, --[[CombatAction RemoteDetonation Description]] "Detonate explosives with remote detonation in the area."),
DisableAimAnim = true,
DisplayName = T(189657731700, --[[CombatAction RemoteDetonation DisplayName]] "Remote Detonation"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
return 0
end,
GetActionDescription = function (self, units)
local description = self.Description
if (description or "") == "" then
description = self:GetActionDisplayName()
end
return description
end,
GetActionResults = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit, args)
local target = ResolveGrenadeTargetPos(args.target)
if not grenade or not target then
return {}
end
args.target = target
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = grenade:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
return GetUnitEquippedDetonator(unit)
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.ThrowRange
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/remote_detonation",
IdDefault = "RemoteDetonationdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectThrowGrenade",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("RemoteDetonate", self.id, ap, ...)
end,
SortKey = 5,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "Consumables",
id = "RemoteDetonation",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(576285892355, --[[CombatAction ThrowGrenadeA DisplayName]] "Grenade"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
return grenade and unit:GetAttackAPCost(self, grenade, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
return CombatActionGrenadeDescription(self, units)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
return T{355482653923, "Throw <name>", name = weapon.DisplayName}
end
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
local target = ResolveGrenadeTargetPos(args.target, unit:GetPos(), grenade)
args.target = target
args.stance = "Standing"
local attack_args = unit:PrepareAttackArgs(self.id, args)
if not grenade or not target then
return {}, attack_args
end
local results = grenade:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
local weapon = unit:GetItemInSlot("Handheld A", "Grenade", 1, 1)
return weapon
end,
GetMaxAimRange = function (self, unit, weapon)
local maxRange = weapon:GetMaxAimRange(unit)
if HasPerk(unit, "Throwing") then
maxRange = maxRange + CharacterEffectDefs.Throwing:ResolveValue("RangeIncrease")
end
return maxRange
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/throw_grenade",
IdDefault = "ThrowGrenadeAdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectThrowGrenade",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ThrowGrenade", self.id, ap, ...)
end,
SortKey = 5,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "Consumables",
id = "ThrowGrenadeA",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(126909368045, --[[CombatAction ThrowGrenadeB DisplayName]] "Grenade"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
return grenade and unit:GetAttackAPCost(self, grenade, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
return CombatActionGrenadeDescription(self, units)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
return T{355482653923, "Throw <name>", name = weapon.DisplayName}
end
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.ThrowGrenadeA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
local weapon = unit:GetItemInSlot("Handheld A", "Grenade", 2, 1)
return weapon
end,
GetMaxAimRange = function (self, unit, weapon)
local maxRange = weapon:GetMaxAimRange(unit)
if HasPerk(unit, "Throwing") then
maxRange = maxRange + CharacterEffectDefs.Throwing:ResolveValue("RangeIncrease")
end
return maxRange
end,
GetUIState = function (self, units, args)
return CombatActions.ThrowGrenadeA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/throw_grenade",
IdDefault = "ThrowGrenadeBdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectThrowGrenade",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ThrowGrenade", self.id, ap, ...)
end,
SortKey = 6,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "Consumables",
id = "ThrowGrenadeB",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(638369035024, --[[CombatAction ThrowGrenadeC DisplayName]] "Grenade"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
return grenade and unit:GetAttackAPCost(self, grenade, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
return CombatActionGrenadeDescription(self, units)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
return T{355482653923, "Throw <name>", name = weapon.DisplayName}
end
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.ThrowGrenadeA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
local weapon = unit:GetItemInSlot("Handheld B", "Grenade", 1, 1)
return weapon
end,
GetMaxAimRange = function (self, unit, weapon)
local maxRange = weapon:GetMaxAimRange(unit)
if HasPerk(unit, "Throwing") then
maxRange = maxRange + CharacterEffectDefs.Throwing:ResolveValue("RangeIncrease")
end
return maxRange
end,
GetUIState = function (self, units, args)
return CombatActions.ThrowGrenadeA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/throw_grenade",
IdDefault = "ThrowGrenadeCdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectThrowGrenade",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ThrowGrenade", self.id, ap, ...)
end,
SortKey = 6,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "Consumables",
id = "ThrowGrenadeC",
})
PlaceObj('CombatAction', {
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(264282791362, --[[CombatAction ThrowGrenadeD DisplayName]] "Grenade"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
return grenade and unit:GetAttackAPCost(self, grenade, false, args and args.aim or 0) or -1
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
return CombatActionGrenadeDescription(self, units)
end,
GetActionDisplayName = function (self, units)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
return T{355482653923, "Throw <name>", name = weapon.DisplayName}
end
end
local name = self.DisplayName
if (name or "") == "" then
name = Untranslated(self.id)
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.ThrowGrenadeA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
local weapon = unit:GetItemInSlot("Handheld B", "Grenade", 2, 1)
return weapon
end,
GetMaxAimRange = function (self, unit, weapon)
local maxRange = weapon:GetMaxAimRange(unit)
if HasPerk(unit, "Throwing") then
maxRange = maxRange + CharacterEffectDefs.Throwing:ResolveValue("RangeIncrease")
end
return maxRange
end,
GetUIState = function (self, units, args)
return CombatActions.ThrowGrenadeA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/throw_grenade",
IdDefault = "ThrowGrenadeDdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectThrowGrenade",
MultiSelectBehavior = "first",
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ThrowGrenade", self.id, ap, ...)
end,
SortKey = 6,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "Consumables",
id = "ThrowGrenadeD",
})
PlaceObj('CombatAction', {
ActionPoints = 2000,
ActivePauseBehavior = "queue",
AimType = "melee",
ConfigurableKeybind = false,
Description = T(105765420738, --[[CombatAction Bandage Description]] "Spend some time healing a wounded ally. You will not be able to perform other actions while bandaging. Your ally will not be able to move but can still attack.\n\nStabilize <GameTerm('Downed')> <em>allies</em> or <em>heal <hp>% of their max HP</em> (based on the <em><medical> skill</em>). Sets your stance to <em>Crouched</em>."),
DisplayName = T(615556944457, --[[CombatAction Bandage DisplayName]] "Bandage"),
EvalTarget = function (self, units, target, args)
local unit = units[1]
if not target or unit:IsOnEnemySide(target) then return -1 end
if not target:HasStatusEffect("Bleeding") and (target.HitPoints >= target.MaxHitPoints) then return -1 end
return (200 - target.HitPoints) or 0
end,
GetAPCost = function (self, unit, args)
local medicine = self:GetAttackWeapons(unit, args)
if not medicine then return -1 end -- can be valid in AI PrecalcAction
return self.ActionPoints
end,
GetActionDescription = function (self, units)
local unit = units[1]
local medkit = self:GetAttackWeapons(unit)
local hp = unit:CalcHealAmount(medkit) or 0
local percent = MulDivRound(100, hp, unit.MaxHitPoints)
if LastLoadedOrLoadingIMode == "IModeCombatMelee" then
return T{930612158384, "Select the unit you would like to bandage, healing them for <hp>% of their max HP.", hp = percent}
end
return T{self.Description, hp = percent}
end,
GetAnyTarget = function (self, units)
return GetBandageTargets(units[1], "any", "ignore")
end,
GetAttackWeapons = function (self, unit, args)
return GetUnitEquippedMedicine(unit)
end,
GetDefaultTarget = function (self, unit)
local units = {unit}
if self:EvalTarget(units, unit) > 0 then
return unit
end
return CombatAction.GetDefaultTarget(self, unit)
end,
GetTargets = function (self, units)
return GetBandageTargets(units[1], "all", "ignore")
end,
GetUIState = function (self, units, args)
local unit = units[1]
if g_Combat and not unit:HasAP(self.ActionPoints) then
return "disabled", GetUnitNoApReason(unit)
end
if not GetBandageTargets(unit, "any", "reachable") then
return "disabled", AttackDisableReasons.NoBandageTarget
end
return "enabled"
end,
Icon = "UI/Icons/Hud/stop_bleeding",
IdDefault = "Bandagedefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectBandage",
MoveStep = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "selfheal",
'Value', 70,
'Tag', "<selfheal>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "base_heal",
'Value', 20,
'Tag', "<base_heal>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "medical_max_heal",
'Value', 30,
'Tag', "<medical_max_heal>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "ReviveConditionLoss",
'Value', 10,
'Tag', "<ReviveConditionLoss>",
}),
PlaceObj('PresetParamNumber', {
'Name', "MaxConditionHPRestore",
'Value', 120,
'Tag', "<MaxConditionHPRestore>",
}),
},
QueuedBadgeText = T(989605585095, --[[CombatAction Bandage QueuedBadgeText]] "BANDAGE"),
RequireState = "any",
RequireWeapon = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("Bandage", self.id, ap, ...)
end,
SortKey = 10,
UIBegin = function (self, units, args)
if self:GetAnyTarget(units) then
if units then
table.sort(units, function (a,b)
return a.Medical > b.Medical and self:GetAttackWeapons(a)
end)
end
CombatActionAttackStart(self, units, args, "IModeCombatMelee")
end
end,
group = "Consumables",
id = "Bandage",
})
PlaceObj('CombatAction', {
ActivePauseBehavior = "queue",
Comment = "used by AI",
Description = T(682794130547, --[[CombatAction Interact Description]] "Interact with nearby objects."),
DisplayName = T(381772065068, --[[CombatAction Interact DisplayName]] "Interact"),
EvalTarget = function (self, units, target)
local closest_unit = ChooseClosestObject(units, target)
local combat_action = target:GetInteractionCombatAction()
if not combat_action then return end
return combat_action:EvalTarget(closest_unit, target)
end,
Execute = function (self, units, args)
local target = args and args.target
if not target then return end
local closest_unit = ChooseClosestObject(units, target)
local combat_action = target:GetInteractionCombatAction(closest_unit)
if not combat_action then return end
if HasCombatActionInProgress(closest_unit) and not closest_unit:IsInterruptable() then return end
return combat_action:Execute(closest_unit, args)
end,
GetAPCost = function (self, unit, args)
if args and args.override_ap_cost then
return args.override_ap_cost
end
local target = args and args.target
if not target then
local targets = self:GetTargets{ unit }
if #targets ~= 1 then
return self.ActionPoints
end
target = targets[1]
end
local combat_action = target:GetInteractionCombatAction(unit)
if not combat_action then return -1 end
local args = args or {}
args.target = target
return combat_action:GetAPCost(unit, args)
end,
GetActionDescription = function (self, units)
local target = self:GetAnyTarget(units)
if not target then return self.Description end
local closest_unit = ChooseClosestObject(units, target)
local combat_action = target:GetInteractionCombatAction(closest_unit)
if not combat_action then return self.Description end
return T{combat_action:GetActionDescription(closest_unit), target = target, unit = closest_unit}
end,
GetActionDisplayName = function (self, units)
local target = self:GetAnyTarget(units)
if not target then return self.DisplayName end
local closest_unit = ChooseClosestObject(units, target)
local combat_action = target:GetInteractionCombatAction(closest_unit)
if not combat_action then return self.Description end
return T{combat_action:GetActionDisplayName(closest_unit), target = target, unit = closest_unit} .. T{697667667158, " (<Nick>)", closest_unit}
end,
GetActionIcon = function (self, units)
local target = self:GetAnyTarget(units)
if not target then return self.Icon end
local combat_action = target:GetInteractionCombatAction()
if not combat_action then return self.Icon end
local closest_unit = ChooseClosestObject(units, target)
return combat_action:GetActionIcon(closest_unit)
end,
GetAnyTarget = function (self, units)
return self:GetTargets(units)[1]
end,
GetDefaultTarget = function (self, unit)
local best_eval, best_target
local targets = self:GetTargets({unit})
if #targets == 0 then return false, false end
return targets[1], 100
end,
GetTargets = function (self, units)
if #units == 0 then return {} end
local interactables = false
for i = 1, #units do
interactables = units[i]:GetReachableObjects("Interactable")
if #interactables > 0 then
break
end
end
local result = { }
for i=1,#interactables do
local interactable = interactables[i]
local closest_unit = ChooseClosestObject(units, interactable, function(o)
local combat_action = interactable:GetInteractionCombatAction(o)
assert(not combat_action or combat_action.group == "Interactions", "Interaction CombatActions must be in the 'Interactions' group")
if not combat_action or combat_action.ShowIn ~= false then
return false
end
return o:CanInteractWith(interactable, combat_action.id)
end)
if closest_unit then
table.insert(result, interactable)
end
end
return result
end,
GetUIState = function (self, units, args)
local unit = units[1]
local target = args and args.target
if target then
local combat_action = target:GetInteractionCombatAction(unit)
if combat_action then
return combat_action:GetUIState(units, args)
end
return "hidden"
end
if not self:GetAnyTarget(units) then
return "hidden"
end
return "enabled"
end,
Icon = "UI/Icons/Hud/interact",
IdDefault = "Interactdefault",
InterruptInExploration = true,
IsAimableAttack = false,
QueuedBadgeText = T(560853521122, --[[CombatAction Interact QueuedBadgeText]] "INTERACT"),
RequireState = "any",
Run = function (self, unit, ap, ...)
local args = ...
local target = args and args.target
if not target or HasCombatActionInProgress(unit) then return end
local combat_action = target:GetInteractionCombatAction(unit)
if not combat_action then return end
return combat_action:Run(unit, ap, args)
end,
ShowIn = false,
SortKey = 12,
UIBegin = function (self, units, args)
CombatActionInteractablesChoice(self, units, args)
end,
group = "ToDelete",
id = "Interact",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(494742880689, --[[CombatAction BuildingConfidence DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_building_confidence",
IdDefault = "BuildingConfidencedefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "BuildingConfidence",
})
PlaceObj('CombatAction', {
ActionPoints = 8000,
ActionType = "Ranged Attack",
AimType = "cone",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(962244361104, --[[CombatAction BulletHell DisplayName]] "<placeholder>"),
Execute = function (self, units, args)
local unit = units[1]
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local damage = base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.weapon = args.weapon or self:GetAttackWeapons(unit, args)
args.num_shots = Clamp(args.weapon.ammo.Amount, self:ResolveValue("min_ammo"), self:ResolveValue("max_ammo"))
args.applied_status = { "Suppressed", "SuppressionChangeStance" }
args.aoe_fx_action = "WeaponAutoFire"
args.aoe_action_id = self.id
args.aoe_damage_bonus = MulDivRound(self:ResolveValue("max_ammo_aoe_damage_bonus"), args.num_shots, self:ResolveValue("max_ammo"))
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetUIState = function (self, units, args)
local unit = units[1]
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "disabled", AttackDisableReasons.RangedWeapon end
local canUse, err = unit:CanUseWeapon(weapon1)
if not canUse then return "disabled", err end
if not table.find(weapon1.AvailableAttacks, "AutoFire") and not table.find(weapon1.AvailableAttacks, "MGBurstFire") then
return "disabled", AttackDisableReasons.WrongWeapon
end
if not weapon1.ammo or weapon1.ammo.Amount < self:ResolveValue("min_ammo") then
return "disabled", AttackDisableReasons.OutOfAmmo
end
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "disabled" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_bullet_hell",
IdDefault = "BulletHelldefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "min_ammo",
'Value', 15,
'Tag', "<min_ammo>",
}),
PlaceObj('PresetParamNumber', {
'Name', "max_ammo",
'Value', 30,
'Tag', "<max_ammo>",
}),
PlaceObj('PresetParamNumber', {
'Name', "max_ammo_aoe_damage_bonus",
'Value', 200,
'Tag', "<max_ammo_aoe_damage_bonus>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("BulletHell", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "SignatureAbilities",
id = "BulletHell",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(496185040855, --[[CombatAction BunsPerk DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_buns_perk",
IdDefault = "BunsPerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "BunsPerk",
})
PlaceObj('CombatAction', {
ActionPointDelta = 1000,
ActionPoints = 1000,
ActionType = "Ranged Attack",
AimType = "cone",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(613567478477, --[[CombatAction DanceForMe DisplayName]] "<placeholder>"),
Execute = function (self, units, args)
local unit = units[1]
local attacks, aim = unit:GetOverwatchAttacksAndAim(self, args)
args.num_attacks = attacks
args.aim = aim
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return CombatActions.Overwatch.GetAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local damage = base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local total, cost = self:GetAPCost(unit)
local attacks = 1
if unit and (cost or -1) >= 0 then
attacks = unit:GetOverwatchAttacksAndAim()
end
local description = GetSignatureActionDescription(self)
description = description .. T{452784485986, "<newline><newline>Max attacks: <em><attacks></em>", attacks = attacks}
return description
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
return CombatActions.Overwatch.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetOverwatchConeParam("MaxRange")
end,
GetMinAimRange = function (self, unit, weapon)
return weapon:GetOverwatchConeParam("MinRange")
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
local unit = units[1]
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "disabled", AttackDisableReasons.RangedWeapon end
if not weapon1.ammo or weapon1.ammo.Amount < 1 then
return "disabled", AttackDisableReasons.OutOfAmmo
end
local cost = self:GetAPCost(unit, args)
if not unit:UIHasAP(cost) then return "disabled" end
local attack = unit:GetDefaultAttackAction()
local state, reason = attack:GetUIState(units, args)
return state, reason
end,
Icon = "UI/Icons/Hud/perk_dance_for_me",
IdDefault = "DanceForMedefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("DanceForMe", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "cancel")
end,
group = "SignatureAbilities",
id = "DanceForMe",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(439812642795, --[[CombatAction DangerClose DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_danger_close",
IdDefault = "DangerClosedefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "DangerClose",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(224326165572, --[[CombatAction DedicatedCamper DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_dedicated_camper",
IdDefault = "DedicatedCamperdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "DedicatedCamper",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(195694738947, --[[CombatAction DesignerExplosives DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_designer_explosives",
IdDefault = "DesignerExplosivesdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "DesignerExplosives",
})
PlaceObj('CombatAction', {
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(355737085755, --[[CombatAction DoubleTossA DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
local action = {id = "DoubleToss", Description = self.Description}
local description = GetSignatureActionDescription(action)
local grenadeDescription = CombatActionGrenadeDescription(self, units)
description = description .. T(866574791377, "<newline><newline>") .. grenadeDescription
return description
end,
GetActionDisplayName = function (self, units)
local action = {id = "DoubleToss", DisplayName = self.DisplayName}
local name = GetSignatureActionDisplayName(action)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
name = name .. T{279081600107, " <name>", name = weapon.DisplayName}
end
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
local grenade = self:GetAttackWeapons(unit)
local target = ResolveGrenadeTargetPos(args.target)
if not target or not grenade then
return {}
end
-- get target_offset from DoubleTossA always (the function can be called for other actions)
local target_offset = CombatActions.DoubleTossA:ResolveValue("target_offset")
local offset = MulDivRound(grenade.AreaOfEffect * const.SlabSizeX, target_offset, 100)
if grenade.coneShaped then
offset = offset / DivRound(360, grenade.coneAngle)
end
local offset_dir = RotateRadius(offset, CalcOrientation(args.step_pos or unit, target) + 90*60)
local args_arr = {}
args_arr[1] = table.copy(args)
args_arr[2] = table.copy(args)
args_arr[1].target = target + offset_dir
args_arr[2].target = target - offset_dir
if args.explosion_pos then
args_arr[1].explosion_pos = args.explosion_pos[1]
args_arr[2].explosion_pos = args.explosion_pos[2]
end
local attacks = {}
for i = 1, 2 do
local results, attack_args = CombatActions.ThrowGrenadeA.GetActionResults(self, unit, args_arr[i])
attacks[i] = results
attacks[i].attack_args = attack_args
end
local results = MergeAttacks(attacks)
return results, attacks[1].attack_args
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetItemInSlot("Handheld A", "Grenade", 1, 1)
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetMaxAimRange(unit)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit)
if not weapon1 or weapon1.Amount < 2 then
return "disabled", AttackDisableReasons.OutOfAmmo
end
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_double_toss",
IdDefault = "DoubleTossAdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "target_offset",
'Value', 75,
'Tag', "<target_offset>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("DoubleToss", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "SignatureAbilities",
id = "DoubleTossA",
})
PlaceObj('CombatAction', {
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(355737085755, --[[CombatAction DoubleTossB DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
local action = {id = "DoubleToss", Description = self.Description}
local description = GetSignatureActionDescription(action)
local grenadeDescription = CombatActionGrenadeDescription(self, units)
description = description .. T(866574791377, "<newline><newline>") .. grenadeDescription
return description
end,
GetActionDisplayName = function (self, units)
local action = {id = "DoubleToss", DisplayName = self.DisplayName}
local name = GetSignatureActionDisplayName(action)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
name = name .. T{279081600107, " <name>", name = weapon.DisplayName}
end
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.DoubleTossA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetItemInSlot("Handheld A", "Grenade", 2, 1)
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetMaxAimRange(unit)
end,
GetUIState = function (self, units, args)
return CombatActions.DoubleTossA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_double_toss",
IdDefault = "DoubleTossBdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "target_offset",
'Value', 75,
'Tag', "<target_offset>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("DoubleToss", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "SignatureAbilities",
id = "DoubleTossB",
})
PlaceObj('CombatAction', {
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(355737085755, --[[CombatAction DoubleTossC DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
local action = {id = "DoubleToss", Description = self.Description}
local description = GetSignatureActionDescription(action)
local grenadeDescription = CombatActionGrenadeDescription(self, units)
description = description .. T(866574791377, "<newline><newline>") .. grenadeDescription
return description
end,
GetActionDisplayName = function (self, units)
local action = {id = "DoubleToss", DisplayName = self.DisplayName}
local name = GetSignatureActionDisplayName(action)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
name = name .. T{279081600107, " <name>", name = weapon.DisplayName}
end
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.DoubleTossA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetItemInSlot("Handheld B", "Grenade", 1, 1)
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetMaxAimRange(unit)
end,
GetUIState = function (self, units, args)
return CombatActions.DoubleTossA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_double_toss",
IdDefault = "DoubleTossCdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "target_offset",
'Value', 75,
'Tag', "<target_offset>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("DoubleToss", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "SignatureAbilities",
id = "DoubleTossC",
})
PlaceObj('CombatAction', {
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "parabola aoe",
AlwaysHits = true,
ConfigurableKeybind = false,
DisplayName = T(355737085755, --[[CombatAction DoubleTossD DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
local base = unit:GetBaseDamage(weapon)
local bonus = GetGrenadeDamageBonus(unit)
return MulDivRound(base, Max(0, 100 + bonus), 100)
end,
GetActionDescription = function (self, units)
local action = {id = "DoubleToss", Description = self.Description}
local description = GetSignatureActionDescription(action)
local grenadeDescription = CombatActionGrenadeDescription(self, units)
description = description .. T(866574791377, "<newline><newline>") .. grenadeDescription
return description
end,
GetActionDisplayName = function (self, units)
local action = {id = "DoubleToss", DisplayName = self.DisplayName}
local name = GetSignatureActionDisplayName(action)
local unit = units[1]
if unit then
local weapon = self:GetAttackWeapons(unit)
if weapon then
name = name .. T{279081600107, " <name>", name = weapon.DisplayName}
end
end
return name
end,
GetActionIcon = function (self, units)
return GetThrowItemIcon(self, units and units[1])
end,
GetActionResults = function (self, unit, args)
return CombatActions.DoubleTossA.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
return unit:GetItemInSlot("Handheld B", "Grenade", 2, 1)
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetMaxAimRange(unit)
end,
GetUIState = function (self, units, args)
return CombatActions.DoubleTossA.GetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_double_toss",
IdDefault = "DoubleTossDdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamPercent', {
'Name', "target_offset",
'Value', 75,
'Tag', "<target_offset>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("DoubleToss", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim")
end,
group = "SignatureAbilities",
id = "DoubleTossD",
})
PlaceObj('CombatAction', {
ActionPoints = 4000,
ActionType = "Melee Attack",
AimType = "melee",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(484685867041, --[[CombatAction ExplodingPalm DisplayName]] "<placeholder>"),
EvalTarget = function (self, units, target, args)
return CombatActions.MeleeAttack.EvalTarget(self, units, target, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
if not args.goto_pos then
args.goto_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.stance = "Standing"
CombatActionExecuteWithMove(self, unit, args)
end,
GetAPCost = function (self, unit, args)
return CombatActions.MeleeAttack.GetAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
args.applied_status = {"Unconscious"}
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
return CombatActions.MeleeAttack.GetAnyTarget(self, units)
end,
GetAttackWeapons = function (self, unit, args)
return not unit:GetActiveWeapons() and unit:GetActiveWeapons("UnarmedWeapon")
end,
GetDefaultTarget = function (self, unit)
return CombatActions.MeleeAttack.GetDefaultTarget(self, unit)
end,
GetTargets = function (self, units)
return CombatActions.MeleeAttack.GetTargets(self, units)
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
local unit = units[1]
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
if not self:GetAttackWeapons(unit) then
return "disabled", AttackDisableReasons.RequiresUnarmed
end
args = args or {}
args.ap_cost_breakdown = args.ap_cost_breakdown or {}
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost, self.id, args) then
return "disabled", GetUnitNoApReason(unit)
end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_exploding_palm",
IdDefault = "ExplodingPalmdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectSignatureAbility",
MoveStep = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("ExplodingPalm", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
return CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
UseFreeMove = true,
group = "SignatureAbilities",
id = "ExplodingPalm",
})
PlaceObj('CombatAction', {
ActionPointDelta = 1000,
ActionPoints = 1000,
ActionType = "Ranged Attack",
ActivePauseBehavior = "queue",
AimType = "cone",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(412689699778, --[[CombatAction EyesOnTheBack DisplayName]] "Eyes On The Back"),
Execute = function (self, units, args)
local unit = units[1]
local attacks, aim = unit:GetOverwatchAttacksAndAim(self, args)
args.num_attacks = attacks
args.aim = aim
local ap = self:GetAPCost(unit, args)
NetStartCombatAction(self.id, unit, ap, args)
end,
GetAPCost = function (self, unit, args)
return CombatActions.Overwatch.GetAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local damage = base
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
local unit = units[1]
local total, cost = self:GetAPCost(unit)
local attacks = 1
if unit and (cost or -1) >= 0 then
attacks = unit:GetOverwatchAttacksAndAim()
end
local description = GetSignatureActionDescription(self)
description = description .. T{452784485986, "<newline><newline>Max attacks: <em><attacks></em>", attacks = attacks}
return description
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
return CombatActions.Overwatch.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon:GetOverwatchConeParam("MaxRange")
end,
GetMinAimRange = function (self, unit, weapon)
return weapon:GetOverwatchConeParam("MinRange")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
local cost = self:GetAPCost(unit, args)
if not unit:UIHasAP(cost) then return "disabled" end
local attack = unit:GetDefaultAttackAction()
local weapon = attack:GetAttackWeapons(unit)
if not IsKindOf(weapon, "Firearm") then
return "disabled", AttackDisableReasons.RangedWeapon
elseif IsKindOf(weapon, "MachineGun") then
return "disabled", AttackDisableReasons.WrongWeapon
end
local state, reason = attack:GetUIState(units, args)
return state, reason
end,
Icon = "UI/Icons/Hud/perk_eyes_on_the_back",
IdDefault = "EyesOnTheBackdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
QueuedBadgeText = T(633993012942, --[[CombatAction EyesOnTheBack QueuedBadgeText]] "OVERWATCH"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("EyesOnTheBack", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAreaAim", "cancel")
end,
group = "SignatureAbilities",
id = "EyesOnTheBack",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(719706520870, --[[CombatAction FleetingShadow DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_fleeting_shadow",
IdDefault = "FleetingShadowdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "FleetingShadow",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(321475789120, --[[CombatAction FoxPerk DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_fox_perk",
IdDefault = "FoxPerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "FoxPerk",
})
PlaceObj('CombatAction', {
ActionPointDelta = 3000,
ActionPoints = 7000,
ActionType = "Melee Attack",
AimType = "melee-charge",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(499085123933, --[[CombatAction GloryHog DisplayName]] "<placeholder>"),
EvalTarget = function (self, units, target, args)
local unit = units[1]
if (not args or not args.goto_pos) and (not IsValid(target) or not unit:GetClosestMeleeRangePos(target)) then
return 0
end
return unit:CalcChanceToHit(target, self, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
if not args.goto_pos then
args.goto_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.available_move_ap = self:ResolveValue("move_ap") * const.Scale.AP
CombatActionExecuteWithMove(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
-- distance-based bonus damage
local max_dist = self:ResolveValue("max_damage_dist") * const.SlabSizeX
local max_bonus = self:ResolveValue("max_damage_bonus")
local dist = Min(unit:GetDist(args.target), max_dist)
args.damage_bonus = MulDivRound(max_bonus, dist, max_dist)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetOneAttackableEnemy(self, unit, nil, CombatActionTargetFilters.Charge, unit, move_ap, self.id)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("MeleeWeapon")
end,
GetDefaultTarget = function (self, unit)
local best_eval, best_target
local units = {unit}
local targets = self:GetTargets(units)
for _, target in ipairs(targets or empty_table) do
local cost = self:GetAPCost(unit, { target = target })
if unit:UIHasAP(cost) then
local eval = self:EvalTarget(units, target)
if not best_eval or eval > best_eval then
best_target, best_eval = target, eval
end
end
end
return best_target, best_eval
end,
GetTargets = function (self, units)
local unit = units[1]
local move_ap = self:ResolveValue("move_ap") * const.Scale.AP
return CombatActionGetAttackableEnemies(self, unit, nil, CombatActionTargetFilters.Charge, unit, move_ap, self.id)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "disabled", AttackDisableReasons.MacheteWeapon end
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
if unit.stance ~= "Standing" then
return "disabled", AttackDisableReasons.OnlyStanding
end
local ap = self:GetAPCost(unit, args)
if not unit:UIHasAP(ap) then return "disabled", GetUnitNoApReason(unit) end
if not self:GetAnyTarget(units) then
return "disabled", AttackDisableReasons.NoTarget
end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_glory_hog",
IdDefault = "GloryHogdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "move_ap",
'Value', 10,
'Tag', "<move_ap>",
}),
PlaceObj('PresetParamPercent', {
'Name', "max_damage_bonus",
'Value', 50,
'Tag', "<max_damage_bonus>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "max_damage_dist",
'Value', 6,
'Tag', "<max_damage_dist>",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
PlaceObj('PresetParamNumber', {
'Name', "tempHp",
'Value', 15,
'Tag', "<tempHp>",
}),
PlaceObj('PresetParamNumber', {
'Name', "minAngle",
'Value', 120,
'Tag', "<minAngle>",
}),
},
RequireState = "any",
RequireTargets = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("GloryHogCharge", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatCharge")
end,
group = "SignatureAbilities",
id = "GloryHog",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(845495135915, --[[CombatAction GrizzlyPerk DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDamage = function (self, unit, target, args)
return CombatActions.MGBurstFire:GetActionDamage(unit, target, args)
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
return CombatActions.MGBurstFire.GetActionResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("MachineGun")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "disabled", AttackDisableReasons.RequiresMachineGun end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_grizzly_perk",
IdDefault = "GrizzlyPerkdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "rechargeTime",
'Tag', "<rechargeTime>",
}),
PlaceObj('PresetParamNumber', {
'Name', "num_shots",
'Value', 8,
'Tag', "<num_shots>",
}),
PlaceObj('PresetParamPercent', {
'Name', "cth_loss_per_shot",
'Tag', "<cth_loss_per_shot>%",
}),
PlaceObj('PresetParamPercent', {
'Name', "dmg_penalty",
'Value', -50,
'Tag', "<dmg_penalty>%",
}),
PlaceObj('PresetParamNumber', {
'Name', "min_shots",
'Value', 1,
'Tag', "<min_shots>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("GrizzlyPerk", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "SignatureAbilities",
id = "GrizzlyPerk",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(310989078300, --[[CombatAction GruntyPerk DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_grunty_perk",
IdDefault = "GruntyPerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "GruntyPerk",
})
PlaceObj('CombatAction', {
ActionType = "Toggle",
ActivePauseBehavior = "instant",
Comment = "toggle",
ConfigurableKeybind = false,
DisplayName = T(744263226529, --[[CombatAction HaveABlast DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
local unit = units[1]
local enabled = self:IsToggledOn(unit)
local description = GetSignatureActionDescription(self)
description = description .. T{237402056493, "<newline><newline><em><status></em>", status = enabled and T(685311187808, "Active") or T(183198352286, --[[Perk or skill that can be disabled]] "Inactive")}
return description
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_have_a_blast",
IdDefault = "HaveABlastdefault",
IsToggledOn = function (self, unit)
return unit and unit:GetEffectValue("HaveABlast") or false
end,
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetEffectValue("HaveABlast", not unit:GetEffectValue("HaveABlast"))
ObjModified("combat_bar")
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "HaveABlast",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(710075976136, --[[CombatAction HawksEye DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_hawks_eye",
IdDefault = "HawksEyedefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "HawksEye",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPointDelta = 3000,
ActionPoints = 6000,
ActionType = "Ranged Attack",
AimType = "mobile",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(401408176064, --[[CombatAction HundredKnives DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
return unit:GetAttackAPCost(self, self:GetAttackWeapons(unit, args), unit.ActionPoint)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local damage = unit:GetBaseDamage(weapon)
return damage, damage, 0
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
args.attack_id = "KnifeThrow"
return GetMobileShotResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
return CombatActions.KnifeThrow:GetAttackWeapons(unit, args)
end,
GetMaxAimRange = function (self, unit, weapon)
return CombatActions.KnifeThrow:GetMaxAimRange(unit, weapon)
end,
GetTargets = function (self, units)
local unit = units[1]
if unit then
return GetEnemies(unit)
end
return {}
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon1 = self:GetAttackWeapons(unit, args)
if not weapon1 then return "disabled", AttackDisableReasons.KnifeWeapon end
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_hundred_knives",
IdDefault = "HundredKnivesdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "mobile_move_ap",
'Value', 8,
'Tag', "<mobile_move_ap>",
}),
PlaceObj('PresetParamNumber', {
'Name', "mobile_num_shots",
'Value', 2,
'Tag', "<mobile_num_shots>",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("HundredKnives", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatMovingAttack")
end,
group = "SignatureAbilities",
id = "HundredKnives",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(916379475854, --[[CombatAction IcePerk DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if unit:OutOfAmmo(weapon2) or unit:IsWeaponJammed(weapon2) then
weapon2 = nil
end
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0, self.ActionPointDelta) or -1
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
args.anim_speed_mod = self:ResolveValue("anim_speed_mod")
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not IsKindOf(weapon, "Firearm") then
return "disabled", AttackDisableReasons.RangedWeapon
elseif IsKindOf(weapon, "Shotgun") then
return "disabled", AttackDisableReasons.WrongWeapon
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_ice_perk",
IdDefault = "IcePerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
PlaceObj('PresetParamNumber', {
'Name', "anim_speed_mod",
'Value', 100000,
'Tag', "<anim_speed_mod>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
PlayVoiceResponse(unit,"PersonalPerkSubtitled")
unit:SetActionCommand("IceAttack", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "SignatureAbilities",
id = "IcePerk",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(671287745703, --[[CombatAction InnerInfo DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_inners_info",
IdDefault = "InnerInfodefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "InnerInfo",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(985157282912, --[[CombatAction JackOfAllTrades DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_jack_of_all_trades",
IdDefault = "JackOfAllTradesdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "JackOfAllTrades",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(978989937559, --[[CombatAction KalynaPerk DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if unit:OutOfAmmo(weapon2) or unit:IsWeaponJammed(weapon2) then
weapon2 = nil
end
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0, self.ActionPointDelta) or -1
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not IsKindOf(weapon, "Firearm") then
return "disabled", AttackDisableReasons.RangedWeapon
elseif IsKindOf(weapon, "Shotgun") then
return "disabled", AttackDisableReasons.WrongWeapon
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_kalyna_perk",
IdDefault = "KalynaPerkdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("KalynaShot", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "SignatureAbilities",
id = "KalynaPerk",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(623714906755, --[[CombatAction KillingWind DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_killing_wind",
IdDefault = "KillingWinddefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "KillingWind",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(620581238795, --[[CombatAction LightStep DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_light_step",
IdDefault = "LightStepdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "LightStep",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(958256324680, --[[CombatAction MakeThemBleed DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_make_them_bleed",
IdDefault = "MakeThemBleeddefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "MakeThemBleed",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(247936211509, --[[CombatAction NailsPerk DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_nails_perk",
IdDefault = "NailsPerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "NailsPerk",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(154407600177, --[[CombatAction NaturalHealing DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_natural_healing",
IdDefault = "NaturalHealingdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "NaturalHealing",
})
PlaceObj('CombatAction', {
ActionPoints = 2000,
ActivePauseBehavior = "queue",
ConfigurableKeybind = false,
DisplayName = T(800932587379, --[[CombatAction Nazdarovya DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not g_Combat then return "disabled", AttackDisableReasons.CombatOnly end
if not unit:UIHasAP(cost) then return "disabled" end
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_nazdarovya",
IdDefault = "Nazdarovyadefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "tempHp",
'Value', 25,
'Tag', "<tempHp>",
}),
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
QueuedBadgeText = T(975564787824, --[[CombatAction Nazdarovya QueuedBadgeText]] "DRINK"),
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("Nazdarovya", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "Nazdarovya",
})
PlaceObj('CombatAction', {
ActionPoints = 10000,
ActionType = "Ranged Attack",
AimType = "allies-attack",
ConfigurableKeybind = false,
DisplayName = T(851787911979, --[[CombatAction OnMyTarget DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
if self.CostBasedOnWeapon then
local weapon = self:GetAttackWeapons(unit, args)
return weapon and unit:GetAttackAPCost(self, weapon, nil, args and args.aim or 0, self.ActionPointDelta) or -1
end
return self.ActionPoints
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
if not args.target_spot_group then
args.num_shots = 0
end
args.fx_action = "WeaponBuckshot"
args.aoe_action_id = self.id
args.aoe_damage_type = "percent"
args.aoe_damage_value = const.Weapons.ShotgunCollateralDamage
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
-- make sure the fx action plays
local shots = results.attacks and results.attacks[1].shots or empty_table
if #shots == 0 then
attack_args.aoe_fx_action = "WeaponBuckshot"
end
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetMaxAimRange = function (self, unit, weapon)
return weapon.WeaponRange
end,
GetMinAimRange = function (self, unit, weapon)
return 2
end,
GetTargets = function (self, units)
local unit = units[1]
return unit and unit:GetVisibleEnemies() or {}
--return CombatActionGetAttackableEnemies(self, unit)
end,
GetUIState = function (self, units, args)
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_on_my_target",
IdDefault = "OnMyTargetdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
},
RequireState = "any",
RequireTargets = true,
Run = function (self, unit, ap, ...)
unit:SetActionCommand("OnMyTarget", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args)
end,
group = "SignatureAbilities",
id = "OnMyTarget",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionPoints = 5000,
ActionType = "Ranged Attack",
AimType = "mobile",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(586171031351, --[[CombatAction RecklessAssault DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
local add = (unit.stance ~= "Standing") and CombatActions.StanceStanding:GetAPCost(unit, args) or 0
return self.ActionPoints + add
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local damage = unit:GetBaseDamage(weapon)
local num_shots = self:ResolveValue("mobile_num_shots")
return damage, damage / num_shots, 0
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local weapon = self:GetAttackWeapons(unit)
args.attack_id = "BurstFire"
args.num_shots = weapon and weapon:GetAutofireShots("BurstFire") or CombatActions.BurstFire:ResolveValue("num_shots")
args.multishot = true
return GetMobileShotResults(self, unit, args)
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("SubmachineGun")
end,
GetTargets = function (self, units)
local unit = units[1]
if unit then
return table.ifilter(GetEnemies(unit), function(i, enemy)
return IsValidTarget(enemy)
end)
end
return {}
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_reckless_assault",
IdDefault = "RecklessAssaultdefault",
IsAimableAttack = false,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "mobile_move_ap",
'Value', 12,
'Tag', "<mobile_move_ap>",
}),
PlaceObj('PresetParamNumber', {
'Name', "mobile_num_shots",
'Value', 5,
'Tag', "<mobile_num_shots>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("RecklessAssault", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatMovingAttack")
end,
group = "SignatureAbilities",
id = "RecklessAssault",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(208299655551, --[[CombatAction SecondStoryMan DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_second_man_story",
IdDefault = "SecondStoryMandefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "SecondStoryMan",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(935618242248, --[[CombatAction ShoulderToShoulder DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_shoulder_to_shoulder",
IdDefault = "ShoulderToShoulderdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "ShoulderToShoulder",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(943208194004, --[[CombatAction SidneyPerk DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_sidney_perk",
IdDefault = "SidneyPerkdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "SidneyPerk",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(558757719170, --[[CombatAction Spotter DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_spotter",
IdDefault = "Spotterdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "Spotter",
})
PlaceObj('CombatAction', {
ActionPoints = 3000,
ActionType = "Melee Attack",
AimType = "melee",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(208002846501, --[[CombatAction SteroidPunch DisplayName]] "<placeholder>"),
EvalTarget = function (self, units, target, args)
return CombatActions.MeleeAttack.EvalTarget(self, units, target, args)
end,
Execute = function (self, units, args)
local unit = units[1]
if CombatActionIsBusy(self, unit) then return end
if not args.goto_pos then
args.goto_pos = unit:GetClosestMeleeRangePos(args.target)
end
args.stance = "Standing"
CombatActionExecuteWithMove(self, unit, args)
end,
GetAPCost = function (self, unit, args)
return GetMeleeAttackAPCost(self, unit, args)
end,
GetActionDamage = function (self, unit, target, args)
local weapon = self:GetAttackWeapons(unit, args)
if not weapon then return 0 end
local base = unit:GetBaseDamage(weapon)
local mod = 100 + MulDivRound(unit.Strength, weapon.DamageMultiplier, 100)
local damage = MulDivRound(base, mod, 100)
return damage, base, damage - base
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local args = table.copy(args)
args.num_shots = 0
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAnyTarget = function (self, units)
return CombatActions.MeleeAttack.GetAnyTarget(self, units)
end,
GetAttackWeapons = function (self, unit, args)
return not unit:GetActiveWeapons() and unit:GetActiveWeapons("UnarmedWeapon")
end,
GetDefaultTarget = function (self, unit)
return CombatActions.MeleeAttack.GetDefaultTarget(self, unit)
end,
GetTargets = function (self, units)
return CombatActions.MeleeAttack.GetTargets(self, units)
end,
GetUIState = function (self, units, args)
if not g_Combat then
return "disabled", AttackDisableReasons.CombatOnly
end
local unit = units[1]
local recharge = unit:GetSignatureRecharge(self.id)
if recharge then
if recharge.on_kill then
return "disabled", AttackDisableReasons.SignatureRechargeOnKill
end
return "disabled", AttackDisableReasons.SignatureRecharge
end
if not self:GetAttackWeapons(unit) then
return "disabled", AttackDisableReasons.RequiresUnarmed
end
args = args or {}
args.ap_cost_breakdown = args.ap_cost_breakdown or {}
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then
return "disabled", GetUnitNoApReason(unit)
end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_steroid_punch",
IdDefault = "SteroidPunchdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectSignatureAbility",
MoveStep = true,
MultiSelectBehavior = "first",
Parameters = {
PlaceObj('PresetParamNumber', {
'Name', "recharge_on_kill",
'Value', 1,
'Tag', "<recharge_on_kill>",
}),
PlaceObj('PresetParamNumber', {
'Name', "pushSlabs",
'Value', 1,
'Tag', "<pushSlabs>",
}),
},
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("SteroidPunch", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
return CombatActions.MeleeAttack.UIBegin(self, units, args)
end,
UseFreeMove = true,
group = "SignatureAbilities",
id = "SteroidPunch",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(378289237011, --[[CombatAction TagTeam DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_tag_team",
IdDefault = "TagTeamdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "TagTeam",
})
PlaceObj('CombatAction', {
ActionCamera = true,
ActionType = "Ranged Attack",
AimType = "line",
ConfigurableKeybind = false,
CostBasedOnWeapon = true,
DisplayName = T(644784782885, --[[CombatAction TheGrim DisplayName]] "<placeholder>"),
GetAPCost = function (self, unit, args)
local weapon1, weapon2 = self:GetAttackWeapons(unit, args)
if unit:OutOfAmmo(weapon2) or unit:IsWeaponJammed(weapon2) then
weapon2 = nil
end
if weapon1 and weapon2 then
return -1
end
if not weapon1 then return -1 end
return unit:GetAttackAPCost(self, weapon1, false, args and args.aim or 0, self.ActionPointDelta) or -1
end,
GetActionDamage = function (self, unit, target, args)
return CombatActionsAttackGenericDamageCalculation(self, unit, args)
end,
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetActionResults = function (self, unit, args)
local attack_args = unit:PrepareAttackArgs(self.id, args)
local results = attack_args.weapon:GetAttackResults(self, attack_args)
return results, attack_args
end,
GetAttackWeapons = function (self, unit, args)
if args and args.weapon then return args.weapon end
return unit:GetActiveWeapons("Firearm")
end,
GetUIState = function (self, units, args)
local unit = units[1]
local weapon = self:GetAttackWeapons(unit, args)
if not IsKindOf(weapon, "Firearm") then
return "disabled", AttackDisableReasons.RangedWeapon
elseif IsKindOf(weapon, "Shotgun") then
return "disabled", AttackDisableReasons.WrongWeapon
end
return CombatActionGenericAttackGetUIState(self, units, args)
end,
Icon = "UI/Icons/Hud/perk_the_grim",
IdDefault = "TheGrimdefault",
IsTargetableAttack = true,
KeybindingFromAction = "actionRedirectSignatureAbility",
MultiSelectBehavior = "first",
RequireState = "any",
Run = function (self, unit, ap, ...)
unit:SetActionCommand("FirearmAttack", self.id, ap, ...)
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
StealthAttack = true,
UIBegin = function (self, units, args)
CombatActionAttackStart(self, units, args, "IModeCombatAttack")
end,
group = "SignatureAbilities",
id = "TheGrim",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(708228622280, --[[CombatAction VengefulTemperament DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_vengeful_temperament",
IdDefault = "VengefulTemperamentdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "VengefulTemperament",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(824128303298, --[[CombatAction WeGotThis DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_we_got_this",
IdDefault = "WeGotThisdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "WeGotThis",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(598595177377, --[[CombatAction WeaponPersonalization DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_weapon_personalization",
IdDefault = "WeaponPersonalizationdefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "WeaponPersonalization",
})
PlaceObj('CombatAction', {
ActionType = "Passive",
ActivePauseBehavior = "instant",
Comment = "passive",
ConfigurableKeybind = false,
DisplayName = T(193034765297, --[[CombatAction YouSeeIgor DisplayName]] "<placeholder>"),
GetActionDescription = function (self, units)
return GetSignatureActionDescription(self)
end,
GetActionDisplayName = function (self, units)
return GetSignatureActionDisplayName(self)
end,
GetUIState = function (self, units, args)
local unit = units[1]
local cost = self:GetAPCost(unit, args)
if cost < 0 then return "hidden" end
if not unit:UIHasAP(cost) then return "disabled" end
return "enabled"
end,
Icon = "UI/Icons/Hud/perk_you_see_igor",
IdDefault = "YouSeeIgordefault",
KeybindingFromAction = "actionRedirectSignatureAbility",
RequireState = "any",
Run = function (self, unit, ap, ...)
return false
end,
ShowIn = "SignatureAbilities",
SortKey = 100,
group = "SignatureAbilities",
id = "YouSeeIgor",
})