Download Data/CombatAction.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 331 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/Data/CombatAction.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/Data/CombatAction.lua
-
curl -L -o CombatAction.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/Data/CombatAction.lua
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", | |
| }) | |