File size: 5,597 Bytes
b6a38d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
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
-- precalc fire adjacency up to VoxelFireMaxDist
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
-- check for fires in voxels around the unit, considering all voxels occupied by that unit
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 |