File size: 7,196 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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
if Platform.cmdline then return end

if FirstLoad then
	debug_pass_draw = false
end
function OnMsg.DoneMap()
	debug_pass_draw = false
	rawset(_G, "g_APCostsShown", false)
end

DefineClass.DebugPassDraw =
{
	__parents = { "CObject" },
	entity = "Floor_Planks",
	flags = {
		efSelectable = false, efWalkable = false, efCollision = false, 
		efApplyToGrids = false, efShadow = false, efSunShadow = false,
		cfConstructible = false,
		cofComponentColorizationMaterial = true,
		cofComponentCollider = false,
	},
}

function DbgDrawPFLevelPass(on, offsetz)
	debug_pass_draw = debug_pass_draw or {}
	for i = #debug_pass_draw, 0, -1 do
		if IsValid(debug_pass_draw[i]) then DoneObject(debug_pass_draw[i]) end
		debug_pass_draw[i] = nil
	end
	if on == false then
		return
	end
	local tile_size = const.SlabSizeX
	local tile_z = const.SlabSizeZ
	local scale = const.PassTileSize * 100 / const.SlabSizeX
	local color1_central = RGB(120,180,130)
	local color1_intermediate = RGB(150,220,160)
	offsetz = offsetz or 5*guic

	local function func(x, y, z)
		local o = PlaceObject("DebugPassDraw")
		table.insert(debug_pass_draw, o)
		NetTempObject(o)
		o:SetScale(scale)
		local vx, vy, vz = WorldToVoxel(x, y, z)
		local _x, _y, _z = VoxelToWorld(vx, vy, vz)
		local inside_tile = abs(x - _x) < tile_size / 2 and abs(y - _y) < tile_size / 2
		if inside_tile then
			--o:SetColorizationMaterial(1, color1_central, 0, 0)
			o:SetColorModifier(color1_central)
		else
			--o:SetColorizationMaterial(1, color1_intermediate, 0, 0)
			o:SetColorModifier(color1_intermediate)
			o:SetAngle(90*60)
		end
		o:SetPos(x, y, z + offsetz)
	end
	local sizex, sizey = terrain.GetMapSize()
	terrain.ForEachPassCenter(func, box(0, 0, 0, sizex, sizey, 100000)) -- all map pflevels (without terrain)
	return #debug_pass_draw
end

function DbgDrawPassSlabs(on, show_terrain_pass, offsetz, bbox)
	local sizex, sizey = terrain.GetMapSize()
	bbox = bbox or box(0, 0, 0, sizex, sizey, 100000)

	debug_pass_draw = debug_pass_draw or {}
	local i, n = 1, #debug_pass_draw
	while i <= n do
		local obj = debug_pass_draw[i]
		if not IsValid(obj) or obj:GetPos():InBox(bbox) then
			if IsValid(obj) then DoneObject(obj) end
			debug_pass_draw[i] = debug_pass_draw[n]
			debug_pass_draw[n] = nil
			n = n - 1
		else
			i = i + 1
		end
	end
	if on == false then
		return
	end

	local floor = IsEditorActive() and XEditorFilters:GetFilter("HideFloor") or 0
	if floor == 0 then floor = 999 end

	local color = RGB(120, 180, 130)
	local colorWater = RGB(0, 0, 130)
	local scale = const.PassTileSize * 100 / const.SlabSizeX
	local scaleWater = scale * 60 / 100
	local ptGrow = point(const.SlabSizeX, const.SlabSizeY, const.SlabSizeZ * 2)
	offsetz = offsetz or 5*guic
	local hide_roofs = IsEditorActive() and not LocalStorage.FilteredCategories["Roofs"] or nil

	local function func(x, y, z)
		if not z and not show_terrain_pass then
			return
		end
		if not terrain.IsPassable(x, y, z, 0) then
			return
		end
		local pt = point(x, y, (z or terrain.GetHeight(x, y)) + offsetz)
		local volume = Extend(empty_box, pt):grow(ptGrow)
		local room = EnumVolumes(volume, "smallest")
		local bld_meta = VolumeBuildingsMeta[room and room.building or false]
		if bld_meta and bld_meta[floor] and pt:z() >= bld_meta[floor].box:minz() - 5 * guim / 10 then
			return -- don't add debug pass that would be hidden because of the floor editor filter
		end
		if hide_roofs then
			local slab, z = WalkableSlabByPoint(pt, true, bnot(const.gofSolidShadow))
			if GetPassSlab(x, y, z) then
				local threshold = IsKindOf(slab, "TerrainCollision") and 15 * guic or 7 * guic
				if abs(z - pt:z()) >= threshold then
					return
				end
			end
		end
		local o = PlaceObject("DebugPassDraw")
		table.insert(debug_pass_draw, o)
		NetTempObject(o)
		o:SetColorModifier(color)
		o:SetScale(scale)
		o:SetPos(pt)
		--if not z and SelectedObj:GetDist(x,y) < 2000 then
		--	z = nil
		--end
		local pass_type = terrain.GetPassType(point(x, y, z))
		if pass_type == pathfind_water_pass_type_idx then
			local o = PlaceObject("DebugPassDraw")
			table.insert(debug_pass_draw, o)
			NetTempObject(o)
			o:SetColorModifier(colorWater)
			o:SetScale(scaleWater)
			o:SetPos(pt:x(), pt:y(), pt:z() + offsetz)
		end
	end
	ForEachPassSlab(bbox, func)
	return #debug_pass_draw
