forked from SCP-CB-CPP/scpcb
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOverlapResolver.bb
More file actions
171 lines (144 loc) · 5.44 KB
/
Copy pathOverlapResolver.bb
File metadata and controls
171 lines (144 loc) · 5.44 KB
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
Function CheckRoomOverlap(r1.Rooms, r2.Rooms)
Return (CalcOverlapArea(r1, r2) > 0)
End Function
Function CalcOverlapArea#(r1.Rooms, r2.Rooms)
If (r1\MaxX <= r2\MinX Or r1\MaxY <= r2\MinY Or r1\MaxZ <= r2\MinZ) Then Return 0
If (r1\MinX >= r2\MaxX Or r1\MinY >= r2\MaxY Or r1\MinZ >= r2\MaxZ) Then Return 0
Return (Min(r1\MaxX, r2\MaxX) - Max(r1\MinX, r2\MinX)) * (Min(r1\MaxZ, r2\MaxZ) - Max(r1\MinZ, r2\MinZ))
End Function
Function CalcAllRoomOverlaps#(r.Rooms)
Local overlapArea# = 0
Local r2.Rooms
For r2 = Each Rooms
If Not r2\RoomTemplate\DisableOverlapCheck Then
If r2<>r Then
overlapArea = overlapArea + CalcOverlapArea(r, r2)
EndIf
EndIf
Next
Return overlapArea
End Function
Function ReportOverlaps()
Local r1.Rooms,r2.Rooms
For r1 = Each Rooms
For r2 = Each Rooms
If r2<>r1 Then
If CheckRoomOverlap(r1, r2) Then
DebugLog "Overlapping rooms: " + r1\RoomTemplate\Name + " / " + r2\RoomTemplate\Name
EndIf
EndIf
Next
Next
End Function
Function RotateRoom(r.Rooms)
RotateEntity r\obj,0,r\angle,0
CalculateRoomExtents(r)
End Function
Function MoveRoom(r.Rooms)
PositionEntity r\obj,r\x,r\y,r\z
RotateEntity r\obj,0,r\angle,0
CalculateRoomExtents(r)
End Function
Function ShouldSkipOverlapCandidate(r.Rooms)
Local rt.RoomTemplates = r\RoomTemplate
Return rt\DisableOverlapCheck Lor rt\Name = "checkpoint1" Lor rt\Name = "checkpoint2" Lor rt\Name = "start"
End Function
Function PreventRoomOverlap(r.Rooms)
If r\RoomTemplate\DisableOverlapCheck Then Return
; Just skip it when it would try to check for the checkpoints
If ShouldSkipOverlapCandidate(r) Then Return
Local r2.Rooms,r3.Rooms
Local overlapAreaBefore1#,overlapAreaAfter1#
Local overlapAreaBefore2#,overlapAreaAfter2#
DebugLog "PreventRoomOverlap: " + r\RoomTemplate\Name
; First, check if the room is actually intersecting at all
overlapAreaBefore1 = CalcAllRoomOverlaps(r)
If overlapAreaBefore1 = 0 Then Return
DebugLog "Room is intersecting, overlapping area = " + overlapAreaBefore1
; Room is intersecting: First, check if the given room is a ROOM2, so we could potentially just turn it by 180 degrees
If r\RoomTemplate\Shape = ROOM2 Then
;Room is a ROOM2, let's check if turning it 180 degrees fixes the overlapping issue
r\angle = r\angle + 180
RotateRoom(r)
overlapAreaAfter1 = CalcAllRoomOverlaps(r)
; room is ROOM2 and was able to be turned by 180 degrees
If overlapAreaAfter1 = 0
DebugLog "ROOM2 turning succesful! " + r\RoomTemplate\Name
Return
EndIf
; room still overlaps after rotate. Check if new position any better
If overlapAreaBefore1 > overlapAreaAfter1 Then
DebugLog "Better position after ROOM2 rotate: " + overlapAreaBefore1 + " -> " + overlapAreaAfter1
overlapAreaBefore1 = overlapAreaAfter1;
Else
; didn't work -> rotate the room back and move to the next step
DebugLog "rollback ROOM2 rotate"
r\angle = r\angle - 180
RotateRoom(r)
EndIf
EndIf
;Room is either not a ROOM2 or the ROOM2 is still intersecting, now trying to swap the room with another of the same type
Local oldX1#,oldZ1#,oldAngle1%
Local oldX2#,oldZ2#,oldAngle2%
For r2 = Each Rooms
If r\RoomTemplate\Shape = r2\RoomTemplate\Shape And r\zone = r2\zone And r <> r2 And (Not ShouldSkipOverlapCandidate(r2)) Then
overlapAreaBefore2 = CalcAllRoomOverlaps(r2)
Local candidatesOverlapAreaBefore# = CalcOverlapArea(r, r2)
DebugLog "Swap overlap area: " + overlapAreaBefore2
; remember original position before swap
oldX1 = r\x
oldZ1 = r\z
oldAngle1 = r\angle
oldX2 = r2\x
oldZ2 = r2\z
oldAngle2 = r2\angle
; swap itself
r\x = oldX2
r\z = oldZ2
r\angle = oldAngle2
MoveRoom(r)
r2\x = oldX1
r2\z = oldZ1
r2\angle = oldAngle1
MoveRoom(r2)
;make sure neither room overlaps with anything after the swap
overlapAreaAfter1 = 0
overlapAreaAfter2 = 0
Local candidatesOverlapAreaAfter# = CalcOverlapArea(r, r2)
For r3 = Each Rooms
If Not r3\RoomTemplate\DisableOverlapCheck Then
If r3 <> r Then
overlapAreaAfter1 = overlapAreaAfter1 + CalcOverlapArea(r, r3);
EndIf
If r3 <> r2 Then
overlapAreaAfter2 = overlapAreaAfter2 + CalcOverlapArea(r2, r3);
EndIf
EndIf
Next
DebugLog "Overlaps after swap: MAIN " + overlapAreaBefore1 + " -> " + overlapAreaAfter1 + ", SWAP " + overlapAreaBefore2 + " -> " + overlapAreaAfter2
; Check if no overlaps after swap - then problem solved, return
If overlapAreaAfter1 = 0 And overlapAreaAfter2 = 0 Then
DebugLog "Successful rooms swap: " + r\RoomTemplate\Name + " / " + r2\RoomTemplate\Name
Return
EndIf
; If we still have overlap - check if overlapping area is smaller than before and continue search
; We subtract the overlap area between the candidates as it is otherwise counted twice, once as part of each sum.
If (overlapAreaAfter1 + overlapAreaAfter2 - candidatesOverlapAreaAfter) < (overlapAreaBefore1 + overlapAreaBefore2 - candidatesOverlapAreaBefore) Then
DebugLog "Partial overlap fix, rooms swap: " + r\RoomTemplate\Name + " / " + r2\RoomTemplate\Name
overlapAreaBefore1 = overlapAreaAfter1
Else
; overlap area is bigger than before - then rollback this change and continue search
DebugLog "Cancel this swap"
r\x = oldX1
r\z = oldZ1
r\angle = oldAngle1
MoveRoom(r)
r2\x = oldX2
r2\z = oldZ2
r2\angle = oldAngle2
MoveRoom(r2)
EndIf
EndIf
Next
DebugLog "Couldn't fix overlap issue for room " + r\RoomTemplate\Name
End Function