Clear unknowns in Act3

This commit is contained in:
Fabian Neundorf 2025-07-31 12:51:39 +02:00
parent 2c20492bf6
commit a90d7f4839
5 changed files with 79 additions and 70 deletions

View File

@ -143,15 +143,15 @@ class Act3 : public LegoWorld {
MxResult ShootPizza(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); MxResult ShootPizza(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up);
MxResult ShootDonut(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); MxResult ShootDonut(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up);
void TriggerHitSound(undefined4 p_param1); void TriggerHitSound(undefined4 p_param1);
MxResult FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2); MxResult HitBrickster(Act3Ammo& p_ammo, const Vector3& p_param2);
MxResult FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2); MxResult HitCop(Act3Ammo& p_ammo, const Vector3& p_param2);
void SetBrickster(Act3Brickster* p_brickster); void SetBrickster(Act3Brickster* p_brickster);
void AddCop(Act3Cop* p_cop); void AddCop(Act3Cop* p_cop);
void FUN_10073400(); void TransitionToGoodEnding();
void FUN_10073430(); void TransitionToBadEnding();
void GoodEnding(const Matrix4& p_destination); void GoodEnding(const Matrix4& p_destination);
void BadEnding(const Matrix4& p_destination); void BadEnding(const Matrix4& p_destination);
void FUN_10073a60(); void DisableHelicopterDot();
// BETA indicates that the following classes access certain members directly. // BETA indicates that the following classes access certain members directly.
friend class Act3Ammo; friend class Act3Ammo;
@ -187,10 +187,10 @@ class Act3 : public LegoWorld {
MxU8 m_donutMissSound; // 0x421b MxU8 m_donutMissSound; // 0x421b
MxU8 m_islanderSound; // 0x421c MxU8 m_islanderSound; // 0x421c
MxU8 m_bricksterDonutSound; // 0x421d MxU8 m_bricksterDonutSound; // 0x421d
undefined m_unk0x421e; // 0x421e undefined m_helicopterDotCount; // 0x421e
Act3List m_unk0x4220; // 0x4220 Act3List m_soundList; // 0x4220
MxPresenter* m_helicopterDots[15]; // 0x4230 MxPresenter* m_helicopterDots[15]; // 0x4230
Act3Script::Script m_unk0x426c; // 0x426c Act3Script::Script m_explanationAnimation; // 0x426c
LegoGameState::Area m_destLocation; // 0x4270 LegoGameState::Area m_destLocation; // 0x4270
}; };

View File