end

function DbgDrawCombatNodes(combatPath, max_cost)
	DbgClearVectors()
	DbgClearTexts()
	local tile_size = const.SlabSizeX
	local ap_mul = const.Scale.AP
	local color = const.clrPaleBlue
	local offs = tile_size*25/100
	local offsz = 10*guic

	for pk_pos, ap in pairs(combatPath and combatPath.paths_ap or empty_table) do
		if not max_cost or ap <= max_cost then
			local x1, y1, z1 = point_unpack(pk_pos)
			z1 = (z1 or terrain.GetHeight(x1, y1)) + offsz
			local txt
			if ap % ap_mul == 0 then
				txt = string.format("%d", ap / ap_mul)
			else
				txt = string.format("%d.%.2d", ap / ap_mul, Max(1, (ap % ap_mul) * 100 / ap_mul))
			end
			local p = point(x1, y1, z1)
			DbgAddText(txt, p, color)
			local prev_pos = combatPath.paths_prev_pos[pk_pos]
			if prev_pos then
				local x2, y2, z2 = point_unpack(prev_pos)
				z2 = (z2 or terrain.GetHeight(x2, y2)) + offsz
				local dx = (x2 - x1) / tile_size
				local dy = (y2 - y1) / tile_size
				local p2 = point(x2, y2, z2)
				if dx == 0 or dy == 0 then
					p2 = p - SetLen(p - p2, tile_size)
				else
					for k = Min(abs(dx), abs(dy)), 2, -1 do
						if dx % k == 0 and dy % k == 0 then
							p2 = p + point(tile_size * dx / k, tile_size * dy / k, 0)
							break
						end
					end
				end
				local v = p - p2
				local len = v:Len()
				DbgAddVector(p - SetLen(v, len - offs), SetLen(v, len - 2*offs), color)
			end
		end
	end
end

function DbgDrawCombatPositions(unit, max_cost)
	if not IsValid(unit) then return end
	local combatPath = PlaceObject("CombatPath")
	combatPath:RebuildPaths(unit, max_cost or unit.ActionPoints)
	DbgDrawCombatNodes(combatPath)
	DoneObject(combatPath)
end

function DbgRecalcDrawCombatNodes(unit)
	if not rawget(_G, "g_APCostsShown") then
		return
	end
	if unit ~= SelectedObj then
		return
	end
	if IsValid(SelectedObj) then
		DbgDrawCombatNodes(GetCombatPath(SelectedObj))
	else
		DbgDrawCombatNodes(false)
	end
end
OnMsg.SelectedObjChange = DbgRecalcDrawCombatNodes
OnMsg.UnitAPChanged = DbgRecalcDrawCombatNodes
OnMsg.UnitMovementDone = DbgRecalcDrawCombatNodes

function OnMsg.UnitAPChanged(unit)
	if unit == SelectedObj then
		DbgRecalcDrawCombatNodes()
	end
end

local function DbgCollapsePointsInBox(b, steps)
	local pts = {}
	ForEachPassSlab(b, function(x, y, z)
		pts[#pts + 1] = stance_pos_pack(x, y, z, 0)
	end)
	local collapsed = CollapsePoints(pts, steps)
	for _, pt in ipairs(pts) do
		local x, y, z = stance_pos_unpack(pt)
		if table.find(collapsed, pt) then
			ShowMe(point(x,y,z))
		else
		end
	end
end

function DbgShowVisFieldCollapsedPositionsArroundCursor(steps, radius)
	ClearShowMe()
	DbgClear()
	steps = steps or 1
	local cursor = GetCursorPos()
	radius = radius or 10*guim
	local b = box(cursor:x() - radius, cursor:y() - radius, 0, cursor:x() + radius + const.SlabSizeX, cursor:y() + radius + const.SlabSizeX, MapSlabsBBox_MaxZ)
	--RebuildVisField(b)
	DbgCollapsePointsInBox(b, steps)
end