|
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 |
|
|
|
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 |
|
|
|
|
|
AddPoint(-1, -1, 0) AddPoint(-1, 1, 0) AddPoint(-1, 1, 1) |
|
AddPoint(-1, 1, 1) AddPoint(-1, -1, 1) AddPoint(-1, -1, 0) |
|
|
|
AddPoint( 1, -1, 0) AddPoint( 1, 1, 0) AddPoint( 1, 1, 1) |
|
AddPoint( 1, 1, 1) AddPoint( 1, -1, 1) AddPoint( 1, -1, 0) |
|
|
|
AddPoint(-1, -1, 0) AddPoint( 1, -1, 0) AddPoint( 1, -1, 1) |
|
AddPoint( 1, -1, 1) AddPoint(-1, -1, 1) AddPoint(-1, -1, 0) |
|
|
|
AddPoint(-1, 1, 0) AddPoint( 1, 1, 0) AddPoint( 1, 1, 1) |
|
AddPoint( 1, 1, 1) AddPoint(-1, 1, 1) AddPoint(-1, 1, 0) |
|
|
|
AddPoint(-1, -1, 0) AddPoint(-1, 1, 0) AddPoint( 1, 1, 0) |
|
AddPoint( 1, 1, 0) AddPoint( 1, -1, 0) AddPoint(-1, -1, 0) |
|
|
|
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 |
|
|
|
|
|
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), |
|
point(const.SlabSizeX / 2, 0, 0), |
|
point(0, const.SlabSizeY / 2, 0), |
|
point(-const.SlabSizeX / 2, 0, 0), |
|
} |
|
|
|
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 |
|
|
|
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)) |
|
|
|
|
|
|
|
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 |
|
|
|
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 |
|
|
|
|
|
if not best_angle then |
|
|
|
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 |
|
|
|
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 |
|
|