Download Lua/Tactical/CombatPath.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 5.58 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/Lua/Tactical/CombatPath.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/Lua/Tactical/CombatPath.lua
-
curl -L -o CombatPath.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/Lua/Tactical/CombatPath.lua
5.58 kB
| DefineClass.CombatPath = { | |
| __parents = { "InitDone" }, | |
| unit = false, | |
| start_pos = false, | |
| stance = false, | |
| ap = 0, | |
| move_modifier = 0, | |
| restrict_area = false, | |
| destinations = empty_table, -- map: packed_pos -> true (possibly occupied points are not present here) | |
| paths_ap = empty_table, -- map: packed_pos -> cost ap | |
| paths_prev_pos = empty_table, -- map: pos -> previous pos (start pos -> false) | |
| closest_free_pos = false, -- closest not occupied pos | |
| destination_stances = false, -- for merged combat path it holds the stance to arrive at that destination | |
| } | |
| function CombatPath:RebuildPaths(unit, ap, pos, stance, ignore_occupied, move_through_occupied, action_id) | |
| stance = stance or unit and unit.stance or "Standing" | |
| ap = ap or unit and unit.ActionPoints or 0 | |
| self.unit = unit | |
| self.stance = stance | |
| self.ap = ap | |
| self.start_pos = pos or unit and unit:GetPos() | |
| if ap < 0 then | |
| self.destinations = nil | |
| self.paths_ap = nil | |
| self.paths_prev_pos = nil | |
| self.closest_free_pos = nil | |
| return | |
| end | |
| local consts = Presets.ConstDef["Action Point Costs"] | |
| local side = unit and unit.team and unit.team.side | |
| local player_controlled = (side == "player1" or side == "player2") | |
| local stance_modifier = 0 | |
| if stance == "Crouch" then | |
| stance_modifier = consts["CrouchModifier"].value | |
| elseif stance == "Prone" then | |
| stance_modifier = consts["ProneModifier"].value | |
| end | |
| local tunnel_mask | |
| if side and side ~= "neutral" and unit.body_type == "Human" then | |
| if stance == "Prone" then | |
| tunnel_mask = player_controlled and const.TunnelMaskPlayerProne or const.TunnelMaskAIProne | |
| else | |
| tunnel_mask = player_controlled and const.TunnelMaskPlayerStanding or const.TunnelMaskAIStanding | |
| end | |
| end | |
| self.move_modifier = unit and unit:GetMoveModifier(stance, action_id) or 0 | |
| local move_modifier = Max(-100, self.move_modifier) | |
| local walk_modifier = stance_modifier + move_modifier | |
| local vertical_move_modifier = 0 | |
| if HasPerk(unit, "DeathFromAbove") then | |
| vertical_move_modifier = CharacterEffectDefs.DeathFromAbove:ResolveValue("vertical_cost_modifier") | |
| end | |
| local tunnel_param = { | |
| unit = unit, | |
| player_controlled = player_controlled, | |
| move_modifier = move_modifier, | |
| walk_modifier = walk_modifier, | |
| walk_stairs_modifier = Max(-100, walk_modifier + vertical_move_modifier), | |
| ladder_modifier = Max(-100, move_modifier + vertical_move_modifier), | |
| drop_down_modifier = Max(-100, move_modifier + vertical_move_modifier), | |
| climb_up_modifier = Max(-100, move_modifier + vertical_move_modifier), | |
| } | |
| local walk_cost = consts["Walk"].value * (100 + walk_modifier) / 100 | |
| local avoid_mines = unit and not player_controlled | |
| self.destinations, self.paths_ap, self.paths_prev_pos, self.closest_free_pos = GetCombatPathPositions(unit, self.start_pos, ap, walk_cost, tunnel_param, tunnel_mask, self.restrict_area, ignore_occupied, move_through_occupied, avoid_mines) | |
| end | |
| function CombatPath:GetAP(pos, endStance) | |
| if not pos then return end | |
| local pos_type = type(pos) | |
| local ap, stance | |
| if pos_type == "number" then | |
| ap = self.paths_ap[pos] | |
| stance = self.stance_at_end or (self.destination_stances and self.destination_stances[pos]) | |
| if endStance and stance and stance ~= endStance then | |
| return ap + GetStanceToStanceAP(stance, endStance) | |
| end | |
| return ap | |
| elseif pos_type == "table" then | |
| local min_cost | |
| for i, p in ipairs(pos) do | |
| local c = self:GetAP(p) | |
| if c and (not min_cost or c < min_cost) then | |
| min_cost = c | |
| end | |
| end | |
| return min_cost | |
| end | |
| pos = point_pack(pos) | |
| ap = self.paths_ap[pos] | |
| stance = self.stance_at_end or (self.destination_stances and self.destination_stances[pos]) | |
| if ap and endStance and stance and stance ~= endStance then | |
| return ap + GetStanceToStanceAP(stance, endStance) | |
| end | |
| return ap | |
| end | |
| function CombatPath:GetCombatPathFromPos(pos) | |
| if not pos then return end | |
| local p = type(pos) == "number" and pos or point_pack(pos) | |
| local paths_prev_pos = self.paths_prev_pos | |
| if not paths_prev_pos[p] then | |
| return | |
| end | |
| local path = {} | |
| while p do | |
| table.insert(path, p) | |
| p = paths_prev_pos[p] | |
| end | |
| return path | |
| end | |
| function CombatPath:GetReachableMeleeRangePositions(target, check_occupied, min_ap) | |
| local list = GetMeleeRangePositions(self.unit, target, nil, check_occupied) | |
| local paths_ap = self.paths_ap | |
| for i = list and #list or 0, 1, -1 do | |
| local ap = paths_ap[list[i]] | |
| if not ap or min_ap and ap < min_ap or not self.destinations[list[i]] then | |
| table.remove(list, i) | |
| end | |
| end | |
| return list | |
| end | |
| function CombatPath:GetClosestMeleeRangePos(target, target_pos, check_free, interaction) | |
| local list = GetMeleeRangePositions(self.unit, target, target_pos, check_free) | |
| local paths_ap = self.paths_ap | |
| local closest, min_ap | |
| for i, packed_pos in ipairs(list) do | |
| local ap = paths_ap[packed_pos] | |
| if ap and (not min_ap or ap < min_ap) and (not check_free or self.destinations[packed_pos]) then | |
| if interaction or IsMeleeRangeTarget(self.unit, packed_pos, nil, target, target_pos) then | |
| closest = packed_pos | |
| min_ap = ap | |
| end | |
| end | |
| end | |
| if closest then | |
| return point(point_unpack(closest)) | |
| end | |
| end | |
| function GetCombatPathLen(path, obj) | |
| local len = 0 | |
| if #path > 0 then | |
| local x1, y1, z1 = point_unpack(path[1]) | |
| for i = 2, #path do | |
| local x2, y2, z2 = point_unpack(path[i]) | |
| len = len + GetLen(x2 - x1, y2 - y1, (z1 or z2) and (z2 or terrain.GetHeight(x2, y2)) - (z1 or terrain.GetHeight(x1, y1)) or 0) | |
| x1, y1, z1 = x2, y2, z2 | |
| end | |
| if IsValid(obj) and obj:IsValidPos() then | |
| len = len + obj:GetVisualDist(x1, y1, z1) | |
| end | |
| end | |
| return len | |
| end | |