File size: 6,081 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
local cardinal_dirs = {"east", "west", "north", "south"}
local dir_angle = { ["east"] = 90 * 60, ["west"] = 270 * 60, ["south"] = 180 * 60, ["north"] = 0 }

local function GetPlaneDir(plane)
	for _, dir in ipairs(cardinal_dirs) do
		if string.match(plane:lower(), dir) then
			return dir
		end
	end
end

MapVar("s_BorderBuildingAutoAttachesRequired", 0)
MapVar("s_BorderBuildingAutoAttachesCreated", 0)

DefineClass.BorderBuilding = {
	__parents = {"AutoAttachObject", "EditorCallbackObject", "EditorSelectedObject"},
	
	properties = {
		{category = "Windows Auto Attaches", id = "east", name = "East", editor = "bool", default = true, help = "Uncheck to remove window auto attaches from this side"},
		{category = "Windows Auto Attaches", id = "west", name = "West", editor = "bool", default = true, help = "Uncheck to remove window auto attaches from this side"},
		{category = "Windows Auto Attaches", id = "north", name = "North", editor = "bool", default = true, help = "Uncheck to remove window auto attaches from this side"},
		{category = "Windows Auto Attaches", id = "south", name = "South", editor = "bool", default = true, help = "Uncheck to remove window auto attaches from this side"},
		{category = "Windows Auto Attaches", id = "Recalc", editor = "buttons", default = false,
			buttons = {
				{ name = "Recalc Visible Sides", func = function(self)
					self:CalcVisibleSides()
				end},
				{ name = "Turn All Sides ON", func = function(self)
					self:TurnAllSides(true)
				end},
				{ name = "Turn All Sides OFF", func = function(self)
					self:TurnAllSides(false)
				end},
			},
		},
	},
	
	texts = false,
}

function BorderBuilding:ShouldAttach(attach)
	s_BorderBuildingAutoAttachesRequired = s_BorderBuildingAutoAttachesRequired + 1
	
	local spot_ann = self:GetSpotAnnotation(attach.spot_idx)
	if not spot_ann then return true end
	
	local dir = GetPlaneDir(spot_ann)
	if not dir then return true end
	
	return self[dir]
end

function BorderBuilding:OnAttachCreated(attach, spot)
	s_BorderBuildingAutoAttachesCreated = s_BorderBuildingAutoAttachesCreated + 1
	
	if IsKindOfClasses(attach, "WindowTunnelObject", "Door") then
		attach.AttachLight = false
	end
end

function BorderBuilding:UpdateAutoAttaches()
	self:SetAutoAttachMode(self:GetAutoAttachMode())
end

function BorderBuilding:GatherWallWindows()
	local spots_used = {}
	local spots = table.imap(AutoAttachPresets[self.class], function(attach)
		spots_used[attach.name] = true
	end)
	local spots = table.keys(spots_used)
	
	local planes = {}
	local sides = {}
	for _, spot_name in ipairs(spots) do
		local first, last = self:GetSpotRange(spot_name)
		for spot_idx = first, last do
			local spot_pos = self:GetSpotPos(spot_idx)
			local spot_ann = self:GetSpotAnnotation(spot_idx)
			if spot_ann then
				local dir = GetPlaneDir(spot_ann)
				if dir then
					local spot = {pos = spot_pos, name = spot_name, idx = spot_idx}
					planes[spot_ann] = planes[spot_ann] or {dir = dir}
					table.insert(planes[spot_ann], spot)
					sides[dir] = sides[dir] or {}
					table.insert(sides[dir], spot)
				end
			end
		end
	end
	
	return planes, sides
end

function BorderBuilding:CalcVisibleSides()
	local center = GetMapBox():Center()
	local planes, sides = self:GatherWallWindows()
	local side_count = {}
	for plane_name, plane in pairs(planes) do
		local dir = GetPlaneDir(plane_name)
		local angle = self:GetAngle() + dir_angle[dir]
		local plane_norm = Rotate(point(4096, 0), angle)
		local plane_data = side_count[dir] or {total = 0, visible = 0}
		side_count[dir] = plane_data
		plane_data.total = plane_data.total + #plane
		if Dot(center - plane[1].pos, plane_norm) > 0 then
			plane_data.visible = plane_data.visible + #plane			
		end
	end
	
	for dir, side in pairs(side_count) do
		self:SetProperty(dir, side.visible > side.total / 2)
	end
	ObjModified(self)
	
	self:UpdateAutoAttaches()
end

function BorderBuilding:TurnAllSides(state)
	for _, dir in pairs(cardinal_dirs) do
		self:SetProperty(dir, state)
	end
	ObjModified(self)
	self:UpdateAutoAttaches()
end

function BorderBuilding:OnEditorSetProperty(prop_id)
	if table.find(cardinal_dirs, prop_id) then
		self:UpdateAutoAttaches()
	end
end

function BorderBuilding:DelayedRecalcAutoAttaches()
	DelayedCall(500, function(self)
		self:CalcVisibleSides()
		self:UpdateAutoAttaches()
	end, self)
end

BorderBuilding.EditorCallbackMove = BorderBuilding.DelayedRecalcAutoAttaches
BorderBuilding.EditorCallbackRotate = BorderBuilding.DelayedRecalcAutoAttaches
BorderBuilding.EditorCallbackPlace = BorderBuilding.DelayedRecalcAutoAttaches

function BorderBuilding:EditorSelect(selected)
	if selected then
		local center = self:GetPos()
		local high_z = self:GetObjectBBox():sizez() + guim
		local _, sides = self:GatherWallWindows()
		for dir, spots in pairs(sides) do
			local pos = point30
			for _, spot in pairs(spots) do
				pos = pos + spot.pos - center
			end
			pos = (pos / #spots):SetZ(high_z)
			local text = PlaceText(dir:upper(), pos, const.clrGreen)
			self:Attach(text)
			text:SetAttachOffset(pos)
			self.texts = self.texts or {}
			table.insert(self.texts, text)
		end
	elseif self.texts then
		for _, text in ipairs(self.texts) do
			if IsValid(text) then
				text:Detach()
				DoneObject(text)
			end
		end
		self.texts = false
	end
end

function BorderBuildingsRecalcVisibleSides()
	s_BorderBuildingAutoAttachesRequired = 0
	s_BorderBuildingAutoAttachesCreated = 0
	
	local buildings = 0
	MapForEach("map", "BorderBuilding", function(bld)
		buildings = buildings + 1
		bld:CalcVisibleSides()
		bld:UpdateAutoAttaches()
	end)
	
	printf("BorderBuilding(s): %d, Auto Attaches Created/Required: %d/%d(%d%%)", buildings, 
		s_BorderBuildingAutoAttachesCreated, s_BorderBuildingAutoAttachesRequired, 
		100 * s_BorderBuildingAutoAttachesCreated / s_BorderBuildingAutoAttachesRequired)
end

function SelectionBorderBuildingToggleWall(dir)
	for _, obj in ipairs(editor.GetSel() or empty_table) do
		if IsKindOf(obj, "BorderBuilding") then
			obj:SetProperty(dir, not obj:GetProperty(dir))
			obj:UpdateAutoAttaches()
		end
	end
end