isle/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp

636 lines
14 KiB
C++
Raw Normal View History

#include "legoplantmanager.h"
#include "3dmanager/lego3dmanager.h"
#include "legocharactermanager.h"
#include "legoentity.h"
#include "legoplants.h"
#include "legovideomanager.h"
#include "legoworld.h"
#include "misc.h"
#include "misc/legostorage.h"
#include "mxmisc.h"
#include "mxticklemanager.h"
#include "mxtimer.h"
#include "scripts.h"
#include "sndanim_actions.h"
#include "viewmanager/viewmanager.h"
#include <stdio.h>
#include <vec.h>
DECOMP_SIZE_ASSERT(LegoPlantManager, 0x2c)
DECOMP_SIZE_ASSERT(LegoPlantManager::AnimEntry, 0x0c)
// GLOBAL: LEGO1 0x100f1660
const char* g_plantLodNames[4][5] = {
{"flwrwht", "flwrblk", "flwryel", "flwrred", "flwrgrn"},
{"treewht", "treeblk", "treeyel", "treered", "tree"},
{"bushwht", "bushblk", "bushyel", "bushred", "bush"},
{"palmwht", "palmblk", "palmyel", "palmred", "palm"}
};
// GLOBAL: LEGO1 0x100f16b0
float g_unk0x100f16b0[] = {0.1f, 0.7f, 0.5f, 0.9f};
// GLOBAL: LEGO1 0x100f16c0
MxU8 g_unk0x100f16c0[] = {1, 2, 2, 3};
// GLOBAL: LEGO1 0x100f315c
MxU32 LegoPlantManager::g_maxSound = 8;
// GLOBAL: LEGO1 0x100f3160
MxU32 g_unk0x100f3160 = 56;
// GLOBAL: LEGO1 0x100f3164
MxU32 g_unk0x100f3164 = 66;
// GLOBAL: LEGO1 0x100f3168
MxS32 LegoPlantManager::g_maxMove[4] = {3, 3, 3, 3};
// GLOBAL: LEGO1 0x100f3178
MxU32 g_plantAnimationId[4] = {30, 33, 36, 39};
// GLOBAL: LEGO1 0x100f3188
char* LegoPlantManager::g_customizeAnimFile = NULL;
// GLOBAL: LEGO1 0x10103180
LegoPlantInfo g_plantInfo[81];
(Proposal) Adjustments to "decomp" language (#308) * Adjustments to "decomp" language * Fix a comment * Fix accidental clang-formatting * Fix order * Fix order * Remove junk * Fix OFFSET * Adjustments based on new suggestions * Annotate globals * Globals in ISLE * More globals * Merge from parser2 branch * Allow prepending space for exact marker match * To eliminate noise, require the 0x prefix on offset for marker match * fix test from previous * Count tab stops for indented functions to reduce MISSED_END_OF_FUNCTION noise * FUNCTION to SYNTHETIC where needed * Missed marker conversion on SetAtomId * pylint cleanup, remove unused code * Fix unexpected function end, add more unit tests * Be more strict about synthetic name syntax * Revert "Missed marker conversion on SetAtomId" This reverts commit d87d665127fae7dd6e5bd48d9af14a0a829bf9e2. * Revert "FUNCTION to SYNTHETIC where needed" This reverts commit 8c815418d261ba8c5f67a9a2cae349fe4ac92db8. * Implicit lookup by name for functions * Fix VTABLE SYNTHETIC and other decomp markers * Get vtable class name * Vtable marker should identify struct * No colon for SIZE comment * Update README.md * Update README.md * Update CONTRIBUTING.md * Update README.md * Update README.md * Update CONTRIBUTING.md * Update README.md * Update CONTRIBUTING.md * Fix destructor/annotation * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md --------- Co-authored-by: disinvite <disinvite@users.noreply.github.com>
2023-12-06 07:10:45 -05:00
// FUNCTION: LEGO1 0x10026220
LegoPlantManager::LegoPlantManager()
{
2023-10-24 19:38:27 -04:00
Init();
}
// FUNCTION: LEGO1 0x100262c0
LegoPlantManager::~LegoPlantManager()
{
delete[] g_customizeAnimFile;
}
// FUNCTION: LEGO1 0x10026330
// FUNCTION: BETA10 0x100c4f90
void LegoPlantManager::Init()
{
for (MxS32 i = 0; i < sizeOfArray(g_plantInfo); i++) {
g_plantInfo[i] = g_plantInfoInit[i];
}
m_worldId = -1;
m_unk0x0c = 0;
m_numEntries = 0;
}
// FUNCTION: LEGO1 0x10026360
// FUNCTION: BETA10 0x100c5032
void LegoPlantManager::LoadWorldInfo(MxS32 p_worldId)
{
m_worldId = p_worldId;
LegoWorld* world = CurrentWorld();
for (MxS32 i = 0; i < sizeOfArray(g_plantInfo); i++) {
CreatePlant(i, world, p_worldId);
}
m_unk0x0c = 0;
}
// FUNCTION: LEGO1 0x100263a0
void LegoPlantManager::Reset(MxS32 p_worldId)
{
MxU32 i;
DeleteObjects(g_sndAnimScript, SndanimScript::c_AnimC1, SndanimScript::c_AnimBld18);
for (i = 0; i < m_numEntries; i++) {
delete m_entries[i];
}
m_numEntries = 0;
for (i = 0; i < sizeOfArray(g_plantInfo); i++) {
RemovePlant(i, p_worldId);
}
m_worldId = -1;
m_unk0x0c = 0;
}
// FUNCTION: LEGO1 0x10026590
// FUNCTION: BETA10 0x100c561e
LegoEntity* LegoPlantManager::CreatePlant(MxS32 p_index, LegoWorld* p_world, MxS32 p_worldId)
{
LegoEntity* entity = NULL;
if (p_index < sizeOfArray(g_plantInfo)) {
MxU32 world = 1 << (MxU8) p_worldId;
if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_unk0x16 != 0) {
if (g_plantInfo[p_index].m_entity == NULL) {
char name[256];
char lodName[256];
sprintf(name, "plant%d", p_index);
sprintf(lodName, "%s", g_plantLodNames[g_plantInfo[p_index].m_variant][g_plantInfo[p_index].m_color]);
LegoROI* roi = CharacterManager()->CreateAutoROI(name, lodName, TRUE);
roi->SetVisibility(TRUE);
entity = roi->GetEntity();
entity->SetLocation(
g_plantInfo[p_index].m_position,
g_plantInfo[p_index].m_direction,
g_plantInfo[p_index].m_up,
FALSE
);
entity->SetType(LegoEntity::e_plant);
g_plantInfo[p_index].m_entity = entity;
}
else {
entity = g_plantInfo[p_index].m_entity;
}
}
}
return entity;
}
// FUNCTION: LEGO1 0x100266c0
// FUNCTION: BETA10 0x100c5859
void LegoPlantManager::RemovePlant(MxS32 p_index, MxS32 p_worldId)
{
if (p_index < sizeOfArray(g_plantInfo)) {
MxU32 world = 1 << (MxU8) p_worldId;
if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_entity != NULL) {
CharacterManager()->ReleaseAutoROI(g_plantInfo[p_index].m_entity->GetROI());
g_plantInfo[p_index].m_entity = NULL;
}
}
}
// FUNCTION: LEGO1 0x10026720
// FUNCTION: BETA10 0x100c5918
MxResult LegoPlantManager::Write(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < sizeOfArray(g_plantInfo); i++) {
LegoPlantInfo* info = &g_plantInfo[i];
if (p_storage->Write(&info->m_variant, sizeof(info->m_variant)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_sound, sizeof(info->m_sound)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_move, sizeof(info->m_move)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_mood, sizeof(info->m_mood)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_color, sizeof(info->m_color)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_initialUnk0x16, sizeof(info->m_initialUnk0x16)) != SUCCESS) {
goto done;
}
}
result = SUCCESS;
done:
return result;
}
// FUNCTION: LEGO1 0x100267b0
// FUNCTION: BETA10 0x100c5a76
MxResult LegoPlantManager::Read(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < sizeOfArray(g_plantInfo); i++) {
LegoPlantInfo* info = &g_plantInfo[i];
if (p_storage->Read(&info->m_variant, sizeof(info->m_variant)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_sound, sizeof(info->m_sound)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_move, sizeof(info->m_move)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_mood, sizeof(info->m_mood)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_color, sizeof(info->m_color)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_unk0x16, sizeof(info->m_unk0x16)) != SUCCESS) {
goto done;
}
info->m_initialUnk0x16 = info->m_unk0x16;
FUN_10026860(i);
}
result = SUCCESS;
done:
return result;
}
// FUNCTION: LEGO1 0x10026860
// FUNCTION: BETA10 0x100c5be0
void LegoPlantManager::FUN_10026860(MxS32 p_index)
{
MxU8 variant = g_plantInfo[p_index].m_variant;
if (g_plantInfo[p_index].m_unk0x16 >= 0) {
float value = g_unk0x100f16c0[variant] - g_plantInfo[p_index].m_unk0x16;
g_plantInfo[p_index].m_position[1] = g_plantInfoInit[p_index].m_position[1] - value * g_unk0x100f16b0[variant];
}
else {
g_plantInfo[p_index].m_position[1] = g_plantInfoInit[p_index].m_position[1];
}
}
// FUNCTION: LEGO1 0x100268e0
// FUNCTION: BETA10 0x100c5c95
LegoPlantInfo* LegoPlantManager::GetInfo(LegoEntity* p_entity)
{
MxS32 i;
for (i = 0; i < sizeOfArray(g_plantInfo); i++) {
if (g_plantInfo[i].m_entity == p_entity) {
break;
}
}
if (i < sizeOfArray(g_plantInfo)) {
return &g_plantInfo[i];
}
return NULL;
}
// FUNCTION: LEGO1 0x10026920
// FUNCTION: BETA10 0x100c5dc9
MxBool LegoPlantManager::SwitchColor(LegoEntity* p_entity)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (info == NULL) {
return FALSE;
}
LegoROI* roi = p_entity->GetROI();
info->m_color++;
if (info->m_color > LegoPlantInfo::e_green) {
info->m_color = LegoPlantInfo::e_white;
}
ViewLODList* lodList = GetViewLODListManager()->Lookup(g_plantLodNames[info->m_variant][info->m_color]);
if (roi->GetUnknown0xe0() >= 0) {
VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveROIDetailFromScene(roi);
}
roi->SetLODList(lodList);
lodList->Release();
CharacterManager()->FUN_10085870(roi);
return TRUE;
}
// FUNCTION: LEGO1 0x100269e0
// FUNCTION: BETA10 0x100c5ee2
MxBool LegoPlantManager::SwitchVariant(LegoEntity* p_entity)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (info == NULL || info->m_unk0x16 != -1) {
return FALSE;
}
LegoROI* roi = p_entity->GetROI();
info->m_variant++;
if (info->m_variant > LegoPlantInfo::e_palm) {
info->m_variant = LegoPlantInfo::e_flower;
}
ViewLODList* lodList = GetViewLODListManager()->Lookup(g_plantLodNames[info->m_variant][info->m_color]);
if (roi->GetUnknown0xe0() >= 0) {
VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveROIDetailFromScene(roi);
}
roi->SetLODList(lodList);
lodList->Release();
CharacterManager()->FUN_10085870(roi);
if (info->m_move != 0 && info->m_move >= g_maxMove[info->m_variant]) {
info->m_move = g_maxMove[info->m_variant] - 1;
}
return TRUE;
}
// FUNCTION: LEGO1 0x10026ad0
// FUNCTION: BETA10 0x100c6049
MxBool LegoPlantManager::SwitchSound(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoPlantInfo* info = GetInfo(p_entity);
if (info != NULL) {
info->m_sound++;
if (info->m_sound >= g_maxSound) {
info->m_sound = 0;
}
result = TRUE;
}
return result;
}
// FUNCTION: LEGO1 0x10026b00
// FUNCTION: BETA10 0x100c60a7
MxBool LegoPlantManager::SwitchMove(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoPlantInfo* info = GetInfo(p_entity);
if (info != NULL) {
info->m_move++;
if (info->m_move >= g_maxMove[info->m_variant]) {
info->m_move = 0;
}
result = TRUE;
}
return result;
}
// FUNCTION: LEGO1 0x10026b40
// FUNCTION: BETA10 0x100c610e
MxBool LegoPlantManager::SwitchMood(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoPlantInfo* info = GetInfo(p_entity);
if (info != NULL) {
info->m_mood++;
if (info->m_mood > 3) {
info->m_mood = 0;
}
result = TRUE;
}
return result;
}
// FUNCTION: LEGO1 0x10026b70
// FUNCTION: BETA10 0x100c6168
MxU32 LegoPlantManager::GetAnimationId(LegoEntity* p_entity)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (info != NULL) {
return g_plantAnimationId[info->m_variant] + info->m_move;
}
return 0;
}
// FUNCTION: LEGO1 0x10026ba0
// FUNCTION: BETA10 0x100c61ba
MxU32 LegoPlantManager::GetSoundId(LegoEntity* p_entity, MxBool p_state)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (p_state) {
return (info->m_mood & 1) + g_unk0x100f3164;
}
if (info != NULL) {
return info->m_sound + g_unk0x100f3160;
}
return 0;
}
// FUNCTION: LEGO1 0x10026be0
// FUNCTION: BETA10 0x100c62bc
void LegoPlantManager::SetCustomizeAnimFile(const char* p_value)
{
if (g_customizeAnimFile != NULL) {
delete[] g_customizeAnimFile;
}
if (p_value != NULL) {
g_customizeAnimFile = new char[strlen(p_value) + 1];
if (g_customizeAnimFile != NULL) {
strcpy(g_customizeAnimFile, p_value);
}
}
else {
g_customizeAnimFile = NULL;
}
}
// FUNCTION: LEGO1 0x10026c50
// FUNCTION: BETA10 0x100c6349
MxBool LegoPlantManager::FUN_10026c50(LegoEntity* p_entity)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (info == NULL) {
return FALSE;
}
return FUN_10026c80(info - g_plantInfo);
}
// FUNCTION: LEGO1 0x10026c80
// FUNCTION: BETA10 0x100c63eb
MxBool LegoPlantManager::FUN_10026c80(MxS32 p_index)
{
if (p_index >= sizeOfArray(g_plantInfo)) {
return FALSE;
}
LegoPlantInfo* info = &g_plantInfo[p_index];
if (info == NULL) {
return FALSE;
}
MxBool result = TRUE;
if (info->m_unk0x16 < 0) {
info->m_unk0x16 = g_unk0x100f16c0[info->m_variant];
}
if (info->m_unk0x16 > 0) {
LegoROI* roi = info->m_entity->GetROI();
info->m_unk0x16--;
if (info->m_unk0x16 == 1) {
info->m_unk0x16 = 0;
}
if (info->m_unk0x16 == 0) {
roi->SetVisibility(FALSE);
}
else {
FUN_10026860(info - g_plantInfo);
info->m_entity->SetLocation(info->m_position, info->m_direction, info->m_up, FALSE);
}
}
else {
result = FALSE;
}
return result;
}
// FUNCTION: LEGO1 0x10026d70
void LegoPlantManager::ScheduleAnimation(LegoEntity* p_entity, MxLong p_length)
{
m_world = CurrentWorld();
if (m_numEntries == 0) {
TickleManager()->RegisterClient(this, 50);
}
AnimEntry* entry = m_entries[m_numEntries] = new AnimEntry;
m_numEntries++;
entry->m_entity = p_entity;
entry->m_roi = p_entity->GetROI();
entry->m_time = Timer()->GetTime() + p_length + 1000;
FUN_100271b0(p_entity, -1);
}
// FUNCTION: LEGO1 0x10026e00
MxResult LegoPlantManager::Tickle()
{
MxLong time = Timer()->GetTime();
if (m_numEntries != 0) {
for (MxS32 i = 0; i < m_numEntries; i++) {
AnimEntry** ppEntry = &m_entries[i];
AnimEntry* entry = *ppEntry;
if (m_world != CurrentWorld() || !entry->m_entity) {
delete entry;
m_numEntries--;
if (m_numEntries != i) {
m_entries[i] = m_entries[m_numEntries];
m_entries[m_numEntries] = NULL;
}
break;
}
if (entry->m_time - time > 1000) {
break;
}
MxMatrix local90;
MxMatrix local48;
MxMatrix locald8(entry->m_roi->GetLocal2World());
Mx3DPointFloat localec(locald8[3]);
ZEROVEC3(locald8[3]);
locald8[1][0] = sin(((entry->m_time - time) * 2) * 0.0062832f) * 0.2;
locald8[1][2] = sin(((entry->m_time - time) * 4) * 0.0062832f) * 0.2;
locald8.Scale(1.03f, 0.95f, 1.03f);
SET3(locald8[3], localec);
entry->m_roi->FUN_100a58f0(locald8);
entry->m_roi->VTable0x14();
if (entry->m_time < time) {
LegoPlantInfo* info = GetInfo(entry->m_entity);
if (info->m_unk0x16 == 0) {
entry->m_roi->SetVisibility(FALSE);
}
else {
FUN_10026860(info - g_plantInfo);
info->m_entity->SetLocation(info->m_position, info->m_direction, info->m_up, FALSE);
}
delete entry;
m_numEntries--;
if (m_numEntries != i) {
i--;
*ppEntry = m_entries[m_numEntries];
m_entries[m_numEntries] = NULL;
}
}
}
}
else {
TickleManager()->UnregisterClient(this);
}
return SUCCESS;
}
// FUNCTION: LEGO1 0x10027120
void LegoPlantManager::FUN_10027120()
{
LegoWorld* world = CurrentWorld();
for (MxS32 i = 0; i < sizeOfArray(g_plantInfo); i++) {
g_plantInfo[i].m_unk0x16 = -1;
g_plantInfo[i].m_initialUnk0x16 = -1;
FUN_10026860(i);
if (g_plantInfo[i].m_entity != NULL) {
g_plantInfo[i].m_entity->SetLocation(
g_plantInfo[i].m_position,
g_plantInfo[i].m_direction,
g_plantInfo[i].m_up,
FALSE
);
}
}
}
// FUNCTION: LEGO1 0x100271b0
void LegoPlantManager::FUN_100271b0(LegoEntity* p_entity, MxS32 p_adjust)
{
LegoPlantInfo* info = GetInfo(p_entity);
if (info != NULL) {
if (info->m_unk0x16 < 0) {
info->m_unk0x16 = g_unk0x100f16c0[info->m_variant];
}
if (info->m_unk0x16 > 0) {
info->m_unk0x16 += p_adjust;
if (info->m_unk0x16 <= 1 && p_adjust < 0) {
info->m_unk0x16 = 0;
}
}
}
}