diff --git a/LEGO1/lego/legoomni/include/historybook.h b/LEGO1/lego/legoomni/include/historybook.h index 3bdc4acf..4e8c9501 100644 --- a/LEGO1/lego/legoomni/include/historybook.h +++ b/LEGO1/lego/legoomni/include/historybook.h @@ -4,6 +4,7 @@ #include "decomp.h" #include "legogamestate.h" #include "legoworld.h" +#include "mxstillpresenter.h" // VTABLE: LEGO1 0x100da328 // SIZE 0x3e4 @@ -36,9 +37,9 @@ public: private: LegoGameState::Area m_transitionDestination; // 0xf8 - undefined m_unk0xfc[104]; // 0xfc - undefined m_unk0x164[560]; // 0x164 - undefined m_unk0x394[80]; // 0x394 + MxStillPresenter* m_alphabet[26]; // 0xfc + MxStillPresenter* m_names[20][7]; // 0x164 + MxStillPresenter* m_scores[20]; // 0x394 }; #endif // HISTORYBOOK_H diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h index e4c725eb..f893f154 100644 --- a/LEGO1/lego/legoomni/include/legogamestate.h +++ b/LEGO1/lego/legoomni/include/legogamestate.h @@ -86,6 +86,32 @@ public: e_unk66 = 66 }; + // SIZE 0x0c + struct ScoreName { + ScoreName* operator=(const ScoreName* p_other); + + MxS16 m_letters[7]; // 0x00 + }; + + // SIZE 0x2c + struct ScoreItem { + undefined2 m_unk0x00; // 0x00 + MxU8 m_state[25]; // 0x02 + ScoreName m_name; // 0x1c + undefined2 m_unk0x2a; // 0x2a + }; + + // SIZE 0x372 + struct Scores { + void WriteScoreHistory(); + void FUN_1003ccf0(LegoFile&); + + inline ScoreItem* GetScore(MxS16 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; } + + MxS16 m_count; // 0x00 + ScoreItem m_scores[20]; // 0x02 + }; + LegoGameState(); ~LegoGameState(); @@ -109,6 +135,7 @@ public: inline Area GetPreviousArea() { return m_previousArea; } inline MxU32 GetUnknown0x41c() { return m_unk0x41c; } inline Area GetUnknown0x42c() { return m_unk0x42c; } + inline Scores* GetScores() { return &m_unk0xa6; } inline void SetDirty(MxBool p_dirty) { m_isDirty = p_dirty; } inline void SetCurrentArea(Area p_currentArea) { m_currentArea = p_currentArea; } @@ -122,14 +149,6 @@ public: void FUN_10039780(MxU8); void FUN_10039940(); - struct ScoreStruct { - void WriteScoreHistory(); - void FUN_1003ccf0(LegoFile&); - - MxU16 m_unk0x00; - undefined m_unk0x02[0x2c][20]; - }; - private: void RegisterState(LegoState* p_state); MxResult WriteVariable(LegoStorage* p_stream, MxVariableTable* p_from, const char* p_variableName); @@ -147,9 +166,9 @@ private: LegoBackgroundColor* m_tempBackgroundColor; // 0x1c LegoFullScreenMovie* m_fullScreenMovie; // 0x20 MxU16 m_unk0x24; // 0x24 - undefined m_unk0x28[128]; // 0x28 - ScoreStruct m_unk0xa6; // 0xa6 - undefined m_unk0x41a[2]; // 0x41a - might be part of the structure at 0xa6 + undefined m_unk0x26[128]; // 0x26 + Scores m_unk0xa6; // 0xa6 + undefined4 m_unk0x418; // 0x418 undefined4 m_unk0x41c; // 0x41c MxBool m_isDirty; // 0x420 Area m_currentArea; // 0x424 diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index ce379f47..9d81f699 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -15,8 +15,9 @@ #include <stdio.h> -// Based on the highest dword offset (0x42c) referenced in the constructor. -// There may be other members that come after. +DECOMP_SIZE_ASSERT(LegoGameState::ScoreName, 0xe) +DECOMP_SIZE_ASSERT(LegoGameState::ScoreItem, 0x2c) +DECOMP_SIZE_ASSERT(LegoGameState::Scores, 0x372) DECOMP_SIZE_ASSERT(LegoGameState, 0x430) // GLOBAL: LEGO1 0x100f3e40 @@ -687,14 +688,21 @@ void LegoGameState::RegisterState(LegoState* p_state) m_stateArray[targetIndex] = p_state; } +// FUNCTION: LEGO1 0x1003c710 +LegoGameState::ScoreName* LegoGameState::ScoreName::operator=(const ScoreName* p_other) +{ + memcpy(m_letters, p_other->m_letters, sizeof(m_letters)); + return this; +} + // STUB: LEGO1 0x1003c870 -void LegoGameState::ScoreStruct::WriteScoreHistory() +void LegoGameState::Scores::WriteScoreHistory() { // TODO } // STUB: LEGO1 0x1003ccf0 -void LegoGameState::ScoreStruct::FUN_1003ccf0(LegoFile&) +void LegoGameState::Scores::FUN_1003ccf0(LegoFile&) { // TODO } diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp index 02f24a6b..64bd9e58 100644 --- a/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/infocenter.cpp @@ -111,7 +111,7 @@ MxResult Infocenter::Create(MxDSAction& p_dsAction) if (m_infocenterState->GetNameLetter(i)) { m_infocenterState->GetNameLetter(i)->Enable(TRUE); m_infocenterState->GetNameLetter(i)->SetTickleState(MxPresenter::e_repeating); - m_infocenterState->GetNameLetter(i)->VTable0x88(((7 - count) / 2 + i) * 29 + 223, 45); + m_infocenterState->GetNameLetter(i)->SetPosition(((7 - count) / 2 + i) * 29 + 223, 45); } } } @@ -596,12 +596,12 @@ MxU8 Infocenter::HandleMouseMove(MxS32 p_x, MxS32 p_y) m_unk0x11c->SetDisplayZ(1000); VideoManager()->SortPresenterList(); m_unk0x11c->Enable(TRUE); - m_unk0x11c->VTable0x88(p_x, p_y); + m_unk0x11c->SetPosition(p_x, p_y); m_unk0x11c->SetDisplayZ(oldDisplayZ); } else { - m_unk0x11c->VTable0x88(p_x, p_y); + m_unk0x11c->SetPosition(p_x, p_y); } FUN_10070d10(p_x, p_y); @@ -1259,7 +1259,7 @@ void Infocenter::UpdateFrameHot(MxBool p_display) VideoManager()->SortPresenterList(); m_frameHotBitmap->Enable(TRUE); - m_frameHotBitmap->VTable0x88(x, y); + m_frameHotBitmap->SetPosition(x, y); m_frameHotBitmap->SetDisplayZ(originalDisplayZ); } else { diff --git a/LEGO1/lego/legoomni/src/isle/historybook.cpp b/LEGO1/lego/legoomni/src/isle/historybook.cpp index 2e6691a7..41a49aed 100644 --- a/LEGO1/lego/legoomni/src/isle/historybook.cpp +++ b/LEGO1/lego/legoomni/src/isle/historybook.cpp @@ -1,5 +1,6 @@ #include "historybook.h" +#include "jukebox.h" #include "legocontrolmanager.h" #include "legoinputmanager.h" #include "legoomni.h" @@ -12,9 +13,9 @@ DECOMP_SIZE_ASSERT(HistoryBook, 0x3e4) // FUNCTION: LEGO1 0x100822f0 HistoryBook::HistoryBook() { - memset(m_unk0xfc, NULL, sizeof(m_unk0xfc)); - memset(m_unk0x164, NULL, sizeof(m_unk0x164)); - memset(m_unk0x394, NULL, sizeof(m_unk0x394)); + memset(m_alphabet, NULL, sizeof(m_alphabet)); + memset(m_names, NULL, sizeof(m_names)); + memset(m_scores, NULL, sizeof(m_scores)); NotificationManager()->Register(this); } @@ -61,10 +62,88 @@ MxLong HistoryBook::Notify(MxParam& p_param) return 0; } -// STUB: LEGO1 0x100826f0 +inline void SetColor(MxStillPresenter* p_presenter, MxU8 p_color, MxU8* p_colors, MxU32 p_x, MxU32 p_y) +{ + if (p_color) { + for (MxS32 lax = 0; lax < 4; lax++) { + if (p_presenter->GetAlphaMask() != NULL) { + memset(NULL, p_colors[p_color - 1], 4); + } + else { + memset(p_presenter->GetBitmap()->GetStart(p_x, p_y + lax), p_colors[p_color - 1], 4); + } + } + } +} + +// FUNCTION: LEGO1 0x100826f0 void HistoryBook::ReadyWorld() { - // TODO + LegoWorld::ReadyWorld(); + GameState()->GetScores()->WriteScoreHistory(); + + char bitmap[] = "A_Bitmap"; + for (MxS16 i = 0; i < 26; i++) { + m_alphabet[i] = (MxStillPresenter*) Find("MxStillPresenter", bitmap); + bitmap[0]++; + } + + MxStillPresenter* scoreboxMaster = (MxStillPresenter*) Find("MxStillPresenter", "ScoreBox"); + MxU8 scoreColors[3] = + {0x76, 0x4c, 0x38}; // yellow - #FFB900, blue - #00548C, red - #CB1220, background - #CECECE, border - #74818B + MxS32 scoreY = 0x79; + + for (MxS16 scoreIndex = 0; scoreIndex < GameState()->GetScores()->m_count; scoreIndex++) { + LegoGameState::ScoreItem* score = GameState()->GetScores()->GetScore(scoreIndex); + + MxStillPresenter** scorebox = &m_scores[scoreIndex]; + *scorebox = scoreboxMaster->Clone(); + + MxS32 scoreX = 0x90; + if (scoreIndex >= 10) { + if (scoreIndex == 10) { + scoreY = 0x79; + } + + scoreX = 0x158; + } + + MxS32 scoreboxX = 1; + MxS32 scoreboxRow = 5; + MxU8* scoreState = score->m_state; + + for (; scoreboxRow > 0; scoreboxRow--) { + for (MxS32 scoreBoxColumn = 0, scoreboxY = 1; scoreBoxColumn < 5; scoreBoxColumn++, scoreboxY += 5) { + SetColor(*scorebox, scoreState[scoreBoxColumn], scoreColors, scoreboxX, scoreboxY); + } + + scoreState += 5; + scoreboxX += 5; + } + + (*scorebox)->Enable(TRUE); + (*scorebox)->SetTickleState(MxPresenter::e_repeating); + (*scorebox)->SetPosition(scoreX + 0xa1, scoreY); + + for (MxS16 letterIndex = 0; letterIndex < (MxS16) _countof(m_names[0]);) { + MxS16 letter = score->m_name.m_letters[letterIndex]; + + if (letter == -1) { + break; + } + + MxS16 nameIndex = letterIndex++; + m_names[scoreIndex][nameIndex] = m_alphabet[letter]->Clone(); + m_names[scoreIndex][nameIndex]->Enable(TRUE); + m_names[scoreIndex][nameIndex]->SetTickleState(MxPresenter::e_repeating); + m_names[scoreIndex][nameIndex]->SetPosition(scoreX, scoreY); + scoreX += 0x17; + } + + scoreY += 0x1b; + } + + PlayMusic(JukeBox::e_informationCenter); } // FUNCTION: LEGO1 0x10082a10 diff --git a/LEGO1/omni/include/mxstillpresenter.h b/LEGO1/omni/include/mxstillpresenter.h index 2a64aa09..0fb92862 100644 --- a/LEGO1/omni/include/mxstillpresenter.h +++ b/LEGO1/omni/include/mxstillpresenter.h @@ -40,7 +40,7 @@ public: void NextFrame() override; // vtable+0x64 void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 void RealizePalette() override; // vtable+0x70 - virtual void VTable0x88(MxS32 p_x, MxS32 p_y); // vtable+0x88 + virtual void SetPosition(MxS32 p_x, MxS32 p_y); // vtable+0x88 virtual MxStillPresenter* Clone(); // vtable+0x8c private: diff --git a/LEGO1/omni/src/video/mxstillpresenter.cpp b/LEGO1/omni/src/video/mxstillpresenter.cpp index e36297c6..049ad48c 100644 --- a/LEGO1/omni/src/video/mxstillpresenter.cpp +++ b/LEGO1/omni/src/video/mxstillpresenter.cpp @@ -148,7 +148,7 @@ void MxStillPresenter::RepeatingTickle() } // FUNCTION: LEGO1 0x100ba040 -void MxStillPresenter::VTable0x88(MxS32 p_x, MxS32 p_y) +void MxStillPresenter::SetPosition(MxS32 p_x, MxS32 p_y) { MxS32 x = m_location.GetX(); MxS32 y = m_location.GetY();