15MxU32 g_unk0x100d7cc8[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0};
29const char* LegoPathController::g_unk0x100f42f0[] = {
49const char* LegoPathController::g_unk0x100f4330[] = {
89 if ((result = Read(&storage)) ==
SUCCESS) {
92 for (i = 0; i < m_numT; i++) {
96 for (i = 0; i < m_numN; i++) {
97 m_unk0x10[i] += p_location;
100 for (i = 0; i < m_numL; i++) {
104 for (j = 0; j <
sizeOfArray(g_unk0x100f42f0); j++) {
105 if (!strcmpi(g_unk0x100f42f0[j], boundary.
GetName())) {
115 for (j = 0; j <
sizeOfArray(g_unk0x100f4330); j++) {
116 if (!strcmpi(g_unk0x100f4330[j], boundary.
GetName())) {
141 if (m_boundaries !=
NULL) {
142 delete[] m_boundaries;
147 if (m_unk0x10 !=
NULL) {
153 if (m_structs !=
NULL) {
159 if (m_edges !=
NULL) {
166 for (j = 0; j <
sizeOfArray(g_unk0x100f42f0); j++) {
167 if (g_ctrlBoundariesA[j].m_controller ==
this) {
172 if (g_ctrlEdgesA[j].m_controller ==
this) {
178 for (j = 0; j <
sizeOfArray(g_unk0x100f4330); j++) {
179 if (g_ctrlBoundariesB[j].m_controller ==
this) {
184 if (g_ctrlEdgesB[j].m_controller ==
this) {
218 assert(p_src < pBoundary->GetNumEdges() && p_dest < pBoundary->GetNumEdges());
223 assert(pSrcE && pDestE);
235 m_actors.insert(p_actor);
256 for (
MxS32 i = 0; i < m_numL; i++) {
261 if (presenters.find(presenter) != presenters.end()) {
267 if (p_position.
Dot(p_position, normal) + normal[3] < 0.0f) {
273 if (boundary !=
NULL) {
282 if (boundary ==
NULL) {
293 vec.
Dot(vec, p_direction) < 0.0f) {
302 if (p_actor->
VTable0x84(boundary, time, p_position, p_direction, *edge, 0.5f) ==
SUCCESS) {
304 m_actors.insert(p_actor);
322 m_actors.insert(p_actor);
334 m_actors.erase(p_actor);
336 for (
MxS32 i = 0; i < m_numL; i++) {
349 for (
MxS32 i = 0; i < m_numL; i++) {
360 for (
MxS32 i = 0; i < m_numL; i++) {
367void LegoPathController::FUN_10046970()
373 for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) {
376 if (m_actors.find(actor) != m_actors.end()) {
387 p_boundaries = m_boundaries;
396 for (
MxS32 i = 0; i < m_numL; i++) {
397 if (!strcmpi(m_boundaries[i].GetName(), p_name)) {
398 return &m_boundaries[i];
409 for (
MxS32 i = 0; i < m_numT; i++) {
430 if (g_ctrlBoundariesA !=
NULL || g_ctrlEdgesA !=
NULL || g_ctrlBoundariesB !=
NULL || g_ctrlEdgesB !=
NULL) {
445 if (g_ctrlBoundariesA ==
NULL || g_ctrlEdgesA ==
NULL) {
449 delete[] g_ctrlBoundariesA;
450 delete[] g_ctrlEdgesA;
451 delete[] g_ctrlBoundariesB;
452 delete[] g_ctrlEdgesB;
453 g_ctrlBoundariesA =
NULL;
455 g_ctrlBoundariesB =
NULL;
464 if (p_storage->
Read(&m_numT,
sizeof(m_numT)) !=
SUCCESS) {
471 if (p_storage->
Read(&m_numN,
sizeof(m_numN)) !=
SUCCESS) {
478 if (p_storage->
Read(&m_numE,
sizeof(m_numE)) !=
SUCCESS) {
485 if (p_storage->
Read(&m_numL,
sizeof(m_numL)) !=
SUCCESS) {
492 if (m_numT > 0 && ReadStructs(p_storage) !=
SUCCESS) {
497 for (
MxS32 i = 0; i < m_numN; i++) {
498 if (ReadVector(p_storage, m_unk0x10[i]) !=
SUCCESS) {
504 if (m_numE > 0 && ReadEdges(p_storage) !=
SUCCESS) {
508 if (m_numL > 0 && ReadBoundaries(p_storage) !=
SUCCESS) {
512 for (
MxS32 j = 0; j < m_numE; j++) {
513 m_pfsE.insert(&m_edges[j]);
523 for (
MxS32 i = 0; i < m_numT; i++) {
526 if (p_storage->
Read(&length,
sizeof(length)) !=
SUCCESS) {
531 m_structs[i].
m_name =
new char[length + 1];
533 if (p_storage->
Read(m_structs[i].m_name, length) !=
SUCCESS) {
537 m_structs[i].
m_name[length] =
'\0';
540 if (p_storage->
Read(&m_structs[i].m_flags,
sizeof(m_structs[i].m_flags)) !=
SUCCESS) {
552 for (
MxS32 i = 0; i < m_numE; i++) {
574 edge.
m_faceA = &m_boundaries[s];
579 edge.
m_ccwA = &m_edges[s];
584 edge.
m_cwA = &m_edges[s];
591 edge.
m_faceB = &m_boundaries[s];
596 edge.
m_ccwB = &m_edges[s];
601 edge.
m_cwB = &m_edges[s];
620 for (
MxS32 i = 0; i < m_numL; i++) {
626 if (p_storage->
Read(&numE,
sizeof(numE)) !=
SUCCESS) {
635 for (j = 0; j < numE; j++) {
640 edges[j] = &m_edges[s];
652 if (p_storage->
Read(&length,
sizeof(length)) !=
SUCCESS) {
657 boundary.
m_name =
new char[length + 1];
663 boundary.
m_name[length] =
'\0';
670 for (j = 0; j < numE; j++) {
761 if (p_newBoundary == p_oldBoundary) {
766 list<LegoBEWithFloat> boundaryList;
767 list<LegoBEWithFloat>::iterator boundaryListIt;
770 LegoBEWithFloatSet::iterator boundarySetItA;
771 LegoBEWithFloatSet::iterator boundarySetItB;
786 if (p_newBoundary == otherFace) {
791 p_grec->erase(p_grec->begin(), p_grec->end());
799 boundarySet.insert(&boundaryList.back());
804 pathCtrlEdgeSet.erase(edge);
808 while (pathCtrlEdgeSet.size() > 0) {
812 boundarySetItA = boundarySetItB = boundarySet.begin();
814 if (boundarySetItB != boundarySet.end()) {
818 while (boundarySetItA != boundarySet.end()) {
832 if (bOther == p_newBoundary) {
833 shouldRemove =
FALSE;
844 if (dist < local14) {
846 p_grec->erase(p_grec->begin(), p_grec->end());
852 }
while (pfs !=
NULL);
861 if (pathCtrlEdgeSet.find(edge) != pathCtrlEdgeSet.end()) {
862 shouldRemove =
FALSE;
877 boundarySet.erase(boundarySetItA);
880 if (boundarySetItB != boundarySet.end()) {
881 boundarySetItA = boundarySetItB;
890 pathCtrlEdgeSet.erase(edgeWithFloat.
m_edge);
891 boundaryList.push_back(edgeWithFloat);
892 boundarySet.insert(&boundaryList.back());
901 if (p_grec->size() > 0) {
909 if (p_grec->size() > 0) {
921 if (p_param9 !=
NULL) {
942 if (p_grec.size() == 0) {
950 p_edge = p_grec.front().m_edge;
956 p_v1 -= *p_edge->
CWVertex(*p_boundary);
958 p_v1 += *p_edge->
CWVertex(*p_boundary);
978 for (
MxS32 i = 0; i < m_numL; i++) {
985 float local28 = p_param3[0].
Dot(p_param3[0], *unk0x14);
987 if (local28 < 0.001 && local28 > -0.001) {
991 float local2c = p_param3[1].
Dot(p_param3[1], *unk0x14);
992 float local34 = p_param3[2].
Dot(p_param3[2], *unk0x14) + unk0x14->
index_operator(3);
993 float local3c = local2c * local2c - local34 * local28 * 4.0f;
995 if (local3c < -0.001) {
999 if (local3c < 0.0f) {
1003 local3c = sqrt(local3c);
1006 float local38 = (local3c - local2c) / (local28 * 2.0f);
1007 float local44 = (-local3c - local2c) / (local28 * 2.0f);
1009 if (!IsBetween(local38, 0.0f, param5)) {
1010 if (IsBetween(local44, 0.0f, param5)) {
1018 if (local8 || FUN_100c17a0(local38, p_param5, 0.0f, param5)) {
1021 local58 *= local38 * local38;
1022 local24 = p_param3[1];
1024 local24 += p_param3[2];
1042 if (local74.
Dot(local74, *unk0x14) >= 0.0f) {
[AI] Handles playback and synchronization of animated LEGO objects, including variable substitution,...
Implementation of LegoStorage for memory-backed buffers.
[AI] An actor that moves along a predefined path, supporting boundary transitions,...
virtual MxResult VTable0x88(LegoPathBoundary *p_boundary, float p_time, LegoEdge &p_srcEdge, float p_srcScale, LegoUnknown100db7f4 &p_destEdge, float p_destScale)
[AI] Moves the actor between two edges across a boundary, recalculates placement and orientation.
virtual void Animate(float p_time)
[AI] Per-frame animation update.
MxU32 GetActorState()
[AI] Gets the current navigation/animation state of the actor.
virtual void VTable0xc4()
[AI] Empty handler for optional custom per-tick transition logic.
void SetController(LegoPathController *p_pathController)
[AI] Assigns a new path controller (used for actor transitions between paths).
@ c_disabled
[AI] Marks as disabled or inactive for path follow logic. [AI]
virtual MxResult VTable0x84(LegoPathBoundary *p_boundary, float p_time, Vector3 &p_p1, Vector3 &p_p4, LegoUnknown100db7f4 &p_destEdge, float p_destScale)
[AI] Moves actor to a destination edge.
LegoPathController * GetController()
[AI] Retrieves pointer to the path controller which governs this actor's movement.
[AI] Represents a path segment or boundary in the navigation network for actors (vehicles,...
LegoAnimPresenterSet & GetPresenters()
[AI] Direct access to the animation presenter set for this boundary.
MxU32 FUN_10057fe0(LegoAnimPresenter *p_presenter)
[AI] Adds an animation presenter to the set if within region, based on spatial bounds.
MxU32 FUN_100586e0(LegoAnimPresenter *p_presenter)
[AI] Removes an animation presenter from the set, or if nullptr resets all presenters' world associat...
[AI] Manager for controlling actors' movement along predefined geometric paths.
void FUN_100468f0(LegoAnimPresenter *p_presenter)
[AI] Processes all boundaries except those with bit3 set, invoking FUN_10057fe0 for the provided anim...
MxResult FUN_10046b30(LegoPathBoundary *&p_boundaries, MxS32 &p_numL)
[AI] Provides current array of boundaries and count as output parameters, for external queries.
MxResult Tickle() override
[AI] Implements the tickle (per-frame update) callback for the controller.
LegoPathBoundary * GetPathBoundary(const char *p_name)
[AI] Searches for a path boundary by name among owned boundaries.
static MxResult Init()
[AI] Static initializer for global controller boundary/edge arrays.
virtual void Destroy()
[AI] Deinitializes path controller, releases all owned resources and unregisters from tickle manager.
MxResult RemoveActor(LegoPathActor *p_actor)
[AI] Removes an actor from the controller, detaches it from controlled boundaries,...
MxResult PlaceActor(LegoPathActor *p_actor, const char *p_name, MxS32 p_src, float p_srcScale, MxS32 p_dest, float p_destScale)
[AI] Places an actor on a boundary at given source/destination edge indices, commonly for track segme...
MxResult FUN_10048310(LegoPathEdgeContainer *p_grec, const Vector3 &p_oldPosition, const Vector3 &p_oldDirection, LegoPathBoundary *p_oldBoundary, const Vector3 &p_newPosition, const Vector3 &p_newDirection, LegoPathBoundary *p_newBoundary, LegoU8 p_mask, MxFloat *p_param9)
[AI] Complex function performing path transition resolution; computes possible edge transition sequen...
virtual MxResult Create(MxU8 *p_data, const Vector3 &p_location, const MxAtomId &p_trigger)
[AI] Initializes the path controller from the provided binary data at the specified location,...
static MxResult Reset()
[AI] Resets (cleans up) global controller boundary/edge arrays allocated by Init().
MxResult FUN_1004a380(Vector3 &p_param1, Vector3 &p_param2, Mx3DPointFloat *p_param3, LegoPathBoundary *&p_boundary, MxFloat &p_param5)
[AI] Finds earliest intersection and placement on a valid boundary for the provided vectors and updat...
MxS32 FUN_1004a240(LegoPathEdgeContainer &p_grec, Vector3 &p_v1, Vector3 &p_v2, float p_f1, LegoUnknown100db7f4 *&p_edge, LegoPathBoundary *&p_boundary)
[AI] Computes path vector and orientation for an actor given a transition along the resolved edge con...
LegoPathController()
[AI] Constructs a LegoPathController, initializing boundary and edge pointers to NULL and counts to z...
void Enable(MxBool p_enable)
[AI] Enables or disables the controller's registration with the tickle manager, controlling per-frame...
void FUN_10046bb0(LegoWorld *p_world)
[AI] Assigns the provided world pointer to all struct triggers owned by this path controller.
void FUN_10046930(LegoAnimPresenter *p_presenter)
[AI] Invokes FUN_100586e0 for each boundary, with the provided animation presenter.
[AI] Represents a trigger/control element in the LEGO world's path system, linked logically to the wo...
void SetWorld(LegoWorld *p_world)
[AI] Binds a world instance to this path struct for context-specific handling.
void SetAtomId(const MxAtomId &p_atomId)
[AI] Sets this struct's AtomId for data/action lookup and dispatch.
Abstract base class providing an interface for file-like storage with binary and text read/write oper...
virtual LegoResult Read(void *p_buffer, LegoU32 p_size)=0
Read bytes from storage into buffer.
void SetEdges(LegoUnknown100db7f4 **p_edges, LegoU8 p_numEdges)
[AI] Assigns the edge list and count for this face.
LegoU8 GetNumEdges()
[AI] Returns the number of edge elements assigned to this face.
LegoU32 IsEqual(LegoWEEdge *p_other)
[AI] Checks if this face object is the same as another.
LegoUnknown100db7f4 ** GetEdges()
[AI] Gets the array of pointers to the edge objects that form this face.
const LegoChar * GetName()
[AI] Returns the name string of this edge, typically used for debugging and lookup.
Mx4DPointFloat m_unk0x14
[AI] 4D plane equation or normal used for polygon/edge side tests. [AI]
float m_unk0x44
[AI] Maximum squared distance from center—polygon bounding radius or similar. [AI]
LegoU8 m_unk0x0d
[AI] Unknown, used for internal status/tracking. [AI]
LegoU8 m_numTriggers
[AI] Number of trigger (path/segment) structures attached to this edge. [AI]
Mx3DPointFloat * m_unk0x50
[AI] Transition direction/unit vector—used for edge trigger geometry. [AI]
Mx4DPointFloat * m_edgeNormals
[AI] Per-edge normals for each polygon segment, allocated dynamically. [AI]
LegoU8 m_flags
[AI] Flags indicating edge state, enabled/disabled, and type bits. [AI]
Mx4DPointFloat * GetEdgeNormal(int index)
[AI] Returns a pointer to the 4D edge normal at the given sub-edge index.
Mx4DPointFloat * GetUnknown0x14()
[AI] Returns a pointer to the cached 4D normal or reference plane for the edge.
LegoChar * m_name
[AI] Edge's name string, dynamically allocated for debug/lookup. [AI]
PathWithTrigger * m_pathTrigger
[AI] Array of triggers influencing entity motion or event logic on this edge. [AI]
Mx3DPointFloat m_unk0x30
[AI] Cached center for the edge polygon, used in geometric calculations. [AI]
Represents the active 3D world, holding all entity, animation, sound, path, and ROI objects.
[AI] Represents a 3D point with floating-point precision, inheriting from Vector3.
[AI] 4D point class for floating point values.
float & index_operator(int idx)
[AI] Explicit indexed access wrapper (alias for operator[]).
[AI] Atomized (unique) string identifier, managed by reference counting.
virtual void UnregisterClient(MxCore *p_client)
[AI] Unregisters (marks for destruction) a previously registered client.
virtual void RegisterClient(MxCore *p_client, MxTime p_interval)
[AI] Registers an MxCore object to receive periodic tickles.
MxLong GetTime()
Returns the current timer value in ms, depending on running state.
virtual float Dot(const float *p_a, const float *p_b) const
[AI] Compute the dot product of the two float arrays interpreted as vectors of 2 elements.
virtual float * GetData()
[AI] Retrieves the mutable in-memory data pointer for this vector.
[AI] 3D vector class, providing vector and cross-product operations in 3D space.
virtual void EqualsCross(const Vector3 &p_a, const Vector3 &p_b)
[AI] Sets this vector to be the cross product of p_a and p_b.
#define DECOMP_SIZE_ASSERT(T, S)
set< LegoAnimPresenter *, LegoAnimPresenterSetCompare > LegoAnimPresenterSet
[AI] Defines a set of LegoAnimPresenter pointers, ordered by pointer value using LegoAnimPresenterSet...
set< LegoPathActor *, LegoPathActorSetCompare > LegoPathActorSet
[AI] Defines a set of LegoPathActor pointers, ordered by pointer value using LegoPathActorSetCompare.
set< LegoPathCtrlEdge *, LegoPathCtrlEdgeCompare > LegoPathCtrlEdgeSet
[AI] Set of pointers to control edges, ordered using LegoPathCtrlEdgeCompare.
multiset< LegoBEWithFloat *, LegoBEWithFloatComparator > LegoBEWithFloatSet
[AI] Multiset of LegoBEWithFloat pointers, ordered by their annotation float value....
#define NULL
[AI] Null pointer value (C/C++ semantics).
#define FAILURE
[AI] Used to indicate a failed operation in result codes.
unsigned char LegoU8
[AI] Unsigned 8-bit integer type used throughout LEGO Island.
#define SUCCESS
[AI] Used to indicate a successful operation in result codes.
MxTimer * Timer()
[AI] Returns the global simulation timer.
MxTickleManager * TickleManager()
[AI] Provides access to the global tickle manager.
[AI] Represents a path edge with extra float data and potential linkage (single-linked).
LegoPathBoundary * m_boundary
[AI] Path boundary this edge belongs to. [AI]
MxFloat m_unk0x0c
[AI] Annotation float; likely an edge priority, weight, parametric value, etc. [AI]
LegoPathCtrlEdge * m_edge
[AI] Pointer to the relevant path control edge. [AI]
LegoBEWithFloat * m_next
[AI] Next node in the edge chain, for linked structures (may be null). [AI]
[AI] Represents an edge within a path boundary, used for path following and geometric computations.
[AI] Represents an edge in the LEGO world geometry graph.
LegoEdge * m_ccwB
[AI] Next edge (counterclockwise) around face B.
LegoWEEdge * m_faceA
[AI] Pointer to the first face sharing this edge.
LegoEdge * m_cwB
[AI] Next edge (clockwise) around face B.
Vector3 * CWVertex(LegoWEEdge &p_face)
[AI] Returns the "clockwise" endpoint of this edge with respect to a given face.
LegoWEEdge * m_faceB
[AI] Pointer to the second face sharing this edge.
LegoEdge * GetCounterclockwiseEdge(LegoWEEdge &p_face)
[AI] Returns the counterclockwise adjacent edge relative to the given face.
Vector3 * m_pointB
[AI] The second endpoint of the edge.
LegoEdge * GetClockwiseEdge(LegoWEEdge &p_face)
[AI] Returns the clockwise adjacent edge relative to the given face.
LegoEdge * m_ccwA
[AI] Next edge (counterclockwise) around face A.
LegoEdge * m_cwA
[AI] Next edge (clockwise) around face A.
Vector3 * m_pointA
[AI] The first endpoint of the edge.
Vector3 * CCWVertex(LegoWEEdge &p_face)
[AI] Returns the "counterclockwise" endpoint of this edge with respect to a given face.
[AI] Helper structure for rapid lookups of controller-boundary pairs, often used for global or indexe...
LegoPathBoundary * m_boundary
[AI] Associated path boundary within the controller. [AI]
LegoPathController * m_controller
[AI] Pointer to owning path controller. [AI]
[AI] Helper structure pairing controllers with edge references for global or fast access.
LegoUnknown100db7f4 * m_edge
[AI] Reference to a specific edge, typically a segment connector or trigger. [AI]
LegoPathController * m_controller
[AI] Pointer to owning path controller. [AI]
[AI] Controller-specific edge used in path navigation.
[AI] Container for path boundary edges, also stores position, direction, and flags.
Mx3DPointFloat m_direction
[AI] 3D direction vector reference, e.g., average or intended facing. [AI]
LegoPathBoundary * m_boundary
[AI] Associated boundary for all contained edges; may be null if container is generic....
Mx3DPointFloat m_position
[AI] 3D position reference for the edge group, e.g., start or mean location. [AI]
void SetBit1(MxU32 p_set)
[AI] Set or clear the c_bit1 flag in m_flags.
MxU32 GetBit1()
[AI] Query if the c_bit1 flag is set.
char * m_name
[AI] Dynamically allocated name for this path struct instance (e.g., a label or trigger identifier).
[AI] Represents an advanced edge in the LEGO Island geometry system, with direction,...
LegoU32 GetMask0x03()
[AI] Returns a mask of flags relevant to the two faces (bits 0 and 1: c_bit1, c_bit2).
@ c_bit4
[AI] Bit flag 4 (purpose unknown)
@ c_bit3
[AI] Bit flag 3 (purpose unknown)
float m_unk0x3c
[AI] Unknown float; likely represents additional metric (possibly precomputed distance/weight).
LegoU32 FUN_10048c40(const Vector3 &p_position)
[AI] Tests if a position is on this edge based on its direction and points, within a precision thresh...
LegoFloat DistanceBetweenMidpoints(const LegoUnknown100db7f4 &p_other)
[AI] Returns the Euclidean distance between the midpoints of this edge and another edge.
Mx3DPointFloat m_unk0x28
[AI] Represents the edge's direction/normal vector or outward face normal.
LegoFloat DistanceToMidpoint(const Vector3 &p_vec)
[AI] Calculates linear distance from a vector position to the 3D midpoint of the edge.
LegoU32 BETA_1004a830(LegoWEGEdge &p_face, LegoU8 p_mask)
[AI] Tests whether a WEG-edge meets complex mask and flag criteria for this edge, depending on mask a...
LegoU16 m_flags
[AI] Internal flags controlling per-face properties and connection status.
LegoWEEdge * OtherFace(LegoWEEdge *p_other)
[AI] Returns the opposite face pointer to the one passed in.
LegoResult FUN_1002ddc0(LegoWEEdge &p_f, Vector3 &p_point) const
[AI] Calculates the edge normal for use from the given face, negating it if called from faceA.
[AI] Represents a path segment with an associated trigger in LEGO Island pathing logic.
LegoPathStruct * m_pathStruct
[AI] Pointer to a path structure associated with this trigger. [AI]
float m_unk0x08
[AI] Distance along the path or trigger threshold (exact semantics unclear). [AI]
unsigned int m_data
[AI] Miscellaneous data value, use determined by path logic. [AI]