diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1a50eda6..61736b13 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -139,7 +139,7 @@ jobs:
       run: |
         reccmp-reccmp -S CONFIGPROGRESS.SVG --svg-icon assets/config.png --target CONFIG | tee CONFIGPROGRESS.TXT
         reccmp-reccmp -S ISLEPROGRESS.SVG --svg-icon assets/isle.png --target ISLE | tee ISLEPROGRESS.TXT
-        reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4357 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT
+        reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4358 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT
 
     - name: Compare Accuracy With Current Master
       shell: bash
diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp
index 8c98dd87..87f1cbdc 100644
--- a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp
+++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp
@@ -48,7 +48,7 @@ void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPa
 {
 	Vector3* ccwV = NULL;
 
-	if (m_unk0x48 > 0 && m_unk0x50 != NULL) {
+	if (m_numTriggers > 0 && m_unk0x50 != NULL) {
 		ccwV = m_edges[0]->CCWVertex(*this);
 		Mx3DPointFloat v;
 
@@ -61,7 +61,7 @@ void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPa
 		float dot2 = v.Dot(&v, m_unk0x50);
 
 		if (dot2 > dot1) {
-			for (MxS32 i = 0; i < m_unk0x48; i++) {
+			for (MxS32 i = 0; i < m_numTriggers; i++) {
 				LegoPathStruct* s = m_pathTrigger[i].m_pathStruct;
 
 				if (m_pathTrigger[i].m_unk0x08 >= dot1 && m_pathTrigger[i].m_unk0x08 < dot2) {
@@ -70,7 +70,7 @@ void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPa
 			}
 		}
 		else if (dot2 < dot1) {
-			for (MxS32 i = 0; i < m_unk0x48; i++) {
+			for (MxS32 i = 0; i < m_numTriggers; i++) {
 				LegoPathStruct* s = m_pathTrigger[i].m_pathStruct;
 
 				if (m_pathTrigger[i].m_unk0x08 >= dot2 && m_pathTrigger[i].m_unk0x08 < dot1) {
diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp
index 887d19f7..a36a9a53 100644
--- a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp
+++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp
@@ -673,15 +673,15 @@ MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage)
 			return FAILURE;
 		}
 
-		if (p_storage->Read(&boundary.m_unk0x48, sizeof(boundary.m_unk0x48)) != SUCCESS) {
+		if (p_storage->Read(&boundary.m_numTriggers, sizeof(boundary.m_numTriggers)) != SUCCESS) {
 			return FAILURE;
 		}
 
-		if (boundary.m_unk0x48 > 0) {
+		if (boundary.m_numTriggers > 0) {
 			boundary.m_unk0x50 = new Mx3DPointFloat;
-			boundary.m_pathTrigger = new LegoWEGEdge::PathWithTrigger[boundary.m_unk0x48];
+			boundary.m_pathTrigger = new LegoWEGEdge::PathWithTrigger[boundary.m_numTriggers];
 
-			for (j = 0; j < boundary.m_unk0x48; j++) {
+			for (j = 0; j < boundary.m_numTriggers; j++) {
 				if (p_storage->Read(&s, sizeof(s)) != SUCCESS) {
 					return FAILURE;
 				}
diff --git a/LEGO1/lego/sources/geom/legoedge.h b/LEGO1/lego/sources/geom/legoedge.h
index 43740bda..881f9325 100644
--- a/LEGO1/lego/sources/geom/legoedge.h
+++ b/LEGO1/lego/sources/geom/legoedge.h
@@ -19,6 +19,12 @@ struct LegoEdge {
 
 	LegoResult FUN_1002ddc0(LegoWEEdge& p_face, Vector3& p_point);
 
+	// FUNCTION: BETA10 0x10184170
+	LegoWEEdge* GetFaceA() { return m_faceA; }
+
+	// FUNCTION: BETA10 0x10184190
+	LegoWEEdge* GetFaceB() { return m_faceB; }
+
 	// FUNCTION: BETA10 0x1001cb80
 	Vector3* GetPointA() { return m_pointA; }
 
diff --git a/LEGO1/lego/sources/geom/legounkown100db7f4.h b/LEGO1/lego/sources/geom/legounkown100db7f4.h
index ef525932..1c9c266d 100644
--- a/LEGO1/lego/sources/geom/legounkown100db7f4.h
+++ b/LEGO1/lego/sources/geom/legounkown100db7f4.h
@@ -93,6 +93,9 @@ public:
 	// FUNCTION: BETA10 0x1001cc60
 	LegoU32 GetMask0x03() { return m_flags & (c_bit1 | c_bit2); }
 
+	// FUNCTION: BETA10 0x101841b0
+	void SetFlags(LegoU16 p_flags) { m_flags = p_flags; }
+
 	inline LegoU32 FUN_10048c40(const Vector3& p_position);
 
 	// SYNTHETIC: LEGO1 0x1009a6c0
diff --git a/LEGO1/lego/sources/geom/legoweedge.cpp b/LEGO1/lego/sources/geom/legoweedge.cpp
index a87072e9..862b247d 100644
--- a/LEGO1/lego/sources/geom/legoweedge.cpp
+++ b/LEGO1/lego/sources/geom/legoweedge.cpp
@@ -20,7 +20,7 @@ LegoWEEdge::~LegoWEEdge()
 }
 
 // FUNCTION: LEGO1 0x1009a5b0
-LegoResult LegoWEEdge::VTable0x04()
+LegoS32 LegoWEEdge::VTable0x04()
 {
 	for (LegoS32 i = 0; i < m_numEdges; i++) {
 		LegoUnknown100db7f4* e1 = m_edges[i];
@@ -52,5 +52,5 @@ LegoResult LegoWEEdge::VTable0x04()
 		}
 	}
 
-	return SUCCESS;
+	return 0;
 }
diff --git a/LEGO1/lego/sources/geom/legoweedge.h b/LEGO1/lego/sources/geom/legoweedge.h
index bc0f6c3c..c2df2758 100644
--- a/LEGO1/lego/sources/geom/legoweedge.h
+++ b/LEGO1/lego/sources/geom/legoweedge.h
@@ -14,7 +14,7 @@ public:
 	LegoWEEdge();
 	virtual ~LegoWEEdge(); // vtable+0x00
 
-	virtual LegoResult VTable0x04(); // vtable+0x04
+	virtual LegoS32 VTable0x04(); // vtable+0x04
 
 	// FUNCTION: BETA10 0x1001c980
 	LegoU8 GetNumEdges() { return m_numEdges; }
diff --git a/LEGO1/lego/sources/geom/legowegedge.cpp b/LEGO1/lego/sources/geom/legowegedge.cpp
index afbe9ddb..6de4fd17 100644
--- a/LEGO1/lego/sources/geom/legowegedge.cpp
+++ b/LEGO1/lego/sources/geom/legowegedge.cpp
@@ -1,9 +1,14 @@
 #include "legowegedge.h"
 
+#include "legounkown100db7f4.h"
+
+#include <assert.h>
+
 DECOMP_SIZE_ASSERT(LegoWEGEdge, 0x54)
 DECOMP_SIZE_ASSERT(LegoWEGEdge::PathWithTrigger, 0x0c)
 
 // FUNCTION: LEGO1 0x1009a730
+// FUNCTION: BETA10 0x101830ec
 LegoWEGEdge::LegoWEGEdge()
 {
 	m_unk0x0d = 0;
@@ -11,7 +16,7 @@ LegoWEGEdge::LegoWEGEdge()
 	m_unk0x14.Clear();
 	m_edgeNormals = NULL;
 	m_flags = 0;
-	m_unk0x48 = 0;
+	m_numTriggers = 0;
 	m_pathTrigger = NULL;
 	m_unk0x50 = NULL;
 }
@@ -37,9 +42,241 @@ LegoWEGEdge::~LegoWEGEdge()
 	}
 }
 
-// STUB: LEGO1 0x1009a8c0
-LegoResult LegoWEGEdge::VTable0x04()
+// FUNCTION: LEGO1 0x1009a8c0
+// FUNCTION: BETA10 0x101832f7
+LegoS32 LegoWEGEdge::VTable0x04()
 {
-	// TODO
-	return SUCCESS;
+	LegoS32 result = 0;
+	m_unk0x30.Clear();
+	LegoWEEdge::VTable0x04();
+
+	assert(m_numEdges > 1);
+
+	Vector3* local20;
+	if (IsEqual(m_edges[0]->m_faceA)) {
+		local20 = m_edges[0]->m_pointB;
+	}
+	else {
+		assert(IsEqual(m_edges[0]->m_faceB));
+		local20 = m_edges[0]->m_pointA;
+	}
+
+	Vector3 *local1c, *local14;
+	if (IsEqual(m_edges[1]->m_faceA)) {
+		local1c = m_edges[1]->m_pointB;
+		local14 = m_edges[1]->m_pointA;
+	}
+	else {
+		assert(IsEqual(m_edges[1]->m_faceB));
+		local1c = m_edges[1]->m_pointA;
+		local14 = m_edges[1]->m_pointB;
+	}
+
+	result = FUN_1009aea0();
+	if (result != 0) {
+		result = -2;
+	}
+
+	assert(m_edgeNormals == NULL);
+	m_edgeNormals = new Mx4DPointFloat[m_numEdges];
+	assert(m_edgeNormals);
+
+	LegoUnknown100db7f4* edge;
+	LegoS32 i;
+
+	for (i = 0; i < m_numEdges; i++) {
+		edge = m_edges[i];
+		m_unk0x30 += *edge->m_pointA;
+		m_unk0x30 += *edge->m_pointB;
+	}
+
+	m_unk0x30 /= m_numEdges * 2;
+	m_unk0x44 = 0.0f;
+
+	for (i = 0; i < m_numEdges; i++) {
+		Mx3DPointFloat local44;
+		edge = m_edges[i];
+
+		local44 = *edge->m_pointA;
+		local44 -= m_unk0x30;
+		float length = local44.LenSquared();
+
+		if (m_unk0x44 < length) {
+			m_unk0x44 = length;
+		}
+
+		local44 = *edge->m_pointB;
+		local44 -= m_unk0x30;
+		length = local44.LenSquared();
+
+		if (m_unk0x44 < length) {
+			m_unk0x44 = length;
+		}
+	}
+
+	m_unk0x44 = sqrt((double) m_unk0x44);
+
+	for (i = 0; i < m_numEdges; i++) {
+		edge = m_edges[i];
+		Vector3& local5c = edge->m_unk0x28;
+
+		if (edge->m_unk0x3c == 0) {
+			local5c = *m_edges[i]->m_pointB;
+			local5c -= *m_edges[i]->m_pointA;
+			edge->m_unk0x3c = local5c.LenSquared();
+
+			if (edge->m_unk0x3c <= 0.0f) {
+				assert(0);
+				if (result == 0) {
+					result = -1;
+				}
+			}
+
+			edge->m_unk0x3c = sqrt((double) edge->m_unk0x3c);
+			local5c /= edge->m_unk0x3c;
+		}
+
+		Mx3DPointFloat local58;
+		Vector3 local64(&m_edgeNormals[i][0]);
+		edge->FUN_1002ddc0(*this, local58);
+		local64.EqualsCross(&local58, &m_unk0x14);
+
+		m_edgeNormals[i][3] = -local64.Dot(m_edges[i]->m_pointA, &local64);
+		if (m_edgeNormals[i][3] + m_unk0x30.Dot(&m_unk0x30, &local64) < 0.0f) {
+			m_edgeNormals[i] *= -1.0f;
+		}
+
+		if (edge->GetFaceA() != NULL && edge->GetFaceB() != NULL) {
+			edge->SetFlags(LegoUnknown100db7f4::c_bit1 | LegoUnknown100db7f4::c_bit2);
+		}
+	}
+
+	if (m_numTriggers > 0) {
+		Vector3* vTrig1 = m_edges[0]->CCWVertex(*this);
+		Vector3* vTrig2 = m_edges[1]->CCWVertex(*this);
+		assert(vTrig1 && vTrig2);
+
+		m_unk0x50 = new Mx3DPointFloat();
+		*m_unk0x50 = *vTrig2;
+		*m_unk0x50 -= *vTrig1;
+
+		if (m_unk0x50->Unitize() < 0) {
+			assert(0);
+			delete m_unk0x50;
+			m_unk0x50 = NULL;
+		}
+
+		if (GetNumEdges() == 4) {
+			float local98 = 0.0f;
+			Mx3DPointFloat localb8(*m_edges[0]->CWVertex(*this));
+			Mx3DPointFloat local80(*m_edges[2]->CCWVertex(*this));
+			Mx3DPointFloat local94(*vTrig2);
+
+			local94 -= *vTrig1;
+			float local9c = sqrt(local94.LenSquared());
+
+			localb8 -= *vTrig1;
+			local80 -= *vTrig1;
+
+			float locala4 = localb8.Dot(m_unk0x50, &localb8);
+			if (local98 < locala4) {
+				local98 = locala4;
+			}
+
+			locala4 = local80.Dot(m_unk0x50, &local80);
+			if (locala4 < local9c) {
+				local9c = locala4;
+			}
+
+			if (local9c < local98) {
+				result = -3;
+			}
+			if (local9c - local98 < 0.0025) {
+				result = -4;
+			}
+
+			local98 += 0.001;
+			local9c -= 0.001;
+
+			for (LegoS32 j = 0; j < m_numTriggers; j++) {
+				if (m_pathTrigger[j].m_unk0x08 < local98) {
+					m_pathTrigger[j].m_unk0x08 = local98;
+				}
+
+				if (m_pathTrigger[j].m_unk0x08 > local9c) {
+					m_pathTrigger[j].m_unk0x08 = local9c;
+				}
+			}
+		}
+		else {
+			result = -5;
+		}
+	}
+
+	return result;
+}
+
+// FUNCTION: LEGO1 0x1009aea0
+// FUNCTION: BETA10 0x10183e2a
+LegoS32 LegoWEGEdge::FUN_1009aea0()
+{
+	LegoU32 localc = FALSE;
+	Mx3DPointFloat local24;
+
+	if (m_numEdges < 3) {
+		return -1;
+	}
+
+	Vector3** local8 = new Vector3*[m_numEdges];
+	LegoS32 i;
+
+	for (i = 0; i < m_numEdges; i++) {
+		local8[i] = m_edges[i]->CWVertex(*this);
+	}
+
+	for (i = 2; i < m_numEdges; i++) {
+		Mx3DPointFloat local3c;
+		Mx3DPointFloat local50;
+		float local28 = 0.0f;
+
+		local3c = *local8[i];
+		local3c -= *local8[i - 1];
+		local50 = *local8[i - 2];
+		local50 -= *local8[i - 1];
+
+		local24.EqualsCross(&local50, &local3c);
+		local28 = local24.LenSquared();
+
+		if (local28 < 0.00001f) {
+			continue;
+		}
+
+		float local58 = sqrt((double) local28);
+		local24 /= local58;
+
+		if (localc) {
+			float local54 = local24.Dot(&m_unk0x14, &local24);
+			if (local54 < 0.98) {
+				delete[] local8;
+				return -2;
+			}
+		}
+		else {
+			m_unk0x14[0] = local24[0];
+			m_unk0x14[1] = local24[1];
+			m_unk0x14[2] = local24[2];
+			m_unk0x14[3] = -local8[i]->Dot(local8[i], &local24);
+			localc = TRUE;
+		}
+	}
+
+	if (local8 != NULL) {
+		delete[] local8;
+	}
+
+	if (!localc) {
+		return -1;
+	}
+
+	return 0;
 }
diff --git a/LEGO1/lego/sources/geom/legowegedge.h b/LEGO1/lego/sources/geom/legowegedge.h
index ef29db9b..77567bfe 100644
--- a/LEGO1/lego/sources/geom/legowegedge.h
+++ b/LEGO1/lego/sources/geom/legowegedge.h
@@ -38,7 +38,7 @@ public:
 	LegoWEGEdge();
 	~LegoWEGEdge() override;
 
-	LegoResult VTable0x04() override; // vtable+0x04
+	LegoS32 VTable0x04() override; // vtable+0x04
 
 	// FUNCTION: BETA10 0x100270c0
 	LegoU32 GetFlag0x10() { return m_flags & c_bit5 ? FALSE : TRUE; }
@@ -72,6 +72,8 @@ public:
 	friend class LegoPathController;
 
 protected:
+	LegoS32 FUN_1009aea0();
+
 	LegoU8 m_flags;                 // 0x0c
 	LegoU8 m_unk0x0d;               // 0x0d
 	LegoChar* m_name;               // 0x10
@@ -79,7 +81,7 @@ protected:
 	Mx4DPointFloat* m_edgeNormals;  // 0x2c
 	Mx3DPointFloat m_unk0x30;       // 0x30
 	float m_unk0x44;                // 0x44
-	LegoU8 m_unk0x48;               // 0x48
+	LegoU8 m_numTriggers;           // 0x48
 	PathWithTrigger* m_pathTrigger; // 0x4c
 	Mx3DPointFloat* m_unk0x50;      // 0x50
 };