@ -648,7 +648,7 @@ void Act3Brickster::Animate(float p_time)
assert(m_shootAnim && m_bInfo); assert(m_shootAnim && m_bInfo);
if (m_unk0x50 < p_time) { if (m_unk0x50 < p_time) {
((Act3*) m_world)->FUN_10073a60(); ((Act3*) m_world)->DisableHelicopterDot();
m_unk0x58 = 0; m_unk0x58 = 0;
assert(SoundManager()->GetCacheSoundManager()); assert(SoundManager()->GetCacheSoundManager());
SoundManager()->GetCacheSoundManager()->Play("thpt", NULL, FALSE); SoundManager()->GetCacheSoundManager()->Play("thpt", NULL, FALSE);

View File

@ -483,10 +483,10 @@ void Act3Ammo::Animate(float p_time)
if (!annihilated) { if (!annihilated) {
if (IsPizza()) { if (IsPizza()) {
m_world->FUN_10073360(*this, position); m_world->HitBrickster(*this, position);
} }
else { else {
m_world->FUN_10073390(*this, position); m_world->HitCop(*this, position);
} }
m_worldSpeed = -1.0f; m_worldSpeed = -1.0f;

View File

@ -430,10 +430,10 @@ void Helicopter::Animate(float p_time)
} }
else { else {
if (m_state->m_unk0x08 == 4) { if (m_state->m_unk0x08 == 4) {
((Act3*) m_world)->FUN_10073400(); ((Act3*) m_world)->TransitionToGoodEnding();
} }
else { else {
((Act3*) m_world)->FUN_10073430(); ((Act3*) m_world)->TransitionToBadEnding();
} }
SetActorState(c_disabled); SetActorState(c_disabled);

View File

@ -102,10 +102,10 @@ Act3Script::Script g_bricksterDonutSounds[] = {
}; };
// GLOBAL: LEGO1 0x100f7814 // GLOBAL: LEGO1 0x100f7814
MxU8 g_unk0x100f7814 = 0; MxU8 g_copSelector = 0;
// GLOBAL: LEGO1 0x100d95e8 // GLOBAL: LEGO1 0x100d95e8
Act3Script::Script g_unk0x100d95e8[] = Act3Script::Script g_explanationAnimations[] =
{Act3Script::c_tlp053in_RunAnim, Act3Script::c_tlp064la_RunAnim, Act3Script::c_tlp068in_RunAnim}; {Act3Script::c_tlp053in_RunAnim, Act3Script::c_tlp064la_RunAnim, Act3Script::c_tlp068in_RunAnim};
// FUNCTION: LEGO1 0x10071d40 // FUNCTION: LEGO1 0x10071d40
@ -246,7 +246,7 @@ Act3::Act3()
m_copter = NULL; m_copter = NULL;
m_shark = NULL; m_shark = NULL;
m_time = -1; m_time = -1;
m_unk0x421e = 0; m_helicopterDotCount = 0;
memset(m_helicopterDots, 0, sizeof(m_helicopterDots)); memset(m_helicopterDots, 0, sizeof(m_helicopterDots));
@ -326,7 +326,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
for (nextPizza = 0; nextPizza < (MxS32) sizeOfArray(m_pizzas); nextPizza++) { for (nextPizza = 0; nextPizza < (MxS32) sizeOfArray(m_pizzas); nextPizza++) {
if (!m_pizzas[nextPizza].IsValid()) { if (!m_pizzas[nextPizza].IsValid()) {
LegoPathBoundary* boundary = NULL; LegoPathBoundary* boundary = NULL;
MxU32 local18 = TRUE; MxU32 noBoundaryIntersected = TRUE;
m_pizzas[nextPizza].Create(this, TRUE, nextPizza); m_pizzas[nextPizza].Create(this, TRUE, nextPizza);
@ -334,26 +334,26 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
return FAILURE; return FAILURE;
} }
MxFloat unk0x19c = *m_pizzas[nextPizza].GetApexParameter(); MxFloat apexParameter = *m_pizzas[nextPizza].GetApexParameter();
if (p_controller->FindIntersectionBoundary( if (p_controller->FindIntersectionBoundary(
p_location, p_location,
p_direction, p_direction,
m_pizzas[nextPizza].GetCoefficients(), m_pizzas[nextPizza].GetCoefficients(),
boundary, boundary,
unk0x19c apexParameter
) == SUCCESS) { ) == SUCCESS) {
Mx3DPointFloat direction; Mx3DPointFloat direction;
direction = p_direction; direction = p_direction;
direction *= unk0x19c; direction *= apexParameter;
direction += p_location; direction += p_location;
assert(m_brickster && m_brickster->GetROI()); assert(m_brickster && m_brickster->GetROI());
direction -= m_brickster->GetROI()->GetLocal2World()[3]; direction -= m_brickster->GetROI()->GetLocal2World()[3];
local18 = FALSE; noBoundaryIntersected = FALSE;
if (m_pizzas[nextPizza].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) { if (m_pizzas[nextPizza].Shoot(p_controller, boundary, apexParameter) == SUCCESS) {
p_controller->PlaceActor(&m_pizzas[nextPizza]); p_controller->PlaceActor(&m_pizzas[nextPizza]);
boundary->AddActor(&m_pizzas[nextPizza]); boundary->AddActor(&m_pizzas[nextPizza]);
m_pizzas[nextPizza].SetWorldSpeed(10.0f); m_pizzas[nextPizza].SetWorldSpeed(10.0f);
@ -361,7 +361,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location,
} }
} }
if (local18 && m_pizzas[nextPizza].Shoot(p_controller, unk0x19c) == SUCCESS) { if (noBoundaryIntersected && m_pizzas[nextPizza].Shoot(p_controller, apexParameter) == SUCCESS) {
p_controller->PlaceActor(&m_pizzas[nextPizza]); p_controller->PlaceActor(&m_pizzas[nextPizza]);
m_pizzas[nextPizza].SetWorldSpeed(10.0f); m_pizzas[nextPizza].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
@ -389,22 +389,22 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location,
return FAILURE; return FAILURE;
} }
MxFloat unk0x19c = *m_donuts[nextDonut].GetApexParameter(); MxFloat apexParameter = *m_donuts[nextDonut].GetApexParameter();
if (p_controller->FindIntersectionBoundary( if (p_controller->FindIntersectionBoundary(
p_location, p_location,
p_direction, p_direction,
m_donuts[nextDonut].GetCoefficients(), m_donuts[nextDonut].GetCoefficients(),
boundary, boundary,
unk0x19c apexParameter
) == SUCCESS) { ) == SUCCESS) {
if (m_donuts[nextDonut].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) { if (m_donuts[nextDonut].Shoot(p_controller, boundary, apexParameter) == SUCCESS) {
p_controller->PlaceActor(&m_donuts[nextDonut]); p_controller->PlaceActor(&m_donuts[nextDonut]);
boundary->AddActor(&m_donuts[nextDonut]); boundary->AddActor(&m_donuts[nextDonut]);
m_donuts[nextDonut].SetWorldSpeed(10.0f); m_donuts[nextDonut].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
} }
} }
else if (m_donuts[nextDonut].Shoot(p_controller, unk0x19c) == SUCCESS) { else if (m_donuts[nextDonut].Shoot(p_controller, apexParameter) == SUCCESS) {
p_controller->PlaceActor(&m_donuts[nextDonut]); p_controller->PlaceActor(&m_donuts[nextDonut]);
m_donuts[nextDonut].SetWorldSpeed(10.0f); m_donuts[nextDonut].SetWorldSpeed(10.0f);
return SUCCESS; return SUCCESS;
@ -468,14 +468,14 @@ void Act3::TriggerHitSound(undefined4 p_param1)
m_bricksterDonutSound = 0; m_bricksterDonutSound = 0;
} }
m_unk0x4220.Insert(g_bricksterDonutSounds[m_bricksterDonutSound++], Act3ListElement::e_replaceAction); m_soundList.Insert(g_bricksterDonutSounds[m_bricksterDonutSound++], Act3ListElement::e_replaceAction);
return; return;
} }
default: default:
return; return;
} }
m_unk0x4220.Insert(objectId, Act3ListElement::e_onlyIfEmpty); m_soundList.Insert(objectId, Act3ListElement::e_onlyIfEmpty);
} }
// FUNCTION: LEGO1 0x10072c30 // FUNCTION: LEGO1 0x10072c30
@ -598,24 +598,24 @@ MxLong Act3::Notify(MxParam& p_param)
MxS32 length; MxS32 length;
LegoBuildingInfo* info = BuildingManager()->GetInfoArray(length); LegoBuildingInfo* info = BuildingManager()->GetInfoArray(length);
m_unk0x421e = 0; m_helicopterDotCount = 0;
while (--length >= 0) { while (--length >= 0) {
if (info[length].m_counter < 0 && info[length].m_boundary != NULL && if (info[length].m_counter < 0 && info[length].m_boundary != NULL &&
info[length].m_entity != NULL) { info[length].m_entity != NULL) {
m_unk0x421e++; m_helicopterDotCount++;
} }
} }
length = 0; length = 0;
m_unk0x421e--; m_helicopterDotCount--;
char buf[80]; char buf[80];
do { do {
sprintf(buf, "HelicopterDotOn%d_Bitmap", length + 1); sprintf(buf, "HelicopterDotOn%d_Bitmap", length + 1);
m_helicopterDots[length] = (MxPresenter*) Find("MxPresenter", buf); m_helicopterDots[length] = (MxPresenter*) Find("MxPresenter", buf);
if (m_unk0x421e > length) { if (m_helicopterDotCount > length) {
m_helicopterDots[length]->Enable(TRUE); m_helicopterDots[length]->Enable(TRUE);
} }
else { else {
@ -626,7 +626,7 @@ MxLong Act3::Notify(MxParam& p_param)
} while (length < (MxS32) sizeOfArray(m_helicopterDots)); } while (length < (MxS32) sizeOfArray(m_helicopterDots));
} }
else { else {
m_unk0x4220.RemoveByObjectIdOrFirst(param.GetAction()->GetObjectId()); m_soundList.RemoveByObjectIdOrFirst(param.GetAction()->GetObjectId());
} }
} }
break; break;
@ -646,7 +646,7 @@ MxLong Act3::Notify(MxParam& p_param)
case c_notificationEndAnim: case c_notificationEndAnim:
if (m_state->m_state == Act3State::e_ready) { if (m_state->m_state == Act3State::e_ready) {
assert(m_copter && m_brickster && m_cop1 && m_cop2); assert(m_copter && m_brickster && m_cop1 && m_cop2);
m_unk0x4220.RemoveByObjectIdOrFirst(0); m_soundList.RemoveByObjectIdOrFirst(0);
m_state->m_state = Act3State::e_initial; m_state->m_state = Act3State::e_initial;
Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
m_copter->HandleClick(); m_copter->HandleClick();
@ -682,9 +682,18 @@ void Act3::ReadyWorld()
AnimationManager()->FUN_1005f6d0(FALSE); AnimationManager()->FUN_1005f6d0(FALSE);
VideoManager()->Get3DManager()->SetFrustrum(90.0f, 0.1f, 125.0f); VideoManager()->Get3DManager()->SetFrustrum(90.0f, 0.1f, 125.0f);
m_unk0x426c = g_unk0x100d95e8[rand() % 3]; m_explanationAnimation = g_explanationAnimations[rand() % 3];
AnimationManager() AnimationManager()->FUN_10060dc0(
->FUN_10060dc0(m_unk0x426c, NULL, TRUE, LegoAnimationManager::e_unk0, NULL, TRUE, FALSE, FALSE, FALSE); m_explanationAnimation,
NULL,
TRUE,
LegoAnimationManager::e_unk0,
NULL,
TRUE,
FALSE,
FALSE,
FALSE
);
m_state->m_state = Act3State::e_ready; m_state->m_state = Act3State::e_ready;
} }
@ -697,11 +706,11 @@ MxResult Act3::Tickle()
return SUCCESS; return SUCCESS;
} }
if (m_unk0x426c != (Act3Script::Script) 0) { if (m_explanationAnimation != (Act3Script::Script) 0) {
if (AnimationManager()->FUN_10064ee0(m_unk0x426c)) { if (AnimationManager()->FUN_10064ee0(m_explanationAnimation)) {
Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
TickleManager()->UnregisterClient(this); TickleManager()->UnregisterClient(this);
m_unk0x426c = (Act3Script::Script) 0; m_explanationAnimation = (Act3Script::Script) 0;
} }
} }
@ -710,7 +719,7 @@ MxResult Act3::Tickle()
// FUNCTION: LEGO1 0x10073360 // FUNCTION: LEGO1 0x10073360
// FUNCTION: BETA10 0x100169d5 // FUNCTION: BETA10 0x100169d5
MxResult Act3::FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2) MxResult Act3::HitBrickster(Act3Ammo& p_ammo, const Vector3& p_param2)
{ {
assert(m_brickster); assert(m_brickster);
m_brickster->FUN_100417a0(p_ammo, p_param2); m_brickster->FUN_100417a0(p_ammo, p_param2);
@ -720,11 +729,11 @@ MxResult Act3::FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2)
// FUNCTION: LEGO1 0x10073390 // FUNCTION: LEGO1 0x10073390
// FUNCTION: BETA10 0x10016a40 // FUNCTION: BETA10 0x10016a40
MxResult Act3::FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2) MxResult Act3::HitCop(Act3Ammo& p_ammo, const Vector3& p_param2)
{ {
assert(m_cop1 && m_cop2); assert(m_cop1 && m_cop2);
if (!(g_unk0x100f7814 & 1)) { if (!(g_copSelector & 1)) {
m_cop1->FUN_10040350(p_ammo, p_param2); m_cop1->FUN_10040350(p_ammo, p_param2);
} }
else { else {
@ -732,7 +741,7 @@ MxResult Act3::FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2)
} }
TriggerHitSound(3); TriggerHitSound(3);
g_unk0x100f7814++; g_copSelector++;
return SUCCESS; return SUCCESS;
} }
@ -756,7 +765,7 @@ void Act3::SetBrickster(Act3Brickster* p_brickster)
} }
// FUNCTION: LEGO1 0x10073400 // FUNCTION: LEGO1 0x10073400
void Act3::FUN_10073400() void Act3::TransitionToGoodEnding()
{ {
m_state->m_state = Act3State::e_goodEnding; m_state->m_state = Act3State::e_goodEnding;
m_destLocation = LegoGameState::e_infomain; m_destLocation = LegoGameState::e_infomain;
@ -764,7 +773,7 @@ void Act3::FUN_10073400()
} }
// FUNCTION: LEGO1 0x10073430 // FUNCTION: LEGO1 0x10073430
void Act3::FUN_10073430() void Act3::TransitionToBadEnding()
{ {
m_state->m_state = Act3State::e_badEnding; m_state->m_state = Act3State::e_badEnding;
m_destLocation = LegoGameState::e_infomain; m_destLocation = LegoGameState::e_infomain;
@ -782,7 +791,7 @@ void Act3::GoodEnding(const Matrix4& p_destination)
m_brickster->SetActorState(LegoPathActor::c_disabled); m_brickster->SetActorState(LegoPathActor::c_disabled);
#ifndef BETA10 #ifndef BETA10
m_unk0x4220.Clear(); m_soundList.Clear();
m_copter->FUN_10004640(p_destination); m_copter->FUN_10004640(p_destination);
DebugPrintf("In Good Ending..."); DebugPrintf("In Good Ending...");
@ -865,7 +874,7 @@ void Act3::BadEnding(const Matrix4& p_destination)
m_cop2->SetActorState(LegoPathActor::c_disabled); m_cop2->SetActorState(LegoPathActor::c_disabled);
m_brickster->SetActorState(LegoPathActor::c_disabled); m_brickster->SetActorState(LegoPathActor::c_disabled);
m_unk0x4220.Clear(); m_soundList.Clear();
m_copter->FUN_10004670(p_destination); m_copter->FUN_10004670(p_destination);
DebugPrintf("In Bad Ending..."); DebugPrintf("In Bad Ending...");
@ -879,10 +888,10 @@ void Act3::BadEnding(const Matrix4& p_destination)
} }
// FUNCTION: LEGO1 0x10073a60 // FUNCTION: LEGO1 0x10073a60
void Act3::FUN_10073a60() void Act3::DisableHelicopterDot()
{ {
m_unk0x421e--; m_helicopterDotCount--;
m_helicopterDots[m_unk0x421e]->Enable(FALSE); m_helicopterDots[m_helicopterDotCount]->Enable(FALSE);
} }
// FUNCTION: LEGO1 0x10073a90 // FUNCTION: LEGO1 0x10073a90