|
MapVar("g_Fire", {}) |
|
MapVar("g_DistToFire", {}) |
|
|
|
local burn_active_terrain = "Dry_BurntGround_01" |
|
local burn_inactive_terrain = "Dry_BurntGround_02" |
|
local burn_terrain_radius = 3 * guim / 2 |
|
local toggledEnumFlags = const.efVisible + const.efWalkable + const.efCollision + const.efApplyToGrids |
|
|
|
const.VoxelFireMaxDist = 5*guim |
|
const.VoxelFireRange = MulDivRound(const.SlabSizeX, 200, 100) |
|
const.BurnDamageMin = 1 |
|
const.BurnDamageMax = 5 |
|
local VoxelFireRange = const.VoxelFireRange |
|
local VoxelFireMaxDist = const.VoxelFireMaxDist |
|
|
|
|
|
function IsBurnActiveCollection(col) |
|
return not not string.match(string.lower(col.Name), "col_burn_active") |
|
end |
|
|
|
function IsBurnInactiveCollection(col) |
|
return not not string.match(string.lower(col.Name), "col_burn_inactive") |
|
end |
|
|
|
function UpdateMapBurningState(burning) |
|
NetUpdateHash("UpdateMapBurningState") |
|
local active_func = burning and CObject.SetEnumFlags or CObject.ClearEnumFlags |
|
local inactive_func = burning and CObject.ClearEnumFlags or CObject.SetEnumFlags |
|
local terrain_old = Presets.TerrainObj.Default[burning and burn_inactive_terrain or burn_active_terrain].idx |
|
local terrain_new = Presets.TerrainObj.Default[burning and burn_active_terrain or burn_inactive_terrain].idx |
|
|
|
g_Fire = {} |
|
g_DistToFire = {} |
|
local queue = {} |
|
for _, col in pairs(Collections) do |
|
if IsBurnActiveCollection(col) then |
|
MapForEach("map", "collection", col.Index, true, function(obj) |
|
active_func(obj, toggledEnumFlags) |
|
if IsKindOf(obj, "ParSystem") and string.match(obj:GetParticlesName(), "Fire") then |
|
local pos = obj:GetPos() |
|
local vx, vy, vz = WorldToVoxel(pos) |
|
local packed_pos = point_pack(vx, vy, vz) |
|
g_Fire[packed_pos] = GameState.Burning or nil |
|
g_DistToFire[packed_pos] = GameState.Burning and 0 or nil |
|
queue[#queue+1] = packed_pos |
|
terrain.ReplaceTypeCircle(pos, burn_terrain_radius, terrain_old, terrain_new) |
|
end |
|
end) |
|
elseif IsBurnInactiveCollection(col) then |
|
MapForEach("map", "collection", col.Index, true, function(obj) |
|
inactive_func(obj, toggledEnumFlags) |
|
end) |
|
end |
|
end |
|
|
|
for _, area in ipairs(g_FireAreas) do |
|
for _, pos in ipairs(area.fire_positions) do |
|
local vx, vy, vz = WorldToVoxel(pos) |
|
local packed_pos = point_pack(vx, vy, vz) |
|
g_Fire[packed_pos] = true |
|
g_DistToFire[packed_pos] = 0 |
|
queue[#queue+1] = packed_pos |
|
end |
|
end |
|
|
|
local qi = 1 |
|
while qi < #queue do |
|
local ppos = queue[qi] |
|
local dist = g_DistToFire[ppos] |
|
local x, y, z = point_unpack(ppos) |
|
local adj, adj_dist |
|
if dist then |
|
adj_dist = dist + const.SlabSizeX |
|
if adj_dist < VoxelFireMaxDist then |
|
adj = point_pack(x + 1, y, z) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
adj = point_pack(x - 1, y, z) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
end |
|
adj_dist = dist + const.SlabSizeY |
|
if adj_dist < VoxelFireMaxDist then |
|
adj = point_pack(x, y + 1, z) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
adj = point_pack(x, y - 1, z) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
end |
|
adj_dist = dist + const.SlabSizeZ |
|
if adj_dist < VoxelFireMaxDist then |
|
adj = point_pack(x, y, z + 1) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
adj = point_pack(x, y, z - 1) |
|
if not g_DistToFire[adj] or g_DistToFire[adj] > adj_dist then |
|
g_DistToFire[adj] = adj_dist |
|
queue[#queue + 1] = adj |
|
end |
|
end |
|
end |
|
qi = qi + 1 |
|
end |
|
UpdatePassType() |
|
end |
|
|
|
function OnMsg.GameStateChanged(changed) |
|
if changed.FireStorm ~= nil then |
|
UpdateMapBurningState(GameState.FireStorm) |
|
end |
|
end |
|
|
|
function OnMsg.EnterSector() |
|
UpdateMapBurningState(GameState.FireStorm) |
|
end |
|
|
|
function AreVoxelsInFireRange(voxels, range) |
|
range = range or VoxelFireRange |
|
|
|
for _, voxel in ipairs(voxels) do |
|
local dist = g_DistToFire[voxel] |
|
if dist and dist < range then |
|
return true, dist |
|
end |
|
end |
|
end |
|
|
|
MapVar("g_dbgFireVisuals", false) |
|
|
|
function ToggleFiresDebug() |
|
if g_dbgFireVisuals then |
|
for _, obj in ipairs(g_dbgFireVisuals) do |
|
DoneObject(obj) |
|
end |
|
g_dbgFireVisuals = false |
|
return |
|
end |
|
|
|
g_dbgFireVisuals = {} |
|
local voxel_box = box(point(-const.SlabSizeX/2, -const.SlabSizeY/2, 0), point(const.SlabSizeX/2, const.SlabSizeY/2, const.SlabSizeZ)) |
|
for ppos, _ in pairs(g_Fire) do |
|
local pt = point(VoxelToWorld(point_unpack(ppos))) |
|
if not pt:IsValidZ() then |
|
pt = pt:SetTerrainZ() |
|
end |
|
|
|
local fire_box = voxel_box + pt |
|
local mesh = PlaceBox(fire_box, const.clrOrange, nil, false) |
|
table.insert(g_dbgFireVisuals, mesh) |
|
end |
|
|
|
for _, unit in ipairs(g_Units) do |
|
local voxels = unit:GetVisualVoxels() |
|
local adjacent, dist = AreVoxelsInFireRange(voxels) |
|
for _, voxel in ipairs(voxels) do |
|
local pt = point(VoxelToWorld(point_unpack(voxel))) |
|
local unit_box = voxel_box + pt |
|
local color = const.clrWhite |
|
if adjacent and dist < const.SlabSizeX then |
|
color = const.clrRed |
|
elseif adjacent then |
|
color = const.clrYellow |
|
end |
|
local mesh = PlaceBox(unit_box, color, nil, false) |
|
table.insert(g_dbgFireVisuals, mesh) |
|
end |
|
end |
|
end |