Merge branch 'master' into more-skateboard-functions

This commit is contained in:
jonschz 2024-05-01 09:43:59 +02:00
commit bb323cfdeb
21 changed files with 542 additions and 245 deletions

View File

@ -18,15 +18,16 @@ struct AnimInfo {
char* m_animName; // 0x00
MxU32 m_objectId; // 0x04
MxS16 m_unk0x08; // 0x08
MxU8 m_unk0x0a; // 0x0a
MxBool m_unk0x0a; // 0x0a
MxU8 m_unk0x0b; // 0x0b
MxU8 m_unk0x0c; // 0x0c
MxU8 m_unk0x0d; // 0x0d
MxU32 m_unk0x10[4]; // 0x10
MxU8 m_modelCount; // 0x20
MxS16 m_unk0x22; // 0x22
ModelInfo* m_models; // 0x24
MxU8 m_unk0x28; // 0x28
MxU8 m_unk0x29; // 0x29
MxBool m_unk0x29; // 0x29
MxS8 m_unk0x2a[3]; // 0x2a
};

View File

@ -37,10 +37,10 @@ struct Vehicle {
// SIZE 0x18
struct Unknown0x3c {
LegoROI* m_roi; // 0x00
MxU32 m_id; // 0x04
MxS32 m_characterId; // 0x04
undefined m_unk0x08[0x08]; // 0x08
float m_unk0x10; // 0x10
undefined m_unk0x14; // 0x14
MxBool m_unk0x14; // 0x14
};
// VTABLE: LEGO1 0x100d8c18
@ -67,10 +67,10 @@ class LegoAnimationManager : public MxCore {
}
void Reset(MxBool p_und);
void FUN_1005ef10();
void FUN_1005f0b0();
void FUN_1005f6d0(MxBool);
void FUN_1005f700(MxBool);
void Suspend();
void Resume();
void FUN_1005f6d0(MxBool p_unk0x400);
void FUN_1005f700(MxBool p_unk0x3a);
MxResult LoadScriptInfo(MxS32 p_scriptIndex);
MxBool FindVehicle(const char* p_name, MxU32& p_index);
MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info);
@ -80,13 +80,13 @@ class LegoAnimationManager : public MxCore {
MxResult FUN_10060dc0(
IsleScript::Script p_objectId,
MxMatrix* p_matrix,
undefined p_param3,
MxBool p_param3,
undefined p_param4,
undefined4 p_param5,
undefined p_param6,
LegoROI* p_roi,
MxBool p_param6,
MxBool p_param7,
MxBool p_param8,
undefined p_param9
MxBool p_param9
);
void FUN_10061010(undefined4);
void FUN_100617c0(MxS32, MxU16&, MxU16&);
@ -108,21 +108,25 @@ class LegoAnimationManager : public MxCore {
void Init();
MxResult FUN_100605e0(
MxU32 p_index,
MxU8 p_unk0x0a,
MxBool p_unk0x0a,
MxMatrix* p_matrix,
undefined,
undefined4,
undefined,
MxBool,
MxBool,
undefined
MxBool p_bool1,
LegoROI* p_roi,
MxBool p_bool2,
MxBool p_bool3,
MxBool p_bool4,
MxBool p_bool5
);
MxResult FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2);
void DeleteAnimations();
MxS8 GetCharacterIndex(const char* p_name);
MxBool FUN_100623a0(AnimInfo& p_info);
void FUN_10062580(AnimInfo& p_info);
MxBool FUN_10062710(AnimInfo& p_info);
void FUN_10063aa0();
void FUN_100648f0(LegoTranInfo*, MxLong);
MxU32 m_scriptIndex; // 0x08
MxS32 m_scriptIndex; // 0x08
MxU16 m_animCount; // 0x0c
MxU16 m_unk0x0e; // 0x0e
MxU16 m_unk0x10; // 0x10
@ -136,10 +140,10 @@ class LegoAnimationManager : public MxCore {
MxLong m_unk0x30[2]; // 0x30
MxBool m_unk0x38; // 0x38
MxBool m_unk0x39; // 0x39
undefined m_unk0x3a; // 0x3a
MxBool m_unk0x3a; // 0x3a
Unknown0x3c m_unk0x3c[40]; // 0x3c
undefined4 m_unk0x3fc; // 0x3fc
MxU8 m_unk0x400; // 0x400
MxBool m_unk0x400; // 0x400
undefined m_unk0x401; // 0x401
MxU8 m_unk0x402; // 0x402
MxLong m_unk0x404; // 0x404
@ -151,10 +155,10 @@ class LegoAnimationManager : public MxCore {
undefined4 m_unk0x41c; // 0x41c
AnimState* m_animState; // 0x420
LegoROIList* m_unk0x424; // 0x424
undefined m_unk0x428; // 0x428
undefined m_unk0x429; // 0x429
MxBool m_unk0x428; // 0x428
MxBool m_unk0x429; // 0x429
undefined m_unk0x42a; // 0x42a
undefined m_unk0x42b; // 0x42b
MxBool m_suspended; // 0x42b
undefined4 m_unk0x42c; // 0x42c
undefined m_unk0x430; // 0x430
undefined4 m_unk0x434[2]; // 0x434

View File

@ -40,7 +40,7 @@ struct LegoCharacter {
MxU32 m_refCount; // 0x04
};
struct LegoCharacterData;
struct LegoCharacterInfo;
typedef map<char*, LegoCharacter*, LegoCharacterComparator> LegoCharacterMap;
@ -64,8 +64,8 @@ class LegoCharacterManager {
void FUN_10083f10(LegoROI* p_roi);
MxBool FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_textureInfo);
LegoExtraActor* GetActor(const char* p_key);
LegoCharacterData* GetData(const char* p_key);
LegoCharacterData* GetData(LegoROI* p_roi);
LegoCharacterInfo* GetInfo(const char* p_key);
LegoCharacterInfo* GetInfo(LegoROI* p_roi);
MxBool SwitchHat(LegoROI* p_roi);
MxU32 FUN_10085140(LegoROI* p_roi, MxBool p_und);
LegoROI* FUN_10085210(const char* p_name, const char* p_lodName, MxBool p_createEntity);

View File

@ -8,7 +8,7 @@ class LegoExtraActor;
class LegoROI;
// SIZE 0x108
struct LegoCharacterData {
struct LegoCharacterInfo {
// SIZE 0x18
struct Part {
MxU8* m_unk0x00; // 0x00
@ -45,7 +45,34 @@ struct LegoCharacterLOD {
float m_up[3]; // 0x4c
};
extern LegoCharacterData g_characterDataInit[66];
enum LegoCharacterLODs {
c_topLOD,
c_bodyLOD,
c_infohatLOD,
c_infogronLOD,
c_headLOD,
c_armlftLOD,
c_armrtLOD,
c_clawlftLOD,
c_clawrtLOD,
c_leglftLOD,
c_legrtLOD
};
enum LegoCharacterParts {
c_bodyPart,
c_infohatPart,
c_infogronPart,
c_headPart,
c_armlftPart,
c_armrtPart,
c_clawlftPart,
c_clawrtPart,
c_leglftPart,
c_legrtPart
};
extern LegoCharacterInfo g_characterInfoInit[66];
extern LegoCharacterLOD g_characterLODs[11];
#endif // LEGOCHARACTERS_H

View File

@ -4,6 +4,7 @@
#include "decomp.h"
#include "mxgeometry/mxmatrix.h"
struct AnimInfo;
class LegoAnimMMPresenter;
// SIZE 0x78
@ -30,7 +31,7 @@ struct LegoTranInfo {
m_unk0x2c.SetIdentity();
}
undefined4 m_unk0x00; // 0x00
AnimInfo* m_animInfo; // 0x00
MxU32 m_index; // 0x04
LegoROI* m_unk0x08; // 0x08
MxMatrix* m_unk0x0c; // 0x0c

View File

@ -64,10 +64,4 @@ void PlayMusic(JukeboxScript::Script p_script);
void SetIsWorldActive(MxBool p_isWorldActive);
void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last);
// FUNCTION: LEGO1 0x10015890
inline MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction)
{
return LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction);
}
#endif // MISC_H

View File

@ -80,7 +80,7 @@ void Radio::Stop()
if (m_state->IsActive()) {
LegoWorld* world = CurrentWorld();
MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtom(), 18);
MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtom(), IsleScript::c_Radio_Ctl);
if (presenter) {
presenter->VTable0x6c(0);

View File

@ -158,8 +158,8 @@ void LegoAnimationManager::Reset(MxBool p_und)
m_animState->SetFlag();
}
undefined unk0x42b = m_unk0x42b;
FUN_1005ef10();
MxBool suspended = m_suspended;
Suspend();
if (m_tranInfoList != NULL) {
delete m_tranInfoList;
@ -172,22 +172,93 @@ void LegoAnimationManager::Reset(MxBool p_und)
DeleteAnimations();
Init();
m_unk0x42b = unk0x42b;
m_suspended = suspended;
m_unk0x428 = m_unk0x3a;
m_unk0x429 = m_unk0x400;
m_unk0x42a = m_unk0x402;
}
// STUB: LEGO1 0x1005ef10
void LegoAnimationManager::FUN_1005ef10()
// FUNCTION: LEGO1 0x1005ef10
// FUNCTION: BETA10 0x1003fc7a
void LegoAnimationManager::Suspend()
{
// TODO
m_animState = (AnimState*) GameState()->GetState("AnimState");
if (m_animState == NULL) {
m_animState = (AnimState*) GameState()->CreateState("AnimState");
}
if (m_scriptIndex == 0) {
m_animState->FUN_10065240(m_animCount, m_anims, m_unk0x3fc);
}
if (!m_suspended) {
m_suspended = TRUE;
m_unk0x428 = m_unk0x3a;
m_unk0x429 = m_unk0x400;
m_unk0x42a = m_unk0x402;
m_unk0x402 = 0;
FUN_10061010(0);
MxS32 i;
for (i = 0; i < (MxS32) _countof(m_unk0x3c); i++) {
LegoROI* roi = m_unk0x3c[i].m_roi;
if (roi != NULL) {
LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName());
if (actor != NULL && actor->GetController() != NULL) {
actor->GetController()->FUN_10046770(actor);
actor->ClearController();
}
CharacterManager()->FUN_10083db0(roi);
}
if (m_unk0x3c[i].m_unk0x14) {
m_unk0x3c[i].m_unk0x14 = FALSE;
MxS32 vehicleId = g_characters[m_unk0x3c[i].m_characterId].m_vehicleId;
if (vehicleId >= 0) {
g_vehicles[vehicleId].m_unk0x05 = FALSE;
LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name);
if (roi != NULL) {
roi->SetVisibility(FALSE);
}
}
}
m_unk0x3c[i].m_roi = NULL;
m_unk0x3c[i].m_characterId = -1;
m_unk0x3c[i].m_unk0x10 = -1.0f;
}
m_unk0x18 = 0;
m_unk0x1a = 0;
m_unk0x3a = FALSE;
m_unk0x400 = FALSE;
m_unk0x414 = 0;
m_unk0x401 = 0;
for (i = 0; i < (MxS32) _countof(g_characters); i++) {
g_characters[i].m_unk0x04 = FALSE;
}
}
}
// STUB: LEGO1 0x1005f0b0
void LegoAnimationManager::FUN_1005f0b0()
// FUNCTION: LEGO1 0x1005f0b0
// FUNCTION: BETA10 0x1003fefe
void LegoAnimationManager::Resume()
{
// TODO
if (m_suspended) {
m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime();
m_unk0x410 = 5000;
m_unk0x3a = m_unk0x428;
m_unk0x400 = m_unk0x429;
m_unk0x402 = m_unk0x42a;
m_suspended = FALSE;
}
}
// FUNCTION: LEGO1 0x1005f130
@ -212,22 +283,22 @@ void LegoAnimationManager::Init()
for (i = 0; i < (MxS32) _countof(m_unk0x3c); i++) {
m_unk0x3c[i].m_roi = NULL;
m_unk0x3c[i].m_id = -1;
m_unk0x3c[i].m_characterId = -1;
m_unk0x3c[i].m_unk0x10 = -1.0f;
m_unk0x3c[i].m_unk0x14 = 0;
m_unk0x3c[i].m_unk0x14 = FALSE;
}
m_unk0x38 = FALSE;
m_unk0x39 = FALSE;
m_unk0x3a = 1;
m_unk0x3a = TRUE;
m_unk0x3fc = 0;
m_unk0x400 = 0;
m_unk0x400 = FALSE;
m_unk0x414 = 0;
m_unk0x418 = 5;
m_unk0x0e = 0;
m_unk0x10 = 0;
m_unk0x401 = 0;
m_unk0x42b = 0;
m_suspended = FALSE;
m_unk0x430 = 0;
m_unk0x42c = 0;
m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime();
@ -251,16 +322,32 @@ void LegoAnimationManager::Init()
m_unk0x424 = new LegoROIList();
}
// STUB: LEGO1 0x1005f6d0
void LegoAnimationManager::FUN_1005f6d0(MxBool)
// FUNCTION: LEGO1 0x1005f6d0
// FUNCTION: BETA10 0x100401e7
void LegoAnimationManager::FUN_1005f6d0(MxBool p_unk0x400)
{
// TODO
if (m_suspended) {
m_unk0x429 = p_unk0x400;
}
else {
m_unk0x400 = p_unk0x400;
if (!p_unk0x400) {
FUN_100627d0(TRUE);
}
}
}
// STUB: LEGO1 0x1005f700
void LegoAnimationManager::FUN_1005f700(MxBool)
// FUNCTION: LEGO1 0x1005f700
// FUNCTION: BETA10 0x1004024c
void LegoAnimationManager::FUN_1005f700(MxBool p_unk0x3a)
{
// TODO
if (m_suspended) {
m_unk0x428 = p_unk0x3a;
}
else {
m_unk0x3a = p_unk0x3a;
}
}
// FUNCTION: LEGO1 0x1005f720
@ -364,7 +451,7 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex)
}
m_anims[j].m_unk0x28 = GetCharacterIndex(m_anims[j].m_animName + strlen(m_anims[j].m_animName) - 2);
m_anims[j].m_unk0x29 = 0;
m_anims[j].m_unk0x29 = FALSE;
for (k = 0; k < 3; k++) {
m_anims[j].m_unk0x2a[k] = -1;
@ -402,12 +489,12 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex)
result = SUCCESS;
m_unk0x402 = 1;
if (m_unk0x42b) {
if (m_suspended) {
m_unk0x428 = m_unk0x3a;
m_unk0x429 = m_unk0x400;
m_unk0x42a = 1;
m_unk0x3a = 0;
m_unk0x400 = 0;
m_unk0x3a = FALSE;
m_unk0x400 = FALSE;
m_unk0x402 = 0;
}
@ -541,7 +628,7 @@ MxResult LegoAnimationManager::ReadModelInfo(LegoFile* p_file, ModelInfo* p_info
// FUNCTION: LEGO1 0x100603c0
void LegoAnimationManager::DeleteAnimations()
{
undefined unk0x42b = m_unk0x42b;
MxBool suspended = m_suspended;
if (m_anims != NULL) {
for (MxS32 i = 0; i < m_animCount; i++) {
@ -560,7 +647,7 @@ void LegoAnimationManager::DeleteAnimations()
}
Init();
m_unk0x42b = unk0x42b;
m_suspended = suspended;
}
// STUB: LEGO1 0x10060570
@ -569,22 +656,100 @@ void LegoAnimationManager::FUN_10060570(MxBool)
// TODO
}
// STUB: LEGO1 0x100605e0
// FUNCTION: LEGO1 0x100605e0
// FUNCTION: BETA10 0x1004152b
MxResult LegoAnimationManager::FUN_100605e0(
MxU32 p_index,
MxU8 p_unk0x0a,
MxBool p_unk0x0a,
MxMatrix* p_matrix,
undefined,
undefined4,
undefined,
MxBool,
MxBool,
undefined
MxBool p_bool1,
LegoROI* p_roi,
MxBool p_bool2,
MxBool p_bool3,
MxBool p_bool4,
MxBool p_bool5
)
{
// TODO
return FAILURE;
MxResult result = FAILURE;
if (m_scriptIndex != -1 && p_index < m_animCount && m_tranInfoList != NULL) {
FUN_100627d0(FALSE);
FUN_10062770();
MxDSAction action;
AnimInfo& animInfo = m_anims[p_index];
if (!p_bool1) {
if (m_unk0x39 || !animInfo.m_unk0x29) {
return FAILURE;
}
if (FUN_100623a0(animInfo)) {
return FAILURE;
}
if (FUN_10062710(animInfo)) {
return FAILURE;
}
}
FUN_10062580(animInfo);
LegoTranInfo* tranInfo = new LegoTranInfo();
tranInfo->m_animInfo = &animInfo;
tranInfo->m_index = ++m_unk0x1c;
tranInfo->m_unk0x10 = 0;
tranInfo->m_unk0x08 = p_roi;
tranInfo->m_unk0x12 = m_anims[p_index].m_unk0x08;
tranInfo->m_unk0x14 = p_unk0x0a;
tranInfo->m_objectId = animInfo.m_objectId;
tranInfo->m_unk0x15 = p_bool2;
if (p_matrix != NULL) {
tranInfo->m_unk0x0c = new MxMatrix(*p_matrix);
}
tranInfo->m_unk0x1c = m_unk0x28;
tranInfo->m_unk0x20 = m_unk0x30;
tranInfo->m_unk0x28 = p_bool3;
tranInfo->m_unk0x29 = p_bool4;
if (m_tranInfoList != NULL) {
m_tranInfoList->Append(tranInfo);
}
char buf[256];
sprintf(buf, "%s:%d", g_strANIMMAN_ID, tranInfo->m_index);
action.SetAtomId(*Lego()->GetScriptAtom(m_scriptIndex));
action.SetObjectId(animInfo.m_objectId);
action.SetUnknown24(-1);
action.AppendExtra(strlen(buf) + 1, buf);
if (StartActionIfUnknown0x13c(action) == SUCCESS) {
BackgroundAudioManager()->LowerVolume();
tranInfo->m_flags |= LegoTranInfo::c_bit2;
animInfo.m_unk0x22++;
m_unk0x404 = Timer()->GetTime();
if (p_bool5) {
FUN_100648f0(tranInfo, m_unk0x404);
}
else if (p_unk0x0a) {
IslePathActor* actor = CurrentActor();
if (actor != NULL) {
actor->SetState(4);
actor->SetWorldSpeed(0.0f);
}
}
m_unk0x39 = TRUE;
result = SUCCESS;
}
}
return result;
}
// FUNCTION: LEGO1 0x100609f0
@ -597,12 +762,12 @@ MxResult LegoAnimationManager::FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix
FUN_100627d0(FALSE);
LegoTranInfo* info = new LegoTranInfo();
info->m_unk0x00 = 0;
info->m_animInfo = NULL;
info->m_index = ++m_unk0x1c;
info->m_unk0x10 = 0;
info->m_unk0x08 = NULL;
info->m_unk0x12 = -1;
info->m_unk0x14 = 0;
info->m_unk0x14 = FALSE;
info->m_objectId = p_objectId;
if (p_matrix != NULL) {
@ -657,7 +822,7 @@ MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEnt
for (MxS32 i = 0; i < (MxS32) _countof(m_unk0x3c); i++) {
if (m_unk0x3c[i].m_roi == roi) {
MxU32 characterId = m_unk0x3c[i].m_id;
MxS32 characterId = m_unk0x3c[i].m_characterId;
g_characters[characterId].m_unk0x07 = TRUE;
MxS32 vehicleId = g_characters[characterId].m_vehicleId;
@ -671,7 +836,7 @@ MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEnt
}
}
if (StartActionIfUnknown0x13c(p_dsAction) == SUCCESS) {
if (LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction) == SUCCESS) {
result = SUCCESS;
}
@ -683,13 +848,13 @@ MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEnt
MxResult LegoAnimationManager::FUN_10060dc0(
IsleScript::Script p_objectId,
MxMatrix* p_matrix,
undefined p_param3,
MxBool p_param3,
undefined p_param4,
undefined4 p_param5,
undefined p_param6,
LegoROI* p_roi,
MxBool p_param6,
MxBool p_param7,
MxBool p_param8,
undefined p_param9
MxBool p_param9
)
{
MxResult result = FAILURE;
@ -702,21 +867,21 @@ MxResult LegoAnimationManager::FUN_10060dc0(
for (MxS32 i = 0; i < m_animCount; i++) {
if (m_anims[i].m_objectId == p_objectId) {
found = TRUE;
undefined unk0x0a;
MxBool unk0x0a;
switch (p_param4) {
case 0:
unk0x0a = m_anims[i].m_unk0x0a;
break;
case 1:
unk0x0a = 1;
unk0x0a = TRUE;
break;
default:
unk0x0a = 0;
unk0x0a = FALSE;
break;
}
result = FUN_100605e0(i, unk0x0a, p_matrix, p_param3, p_param5, p_param6, p_param7, p_param8, p_param9);
result = FUN_100605e0(i, unk0x0a, p_matrix, p_param3, p_roi, p_param6, p_param7, p_param8, p_param9);
break;
}
}
@ -787,6 +952,29 @@ MxS8 LegoAnimationManager::GetCharacterIndex(const char* p_name)
return -1;
}
// STUB: LEGO1 0x100623a0
// FUNCTION: BETA10 0x10043342
MxBool LegoAnimationManager::FUN_100623a0(AnimInfo& p_info)
{
// TODO
return FALSE;
}
// STUB: LEGO1 0x10062580
// FUNCTION: BETA10 0x10043552
void LegoAnimationManager::FUN_10062580(AnimInfo& p_info)
{
// TODO
}
// STUB: LEGO1 0x10062710
// FUNCTION: BETA10 0x10043787
MxBool LegoAnimationManager::FUN_10062710(AnimInfo& p_info)
{
// TODO
return FALSE;
}
// FUNCTION: LEGO1 0x10062770
// FUNCTION: BETA10 0x1004381a
void LegoAnimationManager::FUN_10062770()
@ -862,3 +1050,10 @@ void LegoAnimationManager::FUN_10064740(MxBool)
{
// TODO
}
// STUB: LEGO1 0x100648f0
// FUNCTION: BETA10 0x10045daf
void LegoAnimationManager::FUN_100648f0(LegoTranInfo*, MxLong)
{
// TODO
}

View File

@ -35,7 +35,7 @@ MxU32 g_unk0x100fc4ec = 2;
MxU32 g_unk0x100fc4f0 = 0;
// GLOBAL: LEGO1 0x10104f20
LegoCharacterData g_characterData[66];
LegoCharacterInfo g_chracterInfo[66];
// FUNCTION: LEGO1 0x10082a20
LegoCharacterManager::LegoCharacterManager()
@ -50,22 +50,22 @@ LegoCharacterManager::LegoCharacterManager()
// FUNCTION: LEGO1 0x10083270
void LegoCharacterManager::Init()
{
for (MxS32 i = 0; i < _countof(g_characterData); i++) {
g_characterData[i] = g_characterDataInit[i];
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
g_chracterInfo[i] = g_characterInfoInit[i];
}
}
// FUNCTION: LEGO1 0x100832a0
void LegoCharacterManager::FUN_100832a0()
{
for (MxS32 i = 0; i < _countof(g_characterData); i++) {
LegoCharacterData* data = GetData(g_characterData[i].m_name);
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = GetInfo(g_chracterInfo[i].m_name);
if (data != NULL) {
LegoExtraActor* actor = data->m_actor;
if (info != NULL) {
LegoExtraActor* actor = info->m_actor;
if (actor != NULL && actor->IsA("LegoExtraActor")) {
LegoROI* roi = g_characterData[i].m_roi;
LegoROI* roi = g_chracterInfo[i].m_roi;
MxU32 refCount = GetRefCount(roi);
while (refCount != 0) {
@ -82,37 +82,46 @@ MxResult LegoCharacterManager::Write(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_characterData); i++) {
LegoCharacterData* data = &g_characterData[i];
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = &g_chracterInfo[i];
if (p_storage->Write(&data->m_unk0x0c, sizeof(data->m_unk0x0c)) != SUCCESS) {
if (p_storage->Write(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_unk0x10, sizeof(data->m_unk0x10)) != SUCCESS) {
if (p_storage->Write(&info->m_unk0x10, sizeof(info->m_unk0x10)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_unk0x14, sizeof(data->m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_unk0x14, sizeof(info->m_unk0x14)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[1].m_unk0x08, sizeof(data->m_parts[1].m_unk0x08)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_infohatPart].m_unk0x08, sizeof(info->m_parts[c_infohatPart].m_unk0x08)) !=
SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[1].m_unk0x14, sizeof(data->m_parts[1].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_infohatPart].m_unk0x14, sizeof(info->m_parts[c_infohatPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[2].m_unk0x14, sizeof(data->m_parts[2].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(
&info->m_parts[c_infogronPart].m_unk0x14,
sizeof(info->m_parts[c_infogronPart].m_unk0x14)
) != SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[4].m_unk0x14, sizeof(data->m_parts[4].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_armlftPart].m_unk0x14, sizeof(info->m_parts[c_armlftPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[5].m_unk0x14, sizeof(data->m_parts[5].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_armrtPart].m_unk0x14, sizeof(info->m_parts[c_armrtPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[8].m_unk0x14, sizeof(data->m_parts[8].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_leglftPart].m_unk0x14, sizeof(info->m_parts[c_leglftPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Write(&data->m_parts[9].m_unk0x14, sizeof(data->m_parts[9].m_unk0x14)) != SUCCESS) {
if (p_storage->Write(&info->m_parts[c_legrtPart].m_unk0x14, sizeof(info->m_parts[c_legrtPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
}
@ -128,37 +137,46 @@ MxResult LegoCharacterManager::Read(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_characterData); i++) {
LegoCharacterData* data = &g_characterData[i];
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = &g_chracterInfo[i];
if (p_storage->Read(&data->m_unk0x0c, sizeof(data->m_unk0x0c)) != SUCCESS) {
if (p_storage->Read(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_unk0x10, sizeof(data->m_unk0x10)) != SUCCESS) {
if (p_storage->Read(&info->m_unk0x10, sizeof(info->m_unk0x10)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_unk0x14, sizeof(data->m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_unk0x14, sizeof(info->m_unk0x14)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[1].m_unk0x08, sizeof(data->m_parts[1].m_unk0x08)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_infohatPart].m_unk0x08, sizeof(info->m_parts[c_infohatPart].m_unk0x08)) !=
SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[1].m_unk0x14, sizeof(data->m_parts[1].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_infohatPart].m_unk0x14, sizeof(info->m_parts[c_infohatPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[2].m_unk0x14, sizeof(data->m_parts[2].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(
&info->m_parts[c_infogronPart].m_unk0x14,
sizeof(info->m_parts[c_infogronPart].m_unk0x14)
) != SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[4].m_unk0x14, sizeof(data->m_parts[4].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_armlftPart].m_unk0x14, sizeof(info->m_parts[c_armlftPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[5].m_unk0x14, sizeof(data->m_parts[5].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_armrtPart].m_unk0x14, sizeof(info->m_parts[c_armrtPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[8].m_unk0x14, sizeof(data->m_parts[8].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_leglftPart].m_unk0x14, sizeof(info->m_parts[c_leglftPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
if (p_storage->Read(&data->m_parts[9].m_unk0x14, sizeof(data->m_parts[9].m_unk0x14)) != SUCCESS) {
if (p_storage->Read(&info->m_parts[c_legrtPart].m_unk0x14, sizeof(info->m_parts[c_legrtPart].m_unk0x14)) !=
SUCCESS) {
goto done;
}
}
@ -213,7 +231,7 @@ LegoROI* LegoCharacterManager::GetROI(const char* p_key, MxBool p_createEntity)
actor->SetROI(character->m_roi, FALSE, FALSE);
actor->SetType(LegoEntity::e_character);
actor->SetFlag(LegoActor::c_bit2);
GetData(p_key)->m_actor = actor;
GetInfo(p_key)->m_actor = actor;
}
return character->m_roi;
@ -250,7 +268,7 @@ void LegoCharacterManager::FUN_10083c30(const char* p_name)
character = (*it).second;
if (character->RemoveRef() == 0) {
LegoCharacterData* data = GetData(p_name);
LegoCharacterInfo* info = GetInfo(p_name);
LegoEntity* entity = character->m_roi->GetEntity();
if (entity != NULL) {
@ -264,18 +282,18 @@ void LegoCharacterManager::FUN_10083c30(const char* p_name)
m_characters->erase(it);
if (data != NULL) {
if (data->m_actor != NULL) {
data->m_actor->ClearFlag(LegoEntity::c_bit2);
delete data->m_actor;
if (info != NULL) {
if (info->m_actor != NULL) {
info->m_actor->ClearFlag(LegoEntity::c_bit2);
delete info->m_actor;
}
else if (entity != NULL && entity->GetFlagsIsSet(LegoEntity::c_bit2)) {
entity->ClearFlag(LegoEntity::c_bit2);
delete entity;
}
data->m_roi = NULL;
data->m_actor = NULL;
info->m_roi = NULL;
info->m_actor = NULL;
}
}
}
@ -292,7 +310,7 @@ void LegoCharacterManager::FUN_10083db0(LegoROI* p_roi)
if (character->m_roi == p_roi) {
if (character->RemoveRef() == 0) {
LegoCharacterData* data = GetData(character->m_roi->GetName());
LegoCharacterInfo* info = GetInfo(character->m_roi->GetName());
LegoEntity* entity = character->m_roi->GetEntity();
if (entity != NULL) {
@ -306,18 +324,18 @@ void LegoCharacterManager::FUN_10083db0(LegoROI* p_roi)
m_characters->erase(it);
if (data != NULL) {
if (data->m_actor != NULL) {
data->m_actor->ClearFlag(LegoEntity::c_bit2);
delete data->m_actor;
if (info != NULL) {
if (info->m_actor != NULL) {
info->m_actor->ClearFlag(LegoEntity::c_bit2);
delete info->m_actor;
}
else if (entity != NULL && entity->GetFlagsIsSet(LegoEntity::c_bit2)) {
entity->ClearFlag(LegoEntity::c_bit2);
delete entity;
}
data->m_roi = NULL;
data->m_actor = NULL;
info->m_roi = NULL;
info->m_actor = NULL;
}
}
@ -381,39 +399,39 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key)
Tgl::Renderer* renderer = VideoManager()->GetRenderer();
ViewLODListManager* lodManager = GetViewLODListManager();
LegoTextureContainer* textureContainer = TextureContainer();
LegoCharacterData* data = GetData(p_key);
LegoCharacterInfo* info = GetInfo(p_key);
if (data == NULL) {
if (info == NULL) {
goto done;
}
if (!strcmpi(p_key, "pep")) {
LegoCharacterData* pepper = GetData("pepper");
LegoCharacterInfo* pepper = GetInfo("pepper");
data->m_unk0x0c = pepper->m_unk0x0c;
data->m_unk0x10 = pepper->m_unk0x10;
data->m_unk0x14 = pepper->m_unk0x14;
info->m_unk0x0c = pepper->m_unk0x0c;
info->m_unk0x10 = pepper->m_unk0x10;
info->m_unk0x14 = pepper->m_unk0x14;
for (i = 0; i < _countof(data->m_parts); i++) {
data->m_parts[i] = pepper->m_parts[i];
for (i = 0; i < _countof(info->m_parts); i++) {
info->m_parts[i] = pepper->m_parts[i];
}
}
roi = new LegoROI(renderer);
roi->SetName(p_key);
boundingSphere.Center()[0] = g_characterLODs[0].m_boundingSphere[0];
boundingSphere.Center()[1] = g_characterLODs[0].m_boundingSphere[1];
boundingSphere.Center()[2] = g_characterLODs[0].m_boundingSphere[2];
boundingSphere.Radius() = g_characterLODs[0].m_boundingSphere[3];
boundingSphere.Center()[0] = g_characterLODs[c_topLOD].m_boundingSphere[0];
boundingSphere.Center()[1] = g_characterLODs[c_topLOD].m_boundingSphere[1];
boundingSphere.Center()[2] = g_characterLODs[c_topLOD].m_boundingSphere[2];
boundingSphere.Radius() = g_characterLODs[c_topLOD].m_boundingSphere[3];
roi->SetBoundingSphere(boundingSphere);
boundingBox.Min()[0] = g_characterLODs[0].m_boundingBox[0];
boundingBox.Min()[1] = g_characterLODs[0].m_boundingBox[1];
boundingBox.Min()[2] = g_characterLODs[0].m_boundingBox[2];
boundingBox.Max()[0] = g_characterLODs[0].m_boundingBox[3];
boundingBox.Max()[1] = g_characterLODs[0].m_boundingBox[4];
boundingBox.Max()[2] = g_characterLODs[0].m_boundingBox[5];
boundingBox.Min()[0] = g_characterLODs[c_topLOD].m_boundingBox[0];
boundingBox.Min()[1] = g_characterLODs[c_topLOD].m_boundingBox[1];
boundingBox.Min()[2] = g_characterLODs[c_topLOD].m_boundingBox[2];
boundingBox.Max()[0] = g_characterLODs[c_topLOD].m_boundingBox[3];
boundingBox.Max()[1] = g_characterLODs[c_topLOD].m_boundingBox[4];
boundingBox.Max()[2] = g_characterLODs[c_topLOD].m_boundingBox[5];
roi->SetUnknown0x80(boundingBox);
comp = new CompoundObject();
@ -421,7 +439,7 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key)
for (i = 0; i < _countof(g_characterLODs) - 1; i++) {
char lodName[256];
LegoCharacterData::Part& part = data->m_parts[i];
LegoCharacterInfo::Part& part = info->m_parts[i];
const char* parentName;
if (i == 0 || i == 1) {
@ -495,14 +513,14 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key)
}
CalcLocalTransform(
Mx3DPointFloat(g_characterLODs[0].m_position),
Mx3DPointFloat(g_characterLODs[0].m_direction),
Mx3DPointFloat(g_characterLODs[0].m_up),
Mx3DPointFloat(g_characterLODs[c_topLOD].m_position),
Mx3DPointFloat(g_characterLODs[c_topLOD].m_direction),
Mx3DPointFloat(g_characterLODs[c_topLOD].m_up),
mat
);
roi->WrappedSetLocalTransform(mat);
data->m_roi = roi;
info->m_roi = roi;
success = TRUE;
done:
@ -519,12 +537,12 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key)
MxBool LegoCharacterManager::FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_textureInfo)
{
LegoResult result = SUCCESS;
LegoROI* head = FindChildROI(p_roi, g_characterLODs[4].m_name);
LegoROI* head = FindChildROI(p_roi, g_characterLODs[c_headLOD].m_name);
if (head != NULL) {
char lodName[256];
ViewLODList* lodList = GetViewLODListManager()->Lookup(g_characterLODs[4].m_parentName);
ViewLODList* lodList = GetViewLODListManager()->Lookup(g_characterLODs[c_headLOD].m_parentName);
MxS32 lodSize = lodList->Size();
sprintf(lodName, "%s%s%d", p_roi->GetName(), "head", g_unk0x100fc4e8++);
ViewLODList* dupLodList = GetViewLODListManager()->Create(lodName, lodSize);
@ -532,8 +550,8 @@ MxBool LegoCharacterManager::FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_tex
Tgl::Renderer* renderer = VideoManager()->GetRenderer();
if (p_textureInfo == NULL) {
LegoCharacterData* info = GetData(p_roi->GetName());
LegoCharacterData::Part& part = info->m_parts[3];
LegoCharacterInfo* info = GetInfo(p_roi->GetName());
LegoCharacterInfo::Part& part = info->m_parts[c_headPart];
p_textureInfo = TextureContainer()->Get(part.m_unk0x10[part.m_unk0x0c[part.m_unk0x14]]);
}
@ -565,8 +583,8 @@ MxBool LegoCharacterManager::FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_tex
// FUNCTION: LEGO1 0x10084c00
MxBool LegoCharacterManager::Exists(const char* p_key)
{
for (MxU32 i = 0; i < _countof(g_characterData); i++) {
if (!strcmpi(g_characterData[i].m_name, p_key)) {
for (MxU32 i = 0; i < _countof(g_chracterInfo); i++) {
if (!strcmpi(g_chracterInfo[i].m_name, p_key)) {
return TRUE;
}
}
@ -577,46 +595,46 @@ MxBool LegoCharacterManager::Exists(const char* p_key)
// FUNCTION: LEGO1 0x10084c40
LegoExtraActor* LegoCharacterManager::GetActor(const char* p_key)
{
LegoCharacterData* data = GetData(p_key);
LegoCharacterInfo* info = GetInfo(p_key);
if (data != NULL) {
return data->m_actor;
if (info != NULL) {
return info->m_actor;
}
return NULL;
}
// FUNCTION: LEGO1 0x10084c60
LegoCharacterData* LegoCharacterManager::GetData(const char* p_key)
LegoCharacterInfo* LegoCharacterManager::GetInfo(const char* p_key)
{
MxU32 i;
for (i = 0; i < _countof(g_characterData); i++) {
if (!strcmpi(g_characterData[i].m_name, p_key)) {
for (i = 0; i < _countof(g_chracterInfo); i++) {
if (!strcmpi(g_chracterInfo[i].m_name, p_key)) {
break;
}
}
if (i < _countof(g_characterData)) {
return &g_characterData[i];
if (i < _countof(g_chracterInfo)) {
return &g_chracterInfo[i];
}
return NULL;
}
// FUNCTION: LEGO1 0x10084cb0
LegoCharacterData* LegoCharacterManager::GetData(LegoROI* p_roi)
LegoCharacterInfo* LegoCharacterManager::GetInfo(LegoROI* p_roi)
{
MxU32 i;
for (i = 0; i < _countof(g_characterData); i++) {
if (g_characterData[i].m_roi == p_roi) {
for (i = 0; i < _countof(g_chracterInfo); i++) {
if (g_chracterInfo[i].m_roi == p_roi) {
break;
}
}
if (i < _countof(g_characterData)) {
return &g_characterData[i];
if (i < _countof(g_chracterInfo)) {
return &g_chracterInfo[i];
}
return NULL;
@ -646,13 +664,13 @@ LegoROI* LegoCharacterManager::FindChildROI(LegoROI* p_roi, const char* p_name)
// FUNCTION: LEGO1 0x10084ec0
MxBool LegoCharacterManager::SwitchHat(LegoROI* p_roi)
{
LegoCharacterData* data = GetData(p_roi->GetName());
LegoCharacterInfo* info = GetInfo(p_roi->GetName());
if (data == NULL) {
if (info == NULL) {
return FALSE;
}
LegoCharacterData::Part& part = data->m_parts[1];
LegoCharacterInfo::Part& part = info->m_parts[c_infohatPart];
part.m_unk0x08++;
MxU8 unk0x00 = part.m_unk0x00[part.m_unk0x08];
@ -662,7 +680,7 @@ MxBool LegoCharacterManager::SwitchHat(LegoROI* p_roi)
unk0x00 = part.m_unk0x00[part.m_unk0x08];
}
LegoROI* childROI = FindChildROI(p_roi, g_characterLODs[2].m_name);
LegoROI* childROI = FindChildROI(p_roi, g_characterLODs[c_infohatLOD].m_name);
if (childROI != NULL) {
char lodName[256];
@ -700,14 +718,14 @@ MxBool LegoCharacterManager::SwitchHat(LegoROI* p_roi)
// FUNCTION: LEGO1 0x10085140
MxU32 LegoCharacterManager::FUN_10085140(LegoROI* p_roi, MxBool p_und)
{
LegoCharacterData* data = GetData(p_roi);
LegoCharacterInfo* info = GetInfo(p_roi);
if (p_und) {
return data->m_unk0x14 + g_unk0x100fc4dc;
return info->m_unk0x14 + g_unk0x100fc4dc;
}
if (data != NULL) {
return data->m_unk0x0c + g_unk0x100fc4d8;
if (info != NULL) {
return info->m_unk0x0c + g_unk0x100fc4d8;
}
return 0;

View File

@ -1,7 +1,7 @@
#include "legocharacters.h"
DECOMP_SIZE_ASSERT(LegoCharacterData, 0x108)
DECOMP_SIZE_ASSERT(LegoCharacterData::Part, 0x18)
DECOMP_SIZE_ASSERT(LegoCharacterInfo, 0x108)
DECOMP_SIZE_ASSERT(LegoCharacterInfo::Part, 0x18)
DECOMP_SIZE_ASSERT(LegoCharacterLOD, 0x58)
// Unclear whether g_characterLODs[0] (top) is its own global, see: LegoCharacterManager::CreateROI
@ -172,7 +172,7 @@ const char* g_unk0x100f80a0[] =
{"lego white", "lego black", "lego yellow", "lego red", "lego blue", "lego brown", "lego lt grey", "lego green"};
// GLOBAL: LEGO1 0x100f80c0
LegoCharacterData g_characterDataInit[] = {
LegoCharacterInfo g_characterInfoInit[] = {
{"pepper",
NULL,
NULL,

View File

@ -791,7 +791,7 @@ void LegoGameState::SwitchArea(Area p_area)
FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d);
BackgroundAudioManager()->Stop();
AnimationManager()->FUN_1005ef10();
AnimationManager()->Suspend();
VideoManager()->SetUnk0x554(FALSE);
switch (p_area) {
@ -896,7 +896,7 @@ void LegoGameState::SwitchArea(Area p_area)
else {
SetCameraControllerFromIsle();
CurrentActor()->ResetWorldTransform(TRUE);
AnimationManager()->FUN_1005f0b0();
AnimationManager()->Resume();
}
CurrentActor()->VTable0xe8(p_area, TRUE, 7);
@ -910,7 +910,7 @@ void LegoGameState::SwitchArea(Area p_area)
LoadIsle();
SetCameraControllerFromIsle();
CurrentActor()->ResetWorldTransform(TRUE);
AnimationManager()->FUN_1005f0b0();
AnimationManager()->Resume();
CurrentActor()->VTable0xe8(p_area, TRUE, 7);
break;
case e_police:
@ -1083,28 +1083,28 @@ void LegoGameState::Init()
if (m_loadedAct == e_act1) {
Isle* isle = (Isle*) FindWorld(*g_isleScript, 0);
Helicopter* copter = (Helicopter*) isle->Find(*g_copterScript, 1);
Helicopter* copter = (Helicopter*) isle->Find(*g_copterScript, CopterScript::c_Helicopter_Actor);
if (copter) {
isle->FUN_1001fc80(copter);
isle->VTable0x6c(copter);
delete copter;
}
DuneBuggy* dunebuggy = (DuneBuggy*) isle->Find(*g_dunecarScript, 2);
DuneBuggy* dunebuggy = (DuneBuggy*) isle->Find(*g_dunecarScript, DunecarScript::c_DuneBugy_Actor);
if (dunebuggy) {
isle->FUN_1001fc80(dunebuggy);
isle->VTable0x6c(dunebuggy);
delete dunebuggy;
}
Jetski* jetski = (Jetski*) isle->Find(*g_jetskiScript, 3);
Jetski* jetski = (Jetski*) isle->Find(*g_jetskiScript, JetskiScript::c_Jetski_Actor);
if (jetski) {
isle->FUN_1001fc80(jetski);
isle->VTable0x6c(jetski);
delete jetski;
}
RaceCar* racecar = (RaceCar*) isle->Find(*g_racecarScript, 4);
RaceCar* racecar = (RaceCar*) isle->Find(*g_racecarScript, RacecarScript::c_RaceCar_Actor);
if (racecar) {
isle->FUN_1001fc80(racecar);
isle->VTable0x6c(racecar);

View File

@ -136,6 +136,13 @@ void SetCurrentActor(IslePathActor* p_currentActor)
LegoOmni::GetInstance()->SetCurrentActor(p_currentActor);
}
// FUNCTION: LEGO1 0x10015890
// FUNCTION: BETA10 0x100e4d80
MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction)
{
return LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction);
}
// FUNCTION: LEGO1 0x100158b0
void DeleteAction()
{

View File

@ -630,7 +630,7 @@ void LegoWorld::Enable(MxBool p_enable)
PlantManager()->FUN_10026360(m_scriptIndex);
AnimationManager()->LoadScriptInfo(m_scriptIndex);
BuildingManager()->FUN_1002fa00();
AnimationManager()->FUN_1005f0b0();
AnimationManager()->Resume();
}
GameState()->ResetROI();

View File

@ -666,7 +666,7 @@ void Isle::Enable(MxBool p_enable)
break;
}
AnimationManager()->FUN_10060dc0(script, NULL, 1, 1, 0, 0, FALSE, TRUE, 0);
AnimationManager()->FUN_10060dc0(script, NULL, TRUE, 1, NULL, FALSE, FALSE, TRUE, 0);
}
m_act1state->m_unk0x018 = 0;
@ -694,7 +694,7 @@ void Isle::Enable(MxBool p_enable)
break;
}
AnimationManager()->FUN_10060dc0(script, NULL, 1, 1, 0, 0, FALSE, TRUE, 0);
AnimationManager()->FUN_10060dc0(script, NULL, TRUE, 1, NULL, FALSE, FALSE, TRUE, 0);
}
m_act1state->m_unk0x018 = 0;
@ -857,7 +857,7 @@ MxLong Isle::HandleTransitionEnd()
GameState()->StopArea(LegoGameState::e_previousArea);
m_destLocation = LegoGameState::e_undefined;
VariableTable()->SetVariable("VISIBILITY", "Show Gas");
AnimationManager()->FUN_1005f0b0();
AnimationManager()->Resume();
FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
SetAppCursor(0);
SetIsWorldActive(TRUE);
@ -867,7 +867,7 @@ MxLong Isle::HandleTransitionEnd()
GameState()->StopArea(LegoGameState::e_previousArea);
m_destLocation = LegoGameState::e_undefined;
VariableTable()->SetVariable("VISIBILITY", "Show Policsta");
AnimationManager()->FUN_1005f0b0();
AnimationManager()->Resume();
FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
SetAppCursor(0);
SetIsWorldActive(TRUE);

View File

@ -2,7 +2,7 @@
import struct
import bisect
from functools import cached_property
from typing import List, Optional, Tuple
from typing import Iterator, List, Optional, Tuple
from dataclasses import dataclass
from collections import namedtuple
@ -77,6 +77,18 @@ def match_name(self, name: str) -> bool:
def contains_vaddr(self, vaddr: int) -> bool:
return self.virtual_address <= vaddr < self.virtual_address + self.extent
def read_virtual(self, vaddr: int, size: int) -> memoryview:
ofs = vaddr - self.virtual_address
# Negative index will read from the end, which we don't want
if ofs < 0:
raise InvalidVirtualAddressError
try:
return self.view[ofs : ofs + size]
except IndexError as ex:
raise InvalidVirtualAddressError from ex
def addr_is_uninitialized(self, vaddr: int) -> bool:
"""We cannot rely on the IMAGE_SCN_CNT_UNINITIALIZED_DATA flag (0x80) in
the characteristics field so instead we determine it this way."""
@ -109,6 +121,7 @@ def __init__(self, filename: str, find_str: bool = False) -> None:
self._section_vaddr: List[int] = []
self.find_str = find_str
self._potential_strings = {}
self._relocations = set()
self._relocated_addrs = set()
self.imports = []
self.thunks = []
@ -279,11 +292,49 @@ def _populate_relocations(self):
# We are now interested in the relocated addresses themselves. Seek to the
# address where there is a relocation, then read the four bytes into our set.
reloc_addrs.sort()
self._relocations = set(reloc_addrs)
for section_id, offset in map(self.get_relative_addr, reloc_addrs):
section = self.get_section_by_index(section_id)
(relocated_addr,) = struct.unpack("<I", section.view[offset : offset + 4])
self._relocated_addrs.add(relocated_addr)
def find_float_consts(self) -> Iterator[Tuple[int, int, float]]:
"""Floating point instructions that refer to a memory address can
point to constant values. Search the code sections to find FP
instructions and check whether the pointer address refers to
read-only data."""
# TODO: Should check any section that has code, not just .text
text = self.get_section_by_name(".text")
rdata = self.get_section_by_name(".rdata")
# These are the addresses where a relocation occurs.
# Meaning: it points to an absolute address of something
for addr in self._relocations:
if not text.contains_vaddr(addr):
continue
# Read the two bytes before the relocated address.
# We will check against possible float opcodes
raw = text.read_virtual(addr - 2, 6)
(opcode, opcode_ext, const_addr) = struct.unpack("<BBL", raw)
# Skip right away if this is not const data
if not rdata.contains_vaddr(const_addr):
continue
if opcode_ext in (0x5, 0xD, 0x15, 0x1D, 0x25, 0x2D, 0x35, 0x3D):
if opcode in (0xD8, 0xD9):
# dword ptr -- single precision
(float_value,) = struct.unpack("<f", self.read(const_addr, 4))
yield (const_addr, 4, float_value)
elif opcode in (0xDC, 0xDD):
# qword ptr -- double precision
(float_value,) = struct.unpack("<d", self.read(const_addr, 8))
yield (const_addr, 8, float_value)
def _populate_imports(self):
"""Parse .idata to find imported DLLs and their functions."""
idata_ofs = self.get_section_offset_by_name(".idata")

View File

@ -35,16 +35,6 @@ def from_hex(string: str) -> Optional[int]:
return None
def bytes_to_float(b: bytes) -> Optional[float]:
if len(b) == 4:
return struct.unpack("<f", b)[0]
if len(b) == 8:
return struct.unpack("<d", b)[0]
return None
def bytes_to_dword(b: bytes) -> Optional[int]:
if len(b) == 4:
return struct.unpack("<L", b)[0]
@ -74,18 +64,6 @@ def is_relocated(self, addr: int) -> bool:
return False
def float_replace(self, addr: int, data_size: int) -> Optional[str]:
if callable(self.bin_lookup):
float_bytes = self.bin_lookup(addr, data_size)
if float_bytes is None:
return None
float_value = bytes_to_float(float_bytes)
if float_value is not None:
return f"{float_value} (FLOAT)"
return None
def lookup(
self, addr: int, use_cache: bool = True, exact: bool = False
) -> Optional[str]:
@ -165,25 +143,6 @@ def hex_replace_indirect(self, match: re.Match) -> str:
return match.group(0).replace(match.group(1), self.replace(value))
def hex_replace_float(self, match: re.Match) -> str:
"""Special case for replacements on float instructions.
If the pointer is a float constant, read it from the binary."""
value = int(match.group(1), 16)
# If we can find a variable name for this pointer, use it.
placeholder = self.lookup(value)
# Read what's under the pointer and show the decimal value.
if placeholder is None:
float_size = 8 if "qword" in match.string else 4
placeholder = self.float_replace(value, float_size)
# If we can't read the float, use a regular placeholder.
if placeholder is None:
placeholder = self.replace(value)
return match.group(0).replace(match.group(1), placeholder)
def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]:
# For jumps or calls, if the entire op_str is a hex number, the value
# is a relative offset.
@ -224,9 +183,6 @@ def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]:
if inst.mnemonic == "call":
# Special handling for absolute indirect CALL.
op_str = ptr_replace_regex.sub(self.hex_replace_indirect, inst.op_str)
elif inst.mnemonic.startswith("f"):
# If floating point instruction
op_str = ptr_replace_regex.sub(self.hex_replace_float, inst.op_str)
else:
op_str = ptr_replace_regex.sub(self.hex_replace_always, inst.op_str)

View File

@ -82,6 +82,7 @@ def __init__(
self._load_cvdump()
self._load_markers()
self._find_original_strings()
self._find_float_const()
self._match_imports()
self._match_exports()
self._match_thunks()
@ -249,6 +250,18 @@ def _find_original_strings(self):
self._db.match_string(addr, string)
def _find_float_const(self):
"""Add floating point constants in each binary to the database.
We are not matching anything right now because these values are not
deduped like strings."""
for addr, size, float_value in self.orig_bin.find_float_consts():
self._db.set_orig_symbol(addr, SymbolType.FLOAT, str(float_value), size)
for addr, size, float_value in self.recomp_bin.find_float_consts():
self._db.set_recomp_symbol(
addr, SymbolType.FLOAT, str(float_value), None, size
)
def _match_imports(self):
"""We can match imported functions based on the DLL name and
function symbol name."""

View File

@ -84,6 +84,23 @@ def __init__(self):
self._db = sqlite3.connect(":memory:")
self._db.executescript(_SETUP_SQL)
def set_orig_symbol(
self,
addr: int,
compare_type: Optional[SymbolType],
name: Optional[str],
size: Optional[int],
):
# Ignore collisions here.
if self._orig_used(addr):
return
compare_value = compare_type.value if compare_type is not None else None
self._db.execute(
"INSERT INTO `symbols` (orig_addr, compare_type, name, size) VALUES (?,?,?,?)",
(addr, compare_value, name, size),
)
def set_recomp_symbol(
self,
addr: int,

View File

@ -10,3 +10,4 @@ class SymbolType(Enum):
POINTER = 3
STRING = 4
VTABLE = 5
FLOAT = 6

View File

@ -189,6 +189,7 @@ def substitute_1234(addr: int, _: bool) -> Optional[str]:
assert op_str == "0x5555"
@pytest.mark.skip(reason="changed implementation")
def test_float_replacement():
"""Floating point constants often appear as pointers to data.
A good example is ViewROI::IntrinsicImportance and the subclass override
@ -208,6 +209,7 @@ def bin_lookup(addr: int, _: int) -> Optional[bytes]:
assert op_str == "dword ptr [3.1415927410125732 (FLOAT)]"
@pytest.mark.skip(reason="changed implementation")
def test_float_variable():
"""If there is a variable at the address referenced by a float instruction,
use the name instead of calling into the float replacement handler."""

View File

@ -10,6 +10,7 @@
from typing import Iterator, List, Optional, Tuple
from collections import namedtuple
from isledecomp import Bin as IsleBin
from isledecomp.bin import InvalidVirtualAddressError
from isledecomp.cvdump import Cvdump
from isledecomp.compare import Compare as IsleCompare
from isledecomp.types import SymbolType
@ -87,7 +88,7 @@ def print_sections(sections):
print()
ALLOWED_TYPE_ABBREVIATIONS = ["fun", "dat", "poi", "str", "vta"]
ALLOWED_TYPE_ABBREVIATIONS = ["fun", "dat", "poi", "str", "vta", "flo"]
def match_type_abbreviation(mtype: Optional[SymbolType]) -> str:
@ -456,7 +457,16 @@ def to_roadmap_row(match):
module_name,
)
results = list(map(to_roadmap_row, engine.get_all()))
def roadmap_row_generator(matches):
for match in matches:
try:
yield to_roadmap_row(match)
except InvalidVirtualAddressError:
# This is here to work around the fact that we have RVA
# values (i.e. not real virtual addrs) in our compare db.
pass
results = list(roadmap_row_generator(engine.get_all()))
if args.order is not None:
suggest_order(results, module_map, args.order)