Download Lua/Tactical/Cover.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 8.24 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/Lua/Tactical/Cover.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/Lua/Tactical/Cover.lua
-
curl -L -o Cover.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/Lua/Tactical/Cover.lua
8.24 kB
| DefineClass.CoverObj = { | |
| __parents = { "Object", "ComponentAttach" }, | |
| entity = false, | |
| dbg_mesh = false, | |
| } | |
| function CoverObj:GameInit() | |
| local parent = self:GetParent() | |
| if not self:IsAligned() then | |
| self:Notify("delete") | |
| return | |
| end | |
| end | |
| function CoverObj:IsAligned() | |
| end | |
| function CoverObj:Show() | |
| end | |
| function CoverObj:Hide() | |
| if IsValid(self.dbg_mesh) then | |
| DoneObject(self.dbg_mesh) | |
| self.dbg_mesh = nil | |
| end | |
| end | |
| DefineClass.CoverWall = { | |
| __parents = { "CoverObj" }, | |
| } | |
| function CoverWall:Show() | |
| if not IsValid(self.dbg_mesh) then | |
| self.dbg_mesh = PlaceObject("Mesh") | |
| self.dbg_mesh:SetDepthTest(true) | |
| local width = 3 * const.SlabSizeX / 10 | |
| local height = const.SlabSizeY | |
| local depth = const.SlabSizeZ | |
| width = width / 2 | |
| height = height / 2 | |
| --depth = -depth | |
| local p_pstr = pstr("") | |
| local function AddPoint(x,y,z) | |
| p_pstr:AppendVertex(point(x*width, y*height, z*depth), RGB(120, 20, 180)) | |
| end | |
| -- -x | |
| AddPoint(-1, -1, 0) AddPoint(-1, 1, 0) AddPoint(-1, 1, 1) | |
| AddPoint(-1, 1, 1) AddPoint(-1, -1, 1) AddPoint(-1, -1, 0) | |
| -- +x | |
| AddPoint( 1, -1, 0) AddPoint( 1, 1, 0) AddPoint( 1, 1, 1) | |
| AddPoint( 1, 1, 1) AddPoint( 1, -1, 1) AddPoint( 1, -1, 0) | |
| -- -y | |
| AddPoint(-1, -1, 0) AddPoint( 1, -1, 0) AddPoint( 1, -1, 1) | |
| AddPoint( 1, -1, 1) AddPoint(-1, -1, 1) AddPoint(-1, -1, 0) | |
| -- +y | |
| AddPoint(-1, 1, 0) AddPoint( 1, 1, 0) AddPoint( 1, 1, 1) | |
| AddPoint( 1, 1, 1) AddPoint(-1, 1, 1) AddPoint(-1, 1, 0) | |
| -- z0 | |
| AddPoint(-1, -1, 0) AddPoint(-1, 1, 0) AddPoint( 1, 1, 0) | |
| AddPoint( 1, 1, 0) AddPoint( 1, -1, 0) AddPoint(-1, -1, 0) | |
| -- +z | |
| AddPoint(-1, -1, 1) AddPoint(-1, 1, 1) AddPoint( 1, 1, 1) | |
| AddPoint( 1, 1, 1) AddPoint( 1, -1, 1) AddPoint(-1, -1, 1) | |
| self.dbg_mesh:SetMesh(p_pstr) | |
| self:Attach(self.dbg_mesh) | |
| end | |
| end | |
| function CoverWall:IsAligned() | |
| local x, y, z = self:GetPosXYZ() | |
| local angle = self:GetAngle() | |
| local tx, ty, tz = WallVoxelToWorld(WallWorldToVoxel(x, y, z, angle)) | |
| return x == tx and y == ty and z == tz | |
| end | |
| -- cover shields angle! | |
| local cover_dir_angle = { | |
| ["up"] = 90 * 60, | |
| ["right"] = 2 * 90 * 60, | |
| ["down"] = 3 * 90 * 60, | |
| ["left"] = 0, | |
| } | |
| function GetCoverDirAngle(dir) | |
| return cover_dir_angle[dir] | |
| end | |
| local coverHigh = const.CoverHigh | |
| local coverLow = const.CoverLow | |
| function GetCoversAt(pos_or_obj) | |
| local up, right, down, left = GetCover(pos_or_obj) | |
| if not up then | |
| return | |
| end | |
| local covers = { | |
| [cover_dir_angle.up] = (up == coverHigh or up == coverLow) and up or nil, | |
| [cover_dir_angle.right] = (right == coverHigh or right == coverLow) and right or nil, | |
| [cover_dir_angle.down] = (down == coverHigh or down == coverLow) and down or nil, | |
| [cover_dir_angle.left] = (left == coverHigh or left == coverLow) and left or nil, | |
| } | |
| return next(covers) and covers or nil | |
| end | |
| local cover_offsets = { | |
| point(0, -const.SlabSizeY / 2, 0), -- up | |
| point(const.SlabSizeX / 2, 0, 0), -- "right" | |
| point(0, const.SlabSizeY / 2, 0), -- "down" | |
| point(-const.SlabSizeX / 2, 0, 0), -- "left" | |
| } | |
| function GetCoverOffset(angle) | |
| local idx = 1 + (1 + CardinalDirection(angle) / (90*60)) % 4 | |
| return cover_offsets[idx] | |
| end | |
| function GetAngleCover(pos, angle) | |
| local idx = 1 + (1 + CardinalDirection(angle) / (90*60)) % 4 | |
| local cover = select(idx, GetCover(pos)) | |
| return cover | |
| end | |
| function GetHighestCoverUI(pos_or_obj) | |
| if not IsPoint(pos_or_obj) and pos_or_obj.return_pos then | |
| pos_or_obj = pos_or_obj.return_pos | |
| end | |
| return GetHighestCover(pos_or_obj) | |
| end | |
| function GetCoverTypes(pos_or_obj) | |
| local up, right, down, left = GetCover(pos_or_obj) | |
| if not up then | |
| return | |
| end | |
| local cover_low = up == coverLow or right == coverLow or down == coverLow or left == coverLow | |
| local cover_high = up == coverHigh or right == coverHigh or down == coverHigh or left == coverHigh | |
| return cover_high, cover_low | |
| end | |
| function GetHighestCover(pos_or_obj) | |
| local high, low = GetCoverTypes(pos_or_obj) | |
| if high then | |
| return coverHigh | |
| end | |
| if low then | |
| return coverLow | |
| end | |
| end | |
| function GetUnitOrientationToHighCover(pos, angle) | |
| local up, right, down, left = GetCover(pos) | |
| if not up then | |
| return | |
| end | |
| if up ~= coverHigh and right ~= coverHigh and down ~= coverHigh and left ~= coverHigh then | |
| return | |
| end | |
| local max_diff = 90*60 | |
| local best_angle, best_diff | |
| -- rotations against the cover | |
| local a1 = cover_dir_angle.up + 180*60 | |
| local a2 = cover_dir_angle.right + 180*60 | |
| local a3 = cover_dir_angle.down + 180*60 | |
| local a4 = cover_dir_angle.left + 180*60 | |
| local diff1 = abs(AngleDiff(angle, a1)) | |
| local diff2 = abs(AngleDiff(angle, a2)) | |
| local diff3 = abs(AngleDiff(angle, a3)) | |
| local diff4 = abs(AngleDiff(angle, a4)) | |
| -- avoid facing another high cover | |
| -- up / down | |
| if right == coverHigh and diff2 < max_diff or left == coverHigh and diff4 < max_diff then | |
| if up ~= coverHigh and (not best_diff or diff1 < best_diff) then best_angle, best_diff = a1, diff1 end | |
| if down ~= coverHigh and (not best_diff or diff3 < best_diff) then best_angle, best_diff = a3, diff3 end | |
| end | |
| -- left / right | |
| if up == coverHigh and diff1 < max_diff or down == coverHigh and diff3 < max_diff then | |
| if left ~= coverHigh and (not best_diff or diff4 < best_diff) then best_angle, best_diff = a4, diff4 end | |
| if right ~= coverHigh and (not best_diff or diff2 < best_diff) then best_angle, best_diff = a2, diff2 end | |
| end | |
| -- fallback (can face another high cover) | |
| if not best_angle then | |
| -- up / down | |
| if right == coverHigh and diff2 < max_diff or left == coverHigh and diff4 < max_diff then | |
| if not best_diff or diff1 < best_diff then best_angle, best_diff = a1, diff1 end | |
| if not best_diff or diff3 < best_diff then best_angle, best_diff = a3, diff3 end | |
| end | |
| -- left / right | |
| if up == coverHigh and diff1 < max_diff or down == coverHigh and diff3 < max_diff then | |
| if not best_diff or diff4 < best_diff then best_angle, best_diff = a4, diff4 end | |
| if not best_diff or diff2 < best_diff then best_angle, best_diff = a2, diff2 end | |
| end | |
| end | |
| return best_angle | |
| end | |
| DefineClass.BaseObjectWithCover = { | |
| __parents = { "AutoAttachObject" }, | |
| covers = false, | |
| } | |
| function BaseObjectWithCover:GameInit() | |
| self.covers = self:GetAttaches("CoverObj") | |
| for _, cover in ipairs(self.covers or empty_table) do | |
| if self:GetParent() then | |
| DoneObject(cover) | |
| else | |
| local pos = cover:GetPos() + cover:GetAttachOffset() | |
| cover:Detach() | |
| cover:SetPos(pos) | |
| end | |
| end | |
| if self:GetParent() then | |
| self.covers = {} | |
| end | |
| end | |
| function BaseObjectWithCover:Done() | |
| for _, obj in ipairs(self.covers) do | |
| DoneObject(obj) | |
| end | |
| self.covers = nil | |
| end | |
| DefineClass.BaseCliff = { | |
| __parents = { "FloorAlignedObj", "Deposition" }, | |
| flags = {efPathSlab = true}, | |
| } | |
| DefineClass.BaseTrench = { | |
| __parents = { "FloorAlignedObj", "Deposition" }, | |
| flags = {efPathSlab = true}, | |
| } | |
| local halfVoxelSizeX = const.SlabSizeX / 2 | |
| local halfVoxelSizeY = const.SlabSizeY / 2 | |
| local VoxelSizeZ = const.SlabSizeZ | |
| local clrInvisible = RGBA(0, 0, 0, 0) | |
| local slabx, slaby, slabz = const.SlabSizeX, const.SlabSizeY, const.SlabSizeZ | |
| function GetVoxelBox(padding, world_pos) | |
| padding = padding or 1 | |
| world_pos = world_pos or GetCursorPos() | |
| local surface = terrain.GetHeight(world_pos) | |
| world_pos = (surface and surface > world_pos:z()) and world_pos:SetZ(surface) or world_pos | |
| local x, y, z = VoxelToWorld(WorldToVoxel(world_pos)) | |
| local pt2d = point(x, y) | |
| local offset = point(padding * slabx + slabx / 2, padding * slaby + slaby / 2) | |
| local bbox = box(pt2d - offset, pt2d + offset) | |
| local minz, maxz = z, z | |
| MapForEach(bbox, function(obj) | |
| local obj_bbox = obj:GetEntityBBox() | |
| local obj_z = obj:GetPos():z() | |
| if obj_z then | |
| local obj_minz, obj_maxz = obj_z + obj_bbox:minz(), obj_z + obj_bbox:maxz() | |
| minz = (obj_minz < minz) and obj_minz or minz | |
| maxz = (obj_maxz > maxz) and obj_maxz or maxz | |
| end | |
| end) | |
| minz = minz - slabz / 2 - padding * slabz | |
| maxz = maxz + slabz / 2 + padding * slabz | |
| return box(bbox:min():SetZ(minz), bbox:max():SetZ(maxz)) | |
| end | |
| function GetCoverPercentage(stand_pos, attack_pos, target_stance) | |
| local cover, any, coverage = PosGetCoverPercentageFrom(stand_pos, attack_pos) | |
| if cover == coverLow and target_stance == "Standing" then | |
| cover, coverage = false, 0 | |
| end | |
| return cover, any, coverage or 0 | |
| end | |