|
function CRTrail_AppendLineSegment(_pstr, pt0, pt1, prev_distance, prev_dir_packed, default_direction) |
|
prev_distance = prev_distance or 0 |
|
|
|
local mid = (pt1 + pt0) / 2 |
|
|
|
local dirVector = pt1 - pt0 |
|
local distance = dirVector:Len() |
|
if distance > 25 then |
|
dirVector = SetLen(dirVector, guim) |
|
else |
|
if default_direction and not default_direction:IsValidZ() then |
|
default_direction = default_direction:SetZ(0) |
|
end |
|
dirVector = default_direction or point(0,0,guim) |
|
end |
|
|
|
|
|
local directionPacked = RGBA(127 + MulDivRound(dirVector:x(), 127, guim), 127 + MulDivRound(dirVector:y(), 127, guim), 127 + MulDivRound(dirVector:z(), 127, guim), 0) |
|
prev_dir_packed = prev_dir_packed or directionPacked |
|
|
|
local outside = 2 |
|
local inside = 0 |
|
|
|
_pstr:AppendVertex(pt0, prev_dir_packed, outside, prev_distance) |
|
_pstr:AppendVertex(pt0, prev_dir_packed, inside, prev_distance) |
|
_pstr:AppendVertex(mid , directionPacked, 1, prev_distance + distance / 2) |
|
|
|
_pstr:AppendVertex(pt0, prev_dir_packed, outside, prev_distance) |
|
_pstr:AppendVertex(pt1, directionPacked, outside, prev_distance + distance) |
|
_pstr:AppendVertex(mid, directionPacked, 1, prev_distance + distance / 2) |
|
|
|
|
|
_pstr:AppendVertex(pt1, directionPacked, inside, prev_distance + distance) |
|
_pstr:AppendVertex(pt0, prev_dir_packed, inside, prev_distance) |
|
_pstr:AppendVertex(mid , directionPacked, 1, prev_distance + distance / 2) |
|
|
|
_pstr:AppendVertex(mid, prev_dir_packed, 1, prev_distance + distance / 2) |
|
_pstr:AppendVertex(pt1 , directionPacked, outside, prev_distance + distance) |
|
_pstr:AppendVertex(pt1 , directionPacked, inside, prev_distance + distance) |
|
|
|
return prev_distance + distance, directionPacked |
|
end |
|
|
|
|
|
local function BuildArc(pstr, cone_angle, center, t2c, z_offset) |
|
local Rotate = Rotate |
|
local Min = Min |
|
local AppendVertex = pstr.AppendVertex |
|
local step = 120 |
|
for i = -cone_angle / 2, cone_angle / 2, step do |
|
local pt0 = Rotate(t2c, i) + center |
|
local pt1 = Rotate(t2c, Min(i + step, cone_angle / 2)) + center |
|
|
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
|
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z() + z_offset) |
|
end |
|
end |
|
|
|
local function BuildWall(pstr, pt0, pt1, z_offset) |
|
local AppendVertex = pstr.AppendVertex |
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
|
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z() + z_offset) |
|
end |
|
|
|
local function BuildWallQuads(pstr, pt0, pt1, z_offset) |
|
local pt_mid = (pt1 + pt0) / 2 |
|
BuildWall(pstr, pt0, pt_mid, z_offset) |
|
BuildWall(pstr, pt_mid, pt1, z_offset) |
|
end |
|
|
|
local function BuildCylinderWall(pstr, center, radius, z_offset) |
|
local Rotate = Rotate |
|
local Min = Min |
|
local AppendVertex = pstr.AppendVertex |
|
local steps = 120 |
|
local t2c = point(radius, 0, 0) |
|
for i = 0, steps - 1 do |
|
local current_angle = 60 * 360 * i / steps |
|
local next_angle = 60 * 360 * (i + 1) / steps |
|
local pt0 = Rotate(t2c, current_angle) + center |
|
local pt1 = Rotate(t2c, next_angle) + center |
|
|
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
|
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z() + z_offset) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z() + z_offset) |
|
end |
|
end |
|
|
|
local function FromSpherical(phi, theta, r) |
|
local sin_theta = sin(theta) |
|
local x = r * sin_theta * cos(phi) / 4096 / 4096 |
|
local y = r * sin_theta * sin(phi) / 4096 / 4096 |
|
local z = r * cos(theta) / 4096 |
|
return x, y, z |
|
end |
|
|
|
local function BuildSphere(pstr, radius) |
|
local phi_steps = 40 |
|
local theta_steps = 60 |
|
for phi_step = 0, phi_steps - 1 do |
|
local phi_current = MulDivRound(phi_step, 60 * 360, phi_steps) |
|
local phi_next = MulDivRound(phi_step + 1, 60 * 360, phi_steps) |
|
for theta_step = 0, theta_steps - 1 do |
|
local theta_current = MulDivRound(theta_step, 60 * 180, theta_steps) |
|
local theta_next = MulDivRound(theta_step + 1, 60 * 180, theta_steps) |
|
|
|
local pt0 = point(FromSpherical(phi_current, theta_current, radius)) |
|
local pt1 = point(FromSpherical(phi_next, theta_current, radius)) |
|
local pt2 = point(FromSpherical(phi_next, theta_next, radius)) |
|
local pt3 = point(FromSpherical(phi_current, theta_next, radius)) |
|
|
|
|
|
local AppendVertex = pstr.AppendVertex |
|
AppendVertex(pstr, pt0:x(), pt0:y(), pt0:z()) |
|
AppendVertex(pstr, pt3:x(), pt3:y(), pt3:z()) |
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
|
|
AppendVertex(pstr, pt1:x(), pt1:y(), pt1:z()) |
|
AppendVertex(pstr, pt3:x(), pt3:y(), pt3:z()) |
|
AppendVertex(pstr, pt2:x(), pt2:y(), pt2:z()) |
|
end |
|
end |
|
end |
|
|
|
DefineClass.CRM_AOETilesMaterial = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
{uniform = "point3", id = "center", editor = "point", default = point30, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = "integer", id = "shape_mode", editor = "choice", default = 0, items = { |
|
{value = 0, text = "Top-down Projection"}, |
|
{value = 1, text = "Cone"}, |
|
{value = 2, text = "Pyramid"}, |
|
}}, |
|
|
|
{uniform = true, id = "radius1", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "radius2", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "horizontal_angle", editor = "number", default = 0, scale = 1000, category = "generated", no_edit = true, }, |
|
{uniform = true, id = "vertical_angle", editor = "number", default = 0, scale = 1000, category = "generated", no_edit = true, }, |
|
|
|
{uniform = "point2", id = "ray1", editor = "point", default = point20, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = "point2", id = "ray2", editor = "point", default = point20, scale = 1000, category = "generated", read_only = true, }, |
|
|
|
{uniform = true, id = "start", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "BorderColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "PulseColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "FillColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = "point3", id = "main_ray", editor = "point", default = point30, scale = 1000, }, |
|
{uniform = true, id = "PartialLosColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = true, id = "NoLosColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "BorderWidth", editor = "number", default = 1000, scale = 1000, }, |
|
{uniform = true, id = "GrainStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "InterlacingStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GlowMin", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowMax", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowFreq", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowPow", editor = "number", default = 200, scale = 1000, min = 0, max = 6000, }, |
|
|
|
{uniform = true, id = "PulseSegment", editor = "number", default = 200, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "PulseLength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSpeed", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSize", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GridPosX", editor = "number", default = 0, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridPosY", editor = "number", default = 0, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "GridWaveLength", editor = "number", default = 1400, scale = 1000, min = 0, max = 12000, }, |
|
{uniform = true, id = "GridWavePower", editor = "number", default = 3600, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridEdgeFadeDist", editor = "number", default = 250, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveSpeed", editor = "number", default = 4000, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveDuration", editor = "number", default = 2500, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridWaveDelay", editor = "number", default = 500, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridFadeIn", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridFadeOut", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "GridWidth", editor = "number", default = 30, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "DepthSoftness", editor = "number", default = 0, scale = 1000, min = -1000, max = 1000, }, |
|
{uniform = true, id = "DepthBias", editor = "number", default = 0, scale = 1000, min = -1000, max = 1000, }, |
|
{uniform = true, id = "HeightCutoff", editor = "number", default = 50000, scale = 1000, min = 0, max = 100000, help = "Over this height in meters(or under this height in meters), drawing will be disabled." }, |
|
{uniform = true, id = "Pad02", no_edit = true, editor = "number", default = 0, scale = 1000, min = -1000, max = 1000, }, |
|
|
|
{uniform = true, id = "Transparency0_Distance", no_edit = true, help = "Set by gameplay to visual max distance", editor = "number", default = 200000, scale = 1000, min = 0, max = 200000, }, |
|
{uniform = true, id = "Transparency1_Distance", no_edit = true, help = "Set by gameplay to falloff start distance", editor = "number", default = 200000, scale = 1000, min = 0, max = 200000, }, |
|
{uniform = true, id = "Transparency2_Distance", no_edit = true, help = "Set by gameplay to falloff start distance", editor = "number", default = 200000, scale = 1000, min = 0, max = 200000, }, |
|
{uniform = true, id = "Transparency3_Distance", no_edit = true, help = "Set by gameplay to falloff start distance", editor = "number", default = 200000, scale = 1000, min = 0, max = 200000, }, |
|
|
|
{uniform = true, id = "Transparency0", editor = "number", default = 1000, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "Transparency1", editor = "number", default = 650, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "Transparency2", editor = "number", default = 350, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "Transparency3", editor = "number", default = 300, scale = 1000, min = 0, max = 1000, }, |
|
}, |
|
shader_id = "aoe_tiles_sector", |
|
} |
|
|
|
|
|
DefineClass.AOEActionVisuals = { |
|
__parents = {"Object"}, |
|
|
|
state = false, |
|
thread = false, |
|
} |
|
|
|
function AOEActionVisuals:DoChangeState(state, pos) |
|
|
|
local func_name = "DoChangeState_" .. state |
|
if self[func_name] then |
|
local old_state = self.state |
|
self.state = state |
|
self[func_name](self, old_state, pos) |
|
end |
|
end |
|
|
|
function AOEActionVisuals:StateTransitionThread(state, pos) |
|
self:DoChangeState(state, pos) |
|
self.thread = false |
|
end |
|
|
|
function AOEActionVisuals:SetState(state, pos) |
|
if self.state == state or self.state == "done" then |
|
return |
|
end |
|
|
|
if self.thread then |
|
DeleteThread(self.thread) |
|
end |
|
self.thread = CreateMapRealTimeThread(self.StateTransitionThread, self, state, pos) |
|
end |
|
|
|
function AOEActionVisuals:delete(...) |
|
self.state = "done" |
|
if self.thread then |
|
DeleteThread(self.thread) |
|
end |
|
Object.delete(self, ...) |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.CRM_OverwatchWall = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
{uniform = true, id = "start", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "baseZ", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "FillColor", editor = "color", default = RGB(255, 0, 0), }, |
|
{uniform = true, id = "EdgeColor", editor = "color", default = RGB(255, 255, 0), }, |
|
|
|
{uniform = true, id = "FlashFrequency", editor = "number", default = 5000, scale = 1000 }, |
|
{uniform = true, id = "FlashTime", editor = "number", default = 2000, scale = 1000 }, |
|
{uniform = true, id = "EdgeSize", editor = "number", default = 60, scale = 1000 }, |
|
{uniform = true, id = "FlashColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = "point2", id = "EdgePos0", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = "point2", id = "EdgePos1", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = "point2", id = "EdgePos2", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = "point2", id = "EdgePos3", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
|
|
{uniform = true, id = "FlashSpeed", editor = "number", default = 2000, scale = 1000 }, |
|
{uniform = true, id = "ZUpperBound", editor = "number", default = 2000, scale = 1000, no_edit = true, }, |
|
}, |
|
shader_id = "overwatch_lines", |
|
} |
|
|
|
DefineClass.OverwatchBasedVisuals = { |
|
__parents = {"AOEActionVisuals" }, |
|
|
|
aoe_tiles_mesh = false, |
|
vertical_mesh = false, |
|
material_prefix = false, |
|
center = false, |
|
mode = "Ally", |
|
} |
|
|
|
function OverwatchBasedVisuals:Init() |
|
self.aoe_tiles_mesh = Mesh:new({}) |
|
self.aoe_tiles_mesh:SetMeshFlags(const.mfWorldSpace) |
|
self:Attach(self.aoe_tiles_mesh) |
|
self.vertical_mesh = Mesh:new({}) |
|
self.vertical_mesh:SetMeshFlags(const.mfWorldSpace) |
|
self:Attach(self.vertical_mesh) |
|
end |
|
|
|
local persistent_props = {"center", "radius1", "radius2", "ray1", "ray2", "main_ray", "vertical_angle", "horizontal_angle"} |
|
function OverwatchBasedVisuals:UpdateTilesMaterial(new_mat) |
|
local old_mat = self.aoe_tiles_mesh:GetCRMaterial() |
|
for _, prop_id in ipairs(persistent_props) do |
|
new_mat[prop_id] = old_mat[prop_id] |
|
end |
|
self.aoe_tiles_mesh:SetCRMaterial(new_mat) |
|
end |
|
|
|
function OverwatchBasedVisuals:UpdateVerticalMaterial(old_mat) |
|
old_mat = old_mat or self.vertical_mesh:GetCRMaterial() |
|
old_mat.start = RealTime() |
|
old_mat.dirty = true |
|
self.vertical_mesh:SetCRMaterial(old_mat) |
|
end |
|
|
|
function OverwatchBasedVisuals:DoChangeState_blueprint(old_state, pos) |
|
local overwatch_consts = UnitOverwatchConsts:GetById("UnitOverwatchConsts") |
|
|
|
self.vertical_mesh:SetVisible(false) |
|
local mat = self.aoe_tiles_mesh.CRMaterial |
|
|
|
|
|
|
|
self.aoe_tiles_mesh:SetCRMaterial(mat) |
|
|
|
local mat = CRM_AOETilesMaterial:GetById(self.material_prefix .. "1_Blueprint"):Clone() |
|
self:UpdateTilesMaterial(mat) |
|
end |
|
|
|
function OverwatchBasedVisuals:DoChangeState_confirm(old_state, pos) |
|
local overwatch_consts = UnitOverwatchConsts:GetById("UnitOverwatchConsts") |
|
|
|
local mat = CRM_AOETilesMaterial:GetById(self.material_prefix .. "3_Confirm_" .. self.mode):Clone() |
|
mat.start = RealTime() |
|
mat.GridPosX = (self.center or self:GetPos()):x() |
|
mat.GridPosY = (self.center or self:GetPos()):y() |
|
self:UpdateTilesMaterial(mat) |
|
|
|
self.vertical_mesh:SetOpacity(0) |
|
self.vertical_mesh:SetVisible(true) |
|
self.vertical_mesh:SetOpacity(100, overwatch_consts.confirm_vertical_fadein) |
|
self.aoe_tiles_mesh:SetOpacity(0) |
|
|
|
self.aoe_tiles_mesh:SetOpacity(100, overwatch_consts.confirm_horizontal_fadein) |
|
|
|
Sleep(overwatch_consts.confirm_duration) |
|
|
|
self.vertical_mesh:SetOpacity(0, overwatch_consts.confirm_vertical_fadeout) |
|
local deployed_mat = CRM_AOETilesMaterial:GetById(self.material_prefix .. "4_Deployed_" .. self.mode) |
|
local source_alpha = MulDivRound(GetAlpha(mat.NoLosColor), 1000, 255) |
|
local target_alpha = MulDivRound(GetAlpha(deployed_mat.NoLosColor), 1000, 255) |
|
local alpha = source_alpha > 0 and MulDivRound(target_alpha, 100, source_alpha) or 0 |
|
self.aoe_tiles_mesh:SetOpacity(Max(1, alpha), overwatch_consts.confirm_horizontal_fadeout) |
|
Sleep(Max(overwatch_consts.confirm_vertical_fadeout, overwatch_consts.confirm_horizontal_fadeout)) |
|
if self.state == "confirm" then |
|
self:DoChangeState("deployed") |
|
end |
|
end |
|
|
|
function OverwatchBasedVisuals:DoChangeState_deployed(old_state, pos) |
|
local overwatch_consts = UnitOverwatchConsts:GetById("UnitOverwatchConsts") |
|
|
|
self.aoe_tiles_mesh:SetOpacity(100) |
|
self.vertical_mesh:SetVisible(false) |
|
|
|
local mat = CRM_AOETilesMaterial:GetById(self.material_prefix .. "4_Deployed_" .. self.mode):Clone() |
|
self:UpdateTilesMaterial(mat) |
|
end |
|
|
|
function OverwatchBasedVisuals:DoChangeState_activate(old_state, pos) |
|
local overwatch_consts = UnitOverwatchConsts:GetById("UnitOverwatchConsts") |
|
|
|
Sleep(300) |
|
self.vertical_mesh:SetOpacity(0) |
|
self.vertical_mesh:SetVisible(true) |
|
self:UpdateVerticalMaterial() |
|
self.vertical_mesh:SetOpacity(100, 100) |
|
Sleep(100) |
|
|
|
self.vertical_mesh:SetOpacity(0, overwatch_consts.activate_duration) |
|
|
|
local mat = CRM_AOETilesMaterial:GetById(self.material_prefix .. "5_Activated_" .. self.mode):Clone() |
|
mat.GridPosX = pos:x() |
|
mat.GridPosY = pos:y() |
|
mat.start = RealTime() |
|
mat.dirty = true |
|
self:UpdateTilesMaterial(mat) |
|
|
|
Sleep(overwatch_consts.activate_duration) |
|
if self.state == "activate" then |
|
self:DoChangeState("deployed") |
|
end |
|
end |
|
|
|
DefineClass.OverwatchVisuals = { |
|
__parents = {"OverwatchBasedVisuals" }, |
|
|
|
center = false, |
|
material_prefix = "Overwatch", |
|
} |
|
|
|
function OverwatchVisuals:UpdateFromOverwatch(overwatch) |
|
local step_positions, step_objs = GetStepPositionsInArea(overwatch.pos, overwatch.dist, 0, overwatch.cone_angle, overwatch.angle, "force2d") |
|
local i = 1 |
|
while i <= #step_positions do |
|
if step_objs[i] and IsOnFadedSlab(step_positions[i]) then |
|
table.remove(step_positions, i) |
|
table.remove(step_objs, i) |
|
else |
|
i=i+1 |
|
end |
|
end |
|
local maxvalue, los_values = CheckLOS(step_positions, overwatch.pos, -1, overwatch.stance, -1, false, false) |
|
|
|
self.center = overwatch.pos |
|
|
|
local new_overwatch = not self.aoe_tiles_mesh |
|
local old_mat = self.aoe_tiles_mesh and self.aoe_tiles_mesh.CRMaterial |
|
local aoe_tiles_mesh, avgz = CreateAOETilesSector(step_positions, step_objs, los_values or empty_table, |
|
self.aoe_tiles_mesh, overwatch.pos, overwatch.target_pos, overwatch.min_distance_2d or 1*guim, overwatch.dist, overwatch.cone_angle) |
|
|
|
local pos = aoe_tiles_mesh:GetPos() |
|
|
|
|
|
local minz = 1000000 |
|
local maxz = -1000000 |
|
for _, pos in ipairs(step_positions) do |
|
local z = pos:IsValidZ() and pos:z() or terrain.GetHeight(pos) |
|
minz = Min(minz, z) |
|
maxz = Max(maxz, z) |
|
end |
|
|
|
local center = overwatch.pos |
|
center = center:SetZ(minz) |
|
local t2c = overwatch.dir |
|
t2c = t2c:SetZ(0) |
|
t2c = SetLen(t2c, overwatch.dist) |
|
|
|
local vertical_mesh = self.vertical_mesh |
|
|
|
local z_height = maxz - minz + 3000 |
|
|
|
local m = pstr() |
|
BuildArc(m, overwatch.cone_angle, center, t2c, z_height) |
|
local near_t2c = SetLen(overwatch.dir, 1*guim) |
|
near_t2c = near_t2c:SetZ(0) |
|
BuildArc(m, overwatch.cone_angle, center, near_t2c, z_height) |
|
|
|
local pt0 = Rotate(t2c, -overwatch.cone_angle / 2) + center |
|
local pt1 = Rotate(t2c, overwatch.cone_angle / 2) + center |
|
local pt2 = Rotate(near_t2c, -overwatch.cone_angle / 2) + center |
|
local pt3 = Rotate(near_t2c, overwatch.cone_angle / 2) + center |
|
|
|
BuildWallQuads(m, pt0, pt2, z_height) |
|
BuildWallQuads(m, pt1, pt3, z_height) |
|
|
|
vertical_mesh:SetMesh(m) |
|
|
|
|
|
if not vertical_mesh.CRMaterial then |
|
local mat = CRM_OverwatchWall:GetById("Overwatch_Vertical_" .. self.mode):Clone() |
|
mat.start = RealTime() |
|
mat.baseZ = avgz |
|
mat.ZUpperBound = minz + z_height |
|
mat.EdgePos0 = pt0 |
|
mat.EdgePos1 = pt1 |
|
mat.EdgePos2 = pt2 |
|
mat.EdgePos3 = pt3 |
|
vertical_mesh:SetCRMaterial(mat) |
|
end |
|
|
|
|
|
self:SetPos(pos) |
|
|
|
if not self.state then |
|
self:SetState("confirm") |
|
end |
|
end |
|
|
|
|
|
DefineClass.UnitOverwatchConsts = { |
|
__parents = {"PersistedRenderVars"}, |
|
properties = { |
|
{id = "activate_duration", editor = "number", default = 4000, scale = 1000, }, |
|
{id = "confirm_vertical_fadein", editor = "number", default = 800, scale = 1000, }, |
|
{id = "confirm_horizontal_fadein", editor = "number", default = 800, scale = 1000, }, |
|
{id = "confirm_duration", editor = "number", default = 2400, scale = 1000, }, |
|
{id = "confirm_vertical_fadeout", editor = "number", default = 400, scale = 1000, }, |
|
{id = "confirm_horizontal_fadeout", editor = "number", default = 400, scale = 1000, }, |
|
}, |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DefineClass.CRM_GrenadeSphereMaterial = { |
|
__parents = {"CRMaterial"}, |
|
|
|
properties = { |
|
{uniform = "point3", id = "center", editor = "point", default = point30, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "radius", editor = "number", default = 1000, scale = 1000, category = "generated", read_only = true, }, |
|
|
|
{uniform = true, id = "FillColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "OuterColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "GrainStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "InterlacingStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "UpPower", editor = "number", default = 200, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "ViewPower", editor = "number", default = 200, scale = 1000, min = 0, max = 10000, }, |
|
|
|
}, |
|
shader_id = "grenade_sphere", |
|
} |
|
|
|
DefineClass.CRM_SphereAOETilesMaterial = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
{uniform = "point3", id = "center", editor = "point", default = point30, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "radius", editor = "number", default = 1000, scale = 1000, category = "generated", read_only = true, }, |
|
|
|
{uniform = true, id = "start", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "BorderColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "PulseColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "FillColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = true, id = "PartialLosColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "NoLosColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = true, id = "IsSphere", editor = "number", default = 1, category = "generated", }, |
|
{uniform = true, id = "pad002", editor = "number", default = 0,}, |
|
|
|
{uniform = true, id = "pad003", editor = "number", default = 0,}, |
|
{uniform = true, id = "BorderWidth", editor = "number", default = 1000, scale = 1000, }, |
|
{uniform = true, id = "GrainStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "InterlacingStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GlowMin", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowMax", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowFreq", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowPow", editor = "number", default = 200, scale = 1000, min = 0, max = 6000, }, |
|
|
|
{uniform = true, id = "PulseSegmentsCount", editor = "number", default = 200, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "PulseLength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSpeed", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSize", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GridPosX", editor = "number", default = 0, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridPosY", editor = "number", default = 0, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "GridWaveLength", editor = "number", default = 1400, scale = 1000, min = 0, max = 12000, }, |
|
{uniform = true, id = "GridWavePower", editor = "number", default = 3600, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridEdgeFadeDist", editor = "number", default = 250, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveSpeed", editor = "number", default = 4000, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveDuration", editor = "number", default = 2500, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridWaveDelay", editor = "number", default = 500, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridFadeIn", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridFadeOut", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "GridWidth", editor = "number", default = 30, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "DepthSoftness", editor = "number", default = 0, scale = 1000, min = -1000, max = 1000, }, |
|
{uniform = true, id = "DepthBias", editor = "number", default = 0, scale = 1000, min = -1000, max = 1000, }, |
|
}, |
|
shader_id = "grenade_aoe_tiles_sphere", |
|
} |
|
|
|
|
|
DefineClass.GrenadeAOEVisuals = { |
|
__parents = {"AOEActionVisuals"}, |
|
|
|
group = "", |
|
aoe_tiles_mesh = false, |
|
sphere_mesh = false, |
|
|
|
data = false, |
|
} |
|
|
|
|
|
function GrenadeAOEVisuals:Init(data) |
|
self.data = data |
|
|
|
local sphere_mesh = PlaceObject("Mesh") |
|
self.sphere_mesh = sphere_mesh |
|
|
|
local _pstr = pstr() |
|
BuildSphere(_pstr, data.range) |
|
sphere_mesh:SetMesh(_pstr) |
|
sphere_mesh:SetMeshFlags(sphere_mesh:GetMeshFlags() | const.mfSortByPosZ) |
|
local m = CRM_GrenadeSphereMaterial:GetById("DefaultGrenadeSphere") |
|
sphere_mesh:SetCRMaterial(m) |
|
self:Attach(sphere_mesh) |
|
|
|
self:RecreateAoeTiles(data) |
|
self:SetPos(data.explosion_pos) |
|
end |
|
|
|
function GrenadeAOEVisuals:RecreateAoeTiles(data) |
|
self.data = data |
|
local mesh_pstr = CreateAOETiles(data.step_positions, data.step_objs, data.los_values) |
|
local aoe_tiles_mesh = self.aoe_tiles_mesh |
|
if not aoe_tiles_mesh then |
|
aoe_tiles_mesh = Mesh:new({}) |
|
self.aoe_tiles_mesh = aoe_tiles_mesh |
|
aoe_tiles_mesh:SetAttachOffset(point(0,0,-10)) |
|
aoe_tiles_mesh:SetMeshFlags(aoe_tiles_mesh:GetMeshFlags() | const.mfSortByPosZ | const.mfWorldSpace) |
|
self:Attach(aoe_tiles_mesh) |
|
end |
|
aoe_tiles_mesh:SetMesh(mesh_pstr) |
|
local m = CRM_SphereAOETilesMaterial:GetById("GrenadeTilesCast"):Clone() |
|
m.center = data.explosion_pos |
|
m.radius = data.range |
|
m.dirty = true |
|
aoe_tiles_mesh:SetCRMaterial(m) |
|
end |
|
|
|
|
|
|
|
DefineClass.MortarAOEVisuals = { |
|
__parents = {"OverwatchBasedVisuals"}, |
|
|
|
group = "", |
|
|
|
material_prefix = "Mortar", |
|
|
|
data = false, |
|
} |
|
|
|
function MortarAOEVisuals:Init(data) |
|
self.data = data |
|
|
|
if not data.explosion_pos:IsValidZ() then |
|
data.explosion_pos = data.explosion_pos:SetZ(terrain.GetHeight(data.explosion_pos)) |
|
end |
|
|
|
local vertical_mesh = PlaceObject("Mesh") |
|
self.vertical_mesh = vertical_mesh |
|
|
|
local _pstr = pstr() |
|
BuildCylinderWall(_pstr, point30, data.range, 4000) |
|
vertical_mesh:SetMesh(_pstr) |
|
vertical_mesh:SetMeshFlags(vertical_mesh:GetMeshFlags() | const.mfSortByPosZ) |
|
local mat = CRMaterial:GetById("Overwatch_Vertical_Ally"):Clone() |
|
mat.dirty = true |
|
|
|
mat.start = RealTime() |
|
mat.baseZ = data.explosion_pos:z() - 1000 |
|
mat.EdgePos0 = point30 |
|
mat.EdgePos1 = point30 |
|
mat.EdgePos2 = point30 |
|
mat.EdgePos3 = point30 |
|
mat.ZUpperBound = data.explosion_pos:z() + 4000 |
|
|
|
vertical_mesh:SetCRMaterial(mat) |
|
self:Attach(vertical_mesh) |
|
vertical_mesh:SetVisible(false) |
|
|
|
self:RecreateAoeTiles(data) |
|
self:SetPos(data.explosion_pos) |
|
|
|
if not self.state then |
|
self:SetState("confirm") |
|
end |
|
end |
|
|
|
function MortarAOEVisuals:RecreateAoeTiles(data) |
|
self.data = data |
|
|
|
local step_positions, step_objs, los_values = GetAOETiles(data.explosion_pos, "Standing", data.range + 1000, -1, nil, "force2d") |
|
|
|
local aoe_tiles_mesh_pstr = CreateAOETiles(step_positions, step_objs, los_values) |
|
local aoe_tiles_mesh = self.aoe_tiles_mesh |
|
if not aoe_tiles_mesh then |
|
aoe_tiles_mesh = Mesh:new({}) |
|
self.aoe_tiles_mesh = aoe_tiles_mesh |
|
aoe_tiles_mesh:SetAttachOffset(point(0,0,-10)) |
|
aoe_tiles_mesh:SetMeshFlags(aoe_tiles_mesh:GetMeshFlags() | const.mfSortByPosZ | const.mfWorldSpace) |
|
self:Attach(aoe_tiles_mesh) |
|
end |
|
aoe_tiles_mesh:SetMesh(aoe_tiles_mesh_pstr) |
|
local m = CRM_SphereAOETilesMaterial:GetById("Mortar1_Blueprint"):Clone() |
|
m.center = data.explosion_pos |
|
m.radius = data.range |
|
m.IsSphere = 0 |
|
m.dirty = true |
|
aoe_tiles_mesh:SetCRMaterial(m) |
|
|
|
self:SetPos(data.explosion_pos) |
|
end |
|
|
|
local persistent_props = {"IsSphere", "center", "radius"} |
|
function MortarAOEVisuals:UpdateTilesMaterial(new_mat) |
|
local old_mat = self.aoe_tiles_mesh:GetCRMaterial() |
|
for _, prop_id in ipairs(persistent_props) do |
|
new_mat[prop_id] = old_mat[prop_id] |
|
end |
|
self.aoe_tiles_mesh:SetCRMaterial(new_mat) |
|
end |
|
|
|
function MortarAOEVisuals:UpdateVerticalMaterial(old_mat) |
|
old_mat = old_mat or self.vertical_mesh:GetCRMaterial() |
|
old_mat.start = RealTime() |
|
old_mat.dirty = true |
|
self.vertical_mesh:SetCRMaterial(old_mat) |
|
end |
|
|
|
|
|
|
|
|
|
|
|
DefineClass.CRM_MeleeAOETilesMaterial = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
{uniform = "point3", id = "center", editor = "point", default = point30, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "length", editor = "number", default = 1000, scale = 1000, category = "generated", read_only = true, }, |
|
|
|
{uniform = true, id = "start", editor = "number", default = 0, scale = 1000, category = "generated", read_only = true, }, |
|
{uniform = true, id = "BorderColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "PulseColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "FillColor", editor = "color", default = RGB(255, 255, 255), }, |
|
|
|
{uniform = true, id = "pad003", editor = "number", default = 0,}, |
|
{uniform = true, id = "BorderWidth", editor = "number", default = 1000, scale = 1000, }, |
|
{uniform = true, id = "GrainStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "InterlacingStrength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GlowMin", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowMax", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowFreq", editor = "number", default = 200, scale = 1000, min = 0, max = 5000, }, |
|
{uniform = true, id = "GlowPow", editor = "number", default = 200, scale = 1000, min = 0, max = 6000, }, |
|
|
|
{uniform = true, id = "PulseSegmentsCount", editor = "number", default = 200, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "PulseLength", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSpeed", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "PulseSize", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, }, |
|
|
|
{uniform = true, id = "GridPosX", editor = "number", default = 0, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridPosY", editor = "number", default = 0, scale = 1000, min = 0, max = 1000, }, |
|
{uniform = true, id = "GridWaveLength", editor = "number", default = 1400, scale = 1000, min = 0, max = 12000, }, |
|
{uniform = true, id = "GridWavePower", editor = "number", default = 3600, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridEdgeFadeDist", editor = "number", default = 250, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveSpeed", editor = "number", default = 4000, scale = 1000, min = 0, max = 40000, }, |
|
{uniform = true, id = "GridWaveDuration", editor = "number", default = 2500, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridWaveDelay", editor = "number", default = 500, scale = 1000, min = 0, max = 12000, }, |
|
|
|
{uniform = true, id = "GridFadeIn", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridFadeOut", editor = "number", default = 0, scale = 1000, min = 0, max = 10000, }, |
|
{uniform = true, id = "GridColor", editor = "color", default = RGB(255, 255, 255), }, |
|
{uniform = true, id = "GridWidth", editor = "number", default = 30, scale = 1000, min = 0, max = 12000, }, |
|
}, |
|
shader_id = "melee_aoe_tiles", |
|
} |
|
|
|
|
|
DefineClass.MeleeAOEVisuals = { |
|
__parents = {"AOEActionVisuals"}, |
|
|
|
group = "", |
|
aoe_tiles_mesh = false, |
|
|
|
data = false, |
|
vstate = "Cast", |
|
} |
|
|
|
|
|
function MeleeAOEVisuals:Init(data) |
|
self.data = data |
|
|
|
|
|
self:RecreateAoeTiles(data) |
|
if data.pos then |
|
self:SetPos(data.pos) |
|
end |
|
end |
|
|
|
function MeleeAOEVisuals:RecreateAoeTiles(data) |
|
self.data = data |
|
if not data.pos then |
|
return false |
|
end |
|
|
|
local voxels = data.voxels |
|
if not voxels or #voxels == 0 then |
|
return false |
|
end |
|
local contour = GetRangeContour(voxels, false, false, -200)[1] |
|
|
|
local aoe_tiles_mesh = self.aoe_tiles_mesh |
|
if not aoe_tiles_mesh then |
|
aoe_tiles_mesh = Mesh:new({}) |
|
self.aoe_tiles_mesh = aoe_tiles_mesh |
|
aoe_tiles_mesh:SetAttachOffset(point(0,0,-10)) |
|
aoe_tiles_mesh:SetMeshFlags(aoe_tiles_mesh:GetMeshFlags() | const.mfSortByPosZ | const.mfWorldSpace) |
|
self:Attach(aoe_tiles_mesh) |
|
end |
|
|
|
local u, v = contour:GetMaxTexCoords() |
|
|
|
aoe_tiles_mesh:SetMesh(contour) |
|
local mat_id = self.vstate == "Cast" and ("Melee_" .. self.vstate) or ("Melee_" .. self.vstate .. "_" .. data.mode) |
|
local m = CRM_MeleeAOETilesMaterial:GetById(mat_id):Clone() |
|
m.center = data.pos |
|
m.length = v * 10 |
|
m.dirty = true |
|
aoe_tiles_mesh:SetCRMaterial(m) |
|
|
|
self:SetPos(data.pos) |
|
end |
|
|
|
local function BuildFlat2dArc(_pstr, cone_angle, r0, r1) |
|
local Rotate = Rotate |
|
local Min = Min |
|
local AppendVertex = _pstr.AppendVertex |
|
local step = 120 |
|
for current_angle = -cone_angle / 2, cone_angle / 2, step do |
|
local inner = point(r0, 0, 0) |
|
local outer = point(r1, 0, 0) |
|
local next_angle = Min(current_angle + step, cone_angle / 2) |
|
local pt0 = Rotate(inner, current_angle) |
|
local pt1 = Rotate(inner, next_angle) |
|
local pt2 = Rotate(outer, current_angle) |
|
local pt3 = Rotate(outer, next_angle) |
|
|
|
local current_dist = MulDivRound(current_angle + cone_angle / 2, 1000, cone_angle) |
|
local next_dist = MulDivRound(next_angle + cone_angle / 2, 1000, cone_angle) |
|
|
|
local color = RGB(255, 255, 255) |
|
AppendVertex(_pstr, pt0:x(), pt0:y(), pt0:z(), color, 0, current_dist) |
|
AppendVertex(_pstr, pt1:x(), pt1:y(), pt1:z(), color, 0, next_dist) |
|
AppendVertex(_pstr, pt2:x(), pt2:y(), pt2:z(), color, 1, current_dist) |
|
|
|
AppendVertex(_pstr, pt2:x(), pt2:y(), pt2:z(), color, 1, current_dist) |
|
AppendVertex(_pstr, pt1:x(), pt1:y(), pt1:z(), color, 0, next_dist) |
|
AppendVertex(_pstr, pt3:x(), pt3:y(), pt3:z(), color, 1, next_dist) |
|
end |
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DefineClass.CRM_MercDetectionIndicator = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
{uniform = true, id = "DepthSoftness", editor = "number", default = 0, min = -3000, max = 3000, slider = true, scale = 1000, }, |
|
{uniform = true, id = "FillColor", editor = "color", default = RGBA(16, 16, 16, 255)}, |
|
{uniform = true, id = "BorderColor", editor = "color", default = RGBA(255, 0, 0, 255), alpha = true, }, |
|
{uniform = true, id = "BorderWidth", editor = "number", default = 100, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "FillRatio", editor = "number", default = 100, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "Radius", editor = "number", default = 100, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "Width", editor = "number", default = 100, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "BorderPower", editor = "number", default = 100, scale = 1000, slider = true, min = 0, max = 6000, }, |
|
{uniform = true, id = "FillToSDFRatio", help = "Controlls how fast border interpolates with Fillcolor", editor = "number", default = 1000, scale = 1000, slider = true, min = 0, max = 4000, }, |
|
{uniform = true, id = "SDFCutoff", editor = "number", default = 500, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "Pad0", no_edit = true, editor = "number", default = 500, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
{uniform = true, id = "Pad1", no_edit = true, editor = "number", default = 500, scale = 1000, slider = true, min = 0, max = 1000, }, |
|
}, |
|
shader_id = "awareness_indicator", |
|
} |
|
|
|
DefineClass.CRM_MercDetectionIndicatorBuf = { |
|
__parents = {"CRMaterial"}, |
|
properties = { |
|
}, |
|
|
|
shadow = false, |
|
base = false, |
|
fill = false, |
|
shader_id = "awareness_indicator", |
|
} |
|
|
|
function CRM_MercDetectionIndicatorBuf:Recreate() |
|
self.dirty = false |
|
self.pstr_buffer = self.shadow:WriteBuffer(self.pstr_buffer, 0) |
|
self.pstr_buffer = self.base:WriteBuffer(self.pstr_buffer, #self.pstr_buffer) |
|
self.pstr_buffer = self.fill:WriteBuffer(self.pstr_buffer, #self.pstr_buffer) |
|
end |
|
|
|
DefineClass.MercDetectionConsts = { |
|
__parents = { "PersistedRenderVars" }, |
|
properties = { |
|
{ id = "scale", editor = "number", scale = 1000, min = 200, max = 6000 , default = 2400, }, |
|
{ id = "bar_offset", editor = "number", scale = 1000, min = -10000, max = 10000, default = -300, }, |
|
{ id = "arrow_offset", editor = "number", scale = 1000, min = -10000, max = 10000, default = -1200, }, |
|
{ id = "zoffset", editor = "number", scale = 1000, min = -1000, max = 1000, default = 250, }, |
|
{ id = "fade_in", editor = "number", scale = 1000, min = 0, max = 1000, default = 300, }, |
|
{ id = "fade_out", editor = "number", scale = 1000, min = 0, max = 1000, default = 300, }, |
|
|
|
{ id = "flash_progress_treshold", editor = "number", scale = 1000, min = 0, max = 1000, default = 800, }, |
|
{ id = "single_flash_time", editor = "number", scale = 1000, min = 0, max = 1000, default = 250, }, |
|
|
|
} |
|
} |
|
|
|
DefineClass.MercDetectionIndicator = { |
|
__parents = {"Object"}, |
|
flags = { efWalkable = false, efApplyToGrids = false, efCollision = false }, |
|
unit = false, |
|
progress = false, |
|
flash_thread = false, |
|
} |
|
|
|
function MercDetectionIndicator:SetProgress(num) |
|
num = Clamp(num, 0, 1000) |
|
self.progress = num |
|
|
|
local consts = MercDetectionConsts:GetById("MercDetectionConsts") |
|
if self.progress > consts.flash_progress_treshold and not IsValidThread(self.flash_thread) then |
|
PlayFX("MercDetectionThreshold", "start", self) |
|
self.flash_thread = CreateMapRealTimeThread(function() |
|
local flash_num = 0 |
|
while true do |
|
if not IsValid(self) or self.progress < consts.flash_progress_treshold then |
|
goto cleanup |
|
end |
|
local flash_time = consts.single_flash_time |
|
self.mesh0:SetColorModifier(RGB(0, 100, 100), flash_time) |
|
self.mesh3:SetColorModifier(RGB(0, 100, 100), flash_time) |
|
Sleep(flash_time) |
|
if not IsValid(self) then |
|
goto cleanup |
|
end |
|
local flash_turn = flash_num % 2 == 0 |
|
local mat = CRM_MercDetectionIndicator:GetById(flash_turn and "MercDetectionIndicator_Filled" or "MercDetectionIndicator_Attention"):Clone() |
|
mat.FillRatio = self.progress |
|
self.mesh0.CRMaterial.fill = mat |
|
self.mesh0.CRMaterial.dirty = true |
|
self.mesh0:SetCRMaterial(self.mesh0.CRMaterial) |
|
self.mesh0:SetColorModifier(RGB(100, 100, 100), flash_time) |
|
|
|
local arrow_mat = CRM_MercDetectionIndicator:GetById(flash_turn and "MercDetectionIndicator_Arrow_Filled" or "MercDetectionIndicator_Arrow_Attention"):Clone() |
|
self.mesh3.CRMaterial.fill = arrow_mat |
|
self.mesh3.CRMaterial.dirty = true |
|
self.mesh3:SetCRMaterial(self.mesh3.CRMaterial) |
|
self.mesh3:SetColorModifier(RGB(100, 100, 100), flash_time) |
|
|
|
if self.progress < consts.flash_progress_treshold then |
|
goto cleanup |
|
end |
|
Sleep(flash_time) |
|
Sleep(15) |
|
|
|
flash_num = flash_num + 1 |
|
end |
|
|
|
::cleanup:: |
|
if IsValid(self.mesh0) then |
|
local mat = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Filled"):Clone() |
|
mat.FillRatio = self.progress |
|
self.mesh0.CRMaterial.fill = mat |
|
self.mesh0.CRMaterial.dirty = true |
|
self.mesh0:SetCRMaterial(self.mesh0.CRMaterial) |
|
self.mesh0:SetColorModifier(RGB(100, 100, 100)) |
|
end |
|
if IsValid(self.mesh3) then |
|
self.mesh3:SetColorModifier(RGB(0, 100, 100)) |
|
end |
|
|
|
PlayFX("MercDetectionThreshold", "end", self) |
|
|
|
end) |
|
end |
|
|
|
self.mesh0.CRMaterial.fill.FillRatio = num |
|
self.mesh0.CRMaterial.dirty = true |
|
self.mesh0:SetCRMaterial(self.mesh0.CRMaterial) |
|
|
|
if num < consts.flash_progress_treshold then |
|
self.mesh3:SetColorModifier(RGB(0, 100, 100)) |
|
end |
|
end |
|
|
|
function MercDetectionIndicator:Init() |
|
self:SetOpacity(0) |
|
local consts = MercDetectionConsts:GetById("MercDetectionConsts") |
|
local scale = consts.scale |
|
|
|
local bar_image = "UI/InGame/enemyDetection.copy.tga" |
|
local w, h = UIL.MeasureImage(bar_image) |
|
|
|
self.mesh0 = FlatImageMesh(bar_image, MulDivRound(w, scale, 1000), MulDivRound(h, scale, 1000), 16) |
|
self.mesh0:SetCRMaterial(CRM_MercDetectionIndicatorBuf:new({ |
|
shadow = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Shadow"):Clone(), |
|
base = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Base"):Clone(), |
|
fill = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Filled"):Clone() |
|
})) |
|
self.mesh0:SetMeshFlags(const.mfSortByPosZ) |
|
self:Attach(self.mesh0) |
|
self.mesh0:SetAttachOffset(point(0,consts.bar_offset, consts.zoffset + 5)) |
|
|
|
|
|
local arrow_image = "UI/InGame/enemyDetectionArrow.copy.tga" |
|
local w, h = UIL.MeasureImage(arrow_image) |
|
self.mesh3 = FlatImageMesh(arrow_image, MulDivRound(w, scale, 1000), MulDivRound(h, scale, 1000), 12) |
|
self.mesh3:SetCRMaterial(CRM_MercDetectionIndicatorBuf:new({ |
|
shadow = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Arrow_Shadow"):Clone(), |
|
base = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Arrow"):Clone(), |
|
fill = CRM_MercDetectionIndicator:GetById("MercDetectionIndicator_Arrow"):Clone(), |
|
})) |
|
self.mesh3:SetMeshFlags(const.mfSortByPosZ) |
|
self:Attach(self.mesh3) |
|
self.mesh3:SetAttachOffset(point(0, consts.arrow_offset, consts.zoffset + 5)) |
|
self.mesh3:SetVisible(false) |
|
|
|
self:SetOpacity(100, consts.fade_in) |
|
end |
|
|
|
|
|
DefineClass.CRM_DeploymentGrid = { |
|
__parents = { "CRMaterial" }, |
|
|
|
|
|
properties = { |
|
{ uniform = true, id = "depth_softness", editor = "number", default = 0, scale = 1000, min = -2000, max = 2000, slider = true, }, |
|
{ uniform = true, id = "grid_width", editor = "number", default = 1000, scale = 1000, }, |
|
{ uniform = true, id = "grid_fadedistance", editor = "number", default = 1000, scale = 1000, }, |
|
{ uniform = true, id = "grid_pow", editor = "number", default = 1000, scale = 1000, }, |
|
|
|
{ uniform = true, id = "border_color", editor = "color", default = RGB(255, 255, 255), }, |
|
{ uniform = true, id = "glow_color", editor = "color", default = RGB(255, 255, 255), }, |
|
{ uniform = true, id = "grid_color", editor = "color", default = RGB(255, 255, 255), }, |
|
{ uniform = true, id = "reserved_color", editor = "color", default = RGB(255, 255, 255), no_edit = true, }, |
|
|
|
{ uniform = true, id = "glow_fadedistance", editor = "number", default = 0, scale = 1000, }, |
|
{ uniform = true, id = "glow_pow", editor = "number", default = 1000, scale = 1000, }, |
|
{ uniform = true, id = "glow_min", editor = "number", default = 1000, scale = 1000, }, |
|
{ uniform = true, id = "glow_variation", editor = "number", default = 1000, scale = 1000, }, |
|
|
|
{ uniform = true, id = "border_width", editor = "number", default = 0, scale = 1000, }, |
|
{ uniform = true, id = "fade_distance", editor = "number", default = 10000, scale = 1000, }, |
|
{ uniform = true, id = "fade_power", editor = "number", default = 1000, scale = 1000, }, |
|
|
|
}, |
|
|
|
shader_id = "deployment_grid", |
|
} |
|
|
|
|
|
|
|
DefineClass.GridMarkerDeploymentVisuals = { |
|
__parents = {"AOEActionVisuals"}, |
|
flags = { gofAlwaysRenderable = true, efApplyToGrids = false, efCollision = false}, |
|
|
|
mesh = false, |
|
marker = false, |
|
hover = false, |
|
} |
|
|
|
function GridMarkerDeploymentVisuals:Init() |
|
self.mesh = Mesh:new({}) |
|
self.mesh:SetVisible(false) |
|
self.mesh:SetMesh(self.marker:GetAreaTrianglePstr()) |
|
self.mesh:SetCRMaterial(CRM_DeploymentGrid:GetById("DeploymentArea_Deploy")) |
|
self:Attach(self.mesh) |
|
|
|
self:UpdateState() |
|
end |
|
|
|
function GridMarkerDeploymentVisuals:RecreateGeometry() |
|
self.mesh:SetMesh(self.marker:GetAreaTrianglePstr()) |
|
end |
|
|
|
function GridMarkerDeploymentVisuals:DoChangeState_deploy() |
|
self.mesh:SetCRMaterial(CRM_DeploymentGrid:GetById("DeploymentArea_Deploy")) |
|
self.mesh:SetVisible(true) |
|
end |
|
|
|
function GridMarkerDeploymentVisuals:DoChangeState_travel() |
|
self.mesh:SetCRMaterial(CRM_DeploymentGrid:GetById("DeploymentArea_Travel")) |
|
self.mesh:SetVisible(true) |
|
end |
|
|
|
function GridMarkerDeploymentVisuals:DoChangeState_travel_hover() |
|
self.mesh:SetCRMaterial(CRM_DeploymentGrid:GetById("DeploymentArea_Travel_Hover")) |
|
self.mesh:SetVisible(true) |
|
end |
|
|
|
function GridMarkerDeploymentVisuals:UpdateState() |
|
if rawget(_G, "gv_Deployment") then |
|
self:SetState("deploy") |
|
return |
|
end |
|
if self.hover then |
|
self:SetState("travel_hover") |
|
return |
|
end |
|
self:SetState("travel") |
|
end |
|
|
|
local lastFloor = false |
|
function OnMsg.WallVisibilityChanged() |
|
local camFloor = cameraTac.GetFloor() + 1 |
|
if lastFloor ~= camFloor then |
|
MapGet("map", "GridMarkerDeploymentVisuals", function(o) |
|
o:RecreateGeometry() |
|
end) |
|
|
|
lastFloor = camFloor |
|
end |
|
end |