Isle
Loading...
Searching...
No Matches
legoanimationmanager.cpp
Go to the documentation of this file.
2
4#include "anim/legoanim.h"
5#include "define.h"
6#include "islepathactor.h"
8#include "legoanimpresenter.h"
11#include "legoentitylist.h"
12#include "legoextraactor.h"
13#include "legogamestate.h"
15#include "legomain.h"
16#include "legonavcontroller.h"
17#include "legoroilist.h"
18#include "legosoundmanager.h"
19#include "legovideomanager.h"
20#include "legoworld.h"
21#include "misc.h"
23#include "mxmisc.h"
25#include "mxticklemanager.h"
26#include "mxtimer.h"
27#include "mxutilities.h"
28#include "realtime/realtime.h"
30
31#include <io.h>
32#include <vec.h>
33
42
43// GLOBAL: LEGO1 0x100d8b28
44MxU8 g_unk0x100d8b28[] = {0, 1, 2, 4, 8, 16};
45
46// GLOBAL: LEGO1 0x100f6d20
48 {"bikebd", 0, FALSE},
49 {"bikepg", 0, FALSE},
50 {"bikerd", 0, FALSE},
51 {"bikesy", 0, FALSE},
52 {"motoni", 0, FALSE},
53 {"motola", 0, FALSE},
54 {"board", 0, FALSE}
55};
56
57// GLOBAL: LEGO1 0x100f6d58
58const char* g_cycles[11][17] = {
59 {"CNs001xx",
60 "CNs002xx",
61 "CNs003xx",
62 "CNs004xx",
63 "CNs005xx",
64 "CNs007xx",
65 "CNs006xx",
66 "CNs008xx",
67 "CNs009xx",
68 "CNs010xx",
69 "CNs011xx",
70 "CNs012xx",
71 NULL,
72 NULL,
73 NULL,
74 NULL,
75 NULL},
76 {"CNs001Pe",
77 "CNs002Pe",
78 "CNs003Pe",
79 "CNs004Pe",
80 "CNs005Pe",
81 "CNs007Pe",
82 "CNs006Pe",
83 "CNs008Pe",
84 "CNs009Pe",
85 "CNs010Pe",
86 "CNs001sk",
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 NULL,
92 NULL},
93 {"CNs001Ma",
94 "CNs002Ma",
95 "CNs003Ma",
96 "CNs004Ma",
97 "CNs005Ma",
98 "CNs007Ma",
99 "CNs006Ma",
100 "CNs008Ma",
101 "CNs009Ma",
102 "CNs010Ma",
103 "CNs0x4Ma",
104 NULL,
105 NULL,
106 "CNs011Ma",
107 "CNs012Ma",
108 "CNs013Ma",
109 NULL},
110 {"CNs001Pa",
111 "CNs002Pa",
112 "CNs003Pa",
113 "CNs004Pa",
114 "CNs005Pa",
115 "CNs007Pa",
116 "CNs006Pa",
117 "CNs008Pa",
118 "CNs009Pa",
119 "CNs010Pa",
120 "CNs0x4Pa",
121 NULL,
122 NULL,
123 "CNs011Pa",
124 "CNs012Pa",
125 "CNs013Pa",
126 NULL},
127 {"CNs001Ni",
128 "CNs002Ni",
129 "CNs003Ni",
130 "CNs004Ni",
131 "CNs005Ni",
132 "CNs007Ni",
133 "CNs006Ni",
134 "CNs008Ni",
135 "CNs009Ni",
136 "CNs010Ni",
137 "CNs011Ni",
138 "CNsx11Ni",
139 NULL,
140 NULL,
141 NULL,
142 NULL,
143 NULL},
144 {"CNs001La",
145 "CNs002La",
146 "CNs003La",
147 "CNs004La",
148 "CNs005La",
149 "CNs007La",
150 "CNs006La",
151 "CNs008La",
152 "CNs009La",
153 "CNs010La",
154 "CNs011La",
155 "CNsx11La",
156 NULL,
157 NULL,
158 NULL,
159 NULL,
160 NULL},
161 {"CNs001Br",
162 "CNs002Br",
163 "CNs003Br",
164 "CNs004Br",
165 "CNs005Br",
166 "CNs007Br",
167 "CNs006Br",
168 "CNs008Br",
169 "CNs009Br",
170 "CNs010Br",
171 "CNs011Br",
172 "CNs900Br",
173 "CNs901Br",
174 "CNs011Br",
175 "CNs012Br",
176 "CNs013Br",
177 "CNs014Br"},
178 {"CNs001xx",
179 "CNs002xx",
180 "CNs003xx",
181 "CNs004xx",
182 "CNs005xx",
183 "CNs007xx",
184 "CNs006xx",
185 "CNs008xx",
186 "CNs009xx",
187 "CNs010xx",
188 "CNs001Bd",
189 "CNs012xx",
190 NULL,
191 NULL,
192 NULL,
193 NULL,
194 NULL},
195 {"CNs001xx",
196 "CNs002xx",
197 "CNs003xx",
198 "CNs004xx",
199 "CNs005xx",
200 "CNs007xx",
201 "CNs006xx",
202 "CNs008xx",
203 "CNs009xx",
204 "CNs010xx",
205 "CNs001Pg",
206 "CNs012xx",
207 NULL,
208 NULL,
209 NULL,
210 NULL,
211 NULL},
212 {"CNs001xx",
213 "CNs002xx",
214 "CNs003xx",
215 "CNs004xx",
216 "CNs005xx",
217 "CNs007xx",
218 "CNs006xx",
219 "CNs008xx",
220 "CNs009xx",
221 "CNs010xx",
222 "CNs001Rd",
223 "CNs012xx",
224 NULL,
225 NULL,
226 NULL,
227 NULL,
228 NULL},
229 {"CNs001xx",
230 "CNs002xx",
231 "CNs003xx",
232 "CNs004xx",
233 "CNs005xx",
234 "CNs007xx",
235 "CNs006xx",
236 "CNs008xx",
237 "CNs009xx",
238 "CNs010xx",
239 "CNs001Sy",
240 "CNs012xx",
241 NULL,
242 NULL,
243 NULL,
244 NULL,
245 NULL}
246};
247
248// GLOBAL: LEGO1 0x100f7048
249// GLOBAL: BETA10 0x101e1ee8
251 {"pepper", FALSE, 6, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 1},
252 {"mama", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 2},
253 {"papa", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 3},
254 {"nick", FALSE, 4, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 4},
255 {"laura", FALSE, 5, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 5},
256 {"brickstr", FALSE, -1, 0, FALSE, FALSE, FALSE, 1000, 20000, FALSE, 0, 6},
257 {"studs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
258 {"rhoda", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
259 {"valerie", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
260 {"snap", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
261 {"pt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
262 {"mg", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
263 {"bu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
264 {"ml", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
265 {"nu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
266 {"na", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
267 {"cl", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
268 {"en", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
269 {"re", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
270 {"ro", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
271 {"d1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
272 {"d2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
273 {"d3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
274 {"d4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
275 {"l1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
276 {"l2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
277 {"l3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
278 {"l4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
279 {"l5", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
280 {"l6", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
281 {"b1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
282 {"b2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
283 {"b3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
284 {"b4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
285 {"cm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
286 {"gd", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
287 {"rd", FALSE, 2, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 9},
288 {"pg", FALSE, 1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 8},
289 {"bd", FALSE, 0, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 7},
290 {"sy", FALSE, 3, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 10},
291 {"gn", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
292 {"df", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
293 {"bs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
294 {"lt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
295 {"st", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
296 {"bm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0},
297 {"jk", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}
298};
299
300// GLOBAL: LEGO1 0x100f74b0
301float g_unk0x100f74b0[6][3] = {
302 {10.0f, -1.0f, 1.0f},
303 {7.0f, 144.0f, 100.0f},
304 {5.0f, 100.0f, 36.0f},
305 {3.0f, 36.0f, 25.0f},
306 {1.0f, 25.0f, 16.0f},
307 {-1.0f, 16.0f, 2.0f}
308};
309
310// GLOBAL: LEGO1 0x100f74f8
312
313// GLOBAL: LEGO1 0x100f7500
314float g_unk0x100f7500 = 0.1f;
315
316// GLOBAL: LEGO1 0x100f7504
318
319// FUNCTION: LEGO1 0x1005eb50
321{
322 g_legoAnimationManagerConfig = p_legoAnimationManagerConfig;
323}
324
325// FUNCTION: LEGO1 0x1005eb60
326// FUNCTION: BETA10 0x1003f940
328{
329 m_unk0x1c = 0;
330 m_animState = NULL;
331 m_unk0x424 = NULL;
332
333 Init();
334
336 TickleManager()->RegisterClient(this, 10);
337}
338
339// FUNCTION: LEGO1 0x1005ed30
340// FUNCTION: BETA10 0x1003fa27
342{
344
346
347 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
348 LegoROI* roi = m_extras[i].m_roi;
349
350 if (roi != NULL) {
352
353 if (actor != NULL && actor->GetController() != NULL && CurrentWorld() != NULL) {
354 CurrentWorld()->RemoveActor(actor);
355 actor->SetController(NULL);
356 }
357
359 }
360 }
361
362 if (m_tranInfoList != NULL) {
363 delete m_tranInfoList;
364 }
365
366 if (m_tranInfoList2 != NULL) {
367 delete m_tranInfoList2;
368 }
369
370 DeleteAnimations();
371
372 if (m_unk0x424 != NULL) {
373 FUN_10063aa0();
374 delete m_unk0x424;
375 }
376
378}
379
380// FUNCTION: LEGO1 0x1005ee80
381// FUNCTION: BETA10 0x1003fbc0
383{
384 m_unk0x402 = FALSE;
385
386 if (p_und && m_animState != NULL) {
387 m_animState->Reset();
388 }
389
390 MxBool suspended = m_suspended;
391 Suspend();
392
393 if (m_tranInfoList != NULL) {
394 delete m_tranInfoList;
395 }
396
397 if (m_tranInfoList2 != NULL) {
398 delete m_tranInfoList2;
399 }
400
401 DeleteAnimations();
402 Init();
403
404 m_suspended = suspended;
405 m_suspendedEnableCamAnims = m_enableCamAnims;
406 m_unk0x429 = m_unk0x400;
407 m_unk0x42a = m_unk0x402;
408}
409
410// FUNCTION: LEGO1 0x1005ef10
411// FUNCTION: BETA10 0x1003fc7a
413{
414 m_animState = (AnimState*) GameState()->GetState("AnimState");
415 if (m_animState == NULL) {
416 m_animState = (AnimState*) GameState()->CreateState("AnimState");
417 }
418
419 if (m_worldId == LegoOmni::e_act1) {
420 m_animState->InitFromAnims(m_animCount, m_anims, m_lastExtraCharacterId);
421 }
422
423 if (!m_suspended) {
424 m_suspended = TRUE;
425 m_suspendedEnableCamAnims = m_enableCamAnims;
426 m_unk0x429 = m_unk0x400;
427 m_unk0x42a = m_unk0x402;
428 m_unk0x402 = FALSE;
429
431
432 MxS32 i;
433 for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
434 LegoROI* roi = m_extras[i].m_roi;
435
436 if (roi != NULL) {
438
439 if (actor != NULL && actor->GetController() != NULL) {
440 actor->GetController()->RemoveActor(actor);
441 actor->SetController(NULL);
442 }
443
445 }
446
447 if (m_extras[i].m_unk0x14) {
448 m_extras[i].m_unk0x14 = FALSE;
449
450 MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId;
451 if (vehicleId >= 0) {
452 g_vehicles[vehicleId].m_unk0x05 = FALSE;
453
454 LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name);
455 if (roi != NULL) {
456 roi->SetVisibility(FALSE);
457 }
458 }
459 }
460
461 m_extras[i].m_roi = NULL;
462 m_extras[i].m_characterId = -1;
463 m_extras[i].m_speed = -1.0f;
464 }
465
466 m_unk0x18 = 0;
467 m_unk0x1a = FALSE;
468 m_enableCamAnims = FALSE;
469 m_unk0x400 = FALSE;
470 m_unk0x414 = 0;
471 m_unk0x401 = FALSE;
472
473 for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) {
475 }
476 }
477}
478
479// FUNCTION: LEGO1 0x1005f0b0
480// FUNCTION: BETA10 0x1003fefe
482{
483 if (m_suspended) {
484 m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime();
485 m_unk0x410 = 5000;
486 m_enableCamAnims = m_suspendedEnableCamAnims;
487 m_unk0x400 = m_unk0x429;
488 m_unk0x402 = m_unk0x42a;
489 m_suspended = FALSE;
490 }
491}
492
493// FUNCTION: LEGO1 0x1005f130
494// FUNCTION: BETA10 0x1003ffb7
495void LegoAnimationManager::Init()
496{
497 m_unk0x402 = FALSE;
498 m_worldId = LegoOmni::e_undefined;
499 m_animCount = 0;
500 m_anims = NULL;
501 m_unk0x18 = 0;
502 m_unk0x1a = FALSE;
503 m_tranInfoList = NULL;
504 m_tranInfoList2 = NULL;
505 m_unk0x41c = g_legoAnimationManagerConfig <= 1 ? 10 : 20;
506
507 MxS32 i;
508 for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) {
509 m_unk0x28[i] = NULL;
510 m_unk0x30[i] = 0;
511 }
512
513 for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
514 m_extras[i].m_roi = NULL;
515 m_extras[i].m_characterId = -1;
516 m_extras[i].m_speed = -1.0f;
517 m_extras[i].m_unk0x14 = FALSE;
518 }
519
520 m_unk0x38 = FALSE;
521 m_animRunning = FALSE;
522 m_enableCamAnims = TRUE;
523 m_lastExtraCharacterId = 0;
524 m_unk0x400 = FALSE;
525 m_unk0x414 = 0;
526 m_numAllowedExtras = 5;
527 m_unk0x0e = 0;
528 m_unk0x10 = 0;
529 m_unk0x401 = FALSE;
530 m_suspended = FALSE;
531 m_unk0x430 = FALSE;
532 m_unk0x42c = NULL;
533 m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime();
534 m_unk0x410 = 5000;
535
536 for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) {
539 }
540
541 for (i = 0; i < (MxS32) sizeOfArray(g_vehicles); i++) {
544 }
545
546 if (m_unk0x424 != NULL) {
547 FUN_10063aa0();
548 delete m_unk0x424;
549 }
550
551 m_unk0x424 = new LegoROIList();
552}
553
554// FUNCTION: LEGO1 0x1005f6d0
555// FUNCTION: BETA10 0x100401e7
557{
558 if (m_suspended) {
559 m_unk0x429 = p_unk0x400;
560 }
561 else {
562 m_unk0x400 = p_unk0x400;
563
564 if (!p_unk0x400) {
566 }
567 }
568}
569
570// FUNCTION: LEGO1 0x1005f700
571// FUNCTION: BETA10 0x1004024c
573{
574 if (m_suspended) {
575 m_suspendedEnableCamAnims = p_enableCamAnims;
576 }
577 else {
578 m_enableCamAnims = p_enableCamAnims;
579 }
580}
581
582// FUNCTION: LEGO1 0x1005f720
584{
585 MxResult result = FAILURE;
586 MxS32 i, j, k;
587
588 if (m_worldId != p_worldId) {
589 if (m_tranInfoList != NULL) {
590 delete m_tranInfoList;
591 m_tranInfoList = NULL;
592 }
593
594 if (m_tranInfoList2 != NULL) {
595 delete m_tranInfoList2;
596 m_tranInfoList2 = NULL;
597 }
598
599 for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) {
600 m_unk0x28[i] = NULL;
601 m_unk0x30[i] = 0;
602 }
603
604 m_unk0x38 = FALSE;
605 m_animRunning = FALSE;
606 m_unk0x430 = FALSE;
607 m_unk0x42c = NULL;
608
609 for (j = 0; j < (MxS32) sizeOfArray(g_characters); j++) {
611 }
612
613 m_animState = (AnimState*) GameState()->GetState("AnimState");
614 if (m_animState == NULL) {
615 m_animState = (AnimState*) GameState()->CreateState("AnimState");
616 }
617
618 if (m_worldId == LegoOmni::e_act1) {
619 m_animState->InitFromAnims(m_animCount, m_anims, m_lastExtraCharacterId);
620 }
621
622 DeleteAnimations();
623
624 LegoFile storage;
625
626 if (p_worldId == LegoOmni::e_undefined) {
627 result = SUCCESS;
628 goto done;
629 }
630
631 char filename[128];
632 char path[1024];
633 sprintf(filename, "lego\\data\\%sinf.dta", Lego()->GetWorldName(p_worldId));
634 sprintf(path, "%s", MxOmni::GetHD());
635
636 if (path[strlen(path) - 1] != '\\') {
637 strcat(path, "\\");
638 }
639
640 strcat(path, filename);
641
642 if (_access(path, 4)) {
643 sprintf(path, "%s", MxOmni::GetCD());
644
645 if (path[strlen(path) - 1] != '\\') {
646 strcat(path, "\\");
647 }
648
649 strcat(path, filename);
650
651 if (_access(path, 4)) {
652 goto done;
653 }
654 }
655
656 if (storage.Open(path, LegoFile::c_read) == FAILURE) {
657 goto done;
658 }
659
660 MxU32 version;
661 if (storage.Read(&version, sizeof(version)) == FAILURE) {
662 goto done;
663 }
664
665 if (version != 3) {
666 OmniError("World animation version mismatch", 0);
667 goto done;
668 }
669
670 if (storage.Read(&m_animCount, sizeof(m_animCount)) == FAILURE) {
671 goto done;
672 }
673
674 m_anims = new AnimInfo[m_animCount];
675 memset(m_anims, 0, m_animCount * sizeof(*m_anims));
676
677 for (j = 0; j < m_animCount; j++) {
678 if (ReadAnimInfo(&storage, &m_anims[j]) == FAILURE) {
679 goto done;
680 }
681
682 m_anims[j].m_characterIndex = GetCharacterIndex(m_anims[j].m_name + strlen(m_anims[j].m_name) - 2);
683 m_anims[j].m_unk0x29 = FALSE;
684
685 for (k = 0; k < 3; k++) {
686 m_anims[j].m_unk0x2a[k] = -1;
687 }
688
689 if (m_anims[j].m_location == -1) {
690 for (MxS32 l = 0; l < m_anims[j].m_modelCount; l++) {
691 MxS32 index = GetCharacterIndex(m_anims[j].m_models[l].m_name);
692
693 if (index >= 0) {
694 g_characters[index].m_active = TRUE;
695 }
696 }
697 }
698
699 MxS32 count = 0;
700 for (MxS32 m = 0; m < m_anims[j].m_modelCount; m++) {
701 MxU32 n;
702
703 if (FindVehicle(m_anims[j].m_models[m].m_name, n) && m_anims[j].m_models[m].m_unk0x2c) {
704 m_anims[j].m_unk0x2a[count++] = n;
705 if (count > 3) {
706 break;
707 }
708 }
709 }
710 }
711
712 m_worldId = p_worldId;
713 m_tranInfoList = new LegoTranInfoList();
714 m_tranInfoList2 = new LegoTranInfoList();
715
716 FUN_100617c0(-1, m_unk0x0e, m_unk0x10);
717
718 result = SUCCESS;
719 m_unk0x402 = TRUE;
720
721 if (m_suspended) {
722 m_suspendedEnableCamAnims = m_enableCamAnims;
723 m_unk0x429 = m_unk0x400;
724 m_unk0x42a = TRUE;
725 m_enableCamAnims = FALSE;
726 m_unk0x400 = FALSE;
727 m_unk0x402 = FALSE;
728 }
729
730 if (p_worldId == 0) {
731 m_animState->CopyToAnims(m_animCount, m_anims, m_lastExtraCharacterId);
732 }
733 }
734
735done:
736 if (result == FAILURE) {
737 DeleteAnimations();
738 }
739
740 return result;
741}
742
743// FUNCTION: LEGO1 0x10060140
744MxBool LegoAnimationManager::FindVehicle(const char* p_name, MxU32& p_index)
745{
746 for (MxS32 i = 0; i < sizeOfArray(g_vehicles); i++) {
747 if (!strcmpi(p_name, g_vehicles[i].m_name)) {
748 p_index = i;
749 return TRUE;
750 }
751 }
752
753 return FALSE;
754}
755
756// FUNCTION: LEGO1 0x10060180
758{
759 MxResult result = FAILURE;
760 MxU8 length;
761 MxS32 i, j;
762
763 if (p_storage->Read(&length, sizeof(length)) == FAILURE) {
764 goto done;
765 }
766
767 p_info->m_name = new char[length + 1];
768 if (p_storage->Read(p_info->m_name, length) == FAILURE) {
769 goto done;
770 }
771
772 p_info->m_name[length] = 0;
773 if (p_storage->Read(&p_info->m_objectId, sizeof(p_info->m_objectId)) == FAILURE) {
774 goto done;
775 }
776
777 if (p_storage->Read(&p_info->m_location, sizeof(p_info->m_location)) == FAILURE) {
778 goto done;
779 }
780 if (p_storage->Read(&p_info->m_unk0x0a, sizeof(p_info->m_unk0x0a)) == FAILURE) {
781 goto done;
782 }
783 if (p_storage->Read(&p_info->m_unk0x0b, sizeof(p_info->m_unk0x0b)) == FAILURE) {
784 goto done;
785 }
786 if (p_storage->Read(&p_info->m_unk0x0c, sizeof(p_info->m_unk0x0c)) == FAILURE) {
787 goto done;
788 }
789 if (p_storage->Read(&p_info->m_unk0x0d, sizeof(p_info->m_unk0x0d)) == FAILURE) {
790 goto done;
791 }
792
793 for (i = 0; i < (MxS32) sizeOfArray(p_info->m_unk0x10); i++) {
794 if (p_storage->Read(&p_info->m_unk0x10[i], sizeof(*p_info->m_unk0x10)) != SUCCESS) {
795 goto done;
796 }
797 }
798
799 if (p_storage->Read(&p_info->m_modelCount, sizeof(p_info->m_modelCount)) == FAILURE) {
800 goto done;
801 }
802
803 p_info->m_models = new ModelInfo[p_info->m_modelCount];
804 memset(p_info->m_models, 0, p_info->m_modelCount * sizeof(*p_info->m_models));
805
806 for (j = 0; j < p_info->m_modelCount; j++) {
807 if (ReadModelInfo(p_storage, &p_info->m_models[j]) == FAILURE) {
808 goto done;
809 }
810 }
811
812 result = SUCCESS;
813
814done:
815 return result;
816}
817
818// FUNCTION: LEGO1 0x10060310
820{
821 MxResult result = FAILURE;
822 MxU8 length;
823
824 if (p_storage->Read(&length, 1) == FAILURE) {
825 goto done;
826 }
827
828 p_info->m_name = new char[length + 1];
829 if (p_storage->Read(p_info->m_name, length) == FAILURE) {
830 goto done;
831 }
832
833 p_info->m_name[length] = 0;
834 if (p_storage->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) {
835 goto done;
836 }
837
838 if (p_storage->Read(p_info->m_location, sizeof(p_info->m_location)) != SUCCESS) {
839 goto done;
840 }
841 if (p_storage->Read(p_info->m_direction, sizeof(p_info->m_direction)) != SUCCESS) {
842 goto done;
843 }
844 if (p_storage->Read(p_info->m_up, sizeof(p_info->m_up)) != SUCCESS) {
845 goto done;
846 }
847 if (p_storage->Read(&p_info->m_unk0x2c, sizeof(p_info->m_unk0x2c)) == FAILURE) {
848 goto done;
849 }
850
851 result = SUCCESS;
852
853done:
854 return result;
855}
856
857// FUNCTION: LEGO1 0x100603c0
858void LegoAnimationManager::DeleteAnimations()
859{
860 MxBool suspended = m_suspended;
861
862 if (m_anims != NULL) {
863 for (MxS32 i = 0; i < m_animCount; i++) {
864 delete m_anims[i].m_name;
865
866 if (m_anims[i].m_models != NULL) {
867 for (MxS32 j = 0; j < m_anims[i].m_modelCount; j++) {
868 delete m_anims[i].m_models[j].m_name;
869 }
870
871 delete m_anims[i].m_models;
872 }
873 }
874
875 delete m_anims;
876 }
877
878 Init();
879 m_suspended = suspended;
880}
881
882// FUNCTION: LEGO1 0x10060480
883// FUNCTION: BETA10 0x100412a9
884void LegoAnimationManager::FUN_10060480(const LegoChar* p_characterNames[], MxU32 p_numCharacterNames)
885{
886 for (MxS32 i = 0; i < p_numCharacterNames; i++) {
887 for (MxS32 j = 0; j < sizeOfArray(g_characters); j++) {
888 if (!stricmp(g_characters[j].m_name, p_characterNames[i])) {
890 }
891 }
892 }
893}
894
895// FUNCTION: LEGO1 0x100604d0
896// FUNCTION: BETA10 0x10041335
898{
899 for (MxS32 i = 0; i < (MxS32) sizeOfArray(g_characters); i++) {
900 g_characters[i].m_unk0x08 = p_unk0x08;
901 }
902}
903
904// FUNCTION: LEGO1 0x100604f0
905// FUNCTION: BETA10 0x1004137b
906void LegoAnimationManager::FUN_100604f0(MxS32 p_objectIds[], MxU32 p_numObjectIds)
907{
908 for (MxS32 i = 0; i < p_numObjectIds; i++) {
909 for (MxS32 j = 0; j < m_animCount; j++) {
910 if (m_anims[j].m_objectId == p_objectIds[i]) {
911 m_anims[j].m_unk0x29 = TRUE;
912 }
913 }
914 }
915}
916
917// FUNCTION: LEGO1 0x10060540
918// FUNCTION: BETA10 0x1004140f
920{
921 for (MxS32 i = 0; i < m_animCount; i++) {
922 m_anims[i].m_unk0x29 = p_unk0x29;
923 }
924}
925
926// FUNCTION: LEGO1 0x10060570
927// FUNCTION: BETA10 0x10041463
929{
930 m_animRunning = FALSE;
931 m_unk0x430 = FALSE;
932 m_unk0x42c = NULL;
933
934 if (m_unk0x1a != p_unk0x1a && (m_unk0x1a = p_unk0x1a)) {
935 do {
936 if (FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE) != FAILURE) {
937 return;
938 }
939
940 m_unk0x18++;
941 } while (m_unk0x18 < m_animCount);
942
943 m_unk0x1a = FALSE;
944 m_unk0x18 = 0;
945 }
946}
947
948// FUNCTION: LEGO1 0x100605e0
949// FUNCTION: BETA10 0x1004152b
950MxResult LegoAnimationManager::FUN_100605e0(
951 MxU32 p_index,
952 MxBool p_unk0x0a,
953 MxMatrix* p_matrix,
954 MxBool p_bool1,
955 LegoROI* p_roi,
956 MxBool p_bool2,
957 MxBool p_bool3,
958 MxBool p_bool4,
959 MxBool p_bool5
960)
961{
962 MxResult result = FAILURE;
963
964 if (m_worldId != LegoOmni::e_undefined && p_index < m_animCount && m_tranInfoList != NULL) {
966 FUN_10062770();
967
968 MxDSAction action;
969 AnimInfo& animInfo = m_anims[p_index];
970
971 if (!p_bool1) {
972 if (m_animRunning || !animInfo.m_unk0x29) {
973 return FAILURE;
974 }
975
976 if (FUN_100623a0(animInfo)) {
977 return FAILURE;
978 }
979
980 if (FUN_10062710(animInfo)) {
981 return FAILURE;
982 }
983 }
984
985 FUN_10062580(animInfo);
986
987 LegoTranInfo* tranInfo = new LegoTranInfo();
988 tranInfo->m_animInfo = &animInfo;
989 tranInfo->m_index = ++m_unk0x1c;
990 tranInfo->m_unk0x10 = 0;
991 tranInfo->m_unk0x08 = p_roi;
992 tranInfo->m_location = m_anims[p_index].m_location;
993 tranInfo->m_unk0x14 = p_unk0x0a;
994 tranInfo->m_objectId = animInfo.m_objectId;
995 tranInfo->m_unk0x15 = p_bool2;
996
997 if (p_matrix != NULL) {
998 tranInfo->m_unk0x0c = new MxMatrix(*p_matrix);
999 }
1000
1001 tranInfo->m_unk0x1c = m_unk0x28;
1002 tranInfo->m_unk0x20 = m_unk0x30;
1003 tranInfo->m_unk0x28 = p_bool3;
1004 tranInfo->m_unk0x29 = p_bool4;
1005
1006 if (m_tranInfoList != NULL) {
1007 m_tranInfoList->Append(tranInfo);
1008 }
1009
1010 char buf[256];
1011 sprintf(buf, "%s:%d", g_strANIMMAN_ID, tranInfo->m_index);
1012
1013 action.SetAtomId(*Lego()->GetWorldAtom(m_worldId));
1014 action.SetObjectId(animInfo.m_objectId);
1015 action.SetUnknown24(-1);
1016 action.AppendExtra(strlen(buf) + 1, buf);
1017
1018 if (StartActionIfUnknown0x13c(action) == SUCCESS) {
1020 tranInfo->m_flags |= LegoTranInfo::c_bit2;
1021 animInfo.m_unk0x22++;
1022 m_unk0x404 = Timer()->GetTime();
1023
1024 if (p_bool5) {
1025 FUN_100648f0(tranInfo, m_unk0x404);
1026 }
1027 else if (p_unk0x0a) {
1028 LegoPathActor* actor = UserActor();
1029
1030 if (actor != NULL) {
1032 actor->SetWorldSpeed(0.0f);
1033 }
1034 }
1035
1036 m_animRunning = TRUE;
1037 result = SUCCESS;
1038 }
1039 }
1040
1041 return result;
1042}
1043
1044// FUNCTION: LEGO1 0x100609f0
1045// FUNCTION: BETA10 0x10041a38
1046MxResult LegoAnimationManager::FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2)
1047{
1048 MxResult result = FAILURE;
1049 MxDSAction action;
1050
1052
1053 LegoTranInfo* info = new LegoTranInfo();
1054 info->m_animInfo = NULL;
1055 info->m_index = ++m_unk0x1c;
1056 info->m_unk0x10 = 0;
1057 info->m_unk0x08 = NULL;
1058 info->m_location = -1;
1059 info->m_unk0x14 = FALSE;
1060 info->m_objectId = p_objectId;
1061
1062 if (p_matrix != NULL) {
1063 info->m_unk0x0c = new MxMatrix(*p_matrix);
1064 }
1065
1066 FUN_10062770();
1067
1068 info->m_unk0x1c = m_unk0x28;
1069 info->m_unk0x20 = m_unk0x30;
1070 info->m_unk0x28 = p_und1;
1071 info->m_unk0x29 = p_und2;
1072
1073 if (m_tranInfoList != NULL) {
1074 m_tranInfoList->Append(info);
1075 }
1076
1077 char buf[256];
1078 sprintf(buf, "%s:%d", g_strANIMMAN_ID, info->m_index);
1079
1080 action.SetAtomId(*Lego()->GetWorldAtom(m_worldId));
1081 action.SetObjectId(p_objectId);
1082 action.SetUnknown24(-1);
1083 action.AppendExtra(strlen(buf) + 1, buf);
1084
1085 if (StartActionIfUnknown0x13c(action) == SUCCESS) {
1088 m_animRunning = TRUE;
1089 m_unk0x404 = Timer()->GetTime();
1090 result = SUCCESS;
1091 }
1092
1093 return result;
1094}
1095
1096// FUNCTION: LEGO1 0x10060d00
1098{
1099 MxResult result = FAILURE;
1100 LegoROI* roi = p_entity->GetROI();
1101
1102 if (p_entity->GetType() == LegoEntity::e_actor) {
1104
1105 if (actor) {
1106 LegoPathController* controller = actor->GetController();
1107
1108 if (controller) {
1109 controller->RemoveActor(actor);
1110 actor->SetController(NULL);
1111
1112 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1113 if (m_extras[i].m_roi == roi) {
1114 MxS32 characterId = m_extras[i].m_characterId;
1115 g_characters[characterId].m_unk0x07 = TRUE;
1116 MxS32 vehicleId = g_characters[characterId].m_vehicleId;
1117
1118 if (vehicleId >= 0) {
1119 g_vehicles[vehicleId].m_unk0x05 = FALSE;
1120 }
1121 break;
1122 }
1123 }
1124 }
1125 }
1126 }
1127
1129 result = SUCCESS;
1130 }
1131
1132 return result;
1133}
1134
1135// FUNCTION: LEGO1 0x10060dc0
1136// FUNCTION: BETA10 0x10041f2c
1138 MxU32 p_objectId,
1139 MxMatrix* p_matrix,
1140 MxBool p_param3,
1141 MxU8 p_param4,
1142 LegoROI* p_roi,
1143 MxBool p_param6,
1144 MxBool p_param7,
1145 MxBool p_param8,
1146 MxBool p_param9
1147)
1148{
1149 MxResult result = FAILURE;
1150 MxBool found = FALSE;
1151
1152 if (!Lego()->m_unk0x13c) {
1153 return SUCCESS;
1154 }
1155
1156 for (MxS32 i = 0; i < m_animCount; i++) {
1157 if (m_anims[i].m_objectId == p_objectId) {
1158 found = TRUE;
1159 MxBool unk0x0a;
1160
1161 switch (p_param4) {
1162 case e_unk0:
1163 unk0x0a = m_anims[i].m_unk0x0a;
1164 break;
1165 case e_unk1:
1166 unk0x0a = TRUE;
1167 break;
1168 default:
1169 unk0x0a = FALSE;
1170 break;
1171 }
1172
1173 result = FUN_100605e0(i, unk0x0a, p_matrix, p_param3, p_roi, p_param6, p_param7, p_param8, p_param9);
1174 break;
1175 }
1176 }
1177
1178 if (!found && p_param3 != FALSE) {
1179 result = FUN_100609f0(p_objectId, p_matrix, p_param7, p_param8);
1180 }
1181
1182 return result;
1183}
1184
1185// FUNCTION: LEGO1 0x10060eb0
1186// FUNCTION: BETA10 0x1004206c
1188{
1189 if (Lego()->m_unk0x13c && m_enableCamAnims && !m_animRunning) {
1190 LegoLocation* location = LegoNavController::GetLocation(p_location);
1191
1192 if (location != NULL) {
1193 if (location->m_frequency == 0) {
1194 return;
1195 }
1196
1197 if (location->m_unk0x5c && location->m_frequency < rand() % 100) {
1198 return;
1199 }
1200 }
1201
1202 MxU16 unk0x0e, unk0x10;
1203 if (FUN_100617c0(p_location, unk0x0e, unk0x10) == SUCCESS) {
1204 MxU16 index = unk0x0e;
1205 MxU32 unk0x22 = -1;
1206 MxBool success = FALSE;
1207
1208 for (MxU16 i = unk0x0e; i <= unk0x10; i++) {
1209 AnimInfo& animInfo = m_anims[i];
1210
1211 if ((p_bool || !FUN_100623a0(animInfo)) && !FUN_10062710(animInfo) && animInfo.m_unk0x29 &&
1212 animInfo.m_unk0x22 < unk0x22 && (animInfo.m_unk0x22 == 0 || *animInfo.m_name != 'i') &&
1213 *animInfo.m_name != 'I') {
1214 index = i;
1215 unk0x22 = animInfo.m_unk0x22;
1216 success = TRUE;
1217 }
1218 }
1219
1220 if (success) {
1221 FUN_100605e0(index, m_anims[index].m_unk0x0a, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE);
1222 location->m_unk0x5c = TRUE;
1223 }
1224 }
1225 }
1226}
1227
1228// FUNCTION: LEGO1 0x10061010
1229// FUNCTION: BETA10 0x100422cc
1231{
1232 MxBool unk0x39 = FALSE;
1233
1234 FUN_10064b50(-1);
1235
1236 if (m_tranInfoList != NULL) {
1237 LegoTranInfoListCursor cursor(m_tranInfoList);
1238 LegoTranInfo* tranInfo;
1239
1240 while (cursor.Next(tranInfo)) {
1241 if (tranInfo->m_presenter != NULL) {
1242 // TODO: Match
1243 MxU32 flags = tranInfo->m_flags;
1244
1245 if (tranInfo->m_unk0x14 && tranInfo->m_location != -1 && p_und) {
1246 LegoAnim* anim;
1247
1248 if (tranInfo->m_presenter->GetPresenter() != NULL &&
1249 (anim = tranInfo->m_presenter->GetPresenter()->GetAnimation()) != NULL &&
1250 anim->GetCamAnim() != NULL) {
1251 if (flags & LegoTranInfo::c_bit2) {
1253 tranInfo->m_flags &= ~LegoTranInfo::c_bit2;
1254 }
1255
1256 tranInfo->m_presenter->FUN_1004b840();
1257 tranInfo->m_unk0x14 = FALSE;
1258 }
1259 else {
1260 tranInfo->m_presenter->FUN_1004b8c0();
1261 tranInfo->m_unk0x14 = FALSE;
1262 unk0x39 = TRUE;
1263 }
1264 }
1265 else {
1266 if (flags & LegoTranInfo::c_bit2) {
1268 tranInfo->m_flags &= ~LegoTranInfo::c_bit2;
1269 }
1270
1271 tranInfo->m_presenter->FUN_1004b840();
1272 }
1273 }
1274 else {
1275 if (m_tranInfoList2 != NULL) {
1276 LegoTranInfoListCursor cursor(m_tranInfoList2);
1277
1278 if (!cursor.Find(tranInfo)) {
1279 m_tranInfoList2->Append(tranInfo);
1280 }
1281 }
1282
1283 unk0x39 = TRUE;
1284 }
1285 }
1286 }
1287
1288 m_animRunning = unk0x39;
1289 m_unk0x404 = Timer()->GetTime();
1290}
1291
1292// FUNCTION: LEGO1 0x10061530
1293void LegoAnimationManager::FUN_10061530()
1294{
1295 if (m_tranInfoList2 != NULL) {
1296 LegoTranInfoListCursor cursor(m_tranInfoList2);
1297 LegoTranInfo* tranInfo;
1298
1299 while (cursor.Next(tranInfo)) {
1300 LegoTranInfoListCursor cursor2(m_tranInfoList);
1301
1302 if (cursor2.Find(tranInfo)) {
1303 if (tranInfo->m_presenter != NULL) {
1304 if (tranInfo->m_flags & LegoTranInfo::c_bit2) {
1306 tranInfo->m_flags &= ~LegoTranInfo::c_bit2;
1307 }
1308
1309 tranInfo->m_presenter->FUN_1004b840();
1310 cursor.Detach();
1311 }
1312 }
1313 else {
1314 cursor.Detach();
1315 }
1316 }
1317 }
1318}
1319
1320// FUNCTION: LEGO1 0x100617c0
1321// FUNCTION: BETA10 0x1004240b
1322MxResult LegoAnimationManager::FUN_100617c0(MxS32 p_location, MxU16& p_unk0x0e, MxU16& p_unk0x10)
1323{
1324 MxResult result = FAILURE;
1325 MxU16 unk0x0e = 0;
1326 MxU16 unk0x10 = 0;
1327 MxBool success = FALSE;
1328
1329 if (p_location == -1) {
1330 MxS32 i;
1331
1332 for (i = 0; i < m_animCount; i++) {
1333 if (m_anims[i].m_location == p_location) {
1334 unk0x0e = i;
1335 success = TRUE;
1336 break;
1337 }
1338 }
1339
1340 if (success) {
1341 for (; i < m_animCount && m_anims[i].m_location == p_location; i++) {
1342 unk0x10 = i;
1343 }
1344 }
1345 }
1346 else {
1347 MxS32 i;
1348
1349 for (i = 0; m_animCount > i && m_anims[i].m_location != -1; i++) {
1350 if (m_anims[i].m_location == p_location) {
1351 unk0x0e = i;
1352 success = TRUE;
1353 break;
1354 }
1355 }
1356
1357 if (success) {
1358 for (; i < m_animCount && m_anims[i].m_location == p_location; i++) {
1359 unk0x10 = i;
1360 }
1361 }
1362 }
1363
1364 if (success) {
1365 p_unk0x0e = unk0x0e;
1366 p_unk0x10 = unk0x10;
1367 result = SUCCESS;
1368 }
1369
1370 return result;
1371}
1372
1373// FUNCTION: LEGO1 0x100618f0
1374// FUNCTION: BETA10 0x100425f0
1376{
1377 if (m_tranInfoList != NULL) {
1378 LegoTranInfoListCursor cursor(m_tranInfoList);
1379 LegoTranInfo* tranInfo;
1380
1381 while (cursor.Next(tranInfo)) {
1382 if (tranInfo->m_index == p_index) {
1383 return tranInfo;
1384 }
1385 }
1386 }
1387
1388 return NULL;
1389}
1390
1391// FUNCTION: LEGO1 0x100619f0
1392// FUNCTION: BETA10 0x100426b1
1394{
1395 if (((MxNotificationParam&) p_param).GetSender() == this) {
1396 if (((MxNotificationParam&) p_param).GetNotification() == c_notificationEndAnim) {
1397 FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE);
1398 }
1399 }
1400 else if (((MxNotificationParam&) p_param).GetNotification() == c_notificationEndAnim && m_tranInfoList != NULL) {
1401 LegoTranInfoListCursor cursor(m_tranInfoList);
1402 LegoTranInfo* tranInfo;
1403
1404 MxU32 index = ((LegoEndAnimNotificationParam&) p_param).GetIndex();
1405 MxBool found = FALSE;
1406
1407 while (cursor.Next(tranInfo)) {
1408 if (tranInfo->m_index == index) {
1409 if (m_unk0x430 && m_unk0x42c == tranInfo) {
1410 FUN_10064b50(-1);
1411 }
1412
1413 if (tranInfo->m_flags & LegoTranInfo::c_bit2) {
1415 }
1416
1417 m_animRunning = FALSE;
1418 m_unk0x404 = Timer()->GetTime();
1419
1420 found = TRUE;
1421 cursor.Detach();
1422 delete tranInfo;
1423
1424 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1425 LegoROI* roi = m_extras[i].m_roi;
1426
1427 if (roi != NULL) {
1429 if (actor != NULL) {
1430 actor->Restart();
1431 }
1432 }
1433 }
1434
1435 break;
1436 }
1437 }
1438
1439 if (m_unk0x1a && found) {
1440 m_unk0x18++;
1441
1442 if (m_animCount <= m_unk0x18) {
1443 m_unk0x1a = FALSE;
1444 }
1445 else {
1447 NotificationManager()->Send(this, param);
1448 }
1449 }
1450 }
1451
1452 return 0;
1453}
1454
1455// FUNCTION: LEGO1 0x10061cc0
1456// FUNCTION: BETA10 0x1004293c
1458{
1459 FUN_10061530();
1460
1461 if (!m_unk0x402) {
1462 return SUCCESS;
1463 }
1464
1465 LegoPathActor* actor = UserActor();
1466 LegoROI* roi;
1467
1468 if (actor == NULL || (roi = actor->GetROI()) == NULL) {
1469 return SUCCESS;
1470 }
1471
1472 if (m_unk0x401) {
1473 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1474 LegoROI* roi = m_extras[i].m_roi;
1475
1476 if (roi != NULL && m_extras[i].m_unk0x0d) {
1478
1479 if (actor != NULL && actor->GetController() != NULL) {
1480 actor->GetController()->RemoveActor(actor);
1481 actor->SetController(NULL);
1482 }
1483
1485
1486 if (m_extras[i].m_unk0x14) {
1487 m_extras[i].m_unk0x14 = FALSE;
1488
1489 MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId;
1490 if (vehicleId >= 0) {
1491 g_vehicles[vehicleId].m_unk0x05 = FALSE;
1492
1493 LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name);
1494 if (roi != NULL) {
1495 roi->SetVisibility(FALSE);
1496 }
1497 }
1498 }
1499
1500 m_extras[i].m_roi = NULL;
1503 m_extras[i].m_characterId = -1;
1504 m_extras[i].m_unk0x0d = FALSE;
1505 m_unk0x414--;
1506 }
1507 }
1508
1509 m_unk0x401 = FALSE;
1510 }
1511
1512 MxLong time = Timer()->GetTime();
1513 float speed = actor->GetWorldSpeed();
1514
1515 FUN_10064b50(time);
1516
1517 if (!m_animRunning && time - m_unk0x404 > 10000 && speed < g_unk0x100f74b0[0][0] && speed > g_unk0x100f74b0[5][0]) {
1518 LegoPathBoundary* boundary = actor->GetBoundary();
1519
1520 Mx3DPointFloat position(roi->GetWorldPosition());
1521 Mx3DPointFloat direction(roi->GetWorldDirection());
1522
1523 MxU8 unk0x0c = 0;
1524 MxU8 actorId = GameState()->GetActorId();
1525
1526 if (actorId <= LegoActor::c_laura) {
1527 unk0x0c = g_unk0x100d8b28[actorId];
1528 }
1529
1530 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1531 LegoROI* roi = m_extras[i].m_roi;
1532
1533 if (roi != NULL) {
1534 MxU16 result = FUN_10062110(roi, direction, position, boundary, speed, unk0x0c, m_extras[i].m_unk0x14);
1535
1536 if (result) {
1537 MxMatrix mat;
1538 mat = roi->GetLocal2World();
1539
1540 if (FUN_100605e0(result & USHRT_MAX, FALSE, &mat, TRUE, roi, FALSE, TRUE, TRUE, TRUE) == SUCCESS) {
1541 m_unk0x404 = time;
1542 return SUCCESS;
1543 }
1544 }
1545 }
1546 }
1547 }
1548
1549 if (time - m_unk0x40c > 1000) {
1550 FUN_10063d10();
1551 m_unk0x40c = time;
1552 }
1553
1554 if (time - m_unk0x408 < m_unk0x410) {
1555 return SUCCESS;
1556 }
1557
1558 m_unk0x410 = (rand() * 10000 / SHRT_MAX) + 5000;
1559 m_unk0x408 = time;
1560
1561 if (time - m_unk0x404 > 10000) {
1562 AddExtra(-1, FALSE);
1563 }
1564
1565 double elapsedSeconds = VideoManager()->GetElapsedSeconds();
1566
1567 if (elapsedSeconds < 1.0 && elapsedSeconds > 0.01) {
1568 g_unk0x100f7500 = (g_unk0x100f7500 * 2.0 + elapsedSeconds) / 3.0;
1569
1570 if (elapsedSeconds > 0.2 && m_numAllowedExtras > 2) {
1571 m_numAllowedExtras--;
1572 }
1573 else if (g_unk0x100f7500 < 0.16 && m_numAllowedExtras < m_unk0x41c) {
1574 m_numAllowedExtras++;
1575 }
1576 }
1577
1578 return SUCCESS;
1579}
1580
1581// FUNCTION: LEGO1 0x10062110
1582// FUNCTION: BETA10 0x10042f41
1583MxU16 LegoAnimationManager::FUN_10062110(
1584 LegoROI* p_roi,
1585 Vector3& p_direction,
1586 Vector3& p_position,
1587 LegoPathBoundary* p_boundary,
1588 float p_speed,
1589 MxU8 p_unk0x0c,
1590 MxBool p_unk0x14
1591)
1592{
1593 LegoPathActor* actor = (LegoPathActor*) p_roi->GetEntity();
1594
1595 if (actor != NULL && actor->GetBoundary() == p_boundary && actor->GetActorState() == LegoPathActor::c_initial) {
1597 Mx3DPointFloat direction(p_roi->GetWorldDirection());
1598
1599 if (direction.Dot(direction, p_direction) > 0.707) {
1600 Mx3DPointFloat position(p_roi->GetWorldPosition());
1601
1602 position -= p_position;
1603 float len = position.LenSquared();
1604 float min, max;
1605
1606 for (MxU32 i = 0; i < sizeOfArray(g_unk0x100f74b0); i++) {
1607 if (g_unk0x100f74b0[i][0] < p_speed) {
1608 max = g_unk0x100f74b0[i][1];
1609 min = g_unk0x100f74b0[i][2];
1610 break;
1611 }
1612 }
1613
1614 if (len < max && len > min) {
1615 MxS8 index = GetCharacterIndex(p_roi->GetName());
1616
1617 for (MxU16 i = m_unk0x0e; i <= m_unk0x10; i++) {
1618 if (m_anims[i].m_characterIndex == index && m_anims[i].m_unk0x0c & p_unk0x0c &&
1619 m_anims[i].m_unk0x29) {
1620 MxS32 vehicleId = g_characters[index].m_vehicleId;
1621 if (vehicleId >= 0) {
1622 MxBool found = FALSE;
1623
1624 for (MxS32 j = 0; j < (MxS32) sizeOfArray(m_anims[i].m_unk0x2a); j++) {
1625 if (m_anims[i].m_unk0x2a[j] == vehicleId) {
1626 found = TRUE;
1627 break;
1628 }
1629 }
1630
1631 if (p_unk0x14 != found) {
1632 continue;
1633 }
1634 }
1635
1636 MxU16 result = i;
1637 MxU16 unk0x22 = m_anims[i].m_unk0x22;
1638
1639 for (i = i + 1; i <= m_unk0x10; i++) {
1640 if (m_anims[i].m_characterIndex == index && m_anims[i].m_unk0x0c & p_unk0x0c &&
1641 m_anims[i].m_unk0x29 && m_anims[i].m_unk0x22 < unk0x22) {
1642 result = i;
1643 unk0x22 = m_anims[i].m_unk0x22;
1644 }
1645 }
1646
1647 return result;
1648 }
1649 }
1650 }
1651 }
1652 }
1653 }
1654
1655 return 0;
1656}
1657
1658// FUNCTION: LEGO1 0x10062360
1659// FUNCTION: BETA10 0x100432dd
1660MxS8 LegoAnimationManager::GetCharacterIndex(const char* p_name)
1661{
1662 MxS8 i;
1663
1664 for (i = 0; i < sizeOfArray(g_characters); i++) {
1665 if (!strnicmp(p_name, g_characters[i].m_name, 2)) {
1666 return i;
1667 }
1668 }
1669
1670 return -1;
1671}
1672
1673// FUNCTION: LEGO1 0x100623a0
1674// FUNCTION: BETA10 0x10043342
1675MxBool LegoAnimationManager::FUN_100623a0(AnimInfo& p_info)
1676{
1677 LegoWorld* world = CurrentWorld();
1678
1679 if (world != NULL) {
1680 LegoEntityList* entityList = world->GetEntityList();
1681
1682 if (entityList != NULL) {
1683 Mx3DPointFloat position(p_info.m_unk0x10[0], p_info.m_unk0x10[1], p_info.m_unk0x10[2]);
1684 float und = p_info.m_unk0x10[3];
1685
1686 LegoEntityListCursor cursor(entityList);
1687 LegoEntity* entity;
1688 LegoPathActor* actor = UserActor();
1689
1690 while (cursor.Next(entity)) {
1691 if (entity != actor && entity->IsA("LegoPathActor")) {
1692 LegoROI* roi = entity->GetROI();
1693
1694 if (roi->GetVisibility() && FUN_10062650(position, und, roi)) {
1695 if (!ModelExists(p_info, roi->GetName())) {
1696 return TRUE;
1697 }
1698 }
1699 }
1700 }
1701 }
1702 }
1703
1704 return FALSE;
1705}
1706
1707// FUNCTION: LEGO1 0x10062520
1708// FUNCTION: BETA10 0x100434bf
1709MxBool LegoAnimationManager::ModelExists(AnimInfo& p_info, const char* p_name)
1710{
1711 ModelInfo* models = p_info.m_models;
1712 MxU8 modelCount = p_info.m_modelCount;
1713
1714 if (models != NULL && modelCount) {
1715 for (MxU8 i = 0; i < modelCount; i++) {
1716 if (!strcmpi(models[i].m_name, p_name)) {
1717 return TRUE;
1718 }
1719 }
1720 }
1721
1722 return FALSE;
1723}
1724
1725// FUNCTION: LEGO1 0x10062580
1726// FUNCTION: BETA10 0x10043552
1727void LegoAnimationManager::FUN_10062580(AnimInfo& p_info)
1728{
1729 ModelInfo* models = p_info.m_models;
1730 MxU8 modelCount = p_info.m_modelCount;
1731
1732 if (models != NULL && modelCount) {
1733 for (MxU8 i = 0; i < modelCount; i++) {
1734 LegoPathActor* actor = CharacterManager()->GetExtraActor(models[i].m_name);
1735
1736 if (actor) {
1737 LegoPathController* controller = actor->GetController();
1738
1739 if (controller) {
1740 controller->RemoveActor(actor);
1741 actor->SetController(NULL);
1742
1743 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1744 if (m_extras[i].m_roi == actor->GetROI()) {
1745 MxS32 characterId = m_extras[i].m_characterId;
1746 g_characters[characterId].m_unk0x07 = TRUE;
1747 MxS32 vehicleId = g_characters[characterId].m_vehicleId;
1748
1749 if (vehicleId >= 0) {
1750 g_vehicles[vehicleId].m_unk0x05 = FALSE;
1751 }
1752 break;
1753 }
1754 }
1755 }
1756 }
1757 }
1758 }
1759}
1760
1761// FUNCTION: LEGO1 0x10062650
1762// FUNCTION: BETA10 0x100436e2
1763MxBool LegoAnimationManager::FUN_10062650(Vector3& p_position, float p_und, LegoROI* p_roi)
1764{
1765 if (p_roi != NULL) {
1766 Mx3DPointFloat position(p_position);
1767 position -= p_roi->GetWorldPosition();
1768
1769 float len = position.LenSquared();
1770 if (len <= 0.0f) {
1771 return TRUE;
1772 }
1773
1774 len = sqrt(len);
1775 if (p_roi->GetWorldBoundingSphere().Radius() + p_und >= len) {
1776 return TRUE;
1777 }
1778 }
1779
1780 return FALSE;
1781}
1782
1783// FUNCTION: LEGO1 0x10062710
1784// FUNCTION: BETA10 0x10043787
1785MxBool LegoAnimationManager::FUN_10062710(AnimInfo& p_info)
1786{
1787 MxU8 und = 0;
1788 MxU8 actorId = GameState()->GetActorId();
1789
1790 if (actorId <= LegoActor::c_laura) {
1791 und = g_unk0x100d8b28[actorId];
1792 }
1793
1794 if (!(und & p_info.m_unk0x0c)) {
1795 return TRUE;
1796 }
1797
1798 if (ModelExists(p_info, GameState()->GetActorName())) {
1799 return TRUE;
1800 }
1801
1802 return FALSE;
1803}
1804
1805// FUNCTION: LEGO1 0x10062770
1806// FUNCTION: BETA10 0x1004381a
1808{
1809 if (!m_unk0x38) {
1810 LegoWorld* world = CurrentWorld();
1811
1812 if (world != NULL) {
1813 m_unk0x28[1] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound1");
1814 m_unk0x28[0] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound2");
1815 m_unk0x30[1] = 200;
1816 m_unk0x30[0] = 750;
1817 m_unk0x38 = TRUE;
1818 }
1819 }
1820}
1821
1822// FUNCTION: LEGO1 0x100627d0
1823// FUNCTION: BETA10 0x1004389d
1825{
1826 ViewManager* viewManager = GetViewManager();
1827
1828 if (p_und || viewManager != NULL) {
1829 MxLong time = Timer()->GetTime();
1830
1831 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
1832 LegoROI* roi = m_extras[i].m_roi;
1833
1834 if (roi != NULL) {
1835 MxU16 prefix = *(MxU16*) roi->GetName();
1836 MxLong und = ((m_numAllowedExtras - 2) * 280000 / 18) + 20000;
1837 MxBool maOrPa = prefix == TWOCC('m', 'a') || prefix == TWOCC('p', 'a');
1838
1839 if ((p_und && !maOrPa) ||
1840 (g_characters[m_extras[i].m_characterId].m_unk0x10 >= 0 && time - m_extras[i].m_unk0x08 > und &&
1841 CharacterManager()->GetRefCount(roi) == 1 &&
1842 !viewManager->IsBoundingBoxInFrustum(roi->GetWorldBoundingBox()))) {
1843 m_unk0x414--;
1844
1846 if (actor != NULL && actor->GetController() != NULL) {
1847 actor->GetController()->RemoveActor(actor);
1848 actor->SetController(NULL);
1849 }
1850
1852
1853 if (m_extras[i].m_unk0x14) {
1854 m_extras[i].m_unk0x14 = FALSE;
1855
1856 MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId;
1857 if (vehicleId >= 0) {
1858 g_vehicles[vehicleId].m_unk0x05 = FALSE;
1859
1860 LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name);
1861 if (roi != NULL) {
1862 roi->SetVisibility(FALSE);
1863 }
1864 }
1865 }
1866
1867 m_extras[i].m_roi = NULL;
1870 m_extras[i].m_characterId = -1;
1871 }
1872 }
1873 }
1874 }
1875}
1876
1877// FUNCTION: LEGO1 0x100629b0
1878// FUNCTION: BETA10 0x10043c10
1880{
1881 LegoLocation::Boundary* boundary = NULL;
1882
1883 if (p_und || (!m_animRunning && m_unk0x400)) {
1884 LegoWorld* world = CurrentWorld();
1885
1886 if (world != NULL) {
1888
1889 LegoPathActor* actor = UserActor();
1890 if (actor == NULL || actor->GetWorldSpeed() <= 20.0f) {
1891 MxU32 i;
1892 for (i = 0; i < m_numAllowedExtras && m_extras[i].m_roi != NULL; i++) {
1893 }
1894
1895 if (i != m_numAllowedExtras) {
1896 MxU8 und = rand() % 2 != 0 ? 1 : 2;
1897 MxBool bool1, bool2;
1898
1899 switch (g_unk0x100f7504 % 4) {
1900 case 0:
1901 bool1 = FALSE;
1902 bool2 = FALSE;
1903 break;
1904 case 1:
1905 bool1 = FALSE;
1906 bool2 = TRUE;
1907 break;
1908 default:
1909 bool1 = TRUE;
1910 bool2 = FALSE;
1911 break;
1912 }
1913
1914 if (p_location < 0) {
1915 boundary = new LegoLocation::Boundary;
1916
1917 if (!FUN_10064120(boundary, und == 2, bool2)) {
1918 delete boundary;
1919 boundary = NULL;
1920 }
1921 }
1922 else {
1923 LegoLocation* location = LegoNavController::GetLocation(p_location);
1924
1925 if (location != NULL) {
1926 if (location->m_boundaryA.m_unk0x10 || FUN_10063fb0(&location->m_boundaryA, world)) {
1927 boundary = &location->m_boundaryA;
1928 }
1929 else if (location->m_boundaryB.m_unk0x10 || FUN_10063fb0(&location->m_boundaryB, world)) {
1930 boundary = &location->m_boundaryB;
1931 }
1932 }
1933
1934 bool1 = FALSE;
1935 }
1936
1937 if (boundary != NULL) {
1938 for (i = 0; i < m_numAllowedExtras; i++) {
1939 if (m_extras[i].m_roi == NULL) {
1940 m_lastExtraCharacterId++;
1941
1942 if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) {
1943 m_lastExtraCharacterId = 0;
1944 }
1945
1946 MxU32 characterIdStart = m_lastExtraCharacterId;
1947
1948 MxBool active;
1949 if (bool1) {
1950 active = TRUE;
1951 }
1952 else {
1953 active = rand() % 100 < 50;
1954 }
1955
1956 tryNextCharacter:
1957 if (g_characters[m_lastExtraCharacterId].m_unk0x09 &&
1958 g_characters[m_lastExtraCharacterId].m_unk0x08 &&
1959 !g_characters[m_lastExtraCharacterId].m_inExtras &&
1960 g_characters[m_lastExtraCharacterId].m_active == active) {
1961 if (!CharacterManager()->Exists(g_characters[m_lastExtraCharacterId].m_name)) {
1962 m_extras[i].m_roi = CharacterManager()->GetActorROI(
1963 g_characters[m_lastExtraCharacterId].m_name,
1964 TRUE
1965 );
1966
1968 g_characters[m_lastExtraCharacterId].m_name
1969 );
1970
1971 switch (g_unk0x100f7504++ % 4) {
1972 case 0:
1973 actor->SetUnknown0x0c(und != 1 ? 1 : 2);
1974 break;
1975 case 1: {
1976 actor->SetUnknown0x0c(und);
1977 MxS32 src = boundary->m_src;
1978 boundary->m_src = boundary->m_dest;
1979 boundary->m_dest = src;
1980 break;
1981 }
1982 default:
1983 actor->SetUnknown0x0c(und);
1984 break;
1985 }
1986
1987 if (world->PlaceActor(
1988 actor,
1989 boundary->m_name,
1990 boundary->m_src,
1991 boundary->m_srcScale,
1992 boundary->m_dest,
1993 boundary->m_destScale
1994 ) == SUCCESS) {
1995 MxS32 vehicleId = g_characters[m_lastExtraCharacterId].m_vehicleId;
1996 if (vehicleId >= 0) {
1997 g_vehicles[vehicleId].m_unk0x04 =
1998 rand() % 100 < g_characters[m_lastExtraCharacterId].m_unk0x15;
1999 }
2000
2001 if (FUN_10063b90(
2002 world,
2003 actor,
2004 CharacterManager()->GetMood(m_extras[i].m_roi),
2005 m_lastExtraCharacterId
2006 )) {
2007 m_extras[i].m_unk0x14 = TRUE;
2008 g_vehicles[vehicleId].m_unk0x05 = TRUE;
2009 }
2010 else {
2011 m_extras[i].m_unk0x14 = FALSE;
2012 }
2013
2014 float speed;
2015 if (m_extras[i].m_unk0x14) {
2016 speed = ((float) (rand() * 1.5) / 32767.0f) + 0.9;
2017 }
2018 else {
2019 speed = ((float) (rand() * 1.4) / 32767.0f) + 0.6;
2020 }
2021
2022 actor->SetWorldSpeed(speed);
2023
2024 m_extras[i].m_characterId = m_lastExtraCharacterId;
2025 g_characters[m_lastExtraCharacterId].m_inExtras = TRUE;
2026 m_extras[i].m_unk0x08 = Timer()->GetTime();
2027 m_extras[i].m_speed = -1;
2028 m_extras[i].m_unk0x0d = FALSE;
2029 m_unk0x414++;
2030 return;
2031 }
2032 else {
2033 CharacterManager()->ReleaseActor(m_extras[i].m_roi);
2034 m_extras[i].m_roi = NULL;
2035 continue;
2036 }
2037 }
2038 }
2039
2040 m_lastExtraCharacterId++;
2041
2042 if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) {
2043 m_lastExtraCharacterId = 0;
2044 }
2045
2046 if (m_lastExtraCharacterId == characterIdStart) {
2047 return;
2048 }
2049
2050 goto tryNextCharacter;
2051 }
2052 }
2053 }
2054 }
2055 }
2056 }
2057 }
2058}
2059
2060// FUNCTION: LEGO1 0x10062e20
2061// FUNCTION: BETA10 0x100444cb
2062MxBool LegoAnimationManager::FUN_10062e20(LegoROI* p_roi, LegoAnimPresenter* p_presenter)
2063{
2064 LegoWorld* world = CurrentWorld();
2065
2066 if (world == NULL || m_suspended || !m_unk0x400) {
2067 return FALSE;
2068 }
2069
2070 MxBool inExtras = FALSE;
2071 const char* name = p_roi->GetName();
2072
2074 if (actor != NULL) {
2075 MxS32 characterId = -1;
2076 MxS32 i;
2077
2078 for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) {
2079 if (!strcmpi(name, g_characters[i].m_name)) {
2080 characterId = i;
2081 break;
2082 }
2083 }
2084
2085 if (characterId == -1) {
2086 return FALSE;
2087 }
2088
2089 if (!g_characters[characterId].m_inExtras) {
2090 for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2091 if (m_extras[i].m_roi == NULL) {
2092 m_extras[i].m_roi = p_roi;
2093 break;
2094 }
2095 }
2096
2097 if (i == (MxS32) sizeOfArray(m_extras)) {
2098 return FALSE;
2099 }
2100 }
2101 else {
2102 inExtras = TRUE;
2103
2104 for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2105 if (m_extras[i].m_roi == p_roi) {
2106 break;
2107 }
2108 }
2109
2110 if (i == (MxS32) sizeOfArray(m_extras)) {
2111 return FALSE;
2112 }
2113 }
2114
2115 if (g_characters[characterId].m_unk0x07) {
2116 m_unk0x414--;
2117
2118 if (actor->GetBoundary() == NULL) {
2119 g_characters[characterId].m_unk0x07 = FALSE;
2120
2121 if (g_characters[characterId].m_unk0x0c < 0) {
2122 g_characters[characterId].m_unk0x0c = 0;
2123 }
2124
2125 if (g_characters[characterId].m_unk0x10 < 0) {
2126 g_characters[characterId].m_unk0x10 = 0;
2127 }
2128
2129 m_extras[i].m_roi = NULL;
2130 g_characters[characterId].m_unk0x07 = FALSE;
2131 g_characters[characterId].m_inExtras = FALSE;
2132 return FALSE;
2133 }
2134
2136 }
2137 else {
2138 if (inExtras) {
2139 return FALSE;
2140 }
2141 }
2142
2143 if (GameState()->GetCurrentAct() != LegoGameState::e_act1 && !strcmp(name, "brickstr")) {
2144 return FALSE;
2145 }
2146
2147 MxBool local24 = inExtras && g_characters[characterId].m_unk0x07 &&
2148 (g_characters[characterId].m_unk0x0c < 0 || g_characters[characterId].m_unk0x10 < 0);
2149
2150 MxResult result = 1; // Not a valid MxResult value
2151
2152 if (!local24) {
2153 MxU8 unk0x0c;
2154
2155 switch (rand() % 3) {
2156 case 0:
2157 unk0x0c = 1;
2158 break;
2159 case 1:
2160 unk0x0c = 2;
2161 break;
2162 case 2:
2163 unk0x0c = 0;
2164 break;
2165 }
2166
2167 actor->SetUnknown0x0c(unk0x0c);
2168
2169 Mx3DPointFloat position;
2170 Mx3DPointFloat direction;
2171
2172 position = p_roi->GetWorldPosition();
2173 direction = p_roi->GetWorldDirection();
2174
2175 direction *= -1.0f;
2176 m_extras[i].m_speed = -1.0f;
2177
2178 if (inExtras) {
2179 actor->ClearMaps();
2180 }
2181
2182 if (FUN_10063b90(world, actor, CharacterManager()->GetMood(p_roi), characterId)) {
2183 m_extras[i].m_unk0x14 = TRUE;
2184 }
2185 else {
2186 m_extras[i].m_unk0x14 = FALSE;
2187 }
2188
2189 result = world->PlaceActor(actor, p_presenter, position, direction);
2190 }
2191
2192 if (result != SUCCESS && g_characters[characterId].m_unk0x07) {
2193 result = world->PlaceActor(actor);
2194 }
2195
2196 g_characters[characterId].m_unk0x07 = FALSE;
2197
2198 if (result != SUCCESS) {
2199 m_extras[i].m_roi = NULL;
2200 g_characters[characterId].m_inExtras = FALSE;
2201 }
2202 else {
2203 m_extras[i].m_characterId = characterId;
2204 m_extras[i].m_unk0x08 = Timer()->GetTime();
2205 m_extras[i].m_unk0x0c = TRUE;
2206 m_extras[i].m_unk0x0d = FALSE;
2207 g_characters[characterId].m_inExtras = TRUE;
2208 actor->SetWorldSpeed(0.0f);
2209 m_unk0x414++;
2210 return TRUE;
2211 }
2212 }
2213
2214 return FALSE;
2215}
2216
2217// FUNCTION: LEGO1 0x10063270
2218// FUNCTION: BETA10 0x10044b9a
2220{
2221 if (p_list != NULL) {
2222 LegoWorld* world = CurrentWorld();
2223 LegoROI* roi;
2224 MxU32 i;
2225
2226 for (i = 0; i < sizeOfArray(g_vehicles); i++) {
2227 roi = Lego()->FindROI(g_vehicles[i].m_name);
2228
2229 if (roi != NULL) {
2230 if (!g_vehicles[i].m_unk0x05 && roi->GetVisibility()) {
2232 }
2233 else {
2235 }
2236 }
2237 }
2238
2239 LegoROIListCursor cursor(p_list);
2240
2241 while (cursor.Next(roi)) {
2242 if (roi->GetVisibility() && FUN_10062e20(roi, p_presenter)) {
2243 cursor.Detach();
2244 FUN_10063950(roi);
2245 }
2246 else {
2248
2249 if (actor != NULL) {
2250 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2251 if (m_extras[i].m_roi == roi) {
2252 if (actor->GetController() != NULL) {
2253 actor->GetController()->RemoveActor(actor);
2254 actor->SetController(NULL);
2255 }
2256
2257 if (m_extras[i].m_unk0x14) {
2258 m_extras[i].m_unk0x14 = FALSE;
2259
2260 MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId;
2261 if (vehicleId >= 0) {
2262 g_vehicles[vehicleId].m_unk0x05 = FALSE;
2263
2264 LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name);
2265 if (roi != NULL) {
2266 roi->SetVisibility(FALSE);
2267 }
2268 }
2269 }
2270
2271 m_extras[i].m_roi = NULL;
2274 m_extras[i].m_characterId = -1;
2275 m_extras[i].m_unk0x0d = FALSE;
2276 m_unk0x414--;
2277 break;
2278 }
2279 }
2280 }
2281 }
2282 }
2283
2284 FUN_10063e40(p_presenter);
2285
2286 for (i = 0; i < sizeOfArray(g_vehicles); i++) {
2287 if (!g_vehicles[i].m_unk0x05) {
2288 roi = Lego()->FindROI(g_vehicles[i].m_name);
2289
2290 if (roi != NULL) {
2291 roi->SetVisibility(FALSE);
2292 }
2293 }
2294 }
2295 }
2296}
2297
2298// FUNCTION: LEGO1 0x10063780
2300{
2301 if (p_list != NULL && m_unk0x424 != NULL) {
2302 LegoROIListCursor cursor(p_list);
2303 LegoROI* roi;
2304
2305 while (cursor.Next(roi)) {
2306 const char* name = roi->GetName();
2307
2308 if (CharacterManager()->IsActor(name)) {
2309 m_unk0x424->Append(roi);
2310 cursor.Detach();
2311 }
2312 }
2313 }
2314}
2315
2316// FUNCTION: LEGO1 0x10063950
2317void LegoAnimationManager::FUN_10063950(LegoROI* p_roi)
2318{
2319 if (m_unk0x424 != NULL) {
2320 LegoROIListCursor cursor(m_unk0x424);
2321
2322 if (cursor.Find(p_roi)) {
2324 cursor.Detach();
2325 }
2326 }
2327}
2328
2329// FUNCTION: LEGO1 0x10063aa0
2330void LegoAnimationManager::FUN_10063aa0()
2331{
2332 LegoROIListCursor cursor(m_unk0x424);
2333 LegoROI* roi;
2334
2335 while (cursor.Next(roi)) {
2337 }
2338}
2339
2340// FUNCTION: LEGO1 0x10063b90
2341// FUNCTION: BETA10 0x10044d46
2342MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_actor, MxU8 p_mood, MxU32 p_characterId)
2343{
2344 const char** cycles = g_cycles[g_characters[p_characterId].m_unk0x16];
2345 const char* vehicleWC;
2346 LegoLocomotionAnimPresenter* presenter;
2347
2348 if (g_characters[p_characterId].m_vehicleId >= 0 && g_vehicles[g_characters[p_characterId].m_vehicleId].m_unk0x04 &&
2349 (vehicleWC = cycles[10]) != NULL) {
2350 presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
2351
2352 if (presenter != NULL) {
2353 presenter->FUN_1006d680(p_actor, 1.7f);
2354 }
2355
2358 return TRUE;
2359 }
2360 else {
2361 vehicleWC = cycles[p_mood];
2362 if (vehicleWC != NULL) {
2363 presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
2364
2365 if (presenter != NULL) {
2366 presenter->FUN_1006d680(p_actor, 0.7f);
2367 }
2368 }
2369
2370 if (p_mood >= 2) {
2371 p_mood--;
2372 }
2373
2374 vehicleWC = cycles[p_mood + 4];
2375 if (vehicleWC != NULL) {
2376 presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
2377
2378 if (presenter != NULL) {
2379 presenter->FUN_1006d680(p_actor, 4.0f);
2380 }
2381 }
2382
2383 if (p_mood >= 1) {
2384 p_mood--;
2385 }
2386
2387 vehicleWC = cycles[p_mood + 7];
2388 if (vehicleWC != NULL) {
2389 presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC);
2390
2391 if (presenter != NULL) {
2392 presenter->FUN_1006d680(p_actor, 0.0f);
2393 }
2394 }
2395
2396 return FALSE;
2397 }
2398}
2399
2400// FUNCTION: LEGO1 0x10063d10
2401// FUNCTION: BETA10 0x10045034
2402void LegoAnimationManager::FUN_10063d10()
2403{
2404 if (CurrentWorld() != NULL) {
2405 MxLong time = Timer()->GetTime();
2406
2407 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2408 LegoROI* roi = m_extras[i].m_roi;
2409
2410 if (roi != NULL) {
2411 if (m_extras[i].m_unk0x0c && g_characters[m_extras[i].m_characterId].m_unk0x0c >= 0 &&
2412 g_characters[m_extras[i].m_characterId].m_unk0x0c < time - m_extras[i].m_unk0x08) {
2413
2414 m_extras[i].m_unk0x0c = FALSE;
2415
2417 if (actor != NULL) {
2418 float speed = m_extras[i].m_speed;
2419
2420 if (speed < 0.0f) {
2421 if (m_extras[i].m_unk0x14) {
2422 speed = ((float) (rand() * 1.5) / 32767.0f) + 0.9;
2423 }
2424 else {
2425 speed = ((float) (rand() * 1.4) / 32767.0f) + 0.6;
2426 }
2427 }
2428
2429 actor->SetWorldSpeed(speed);
2430 }
2431 }
2432 else {
2434 if (actor != NULL) {
2435 actor->Restart();
2436 }
2437 }
2438 }
2439 }
2440 }
2441}
2442
2443// FUNCTION: LEGO1 0x10063e40
2444void LegoAnimationManager::FUN_10063e40(LegoAnimPresenter* p_presenter)
2445{
2446 if (m_unk0x424 != NULL) {
2447 LegoROIListCursor cursor(m_unk0x424);
2448 LegoROI* roi;
2449
2450 while (cursor.Next(roi)) {
2451 if (!FUN_10062e20(roi, p_presenter)) {
2453 }
2454
2455 cursor.Detach();
2456 }
2457 }
2458}
2459
2460// FUNCTION: LEGO1 0x10063fb0
2461// FUNCTION: BETA10 0x100452a7
2462MxBool LegoAnimationManager::FUN_10063fb0(LegoLocation::Boundary* p_boundary, LegoWorld* p_world)
2463{
2464 if (p_boundary->m_name != NULL) {
2465 Mx3DPointFloat vec;
2466 LegoPathBoundary* boundary = p_world->FindPathBoundary(p_boundary->m_name);
2467 LegoUnknown100db7f4* pSrcE = (LegoUnknown100db7f4*) boundary->GetEdges()[p_boundary->m_src];
2468 return FUN_10064010(boundary, pSrcE, p_boundary->m_srcScale);
2469 }
2470
2471 return FALSE;
2472}
2473
2474// FUNCTION: LEGO1 0x10064010
2475// FUNCTION: BETA10 0x100453a5
2476MxBool LegoAnimationManager::FUN_10064010(LegoPathBoundary* p_boundary, LegoUnknown100db7f4* p_edge, float p_destScale)
2477{
2478 Mx3DPointFloat p1;
2479 Vector3* v1 = p_edge->CWVertex(*p_boundary);
2480 Vector3* v2 = p_edge->CCWVertex(*p_boundary);
2481
2482 assert(v1 && v2);
2483
2484 p1 = *v2;
2485 p1 -= *v1;
2486 p1 *= p_destScale;
2487 p1 += *v1;
2488
2489 BoundingBox boundingBox;
2490 Mx3DPointFloat vec(1.0f, 1.0f, 1.0f);
2491
2492 boundingBox.Min() = p1;
2493 boundingBox.Min() -= vec;
2494 boundingBox.Max() = p1;
2495 boundingBox.Max() += vec;
2496
2497 if (GetViewManager()->IsBoundingBoxInFrustum(boundingBox) == FALSE) {
2498 return TRUE;
2499 }
2500
2501 return FALSE;
2502}
2503
2504// FUNCTION: LEGO1 0x10064120
2505// FUNCTION: BETA10 0x100454f5
2506MxBool LegoAnimationManager::FUN_10064120(LegoLocation::Boundary* p_boundary, MxBool p_bool1, MxBool p_bool2)
2507{
2508 MxU32 local2c = 12;
2509 float destScale = ((rand() * 0.5) / 32767.0) + 0.25;
2510 LegoPathActor* actor = UserActor();
2511
2512 if (actor == NULL) {
2513 return FALSE;
2514 }
2515
2516 LegoPathBoundary* boundary = actor->GetBoundary();
2517
2518 if (boundary == NULL) {
2519 return FALSE;
2520 }
2521
2522 Mx3DPointFloat direction = actor->GetWorldDirection();
2523 float local4c = 0.0f;
2524 LegoUnknown100db7f4* local50 = NULL;
2525 LegoS32 numEdges = boundary->GetNumEdges();
2526 Mx3DPointFloat vec;
2528 MxS32 i;
2529
2530 for (i = 0; i < numEdges; i++) {
2531 e = (LegoUnknown100db7f4*) boundary->GetEdges()[i];
2532 e->FUN_1002ddc0(*boundary, vec);
2533 float dot = vec.Dot(direction, vec);
2534
2535 if (dot > local4c) {
2536 local50 = e;
2537 local4c = dot;
2538 }
2539 }
2540
2541 e = local50;
2542 do {
2543 e = (LegoUnknown100db7f4*) e->GetCounterclockwiseEdge(*boundary);
2544 if (e->GetMask0x03()) {
2545 break;
2546 }
2547 } while (e != local50);
2548
2549 if (e == local50) {
2550 return FALSE;
2551 }
2552
2553 LegoUnknown100db7f4* local34 = e;
2554 LegoUnknown100db7f4* local8 = local50;
2555
2556 while (local2c--) {
2557 if (local34 != NULL) {
2558 if (local34->BETA_1004a830(*boundary, LegoWEGEdge::c_bit1) && FUN_10064010(boundary, local34, destScale) &&
2559 (!p_bool2 || FUN_10064010(boundary, local8, destScale))) {
2560 p_boundary->m_srcScale = p_boundary->m_destScale = destScale;
2561 p_boundary->m_name = boundary->GetName();
2562 numEdges = boundary->GetNumEdges();
2563
2564 for (i = 0; i < numEdges; i++) {
2565 LegoUnknown100db7f4* e = (LegoUnknown100db7f4*) boundary->GetEdges()[i];
2566
2567 if (local34 == e) {
2568 p_boundary->m_src = i;
2569 }
2570 else if (local8 == e) {
2571 p_boundary->m_dest = i;
2572 }
2573 }
2574
2575 return TRUE;
2576 }
2577
2578 local8 = local34;
2579 boundary = (LegoPathBoundary*) local34->OtherFace(boundary);
2580 local50 = local34;
2581
2582 do {
2583 if (p_bool1) {
2584 local34 = (LegoUnknown100db7f4*) local34->GetCounterclockwiseEdge(*boundary);
2585 }
2586 else {
2587 local34 = (LegoUnknown100db7f4*) local34->GetClockwiseEdge(*boundary);
2588 }
2589 } while (!local34->GetMask0x03() && local34 != local50);
2590
2591 if (local34 == local50) {
2592 return FALSE;
2593 }
2594 }
2595 }
2596
2597 return FALSE;
2598}
2599
2600// FUNCTION: LEGO1 0x10064380
2601// FUNCTION: BETA10 0x1004583a
2602MxResult LegoAnimationManager::FUN_10064380(
2603 const char* p_name,
2604 const char* p_boundaryName,
2605 MxS32 p_src,
2606 float p_srcScale,
2607 MxS32 p_dest,
2608 float p_destScale,
2609 MxU32 p_undIdx1,
2610 MxS32 p_unk0x0c,
2611 MxU32 p_undIdx2,
2612 MxS32 p_unk0x10,
2613 float p_speed
2614)
2615{
2616 LegoWorld* world = CurrentWorld();
2617 MxS32 extraIndex = -1;
2618 LegoExtraActor* actor = NULL;
2619 MxS32 i;
2620
2621 for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2622 LegoROI* roi = m_extras[i].m_roi;
2623
2624 if (roi == NULL && extraIndex == -1) {
2625 extraIndex = i;
2626 }
2627
2628 if (roi != NULL && !strcmpi(roi->GetName(), p_name)) {
2629 actor = CharacterManager()->GetExtraActor(p_name);
2630
2631 if (actor != NULL && actor->GetController() != NULL) {
2632 actor->GetController()->RemoveActor(actor);
2633 actor->SetController(NULL);
2634 actor->ClearMaps();
2635 }
2636
2637 break;
2638 }
2639 }
2640
2641 if (actor == NULL && extraIndex != -1) {
2642 i = extraIndex;
2643
2644 MxS32 characterId;
2645 for (characterId = 0; characterId < (MxS32) sizeOfArray(g_characters); characterId++) {
2646 if (!strcmpi(g_characters[characterId].m_name, p_name)) {
2647 break;
2648 }
2649 }
2650
2651 if (characterId > sizeOfArray(g_characters)) {
2652 return FAILURE;
2653 }
2654
2655 m_extras[extraIndex].m_roi = CharacterManager()->GetActorROI(p_name, TRUE);
2656 m_extras[extraIndex].m_characterId = characterId;
2657 m_extras[extraIndex].m_speed = p_speed;
2658
2659 actor = CharacterManager()->GetExtraActor(p_name);
2660 m_unk0x414++;
2661 }
2662
2663 if (actor != NULL) {
2664 MxU8 unk0x0c = rand() % 2 != 0 ? 1 : 2;
2665 actor->SetUnknown0x0c(unk0x0c);
2666 actor->SetWorldSpeed(0.0f);
2667
2668 if (world->PlaceActor(actor, p_boundaryName, p_src, p_srcScale, p_dest, p_destScale) != SUCCESS) {
2669 CharacterManager()->ReleaseActor(m_extras[i].m_roi);
2670 m_extras[i].m_roi = NULL;
2671 m_unk0x414--;
2672 return FAILURE;
2673 }
2674
2675 MxS32 characterId = m_extras[i].m_characterId;
2676 const char** cycles = g_cycles[g_characters[characterId].m_unk0x16];
2677
2678 LegoLocomotionAnimPresenter* presenter =
2679 (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx1]);
2680 if (presenter != NULL) {
2681 presenter->FUN_1006d680(actor, 0.0f);
2682 }
2683
2684 presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx2]);
2685 if (presenter != NULL) {
2686 presenter->FUN_1006d680(actor, 4.0f);
2687 }
2688
2689 m_extras[i].m_unk0x08 = Timer()->GetTime();
2690 m_extras[i].m_unk0x0c = TRUE;
2691 m_extras[i].m_speed = p_speed;
2692
2693 g_characters[characterId].m_unk0x0c = p_unk0x0c;
2694 g_characters[characterId].m_unk0x10 = p_unk0x10;
2695 g_characters[characterId].m_inExtras = TRUE;
2696 return SUCCESS;
2697 }
2698
2699 return FAILURE;
2700}
2701
2702// FUNCTION: LEGO1 0x10064670
2704{
2705 MxBool success = FALSE;
2706
2707 if (p_position != NULL) {
2708 Mx3DPointFloat vec(98.875f, 0.0f, -46.1564f);
2709 vec -= *p_position;
2710
2711 if (vec.LenSquared() < 800.0f) {
2712 success = TRUE;
2713 }
2714 }
2715 else {
2716 success = TRUE;
2717 }
2718
2719 if (success) {
2720 return FUN_10064380("brickstr", "EDG02_95", 1, 0.5f, 3, 0.5f, rand() % 3 + 14, -1, rand() % 3, -1, 0.5f);
2721 }
2722
2723 return FAILURE;
2724}
2725
2726// FUNCTION: LEGO1 0x10064740
2728{
2729 MxBool success = FALSE;
2730
2731 if (p_position != NULL) {
2732 Mx3DPointFloat vec(-21.375f, 0.0f, -41.75f);
2733 vec -= *p_position;
2734
2735 if (vec.LenSquared() < 1000.0f) {
2736 success = TRUE;
2737 }
2738 }
2739 else {
2740 success = TRUE;
2741 }
2742
2743 if (success) {
2744 if (GameState()->GetActorId() != LegoActor::c_mama) {
2745 FUN_10064380("mama", "USR00_47", 1, 0.43f, 3, 0.84f, rand() % 3 + 13, -1, rand() % 3, -1, 0.7f);
2746 }
2747
2748 if (GameState()->GetActorId() != LegoActor::c_papa) {
2749 FUN_10064380("papa", "USR00_193", 3, 0.55f, 1, 0.4f, rand() % 3 + 13, -1, rand() % 3, -1, 0.9f);
2750 }
2751
2752 return SUCCESS;
2753 }
2754
2755 return FAILURE;
2756}
2757
2758// FUNCTION: LEGO1 0x10064880
2759// FUNCTION: BETA10 0x10045d02
2760MxResult LegoAnimationManager::FUN_10064880(const char* p_name, MxS32 p_unk0x0c, MxS32 p_unk0x10)
2761{
2762 for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) {
2763 LegoROI* roi = m_extras[i].m_roi;
2764
2765 if (roi != NULL) {
2766 if (!strcmpi(roi->GetName(), p_name)) {
2767 g_characters[m_extras[i].m_characterId].m_unk0x0c = p_unk0x0c;
2768 g_characters[m_extras[i].m_characterId].m_unk0x10 = p_unk0x10;
2769 return SUCCESS;
2770 }
2771 }
2772 }
2773
2774 return FAILURE;
2775}
2776
2777// FUNCTION: LEGO1 0x100648f0
2778// FUNCTION: BETA10 0x10045daf
2779void LegoAnimationManager::FUN_100648f0(LegoTranInfo* p_tranInfo, MxLong p_unk0x404)
2780{
2781 if (m_unk0x402 && p_tranInfo->m_unk0x14) {
2782 p_tranInfo->m_flags |= LegoTranInfo::c_bit1;
2783 m_unk0x430 = TRUE;
2784 m_unk0x42c = p_tranInfo;
2785 m_unk0x434 = p_unk0x404;
2786 m_unk0x438 = p_unk0x404 + 1000;
2787
2788 ViewROI* viewROI = VideoManager()->GetViewROI();
2789 m_unk0x43c = viewROI->GetLocal2World();
2790 p_tranInfo->m_unk0x2c = m_unk0x43c;
2791
2792 LegoPathActor* actor = UserActor();
2793 if (actor != NULL) {
2795 actor->SetWorldSpeed(0.0f);
2796 }
2797
2798 LegoLocation* location = NavController()->GetLocation(p_tranInfo->m_location);
2799 if (location != NULL) {
2800 CalcLocalTransform(location->m_position, location->m_direction, location->m_up, m_unk0x484);
2801 m_unk0x4cc.SetStartEnd(m_unk0x43c, m_unk0x484);
2802 m_unk0x4cc.NormalizeDirection();
2803 }
2804 else {
2805 p_tranInfo->m_flags &= ~LegoTranInfo::c_bit1;
2806 m_unk0x430 = FALSE;
2807 }
2808
2809 Mx3DPointFloat vec;
2810 vec.Clear();
2811 viewROI->FUN_100a5a30(vec);
2812 }
2813}
2814
2815// FUNCTION: LEGO1 0x10064b50
2816// FUNCTION: BETA10 0x10045f14
2817void LegoAnimationManager::FUN_10064b50(MxLong p_time)
2818{
2819 if (m_unk0x430 && m_unk0x42c != NULL) {
2820 MxMatrix mat;
2821
2822 if (p_time < 0 || m_unk0x438 <= p_time) {
2823 m_unk0x430 = FALSE;
2824 m_unk0x42c->m_flags &= ~LegoTranInfo::c_bit1;
2825 m_unk0x42c = NULL;
2826 mat = m_unk0x484;
2827 }
2828 else {
2829 float und = (float) (p_time - m_unk0x434) / (float) (m_unk0x438 - m_unk0x434);
2830
2831 float sub[3];
2832 sub[0] = (m_unk0x484[3][0] - m_unk0x43c[3][0]) * und;
2833 sub[1] = (m_unk0x484[3][1] - m_unk0x43c[3][1]) * und;
2834 sub[2] = (m_unk0x484[3][2] - m_unk0x43c[3][2]) * und;
2835
2836 m_unk0x4cc.InterpolateToMatrix(mat, (float) (p_time - m_unk0x434) / 1000.0f);
2837
2838 VPV3(mat[3], m_unk0x43c[3], sub);
2839 mat[3][3] = 1.0f;
2840 }
2841
2842 LegoROI* viewROI = VideoManager()->GetViewROI();
2843
2844 viewROI->WrappedSetLocalTransform(mat);
2845 VideoManager()->Get3DManager()->Moved(*viewROI);
2847 viewROI->GetWorldPosition(),
2848 viewROI->GetWorldDirection(),
2849 viewROI->GetWorldUp(),
2850 viewROI->GetWorldVelocity()
2851 );
2852 }
2853}
2854
2855// FUNCTION: LEGO1 0x10064ee0
2857{
2858 if (m_tranInfoList != NULL) {
2859 LegoTranInfoListCursor cursor(m_tranInfoList);
2860 LegoTranInfo* tranInfo;
2861
2862 while (cursor.Next(tranInfo)) {
2863 if (tranInfo->m_animInfo->m_objectId == p_objectId) {
2864 if (tranInfo->m_presenter) {
2865 return tranInfo->m_presenter->FUN_1004b830();
2866 }
2867 else {
2868 return FALSE;
2869 }
2870 }
2871 }
2872 }
2873
2874 return FALSE;
2875}
2876
2877// FUNCTION: LEGO1 0x10064ff0
2879{
2880 m_unk0x0c = 0;
2881 m_unk0x10 = NULL;
2882 m_locationsFlagsLength = 0;
2883 m_locationsFlags = NULL;
2884}
2885
2886// FUNCTION: LEGO1 0x10065150
2888{
2889 delete[] m_unk0x10;
2890 delete[] m_locationsFlags;
2891}
2892
2893// FUNCTION: LEGO1 0x100651d0
2894void AnimState::CopyToAnims(MxU32, AnimInfo* p_anims, MxU32& p_outExtraCharacterId)
2895{
2896 if (m_unk0x10 != NULL) {
2897 for (MxS32 i = 0; i < m_unk0x0c; i++) {
2898 p_anims[i].m_unk0x22 = m_unk0x10[i];
2899 }
2900
2901 p_outExtraCharacterId = m_extraCharacterId;
2902
2903 for (MxS32 j = 0; j < m_locationsFlagsLength; j++) {
2905 if (location != NULL) {
2906 location->m_unk0x5c = m_locationsFlags[j];
2907 }
2908 }
2909 }
2910}
2911
2912// FUNCTION: LEGO1 0x10065240
2913void AnimState::InitFromAnims(MxU32 p_animsLength, AnimInfo* p_anims, MxU32 p_extraCharacterId)
2914{
2915 if (m_unk0x10 == NULL) {
2916 m_unk0x0c = p_animsLength;
2917 m_unk0x10 = new MxU16[p_animsLength];
2919 m_locationsFlagsLength = numLocations;
2920 m_locationsFlags = new MxBool[numLocations];
2921 }
2922
2923 m_extraCharacterId = p_extraCharacterId;
2924
2925 for (MxS32 i = 0; i < m_unk0x0c; i++) {
2926 m_unk0x10[i] = p_anims[i].m_unk0x22;
2927 }
2928
2929 for (MxS32 j = 0; j < m_locationsFlagsLength; j++) {
2931 if (location != NULL) {
2932 m_locationsFlags[j] = location->m_unk0x5c;
2933 }
2934 }
2935}
2936
2937// FUNCTION: LEGO1 0x100652d0
2938// FUNCTION: BETA10 0x10046621
2940{
2941 MxResult result = LegoState::Serialize(p_storage);
2942
2943 if (result == SUCCESS) {
2944 if (p_storage->IsReadMode()) {
2945 MxS32 i;
2946
2947 p_storage->ReadU32(m_extraCharacterId);
2948
2949 if (m_unk0x10) {
2950 delete[] m_unk0x10;
2951 }
2952
2953 p_storage->ReadU32(m_unk0x0c);
2954
2955#ifndef BETA10
2956 if (m_unk0x0c != 0) {
2957 m_unk0x10 = new MxU16[m_unk0x0c];
2958 }
2959 else {
2960 m_unk0x10 = NULL;
2961 }
2962#else
2963 m_unk0x10 = new MxU16[m_unk0x0c];
2964#endif
2965
2966 for (i = 0; i < m_unk0x0c; i++) {
2967 p_storage->ReadU16(m_unk0x10[i]);
2968 }
2969
2970 // Note that here we read first and then free memory in contrast to above
2971 p_storage->ReadU32(m_locationsFlagsLength);
2972
2973#ifndef BETA10
2974 if (m_locationsFlags) {
2975 delete[] m_locationsFlags;
2976 }
2977
2978 if (m_locationsFlagsLength != 0) {
2979 m_locationsFlags = new MxBool[m_locationsFlagsLength];
2980 }
2981 else {
2982 m_locationsFlags = NULL;
2983 }
2984#else
2985 m_locationsFlags = new MxBool[m_locationsFlagsLength];
2986#endif
2987
2988 for (i = 0; i < m_locationsFlagsLength; i++) {
2989 p_storage->ReadU8(m_locationsFlags[i]);
2990 }
2991 }
2992 else if (p_storage->IsWriteMode()) {
2993 MxS32 i;
2994
2995 p_storage->WriteU32(m_extraCharacterId);
2996 p_storage->WriteU32(m_unk0x0c);
2997
2998 for (i = 0; i < m_unk0x0c; i++) {
2999 p_storage->WriteU16(m_unk0x10[i]);
3000 }
3001
3002 p_storage->WriteU32(m_locationsFlagsLength);
3003 for (i = 0; i < m_locationsFlagsLength; i++) {
3004 p_storage->WriteU8(m_locationsFlags[i]);
3005 }
3006 }
3007 }
3008
3009 return result;
3010}
3011
3012// FUNCTION: LEGO1 0x100654f0
3014{
3015 if (m_unk0x10 != NULL) {
3016 m_extraCharacterId = 0;
3017
3018 for (MxS32 i = 0; i < m_unk0x0c; i++) {
3019 m_unk0x10[i] = 0;
3020 }
3021
3022 for (MxS32 j = 0; j < m_locationsFlagsLength; j++) {
3024 m_locationsFlags[j] = 0;
3025 }
3026 }
3027
3028 return TRUE;
3029 }
3030
3031 return FALSE;
3032}
[AI] Persistent serializable animation state for resuming animations and restoring global animation p...
AnimState()
Constructor. [AI].
void CopyToAnims(MxU32, AnimInfo *p_anims, MxU32 &p_outExtraCharacterId)
[AI] Writes tracked usage data to animations.
MxBool Reset() override
[AI] Resets all tracked animation usage to default.
~AnimState() override
Destructor, releases animation tracking arrays. [AI].
MxResult Serialize(LegoStorage *p_storage) override
[AI] Serialize state to or from disk for save/load.
void InitFromAnims(MxU32 p_animsLength, AnimInfo *p_anims, MxU32 p_extraCharacterId)
[AI] Reads usage state from animations and stores it in this AnimState.
[AI] Represents an axis-aligned bounding box in 3D space, using minimum and maximum points.
Definition: roi.h:20
const Vector3 & Min() const
[AI] Const accessor for the minimum corner of the bounding box.
Definition: roi.h:26
const Vector3 & Max() const
[AI] Const accessor for the maximum corner of the bounding box.
Definition: roi.h:36
const float & Radius() const
[AI] Const accessor for the sphere radius.
Definition: roi.h:72
BOOL Moved(ViewROI &rROI)
[AI] Notifies the manager that the ROI has moved and needs spatial update.
@ c_laura
Laura ([AI])
Definition: legoactor.h:21
@ c_mama
Mama ([AI])
Definition: legoactor.h:18
@ c_papa
Papa ([AI])
Definition: legoactor.h:19
virtual void ClearMaps()
[AI] Deallocates all animation map structures and selects no animation; resets current animation inde...
void FUN_1004b840()
[AI] Helper routine to end all actions except the central one, handle action teardown,...
LegoAnimPresenter * GetPresenter()
[AI] Returns the main subordinate LegoAnimPresenter currently managed by this MM presenter.
MxBool FUN_1004b830()
[AI] Returns true if the presenter state has reached or surpassed e_unk6.
void FUN_1004b8c0()
[AI] Calls the state transition handler, forcing the presenter's tickle progression for special handl...
[AI] Handles playback and synchronization of animated LEGO objects, including variable substitution,...
LegoAnim * GetAnimation()
[AI] Returns the current animation resource in use.
[AI] Root class for all node-based animation blending/structure.
Definition: legoanim.h:356
LegoAnimScene * GetCamAnim()
[AI] Gets the optional camera/scene animation track.
Definition: legoanim.h:378
[AI] Animation manager handling all world and character animation state, loading, and logic for extra...
MxLong Notify(MxParam &p_param) override
[AI] Handles system/game notifications, e.g.
void PurgeExtra(MxBool p_und)
[AI] Removes all extras matching current world/time criteria (but not the player's current character)...
MxResult StartEntityAction(MxDSAction &p_dsAction, LegoEntity *p_entity)
[AI] Starts a DSAction for a specific entity, managing controller/actor logic if relevant.
void FUN_10063780(LegoROIList *p_list)
[AI] Examines an ROI list and adds all actors of type to internal "pending" list for extras.
MxBool FUN_10064ee0(MxU32 p_objectId)
[AI] Determines if any currently running animation is assigned to the given objectId,...
void FUN_10060540(MxBool p_unk0x29)
[AI] Sets the 'enabled for random camera animation' flag for all animations.
void FUN_10060480(const LegoChar *p_characterNames[], MxU32 p_numCharacterNames)
[AI] Marks characters in the global character list (g_characters) as available for animation accordin...
MxResult FUN_10060dc0(MxU32 p_objectId, MxMatrix *p_matrix, MxBool p_param3, MxU8 p_param4, LegoROI *p_roi, MxBool p_param6, MxBool p_param7, MxBool p_param8, MxBool p_param9)
[AI] Helper for starting a specific animation, including world matrix and camera settings.
MxBool FindVehicle(const char *p_name, MxU32 &p_index)
[AI] Looks up a vehicle by name, returning its index if found.
void Reset(MxBool p_und)
[AI] Resets all internal state; optionally resets animation state too.
void FUN_10061010(MxBool p_und)
[AI] Cancels all camera/transition animations and resets camera after completion.
@ e_unk1
[AI] Unknown/unspecified play mode
@ e_unk0
[AI] Unknown/unspecified play mode
~LegoAnimationManager() override
Destructor, cleans up all allocations and deregisters from tickle/notify. [AI].
void FUN_100604f0(MxS32 p_objectIds[], MxU32 p_numObjectIds)
[AI] Enables/disables certain animations by object id list (sets m_unk0x29 flag in AnimInfo).
MxResult LoadWorldInfo(LegoOmni::World p_worldId)
[AI] Loads all world animation and extra info.
MxResult Tickle() override
[AI] Called by tick manager, processes world/time-based animation logic, including spawning extras an...
MxResult ReadModelInfo(LegoStorage *p_storage, ModelInfo *p_info)
[AI] Reads a single ModelInfo out of storage.
void FUN_10060570(MxBool p_unk0x1a)
[AI] Sets whether the manager should immediately trigger camera transition animations in quick succes...
void Resume()
[AI] Resumes animation manager from suspension, restoring all previously suspended state.
void FUN_100604d0(MxBool p_unk0x08)
[AI] Sets the m_unk0x08 flag for all characters.
MxResult FUN_10064880(const char *p_name, MxS32 p_unk0x0c, MxS32 p_unk0x10)
[AI] Updates specified character's extra animation idle/play time values for active extras.
void FUN_10062770()
[AI] Initializes sound transitions if not already active for the current world.
void EnableCamAnims(MxBool p_enableCamAnims)
[AI] Sets whether camera-based queued animations are enabled for the world.
void FUN_10063270(LegoROIList *p_list, LegoAnimPresenter *p_presenter)
[AI] Handles "extras" onboarding by evaluating visibility and position for presenter-based animation.
LegoAnimationManager()
Default constructor. [AI].
void CameraTriggerFire(LegoPathActor *p_actor, MxBool, MxU32 p_location, MxBool p_bool)
[AI] Triggers a camera animation based on user and location state.
MxResult ReadAnimInfo(LegoStorage *p_storage, AnimInfo *p_info)
[AI] Reads an AnimInfo entry from file storage, building model list and parsing parameters.
void Suspend()
[AI] Suspends all activity, saving out transition/animation state, and disables extra processing.
MxResult FUN_10064740(Vector3 *p_position)
[AI] Similar to FUN_10064670, but triggers a different special animation event for secondary location...
MxResult FUN_10064670(Vector3 *p_position)
[AI] Activates special triggered animation in response to player position near given point.
LegoTranInfo * GetTranInfo(MxU32 p_index)
[AI] Retrieves an active transition info, or NULL if not found.
static void configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig)
[AI] Updates the configuration values (global) for animation manager's allowed number of extras,...
void AddExtra(MxS32 p_location, MxBool p_und)
[AI] Spawns a new extra actor at a boundary or location, if capacity and logic allow.
void FUN_1005f6d0(MxBool p_unk0x400)
[AI] Enables or disables extras (extra actors).
LegoExtraActor * GetExtraActor(const char *p_name)
[AI] Returns an extra actor associated with a given character name, or NULL if not found.
void ReleaseActor(const char *p_name)
[AI] Releases a character/ROI by name, decrementing its reference count and deleting if zero.
LegoROI * GetActorROI(const char *p_name, MxBool p_createEntity)
[AI] Returns a LegoROI for the given character name, creating and registering the actor if necessary.
Notification parameter for signaling the end of an animation in the LEGO Island engine.
[AI] Cursor class for iterating through a LegoEntityList.
[AI] A strongly typed list for holding LegoEntity pointers.
[AI] Represents an entity that can be placed and managed in the LEGO Island world.
Definition: legoentity.h:16
Mx3DPointFloat GetWorldDirection()
[AI] Gets the normalized world-space direction vector, optionally updating from ROI....
Definition: legoentity.cpp:202
virtual void SetWorldSpeed(MxFloat p_worldSpeed)
[AI] Sets the current world speed value for this entity (used to control motion/animation rate).
Definition: legoentity.h:98
LegoROI * GetROI()
[AI] Gets the ROI (Realtime Object Instance) associated with this entity. [AI]
Definition: legoentity.h:161
MxU8 GetType()
[AI] Gets the type of this entity (one of the enum Type values). [AI]
Definition: legoentity.h:164
MxFloat GetWorldSpeed()
[AI] Gets the entity's current world speed state. [AI]
Definition: legoentity.h:158
@ e_actor
[AI] Standard character entity controlled by scripts or user [AI]
Definition: legoentity.h:20
MxBool IsA(const char *p_name) const override
[AI] Polymorphic type check for this entity given a string.
Definition: legoentity.h:59
Represents a special actor in the world with additional animation state machines and complex interact...
void Restart()
Checks whether this actor's previous boundary was "blocked" and re-enables movement if allowed; calle...
void SetWorldSpeed(MxFloat p_worldSpeed) override
Sets the world speed for this actor, factoring in its current animation/interaction state.
void SetUnknown0x0c(undefined p_unk0x0c)
Sets the internal unknown flag (possible randomization/collision state controller).
Implementation of LegoStorage for file-backed storage using stdio FILE*.
Definition: legostorage.h:387
LegoResult Read(void *p_buffer, LegoU32 p_size) override
Reads bytes from file at current position.
Definition: legostorage.cpp:50
LegoResult Open(const char *p_name, LegoU32 p_mode)
Opens a file with given name and mode, closing existing file if needed.
LegoState * CreateState(const char *p_stateName)
Creates an instance of given state, registers it, and returns pointer.
@ e_act1
Act 1: the first main segment of the game. [AI].
Definition: legogamestate.h:84
MxU8 GetActorId()
Returns the current selected actor ID. [AI].
LegoState * GetState(const char *p_stateName)
Find an existing state (LegoState-derived) object by its registered script/class name.
[AI] Specialized presenter class for handling locomotion animation playback and state in the LEGO Isl...
void FUN_1006d680(LegoAnimActor *p_actor, MxFloat p_value)
[AI] Binds a LegoAnimActor to the internal animation context and ROI mapping.
static MxS32 GetNumLocations()
[AI] Static: Retrieves the number of named locations registered in the navigation system.
static LegoLocation * GetLocation(MxU32 p_location)
[AI] Static: Retrieves the pointer to a LegoLocation struct by its index.
static LegoOmni * GetInstance()
[AI] Returns the current LegoOmni singleton pointer, cast from MxOmni.
Definition: legomain.cpp:305
MxResult StartActionIfUnknown0x13c(MxDSAction &p_dsAction)
[AI] Starts action if the unknown0x13c member is set; otherwise returns success.
Definition: legomain.h:468
World
[AI] Identifiers for all unique, script-driven world environments in LEGO Island.
Definition: legomain.h:57
@ e_undefined
[AI] No world specified. [AI]
Definition: legomain.h:58
@ e_act1
[AI] Act 1 main world. [AI]
Definition: legomain.h:59
LegoROI * FindROI(const char *p_name)
[AI] Finds a top-level LegoROI (region of interest/3D object) by name string.
Definition: legomain.cpp:408
[AI] An actor that moves along a predefined path, supporting boundary transitions,...
Definition: legopathactor.h:32
MxU32 GetActorState()
[AI] Gets the current navigation/animation state of the actor.
void SetController(LegoPathController *p_pathController)
[AI] Assigns a new path controller (used for actor transitions between paths).
@ c_initial
[AI] Default state upon creation or reset. [AI]
Definition: legopathactor.h:37
@ c_disabled
[AI] Marks as disabled or inactive for path follow logic. [AI]
Definition: legopathactor.h:41
LegoPathController * GetController()
[AI] Retrieves pointer to the path controller which governs this actor's movement.
LegoPathBoundary * GetBoundary()
[AI] Retrieves the current path boundary associated with this actor.
void SetActorState(MxU32 p_actorState)
[AI] Sets the navigation/path state of the actor.
[AI] Represents a path segment or boundary in the navigation network for actors (vehicles,...
[AI] Manager for controlling actors' movement along predefined geometric paths.
MxResult RemoveActor(LegoPathActor *p_actor)
[AI] Removes an actor from the controller, detaches it from controlled boundaries,...
[AI] A typed list cursor for iterating over a LegoROIList.
Definition: legoroilist.h:53
[AI] A specialized pointer list for managing LegoROI instances.
Definition: legoroilist.h:25
[AI] Represents a Real-time Object Instance enriched with LEGO-specific functionality.
Definition: legoroi.h:43
const LegoChar * GetName() const
[AI] Gets this ROI's name.
Definition: legoroi.h:287
LegoEntity * GetEntity()
[AI] Gets the entity associated with this ROI (or NULL).
Definition: legoroi.h:293
void UpdateListener(const float *p_position, const float *p_direction, const float *p_up, const float *p_velocity)
[AI] Updates the 3D sound listener properties in DirectSound, reflecting player/world changes.
virtual MxResult Serialize(LegoStorage *p_storage)
[AI] Serialize state to a storage (for save/load).
Definition: legostate.h:141
Abstract base class providing an interface for file-like storage with binary and text read/write oper...
Definition: legostorage.h:16
LegoStorage * WriteU32(MxU32 p_data)
Writes a 32-bit unsigned value to storage.
Definition: legostorage.h:145
LegoStorage * ReadU32(MxU32 &p_data)
Reads a 32-bit unsigned value from storage.
Definition: legostorage.h:252
LegoStorage * WriteU8(LegoU8 p_data)
Writes an 8-bit unsigned value to storage.
Definition: legostorage.h:99
virtual LegoBool IsWriteMode()
Returns TRUE if object was opened in write mode.
Definition: legostorage.h:72
LegoStorage * ReadU8(LegoU8 &p_data)
Reads an 8-bit unsigned value from storage.
Definition: legostorage.h:206
LegoStorage * ReadU16(LegoU16 &p_data)
Reads a 16-bit unsigned value from storage.
Definition: legostorage.h:228
virtual LegoResult Read(void *p_buffer, LegoU32 p_size)=0
Read bytes from storage into buffer.
virtual LegoBool IsReadMode()
Returns TRUE if object was opened in read mode.
Definition: legostorage.h:78
LegoStorage * WriteU16(LegoU16 p_data)
Writes a 16-bit unsigned value to storage.
Definition: legostorage.h:121
@ c_read
Open for read operations. [AI].
Definition: legostorage.h:23
[AI] Cursor/iterator for traversing a LegoTranInfoList.
[AI] List container holding pointers to LegoTranInfo objects for use in transfer/pathfinding/ROIs.
double GetElapsedSeconds()
[AI] Returns the elapsed wall clock seconds since the last Tickle update (frame time).
Lego3DManager * Get3DManager()
[AI] Returns the Lego3DManager for this manager, which owns all 3D scene representations and view con...
LegoROI * GetViewROI()
[AI] Returns the viewpoint ROI for the current view/camera.
LegoU8 GetNumEdges()
[AI] Returns the number of edge elements assigned to this face.
Definition: legoweedge.h:43
LegoUnknown100db7f4 ** GetEdges()
[AI] Gets the array of pointers to the edge objects that form this face.
Definition: legoweedge.h:49
const LegoChar * GetName()
[AI] Returns the name string of this edge, typically used for debugging and lookup.
Definition: legowegedge.h:79
@ c_bit1
[AI] Edge-specific flag (purpose determined by logic in edge processing)
Definition: legowegedge.h:35
Represents the active 3D world, holding all entity, animation, sound, path, and ROI objects.
Definition: legoworld.h:49
MxResult PlaceActor(LegoPathActor *p_actor, const char *p_name, MxS32 p_src, float p_srcScale, MxS32 p_dest, float p_destScale)
Places an actor along a path, from source to destination, using named references and scaling.
Definition: legoworld.cpp:267
LegoPathBoundary * FindPathBoundary(const char *p_name)
Finds a path boundary in all path controllers by name.
Definition: legoworld.cpp:385
LegoEntityList * GetEntityList()
Returns the current list of entities.
Definition: legoworld.h:283
MxCore * Find(const char *p_class, const char *p_name)
Finds an object of a given class and name in the world.
Definition: legoworld.cpp:573
void RemoveActor(LegoPathActor *p_actor)
Removes an actor from all known path controllers.
Definition: legoworld.cpp:325
[AI] Represents a 3D point with floating-point precision, inheriting from Vector3.
Definition: mxgeometry3d.h:14
void RaiseVolume()
[AI] Requests that the background music volume is raised (decrements suppression counter); triggers f...
void LowerVolume()
[AI] Requests a reduction in current background music volume, queuing for fade out (increments suppre...
[AI] Represents an action deserialized from SI chunks, holding key animation or script parameters suc...
Definition: mxdsaction.h:17
void AppendExtra(MxU16 p_extraLength, const char *p_extraData)
[AI] Concatenates or stores extra data associated with this action, robust for multi-part actions.
Definition: mxdsaction.cpp:225
virtual void SetAtomId(MxAtomId p_atomId)
[AI] Sets the atom id for this object instance, used for indexing or lookup.
Definition: mxdsobject.h:118
void SetUnknown24(MxS16 p_unk0x24)
[AI] Sets the unknown field at 0x24 (possibly version/state).
Definition: mxdsobject.h:151
void SetObjectId(MxU32 p_objectId)
[AI] Sets the object id (for serialization or lookup).
Definition: mxdsobject.h:147
MxBool Next()
[AI]
void Detach()
[AI]
MxBool Find(T p_obj)
[AI]
void Append(T p_obj)
[AI]
Definition: mxlist.h:100
[AI] Represents a 4x4 transformation matrix, specialized for the LEGO Island engine and derived from ...
Definition: mxmatrix.h:16
void Unregister(MxCore *p_listener)
[AI] Removes a previously registered listener and flushes any pending notifications for it.
void Register(MxCore *p_listener)
[AI] Registers a listener object to receive notifications.
MxResult Send(MxCore *p_listener, const MxNotificationParam &p_param)
[AI] Queues a notification to be sent to a specific registered listener.
[AI] Parameter object representing a single notification or event, carrying an identifier and sender ...
static const char * GetCD()
[AI] Retrieves the configured CD-ROM media path string used for resource location.
Definition: mxomni.cpp:375
static const char * GetHD()
[AI] Retrieves the configured hard disk media path string used for resource location.
Definition: mxomni.cpp:363
[AI] MxParam serves as a polymorphic base class for parameter passing in event and notification syste...
Definition: mxparam.h:7
[AI] Abstract base class for all presenter types in the LEGO Island engine, responsible for managing ...
Definition: mxpresenter.h:20
void SetStartEnd(Matrix4 &p_m1, Matrix4 &p_m2)
Sets start and end quaternions by converting two matrices to quaternion form.
int InterpolateToMatrix(Matrix4 &p_matrix, float p_f)
Interpolates between start and end quaternions using spherical interpolation (slerp) and produces a 4...
long NormalizeDirection()
Ensures shortest path interpolation by potentially flipping the end quaternion's sign.
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.
Definition: mxtimer.h:50
const BoundingSphere & GetWorldBoundingSphere() const override
Returns the object's bounding sphere in world coordinates.
const float * GetWorldUp() const
Returns a pointer to the world up vector from the transformation matrix.
const float * GetWorldPosition() const
Returns a pointer to the world position from the transformation matrix (translation row).
const float * GetWorldDirection() const
Returns a pointer to the world direction vector (forward axis) from the transformation matrix.
const Matrix4 & GetLocal2World() const
Accessor for the current local-to-world transformation matrix.
void WrappedSetLocalTransform(const Matrix4 &p_transform)
Wraps SetLocalTransform, for possible override or interface uniformity.
void FUN_100a5a30(const Vector3 &p_world_velocity)
Sets the world velocity to the provided vector.
const float * GetWorldVelocity() const override
Returns a pointer to the object's velocity vector in world space.
const BoundingBox & GetWorldBoundingBox() const override
Returns the object's bounding box in world coordinates.
unsigned char GetVisibility()
[AI] Returns the visibility flag; true if visible, false if hidden.
Definition: roi.h:228
void SetVisibility(unsigned char p_visible)
[AI] Sets the visibility flag to the provided value.
Definition: roi.h:235
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.
[AI] 3D vector class, providing vector and cross-product operations in 3D space.
Definition: vector.h:249
void Clear() override
[AI] Sets every coordinate (x, y, z) to zero.
float LenSquared() const override
[AI] Computes the squared magnitude (x^2 + y^2 + z^2) of this vector.
[AI] Manages all ViewROI objects that are rendered in a given scene, handles frustum culling,...
Definition: viewmanager.h:16
unsigned int IsBoundingBoxInFrustum(const BoundingBox &p_bounding_box)
[AI] Determines if a bounding box is (partially) inside the camera's view frustum using frustum-plane...
Definition: viewmanager.cpp:64
[AI] ViewROI objects represent viewable and placeable objects in the scene, each holding their own tr...
Definition: viewroi.h:13
#define TRUE
Definition: d3drmdef.h:28
#define FALSE
Definition: d3drmdef.h:27
#define DECOMP_SIZE_ASSERT(T, S)
Definition: decomp.h:19
#define sizeOfArray(arr)
Definition: decomp.h:23
const char * g_strANIMMAN_ID
[AI] Used to reference the animation manager identifier during entity or animation handling.
Definition: define.cpp:129
MxU8 g_unk0x100d8b28[]
const char * g_cycles[11][17]
LegoAnimationManager::Character g_characters[47]
float g_unk0x100f7500
LegoAnimationManager::Vehicle g_vehicles[]
float g_unk0x100f74b0[6][3]
MxS32 g_legoAnimationManagerConfig
MxS32 g_unk0x100f7504
#define NULL
[AI] Null pointer value (C/C++ semantics).
Definition: legotypes.h:26
char LegoChar
[AI] Alias for char, for use in character/byte data and string handling.
Definition: legotypes.h:83
#define FAILURE
[AI] Used to indicate a failed operation in result codes.
Definition: legotypes.h:34
long LegoS32
[AI] Signed 32-bit integer type for cross-platform compatibility.
Definition: legotypes.h:65
#define SUCCESS
[AI] Used to indicate a successful operation in result codes.
Definition: legotypes.h:30
LegoGameState * GameState()
[AI] Accessor for the game's central game state controller. [AI]
Definition: misc.cpp:61
MxResult StartActionIfUnknown0x13c(MxDSAction &p_dsAction)
[AI] Triggers a DSAction if a certain unknown flag (0x13c) is set.
Definition: misc.cpp:175
LegoVideoManager * VideoManager()
[AI] Accessor for the game's LegoVideoManager subsystem. Used for managing 3D/video hardware....
Definition: misc.cpp:29
LegoCharacterManager * CharacterManager()
[AI] Accessor for the character manager, which manages in-game characters/NPCs. [AI]
Definition: misc.cpp:101
LegoSoundManager * SoundManager()
[AI] Accessor for the game's LegoSoundManager subsystem from the global LegoOmni instance....
Definition: misc.cpp:22
MxBackgroundAudioManager * BackgroundAudioManager()
[AI] Accessor for the background audio manager. Used for background music and ambient sounds....
Definition: misc.cpp:37
ViewManager * GetViewManager()
[AI] Accessor for the current ViewManager, managing rendering views/cameras. [AI]
Definition: misc.cpp:108
LegoWorld * CurrentWorld()
[AI] Accessor for the currently active LegoWorld instance. [AI]
Definition: misc.cpp:93
LegoNavController * NavController()
[AI] Accessor for the navigation controller, managing player/camera navigation. [AI]
Definition: misc.cpp:77
LegoOmni * Lego()
[AI] Retrieves the global LegoOmni singleton instance, providing access to core subsystems.
Definition: misc.cpp:16
LegoPathActor * UserActor()
[AI] Accessor for the user (player-controllable) LegoPathActor. [AI]
Definition: misc.cpp:85
MxTimer * Timer()
[AI] Returns the global simulation timer.
Definition: mxmisc.cpp:33
MxNotificationManager * NotificationManager()
[AI] Returns the notification manager for system-wide state/update notifications.
Definition: mxmisc.cpp:17
MxTickleManager * TickleManager()
[AI] Provides access to the global tickle manager.
Definition: mxmisc.cpp:25
@ c_notificationEndAnim
[AI] End of an animation [AI]
MxU8 MxBool
[AI]
Definition: mxtypes.h:124
MxLong MxResult
[AI]
Definition: mxtypes.h:106
#define TWOCC(a, b)
[AI] Macro to compose a 16-bit code from two 8-bit characters (e.g., for type IDs).
Definition: mxtypes.h:151
int MxLong
[AI]
Definition: mxtypes.h:83
unsigned char MxU8
[AI]
Definition: mxtypes.h:8
signed int MxS32
[AI]
Definition: mxtypes.h:38
unsigned short MxU16
[AI]
Definition: mxtypes.h:20
unsigned int MxU32
[AI]
Definition: mxtypes.h:32
signed char MxS8
[AI]
Definition: mxtypes.h:14
void OmniError(const char *p_message, MxS32 p_status)
Displays or logs an error message using the current user message handler, or aborts on error status i...
void CalcLocalTransform(const Vector3 &p_posVec, const Vector3 &p_dirVec, const Vector3 &p_upVec, Matrix4 &p_outMatrix)
[AI] Computes a transformation matrix based on a position, direction, and up vector.
Definition: realtime.cpp:7
[AI] Describes a specific animation, containing animation parameters, model list, and related metadat...
float m_unk0x10[4]
Animation parameters: start/target position and radius. [AI].
MxBool m_unk0x29
Animation is active/available/playable. [AI].
MxU16 m_unk0x22
Use-count or instance count for this animation. [AI].
ModelInfo * m_models
Array of ModelInfo structs for the animation's involved models. [AI].
MxU8 m_unk0x0c
Bitmask related to actor/vehicle ability to use this animation (see g_unk0x100d8b28)....
MxU32 m_objectId
Object ID corresponding to this animation; used as a unique key. [AI].
MxBool m_unk0x0a
Boolean to control startup/behavioral logic. [AI].
MxS8 m_unk0x2a[3]
Vehicle indices or similar (max 3), for use by certain actors. [AI].
MxU8 m_unk0x0b
Purpose unknown; animation-related flag. [AI].
MxU8 m_unk0x0d
Additional animation state flag. [AI].
char * m_name
Animation name. [AI].
MxS8 m_characterIndex
Index into g_characters for the owning character (-1 if not set). [AI].
MxS16 m_location
Location index if relevant (−1 for omni/global). [AI].
MxU8 m_modelCount
Number of models referenced in m_models array. [AI].
[AI] Items related to the Extra string of key-value pairs found in MxOb.
Definition: extra.h:14
[AI] Static definition of a character, its animation settings, flags, and world identity.
MxS32 m_unk0x10
Maximum idle time before main animation for this character (milliseconds). [AI].
MxBool m_active
Runtime flag; TRUE if animation for this character is currently activated (in any mode)....
MxBool m_unk0x08
Boolean, TRUE if this character is eligible for "extra" animation. [AI].
MxU8 m_unk0x15
Probability (0–100) used for random vehicle assignment. [AI].
MxBool m_unk0x07
Flag for reuse/destruction logic; meaning: pending return to actor pool. [AI].
MxS8 m_unk0x16
Index in g_cycles, used for finding correct main/alternative cycle animations for this character....
MxS8 m_vehicleId
Index into the vehicle array for this character's vehicle, −1 if not relevant. [AI].
MxBool m_inExtras
True if this character is currently active as an 'extra'. [AI].
MxS32 m_unk0x0c
Minimum idle time before main animation for this character (milliseconds). [AI].
MxBool m_unk0x0d
Indicates that this extra is to be purged/removed at next tick. [AI].
LegoROI * m_roi
ROI object for this extra; NULL if slot unused. [AI].
float m_speed
Animation speed for the extra; negative to indicate not set. [AI].
MxLong m_unk0x08
Last time this extra was updated or used, ms. [AI].
MxS32 m_characterId
Index into g_characters, currently loaded actor type. [AI].
MxBool m_unk0x14
TRUE if this extra is currently in a vehicle animation. [AI].
MxBool m_unk0x0c
Used to signal waiting for an animation activation. [AI].
[AI] Static definition of a vehicle, including its name and state flags.
MxBool m_unk0x04
TRUE if this vehicle is to be used in the next animation cycle. [AI].
MxBool m_unk0x05
TRUE if this vehicle is reserved by an actor present as an extra. [AI].
Vector3 * CWVertex(LegoWEEdge &p_face)
[AI] Returns the "clockwise" endpoint of this edge with respect to a given face.
Definition: legoedge.cpp:56
LegoEdge * GetCounterclockwiseEdge(LegoWEEdge &p_face)
[AI] Returns the counterclockwise adjacent edge relative to the given face.
Definition: legoedge.cpp:41
LegoEdge * GetClockwiseEdge(LegoWEEdge &p_face)
[AI] Returns the clockwise adjacent edge relative to the given face.
Definition: legoedge.cpp:27
Vector3 * CCWVertex(LegoWEEdge &p_face)
[AI] Returns the "counterclockwise" endpoint of this edge with respect to a given face.
Definition: legoedge.cpp:69
Defines a logical boundary associated with a location for things such as triggers,...
Definition: legolocations.h:24
MxS32 m_dest
Destination zone or tile index for this boundary. [AI].
Definition: legolocations.h:28
MxS32 m_src
Source zone or tile index for this boundary. [AI].
Definition: legolocations.h:26
MxBool m_unk0x10
Unknown flag. Presumed to control boundary activation/enabling or directionality. [AI].
Definition: legolocations.h:30
const char * m_name
Name of the boundary, typically referencing a map edge or connection. [AI].
Definition: legolocations.h:25
float m_destScale
Destination scaling factor. [AI].
Definition: legolocations.h:29
float m_srcScale
Source scaling factor, modifies transition logic or geometric mapping. [AI].
Definition: legolocations.h:27
Data structure representing a named spatial location and orientation in the LEGO Island world,...
Definition: legolocations.h:16
Boundary m_boundaryA
First logical boundary associated with this location, for zone transitions or triggers....
Definition: legolocations.h:38
float m_position[3]
Cartesian position of the location (x, y, z). [AI].
Definition: legolocations.h:35
Boundary m_boundaryB
Second logical boundary, enables junctions or asymmetric transitions. [AI].
Definition: legolocations.h:39
MxU8 m_frequency
Frequency or priority, may control how often this location is used/appears in algorithms....
Definition: legolocations.h:41
float m_direction[3]
Direction vector, describes primary view or travel direction. [AI].
Definition: legolocations.h:36
float m_up[3]
Up vector, for orientation (used in look-at or camera frames). [AI].
Definition: legolocations.h:37
MxBool m_unk0x5c
Unknown flag, seems to mark special locations or enable/disable associated logic. [AI].
Definition: legolocations.h:40
[AI] Holds transformation and animation information for a LEGO object/ROI, especially in the context ...
Definition: legotraninfo.h:17
MxU32 m_index
[AI] Index for this transform instance; often used to correlate to a list or animation track....
Definition: legotraninfo.h:49
MxBool m_unk0x14
[AI] Boolean flag for an unknown state, frequently used in transformation validity or activation gati...
Definition: legotraninfo.h:54
@ c_bit1
[AI] Unknown flag (likely used for specialized transformation states). [AI]
Definition: legotraninfo.h:20
@ c_bit2
[AI] Unknown flag (likely used for specialized transformation states). [AI]
Definition: legotraninfo.h:21
LegoROI * m_unk0x08
[AI] [AI_SUGGESTED_NAME: targetROI] Pointer to the LEGO ROI (object in world) this transformation app...
Definition: legotraninfo.h:50
MxBool m_unk0x15
[AI] Boolean flag set TRUE on construction, usage context required. Could indicate active/valid statu...
Definition: legotraninfo.h:55
AnimInfo * m_animInfo
[AI] Pointer to animation state information associated with this transformation instance (likely cont...
Definition: legotraninfo.h:48
MxMatrix m_unk0x2c
[AI] Current transformation matrix for this entry; reset to identity at construction and modified by ...
Definition: legotraninfo.h:62
MxLong * m_unk0x20
[AI] [AI_SUGGESTED_NAME: animationFramePtr] Pointer to a long integer, possibly for tracking current ...
Definition: legotraninfo.h:58
MxPresenter ** m_unk0x1c
[AI] [AI_SUGGESTED_NAME: presenterList] Pointer to an array of presenter objects. Allows for chained/...
Definition: legotraninfo.h:57
LegoAnimMMPresenter * m_presenter
[AI] Pointer to a specific animation presenter managing this transform's animation (controls playback...
Definition: legotraninfo.h:59
MxMatrix * m_unk0x0c
[AI] [AI_SUGGESTED_NAME: overrideMatrix] Optional pointer to a dynamically allocated matrix for custo...
Definition: legotraninfo.h:51
MxU32 m_objectId
[AI] Unique identifier for this object/transform pair; used for lookup or dispatch....
Definition: legotraninfo.h:56
MxU8 m_unk0x10
[AI] Unknown; likely used for frame counters, step markers, or status flags in animation/transformati...
Definition: legotraninfo.h:52
MxS16 m_location
[AI] Location index within a parent object, animation group, or part-based system....
Definition: legotraninfo.h:53
MxBool m_unk0x28
[AI] Another Boolean flag; TRUE by default. Likely used as part of a multi-flag state or for controll...
Definition: legotraninfo.h:60
MxBool m_unk0x29
[AI] Another Boolean flag; TRUE by default. Possibly for progression or sequencing within animation h...
Definition: legotraninfo.h:61
MxU32 m_flags
[AI] Miscellaneous flag word. Used for c_bit1, c_bit2, or internal mechanics related to transformatio...
Definition: legotraninfo.h:63
[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).
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...
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] Contains information about a model used in an animation, including name and orientation.
MxU8 m_unk0x2c
Unknown purpose, acts as a boolean/flag. [AI].
MxU8 m_unk0x04
Unknown byte flag. [AI].
char * m_name
Name of the model. [AI].
float m_location[3]
Location/origin for the model in 3D space. [AI].
float m_direction[3]
Forward/direction vector. [AI].
float m_up[3]
Up vector for the model orientation. [AI].
#define VPV3(to, v, w)
Definition: vec.h:370