CGBASupport implementations

This commit is contained in:
Jack Andersen 2016-12-31 20:46:52 -10:00
parent db7c2aeaf2
commit 0d4ea76c7f
11 changed files with 683 additions and 81 deletions

View File

@ -39,6 +39,8 @@ public:
static OSTime ToWiiTime(std::chrono::system_clock::time_point time); static OSTime ToWiiTime(std::chrono::system_clock::time_point time);
static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime); static std::chrono::system_clock::time_point FromWiiTime(OSTime wiiTime);
static u64 GetGCTicks();
static OSCalendarTime ToCalendarTime(OSTime time) { return ToCalendarTime(FromWiiTime(time)); } static OSCalendarTime ToCalendarTime(OSTime time) { return ToCalendarTime(FromWiiTime(time)); }
static OSCalendarTime ToCalendarTime(std::chrono::system_clock::time_point time); static OSCalendarTime ToCalendarTime(std::chrono::system_clock::time_point time);
}; };

View File

@ -21,6 +21,13 @@ const char* CBasics::Stringize(const char* fmt, ...)
return STRINGIZE_STR; return STRINGIZE_STR;
} }
u64 CBasics::GetGCTicks()
{
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count();
return nanos * 486000000 / 1000000000;
}
const u64 CBasics::SECONDS_TO_2000 = 946684800LL; const u64 CBasics::SECONDS_TO_2000 = 946684800LL;
const u64 CBasics::TICKS_PER_SECOND = 60750000LL; const u64 CBasics::TICKS_PER_SECOND = 60750000LL;

View File

@ -20,11 +20,11 @@ CPersistentOptions::CPersistentOptions(CBitStreamReader& stream)
xc4_ = stream.ReadEncoded(2); xc4_ = stream.ReadEncoded(2);
xc8_ = stream.ReadEncoded(1); xc8_ = stream.ReadEncoded(1);
xcc_logScanCount = stream.ReadEncoded(7); xcc_logScanCount = stream.ReadEncoded(7);
xd0_24_ = stream.ReadEncoded(1); xd0_24_fusionLinked = stream.ReadEncoded(1);
xd0_25_hasHardMode = stream.ReadEncoded(1); xd0_25_normalModeBeat = stream.ReadEncoded(1);
xd0_26_hardModeBeat = stream.ReadEncoded(1); xd0_26_hardModeBeat = stream.ReadEncoded(1);
xd0_27_ = stream.ReadEncoded(1); xd0_27_fusionBeat = stream.ReadEncoded(1);
xd0_28_hasFusion = stream.ReadEncoded(1); xd0_28_fusionSuitActive = stream.ReadEncoded(1);
xd0_29_allItemsCollected = stream.ReadEncoded(1); xd0_29_allItemsCollected = stream.ReadEncoded(1);
xbc_ = stream.ReadEncoded(2); xbc_ = stream.ReadEncoded(2);
@ -66,11 +66,11 @@ void CPersistentOptions::PutTo(CBitStreamWriter& w) const
w.WriteEncoded(xc4_, 2); w.WriteEncoded(xc4_, 2);
w.WriteEncoded(xc8_, 1); w.WriteEncoded(xc8_, 1);
w.WriteEncoded(xcc_logScanCount, 7); w.WriteEncoded(xcc_logScanCount, 7);
w.WriteEncoded(xd0_24_, 1); w.WriteEncoded(xd0_24_fusionLinked, 1);
w.WriteEncoded(xd0_25_hasHardMode, 1); w.WriteEncoded(xd0_25_normalModeBeat, 1);
w.WriteEncoded(xd0_26_hardModeBeat, 1); w.WriteEncoded(xd0_26_hardModeBeat, 1);
w.WriteEncoded(xd0_27_, 1); w.WriteEncoded(xd0_27_fusionBeat, 1);
w.WriteEncoded(xd0_28_hasFusion, 1); w.WriteEncoded(xd0_28_fusionSuitActive, 1);
w.WriteEncoded(xd0_29_allItemsCollected, 1); w.WriteEncoded(xd0_29_allItemsCollected, 1);
w.WriteEncoded(xbc_, 2); w.WriteEncoded(xbc_, 2);

View File

@ -23,11 +23,11 @@ class CPersistentOptions
{ {
struct struct
{ {
bool xd0_24_ : 1; bool xd0_24_fusionLinked : 1;
bool xd0_25_hasHardMode : 1; bool xd0_25_normalModeBeat : 1;
bool xd0_26_hardModeBeat : 1; bool xd0_26_hardModeBeat : 1;
bool xd0_27_ : 1; bool xd0_27_fusionBeat : 1;
bool xd0_28_hasFusion : 1; bool xd0_28_fusionSuitActive : 1;
bool xd0_29_allItemsCollected : 1; bool xd0_29_allItemsCollected : 1;
}; };
u16 _dummy = 0; u16 _dummy = 0;
@ -39,12 +39,16 @@ public:
bool GetCinematicState(ResId mlvlId, TEditorId cineId) const; bool GetCinematicState(ResId mlvlId, TEditorId cineId) const;
void SetCinematicState(ResId mlvlId, TEditorId cineId, bool state); void SetCinematicState(ResId mlvlId, TEditorId cineId, bool state);
bool GetPlayerHasHardMode() const { return xd0_25_hasHardMode; } bool GetPlayerLinkedFusion() const { return xd0_24_fusionLinked; }
void SetPlayerHasHardMode(bool v) { xd0_25_hasHardMode = v; } void SetPlayerLinkedFusion(bool v) { xd0_24_fusionLinked = v; }
bool GetPlayerBeatNormalMode() const { return xd0_25_normalModeBeat; }
void SetPlayerBeatNormalMode(bool v) { xd0_25_normalModeBeat = v; }
bool GetPlayerBeatHardMode() const { return xd0_26_hardModeBeat; } bool GetPlayerBeatHardMode() const { return xd0_26_hardModeBeat; }
void SetPlayerBeatHardMode(bool v) { xd0_26_hardModeBeat = v; } void SetPlayerBeatHardMode(bool v) { xd0_26_hardModeBeat = v; }
bool GetPlayerHasFusion() const { return xd0_28_hasFusion; } bool GetPlayerBeatFusion() const { return xd0_27_fusionBeat; }
void SetPlayerHasFusion(bool v) { xd0_28_hasFusion = v; } void SetPlayerBeatFusion(bool v) { xd0_27_fusionBeat = v; }
bool GetPlayerFusionSuitActive() const { return xd0_28_fusionSuitActive; }
void SetPlayerFusionSuitActive(bool v) { xd0_28_fusionSuitActive = v; }
bool GetAllItemsCollected() const { return xd0_29_allItemsCollected; } bool GetAllItemsCollected() const { return xd0_29_allItemsCollected; }
void SetAllItemsCollected(bool v) { xd0_29_allItemsCollected = v; } void SetAllItemsCollected(bool v) { xd0_29_allItemsCollected = v; }
u32 GetLogScanCount() const { return xcc_logScanCount; } u32 GetLogScanCount() const { return xcc_logScanCount; }

View File

@ -191,27 +191,27 @@ void CGameState::ReadPersistentOptions(CBitStreamReader& r)
void CGameState::ImportPersistentOptions(const CPersistentOptions& opts) void CGameState::ImportPersistentOptions(const CPersistentOptions& opts)
{ {
if (opts.xd0_24_) if (opts.xd0_24_fusionLinked)
xa8_systemOptions.xd0_24_ = true; xa8_systemOptions.xd0_24_fusionLinked = true;
if (opts.xd0_27_) if (opts.xd0_27_fusionBeat)
xa8_systemOptions.xd0_27_ = true; xa8_systemOptions.xd0_27_fusionBeat = true;
if (&opts != &xa8_systemOptions) if (&opts != &xa8_systemOptions)
memcpy(xa8_systemOptions.x0_, opts.x0_, 98); memcpy(xa8_systemOptions.x0_, opts.x0_, 98);
xa8_systemOptions.SetLogScanCount(opts.GetLogScanCount()); xa8_systemOptions.SetLogScanCount(opts.GetLogScanCount());
xa8_systemOptions.SetAllItemsCollected(opts.GetAllItemsCollected()); xa8_systemOptions.SetAllItemsCollected(opts.GetAllItemsCollected());
xa8_systemOptions.SetPlayerHasHardMode(opts.GetPlayerHasHardMode()); xa8_systemOptions.SetPlayerBeatNormalMode(opts.GetPlayerBeatNormalMode());
xa8_systemOptions.SetPlayerBeatHardMode(opts.GetPlayerBeatHardMode()); xa8_systemOptions.SetPlayerBeatHardMode(opts.GetPlayerBeatHardMode());
} }
void CGameState::ExportPersistentOptions(CPersistentOptions& opts) const void CGameState::ExportPersistentOptions(CPersistentOptions& opts) const
{ {
if (xa8_systemOptions.xd0_24_) if (xa8_systemOptions.xd0_24_fusionLinked)
opts.xd0_24_ = true; opts.xd0_24_fusionLinked = true;
if (xa8_systemOptions.xd0_27_) if (xa8_systemOptions.xd0_27_fusionBeat)
opts.xd0_27_ = true; opts.xd0_27_fusionBeat = true;
if (&opts != &xa8_systemOptions) if (&opts != &xa8_systemOptions)
memcpy(opts.x0_, xa8_systemOptions.x0_, 98); memcpy(opts.x0_, xa8_systemOptions.x0_, 98);
opts.SetPlayerHasFusion(xa8_systemOptions.GetPlayerHasFusion()); opts.SetPlayerFusionSuitActive(xa8_systemOptions.GetPlayerFusionSuitActive());
} }
void CGameState::WriteBackupBuf() void CGameState::WriteBackupBuf()

View File

@ -281,7 +281,7 @@ void CFrontEndUI::SNewFileSelectFrame::ActivateNewGamePopup()
PlayAdvanceSfx(); PlayAdvanceSfx();
if (g_GameState->SystemOptions().GetPlayerHasHardMode()) if (g_GameState->SystemOptions().GetPlayerBeatNormalMode())
{ {
x48_textpane_popupadvance.SetPairText(g_MainStringTable->GetString(102)); x48_textpane_popupadvance.SetPairText(g_MainStringTable->GetString(102));
x50_textpane_popupcancel.SetPairText(g_MainStringTable->GetString(94)); x50_textpane_popupcancel.SetPairText(g_MainStringTable->GetString(94));
@ -418,7 +418,7 @@ void CFrontEndUI::SNewFileSelectFrame::DoPopupAdvance(CGuiTableGroup* caller)
} }
else else
{ {
if (g_GameState->SystemOptions().GetPlayerHasHardMode()) if (g_GameState->SystemOptions().GetPlayerBeatNormalMode())
{ {
if (x40_tablegroup_popup->GetUserSelection() == 1) if (x40_tablegroup_popup->GetUserSelection() == 1)
{ {
@ -488,32 +488,239 @@ CFrontEndUI::SGBASupportFrame::SGBASupportFrame()
void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SetUIText(EUIType tp) void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SetUIText(EUIType tp)
{ {
int instructions = -1;
int yes = -1;
int no = -1;
bool cableVisible = false;
bool circleGcVisible = false;
bool circleGbaVisible = false;
bool circleStartVisible = false;
bool pakoutVisible = false;
bool gbaScreenVisible = false;
bool connectVisible = false;
switch (tp)
{
case EUIType::InsertPak:
instructions = 73; // Insert Game Pak
no = 82;
yes = 83;
pakoutVisible = true;
circleGbaVisible = true;
break;
case EUIType::ConnectSocket:
instructions = 68; // Connect socket
no = 82;
yes = 83;
cableVisible = true;
circleGcVisible = true;
circleGbaVisible = true;
break;
case EUIType::PressStartAndSelect:
instructions = 74; // Hold start and select
no = 82;
yes = 83;
cableVisible = true;
circleStartVisible = true;
gbaScreenVisible = true;
break;
case EUIType::BeginLink:
instructions = 75; // Begin link?
no = 82;
yes = 83;
cableVisible = true;
gbaScreenVisible = true;
break;
case EUIType::TurnOffGBA:
instructions = 76; // Turn off GBA
no = 82;
yes = 83;
cableVisible = true;
gbaScreenVisible = true;
circleStartVisible = true;
break;
case EUIType::Linking:
x4_gbaSupport->StartLink();
instructions = 72; // Linking
cableVisible = true;
gbaScreenVisible = true;
connectVisible = true;
break;
case EUIType::LinkFailed:
instructions = 69; // Link failed
no = 82;
yes = 83;
cableVisible = true;
circleGcVisible = true;
circleGbaVisible = true;
circleStartVisible = true;
gbaScreenVisible = true;
break;
case EUIType::LinkCompleteOrLinking:
yes = 83;
instructions = x40_linkInProgress + 71; // Complete or linking
cableVisible = true;
gbaScreenVisible = true;
break;
case EUIType::Complete:
case EUIType::Cancelled:
default:
break;
}
std::wstring instructionsStr;
if (instructions != -1)
instructionsStr = g_MainStringTable->GetString(instructions);
xc_textpane_instructions.SetPairText(instructionsStr);
std::wstring yesStr;
if (yes != -1)
yesStr = g_MainStringTable->GetString(yes);
x14_textpane_yes->TextSupport()->SetText(yesStr);
std::wstring noStr;
if (no != -1)
noStr = g_MainStringTable->GetString(no);
x18_textpane_no->TextSupport()->SetText(noStr);
x1c_model_gc->SetVisibility(true, ETraversalMode::Children);
x20_model_gba->SetVisibility(true, ETraversalMode::Children);
x24_model_cable->SetVisibility(cableVisible, ETraversalMode::Children);
x28_model_circlegcport->SetVisibility(circleGcVisible, ETraversalMode::Children);
x2c_model_circlegbaport->SetVisibility(circleGbaVisible, ETraversalMode::Children);
x30_model_circlestartselect->SetVisibility(circleStartVisible, ETraversalMode::Children);
x34_model_pakout->SetVisibility(pakoutVisible, ETraversalMode::Children);
x38_model_gbascreen->SetVisibility(gbaScreenVisible, ETraversalMode::Children);
x3c_model_connect->SetVisibility(connectVisible, ETraversalMode::Children);
x0_uiType = tp;
} }
void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::ProcessUserInput(const CFinalInput &input, bool sui) static const CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType NextLinkUI[] =
{ {
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::ConnectSocket,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::PressStartAndSelect,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::BeginLink,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Linking,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::TurnOffGBA,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Complete,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::InsertPak,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty
};
static const CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType PrevLinkUI[] =
{
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty,
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty
};
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EAction
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::ProcessUserInput(const CFinalInput &input, bool linkInProgress)
{
if (linkInProgress != x40_linkInProgress)
{
x40_linkInProgress = linkInProgress;
SetUIText(x0_uiType);
}
switch (x0_uiType)
{
case EUIType::InsertPak:
case EUIType::ConnectSocket:
case EUIType::PressStartAndSelect:
case EUIType::BeginLink:
case EUIType::LinkFailed:
case EUIType::LinkCompleteOrLinking:
case EUIType::TurnOffGBA:
if (input.PA())
{
PlayAdvanceSfx();
SetUIText(NextLinkUI[int(x0_uiType)]);
}
else if (input.PB())
{
EUIType prevUi = PrevLinkUI[int(x0_uiType)];
if (prevUi == EUIType::Empty)
break;
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
SetUIText(prevUi);
}
break;
case EUIType::Linking:
if (x4_gbaSupport->GetPhase() == CGBASupport::EPhase::Complete)
{
if (x4_gbaSupport->IsFusionLinked())
g_GameState->SystemOptions().SetPlayerLinkedFusion(true);
if (x4_gbaSupport->IsFusionBeat())
g_GameState->SystemOptions().SetPlayerBeatFusion(true);
if (x4_gbaSupport->IsFusionLinked())
{
PlayAdvanceSfx();
SetUIText(EUIType::LinkCompleteOrLinking);
}
else
{
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
SetUIText(EUIType::LinkFailed);
}
}
break;
case EUIType::Complete:
return EAction::Complete;
case EUIType::Cancelled:
return EAction::Cancelled;
default: break;
}
return EAction::None;
} }
void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Update(float dt) void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Update(float dt)
{ {
x4_gbaSupport->Update(dt);
x8_frme->Update(dt);
} }
void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::FinishedLoading() void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::FinishedLoading()
{ {
xc_textpane_instructions = FindTextPanePair(x8_frme, "textpane_instructions");
x14_textpane_yes = static_cast<CGuiTextPane*>(x8_frme->FindWidget("textpane_yes"));
x18_textpane_no = static_cast<CGuiTextPane*>(x8_frme->FindWidget("textpane_no"));
x1c_model_gc = static_cast<CGuiModel*>(x8_frme->FindWidget("model_gc"));
x20_model_gba = static_cast<CGuiModel*>(x8_frme->FindWidget("model_gba"));
x24_model_cable = static_cast<CGuiModel*>(x8_frme->FindWidget("model_cable"));
x28_model_circlegcport = static_cast<CGuiModel*>(x8_frme->FindWidget("model_circlegcport"));
x2c_model_circlegbaport = static_cast<CGuiModel*>(x8_frme->FindWidget("model_circlegbaport"));
x30_model_circlestartselect = static_cast<CGuiModel*>(x8_frme->FindWidget("model_circlestartselect"));
x34_model_pakout = static_cast<CGuiModel*>(x8_frme->FindWidget("model_pakout"));
x38_model_gbascreen = static_cast<CGuiModel*>(x8_frme->FindWidget("model_gbascreen"));
x3c_model_connect = static_cast<CGuiModel*>(x8_frme->FindWidget("model_connect"));
SetUIText(EUIType::InsertPak);
} }
void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Draw() void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Draw()
{ {
x8_frme->Draw(CGuiWidgetDrawParms::Default);
} }
CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SGBALinkFrame(const CGuiFrame* linkFrame, CGBASupport* support, bool) CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SGBALinkFrame(CGuiFrame* linkFrame,
CGBASupport* support,
bool linkInProgress)
: x4_gbaSupport(support), x8_frme(linkFrame), x40_linkInProgress(linkInProgress)
{ {
support->InitializeSupport();
FinishedLoading();
} }
void CFrontEndUI::SGBASupportFrame::FinishedLoading() void CFrontEndUI::SGBASupportFrame::FinishedLoading()
@ -536,17 +743,17 @@ void CFrontEndUI::SGBASupportFrame::FinishedLoading()
x2c_tablegroup_fusionsuit->SetIsActive(false); x2c_tablegroup_fusionsuit->SetIsActive(false);
x2c_tablegroup_fusionsuit->SetIsVisible(false); x2c_tablegroup_fusionsuit->SetIsVisible(false);
x2c_tablegroup_fusionsuit->SetD1(false); x2c_tablegroup_fusionsuit->SetD1(false);
x2c_tablegroup_fusionsuit->SetUserSelection(g_GameState->SystemOptions().GetPlayerHasFusion()); x2c_tablegroup_fusionsuit->SetUserSelection(g_GameState->SystemOptions().GetPlayerFusionSuitActive());
SetTableColors(x28_tablegroup_options); SetTableColors(x28_tablegroup_options);
SetTableColors(x2c_tablegroup_fusionsuit); SetTableColors(x2c_tablegroup_fusionsuit);
x28_tablegroup_options->SetMenuAdvanceCallback( x28_tablegroup_options->SetMenuAdvanceCallback(
std::bind(&SGBASupportFrame::DoOptionsAdvance, this, std::placeholders::_1)); std::bind(&SGBASupportFrame::DoAdvance, this, std::placeholders::_1));
x28_tablegroup_options->SetMenuSelectionChangeCallback( x28_tablegroup_options->SetMenuSelectionChangeCallback(
std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1)); std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1));
x28_tablegroup_options->SetMenuCancelCallback( x28_tablegroup_options->SetMenuCancelCallback(
std::bind(&SGBASupportFrame::DoOptionsCancel, this, std::placeholders::_1)); std::bind(&SGBASupportFrame::DoCancel, this, std::placeholders::_1));
x2c_tablegroup_fusionsuit->SetMenuSelectionChangeCallback( x2c_tablegroup_fusionsuit->SetMenuSelectionChangeCallback(
std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1)); std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1));
} }
@ -574,35 +781,172 @@ void CFrontEndUI::SGBASupportFrame::SetTableColors(CGuiTableGroup* tbgp) const
zeus::CColor{0.627450f, 0.627450f, 0.627450f, 0.784313f}); zeus::CColor{0.627450f, 0.627450f, 0.627450f, 0.784313f});
} }
void CFrontEndUI::SGBASupportFrame::Update(float dt, CSaveUI* saveUI)
{
bool doUpdate = false;
if (saveUI)
if (saveUI->GetUIType() == CSaveUI::EUIType::SaveProgress)
doUpdate = true;
if (doUpdate != x38_lastDoUpdate)
{
x38_lastDoUpdate = doUpdate;
ResetCompletionFlags();
}
if (x0_gbaLinkFrame)
x0_gbaLinkFrame->Update(dt);
else if (x24_loadedFrame)
x24_loadedFrame->Update(dt);
bool showFusionSuit = g_GameState->SystemOptions().GetPlayerLinkedFusion() &&
g_GameState->SystemOptions().GetPlayerBeatNormalMode();
bool showFusionSuitProceed = showFusionSuit && x28_tablegroup_options->GetUserSelection() == 1;
x2c_tablegroup_fusionsuit->SetIsActive(showFusionSuitProceed);
x2c_tablegroup_fusionsuit->SetIsVisible(showFusionSuitProceed);
x24_loadedFrame->FindWidget("textpane_proceed")->SetIsVisible(showFusionSuitProceed);
std::wstring instructionStr;
if (x28_tablegroup_options->GetUserSelection() == 1)
{
/* Fusion Suit */
if (x3a_mpNotComplete)
instructionStr = g_MainStringTable->GetString(80); // MP not complete
else if (!showFusionSuit)
instructionStr = g_MainStringTable->GetString(78); // To enable fusion suit
}
else
{
/* NES Metroid */
if (x39_fusionNotComplete)
instructionStr = g_MainStringTable->GetString(79); // You have not completed fusion
else if (!g_GameState->SystemOptions().GetPlayerBeatFusion())
instructionStr = g_MainStringTable->GetString(77); // To play NES Metroid
}
x30_textpane_instructions.SetPairText(instructionStr);
}
CFrontEndUI::SGBASupportFrame::EAction CFrontEndUI::SGBASupportFrame::EAction
CFrontEndUI::SGBASupportFrame::ProcessUserInput(const CFinalInput& input, CSaveUI* sui) CFrontEndUI::SGBASupportFrame::ProcessUserInput(const CFinalInput& input, CSaveUI* sui)
{ {
return EAction::Zero; x8_action = EAction::None;
if (sui)
sui->ProcessUserInput(input);
if (x38_lastDoUpdate)
{
if (x0_gbaLinkFrame)
{
SGBALinkFrame::EAction action = x0_gbaLinkFrame->ProcessUserInput(input, sui);
if (action != SGBALinkFrame::EAction::None)
{
x0_gbaLinkFrame.reset();
if (action == SGBALinkFrame::EAction::Complete)
{
if (x28_tablegroup_options->GetUserSelection() == 0 &&
!g_GameState->SystemOptions().GetPlayerBeatFusion())
x39_fusionNotComplete = true;
else if (sui)
sui->SaveNESState();
else if (x24_loadedFrame)
x24_loadedFrame->ProcessUserInput(input);
}
}
}
}
return x8_action;
} }
void CFrontEndUI::SGBASupportFrame::Draw() const void CFrontEndUI::SGBASupportFrame::Draw() const
{ {
if (!x38_) if (!x38_lastDoUpdate)
return; return;
if (x0_gbaLinkFrame) if (x0_gbaLinkFrame)
{ x0_gbaLinkFrame->Draw();
else if (x24_loadedFrame)
} x24_loadedFrame->Draw(CGuiWidgetDrawParms::Default);
} }
void CFrontEndUI::SGBASupportFrame::DoOptionsCancel(CGuiTableGroup* caller) void CFrontEndUI::SGBASupportFrame::DoCancel(CGuiTableGroup* caller)
{ {
if (x39_fusionNotComplete || x3a_mpNotComplete)
{
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
}
else
{
x8_action = EAction::GoBack;
x28_tablegroup_options->SetUserSelection(0);
x2c_tablegroup_fusionsuit->SetIsActive(false);
x30_textpane_instructions.SetPairText(L"");
SetTableColors(x28_tablegroup_options);
}
} }
void CFrontEndUI::SGBASupportFrame::DoSelectionChange(CGuiTableGroup* caller) void CFrontEndUI::SGBASupportFrame::DoSelectionChange(CGuiTableGroup* caller)
{ {
if (caller == x28_tablegroup_options)
{
CSfxManager::SfxStart(1093, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
x3a_mpNotComplete = false;
x39_fusionNotComplete = false;
}
else
{
CSfxManager::SfxStart(1095, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
bool fusionActive = x2c_tablegroup_fusionsuit->GetUserSelection() == 1;
g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionActive);
g_GameState->GetPlayerState()->SetIsFusionEnabled(fusionActive);
}
SetTableColors(caller);
} }
void CFrontEndUI::SGBASupportFrame::DoOptionsAdvance(CGuiTableGroup* caller) void CFrontEndUI::SGBASupportFrame::DoAdvance(CGuiTableGroup* caller)
{ {
switch (x28_tablegroup_options->GetUserSelection())
{
case 1:
/* Fusion Suit */
if (x3a_mpNotComplete)
{
x3a_mpNotComplete = false;
PlayAdvanceSfx();
}
else if (g_GameState->SystemOptions().GetPlayerBeatNormalMode())
{
if (g_GameState->SystemOptions().GetPlayerLinkedFusion())
return;
x0_gbaLinkFrame = std::make_unique<SGBALinkFrame>(x18_gbaLink.GetObj(), x4_gbaSupport.get(), false);
PlayAdvanceSfx();
}
else
{
x3a_mpNotComplete = true;
CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
}
break;
case 0:
/* NES Metroid */
if (x39_fusionNotComplete)
{
x39_fusionNotComplete = false;
PlayAdvanceSfx();
}
else if (g_GameState->SystemOptions().GetPlayerBeatFusion())
{
x8_action = EAction::PlayNESMetroid;
}
else
{
x0_gbaLinkFrame = std::make_unique<SGBALinkFrame>(x18_gbaLink.GetObj(), x4_gbaSupport.get(), false);
PlayAdvanceSfx();
}
break;
default: break;
}
} }
void CFrontEndUI::SGuiTextPair::SetPairText(const std::wstring& str) void CFrontEndUI::SGuiTextPair::SetPairText(const std::wstring& str)
@ -1311,10 +1655,10 @@ void CFrontEndUI::ProcessUserInput(const CFinalInput& input, CArchitectureQueue&
{ {
switch (xe4_gbaSupportFrme->ProcessUserInput(input, xdc_saveUI.get())) switch (xe4_gbaSupportFrme->ProcessUserInput(input, xdc_saveUI.get()))
{ {
case SGBASupportFrame::EAction::One: case SGBASupportFrame::EAction::GoBack:
StartStateTransition(EScreen::Three); StartStateTransition(EScreen::Three);
return; return;
case SGBASupportFrame::EAction::Two: case SGBASupportFrame::EAction::PlayNESMetroid:
xf4_curAudio->StopMixing(); xf4_curAudio->StopMixing();
xec_emuFrme = std::make_unique<SNesEmulatorFrame>(); xec_emuFrme = std::make_unique<SNesEmulatorFrame>();
if (xdc_saveUI) if (xdc_saveUI)

View File

@ -175,53 +175,88 @@ public:
{ {
enum class EUIType enum class EUIType
{ {
Zero, Empty = -1,
One, InsertPak = 0,
Two, ConnectSocket = 1,
Three, PressStartAndSelect = 2,
Four, BeginLink = 3,
Five, Linking = 4,
Six, LinkFailed = 5,
Seven LinkCompleteOrLinking = 6,
TurnOffGBA = 7,
Complete = 8,
Cancelled = 9
}; };
enum class EAction
{
None = 0,
Complete = 1,
Cancelled = 2
};
EUIType x0_uiType;
CGBASupport* x4_gbaSupport;
CGuiFrame* x8_frme;
SGuiTextPair xc_textpane_instructions;
CGuiTextPane* x14_textpane_yes = nullptr;
CGuiTextPane* x18_textpane_no = nullptr;
CGuiModel* x1c_model_gc = nullptr;
CGuiModel* x20_model_gba = nullptr;
CGuiModel* x24_model_cable = nullptr;
CGuiModel* x28_model_circlegcport = nullptr;
CGuiModel* x2c_model_circlegbaport = nullptr;
CGuiModel* x30_model_circlestartselect = nullptr;
CGuiModel* x34_model_pakout = nullptr;
CGuiModel* x38_model_gbascreen = nullptr;
CGuiModel* x3c_model_connect = nullptr;
bool x40_linkInProgress;
void SetUIText(EUIType tp); void SetUIText(EUIType tp);
void ProcessUserInput(const CFinalInput &input, bool sui); EAction ProcessUserInput(const CFinalInput &input, bool linkInProgress);
void Update(float dt); void Update(float dt);
void FinishedLoading(); void FinishedLoading();
void Draw(); void Draw();
SGBALinkFrame(const CGuiFrame* linkFrame, CGBASupport* support, bool); SGBALinkFrame(CGuiFrame* linkFrame, CGBASupport* support, bool linkInProgress);
}; };
enum class EAction enum class EAction
{ {
Zero, None,
One, GoBack,
Two PlayNESMetroid
}; };
std::unique_ptr<SGBALinkFrame> x0_gbaLinkFrame; std::unique_ptr<SGBALinkFrame> x0_gbaLinkFrame;
std::unique_ptr<CGBASupport> x4_gbaSupport; std::unique_ptr<CGBASupport> x4_gbaSupport;
EAction x8_action = EAction::None;
TLockedToken<CGuiFrame> xc_gbaScreen; TLockedToken<CGuiFrame> xc_gbaScreen;
TLockedToken<CGuiFrame> x18_gbaLink; TLockedToken<CGuiFrame> x18_gbaLink;
CGuiFrame* x24_loadedFrame = nullptr; CGuiFrame* x24_loadedFrame = nullptr;
CGuiTableGroup* x28_tablegroup_options = nullptr; CGuiTableGroup* x28_tablegroup_options = nullptr;
CGuiTableGroup* x2c_tablegroup_fusionsuit = nullptr; CGuiTableGroup* x2c_tablegroup_fusionsuit = nullptr;
SGuiTextPair x30_textpane_instructions; SGuiTextPair x30_textpane_instructions;
bool x38_ = false; bool x38_lastDoUpdate = false;
bool x39_ = false; bool x39_fusionNotComplete = false;
bool x3a_ = false; bool x3a_mpNotComplete = false;
SGBASupportFrame(); SGBASupportFrame();
void FinishedLoading(); void FinishedLoading();
bool PumpLoad(); bool PumpLoad();
void SetTableColors(CGuiTableGroup* tbgp) const; void SetTableColors(CGuiTableGroup* tbgp) const;
void Update(float dt, CSaveUI* saveUI);
EAction ProcessUserInput(const CFinalInput& input, CSaveUI* sui); EAction ProcessUserInput(const CFinalInput& input, CSaveUI* sui);
void Draw() const; void Draw() const;
void DoOptionsCancel(CGuiTableGroup* caller); void ResetCompletionFlags()
{
x39_fusionNotComplete = false;
x3a_mpNotComplete = false;
}
void DoCancel(CGuiTableGroup* caller);
void DoSelectionChange(CGuiTableGroup* caller); void DoSelectionChange(CGuiTableGroup* caller);
void DoOptionsAdvance(CGuiTableGroup* caller); void DoAdvance(CGuiTableGroup* caller);
}; };
struct SFrontEndFrame struct SFrontEndFrame

View File

@ -1,10 +1,57 @@
#include "CGBASupport.hpp" #include "CGBASupport.hpp"
#include "CDvdRequest.hpp"
#include "CBasics.hpp"
namespace urde namespace urde
{ {
namespace MP1 namespace MP1
{ {
#define GBA_JSTAT_MASK 0x3a
#define GBA_JSTAT_FLAGS_SHIFT 4
#define GBA_JSTAT_FLAGS_MASK 0x30
#define GBA_JSTAT_PSF1 0x20
#define GBA_JSTAT_PSF0 0x10
#define GBA_JSTAT_SEND 0x08
#define GBA_JSTAT_RECV 0x02
#define GBA_READY 0
#define GBA_NOT_READY 1
#define GBA_BUSY 2
#define GBA_JOYBOOT_UNKNOWN_STATE 3
#define GBA_JOYBOOT_ERR_INVALID 4
static s32 GBAJoyBootAsync(s32 chan, s32 paletteColor, s32 paletteSpeed,
u8* programp, s32 length, u8* status)
{
return GBA_READY;
}
static s32 GBAGetProcessStatus(s32 chan, u8* percentp)
{
return GBA_READY;
}
static s32 GBAGetStatus(s32 chan, u8* status)
{
return GBA_READY;
}
static s32 GBAReset(s32 chan, u8* status)
{
return GBA_READY;
}
static s32 GBARead(s32 chan, u8* dst, u8* status)
{
return GBA_READY;
}
static s32 GBAWrite(s32 chan, u8* src, u8* status)
{
return GBA_READY;
}
CGBASupport* CGBASupport::SharedInstance = nullptr; CGBASupport* CGBASupport::SharedInstance = nullptr;
CGBASupport::CGBASupport() CGBASupport::CGBASupport()
@ -13,7 +60,7 @@ CGBASupport::CGBASupport()
x28_fileSize = ROUND_UP_32(Length()); x28_fileSize = ROUND_UP_32(Length());
x2c_buffer.reset(new u8[x28_fileSize]); x2c_buffer.reset(new u8[x28_fileSize]);
x30_dvdReq = AsyncRead(x2c_buffer.get(), x28_fileSize); x30_dvdReq = AsyncRead(x2c_buffer.get(), x28_fileSize);
//InitDSPComm(); //GBAInit();
SharedInstance = this; SharedInstance = this;
} }
@ -22,10 +69,150 @@ CGBASupport::~CGBASupport()
SharedInstance = nullptr; SharedInstance = nullptr;
} }
bool CGBASupport::IsReady() const bool CGBASupport::PollResponse()
{ {
u8 status;
if (GBAReset(x40_siChan, &status) == GBA_NOT_READY)
if (GBAReset(x40_siChan, &status) == GBA_NOT_READY)
return false;
if (GBAGetStatus(x40_siChan, &status) == GBA_NOT_READY)
return false;
if (status != (GBA_JSTAT_PSF1 | GBA_JSTAT_SEND))
return false;
u8 bytes[4];
if (GBARead(x40_siChan, bytes, &status) == GBA_NOT_READY)
return false;
if (reinterpret_cast<u32&>(bytes) != SBIG('AMTE'))
return false;
if (GBAGetStatus(x40_siChan, &status) == GBA_NOT_READY)
return false;
if (status != GBA_JSTAT_PSF1)
return false;
if (GBAWrite(x40_siChan, (unsigned char*)"AMTE", &status) == GBA_NOT_READY)
return false;
if (GBAGetStatus(x40_siChan, &status) == GBA_NOT_READY)
return false;
if ((status & GBA_JSTAT_FLAGS_MASK) != GBA_JSTAT_FLAGS_MASK)
return false;
u64 profStart = CBasics::GetGCTicks();
const u64 timeToSpin = 486000000 / 8000;
for (;;)
{
u64 curTime = CBasics::GetGCTicks();
if (curTime - profStart > timeToSpin)
return true;
if (GBAGetStatus(x40_siChan, &status) == GBA_NOT_READY)
continue;
if (!(status & GBA_JSTAT_SEND))
continue;
if (GBAGetStatus(x40_siChan, &status) == GBA_NOT_READY)
continue;
if (status != (GBA_JSTAT_FLAGS_MASK | GBA_JSTAT_SEND))
continue;
break;
}
if (GBARead(x40_siChan, bytes, &status) != GBA_READY)
return false;
/* CRC Here */
x44_fusionLinked = (bytes[2] & 0x2) != 0;
if (x44_fusionLinked && (bytes[2] & 0x1) != 0)
x45_fusionBeat = true;
return true;
}
void CGBASupport::Update(float dt)
{
switch (x34_phase)
{
case EPhase::LoadClientPad:
IsReady();
break;
case EPhase::StartProbeTimeout:
x38_timeout = 4.f;
x34_phase = EPhase::PollProbe;
case EPhase::PollProbe:
/* SIProbe poll normally occurs here with 4 second timeout */
x34_phase = EPhase::StartJoyBusBoot;
case EPhase::StartJoyBusBoot:
x34_phase = EPhase::PollJoyBusBoot;
GBAJoyBootAsync(x40_siChan, x40_siChan * 2, 2, x2c_buffer.get(), x28_fileSize, &x3c_status);
break;
case EPhase::PollJoyBusBoot:
if (GBAGetProcessStatus(x40_siChan, &x3c_status) == GBA_BUSY)
break;
if (GBAGetStatus(x40_siChan, &x3c_status) == GBA_NOT_READY)
{
x34_phase = EPhase::Failed;
break;
}
x38_timeout = 4.f;
x34_phase = EPhase::DataTransfer;
break;
case EPhase::DataTransfer:
if (PollResponse())
{
x34_phase = EPhase::Complete;
break;
}
x38_timeout = std::max(0.f, x38_timeout - dt);
if (x38_timeout == 0.f)
x34_phase = EPhase::Failed;
break;
default: break;
}
}
bool CGBASupport::IsReady()
{
if (x34_phase != EPhase::LoadClientPad)
return true;
if (x30_dvdReq->IsComplete())
{
x30_dvdReq.reset();
x34_phase = EPhase::Standby;
/* Conveniently already little-endian */
reinterpret_cast<u32&>(x2c_buffer[0xc8]) = u32(CBasics::GetGCTicks());
x2c_buffer[0xaf] = 'E';
x2c_buffer[0xbd] = 0xc9;
return true;
}
return false; return false;
} }
void CGBASupport::InitializeSupport()
{
x34_phase = EPhase::Standby;
x38_timeout = 0.f;
x3c_status = false;
x40_siChan = -1;
x44_fusionLinked = false;
x45_fusionBeat = false;
}
void CGBASupport::StartLink()
{
x34_phase = EPhase::StartProbeTimeout;
x40_siChan = -1;
}
} }
} }

View File

@ -10,20 +10,43 @@ namespace MP1
class CGBASupport : public CDvdFile class CGBASupport : public CDvdFile
{ {
public:
enum class EPhase
{
LoadClientPad,
Standby,
StartProbeTimeout,
PollProbe,
StartJoyBusBoot,
PollJoyBusBoot,
DataTransfer,
Complete,
Failed
};
private:
u32 x28_fileSize; u32 x28_fileSize;
std::unique_ptr<u8[]> x2c_buffer; std::unique_ptr<u8[]> x2c_buffer;
std::shared_ptr<IDvdRequest> x30_dvdReq; std::shared_ptr<IDvdRequest> x30_dvdReq;
u32 x34_ = 0; EPhase x34_phase = EPhase::LoadClientPad;
float x38_ = 0.f; float x38_timeout = 0.f;
bool x3c_ = false; u8 x3c_status = 0;
u32 x40_ = -1; u32 x40_siChan = -1;
bool x44_ = false; bool x44_fusionLinked = false;
bool x45_ = false; bool x45_fusionBeat = false;
static CGBASupport* SharedInstance; static CGBASupport* SharedInstance;
public: public:
CGBASupport(); CGBASupport();
~CGBASupport(); ~CGBASupport();
bool IsReady() const; bool PollResponse();
void Update(float dt);
bool IsReady();
void InitializeSupport();
void StartLink();
EPhase GetPhase() const { return x34_phase; }
bool IsFusionLinked() const { return x44_fusionLinked; }
bool IsFusionBeat() const { return x45_fusionBeat; }
}; };
} }

View File

@ -754,7 +754,7 @@ void CMemoryCardDriver::UpdateCardFormat(ECardResult result)
void CMemoryCardDriver::BuildNewFileSlot(u32 saveIdx) void CMemoryCardDriver::BuildNewFileSlot(u32 saveIdx)
{ {
g_GameState->SetFileIdx(saveIdx); g_GameState->SetFileIdx(saveIdx);
bool fusionBackup = g_GameState->SystemOptions().GetPlayerHasFusion(); bool fusionBackup = g_GameState->SystemOptions().GetPlayerFusionSuitActive();
std::unique_ptr<SGameFileSlot>& slot = xe4_fileSlots[saveIdx]; std::unique_ptr<SGameFileSlot>& slot = xe4_fileSlots[saveIdx];
if (!slot) if (!slot)
@ -765,7 +765,7 @@ void CMemoryCardDriver::BuildNewFileSlot(u32 saveIdx)
g_GameState->ReadPersistentOptions(r); g_GameState->ReadPersistentOptions(r);
ImportPersistentOptions(); ImportPersistentOptions();
g_GameState->SetCardSerial(x28_cardSerial); g_GameState->SetCardSerial(x28_cardSerial);
g_GameState->SystemOptions().SetPlayerHasFusion(fusionBackup); g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionBackup);
} }
void CMemoryCardDriver::EraseFileSlot(u32 saveIdx) void CMemoryCardDriver::EraseFileSlot(u32 saveIdx)

View File

@ -108,7 +108,7 @@ void CMain::ResetGameState()
x128_globalObjects.ResetGameState(); x128_globalObjects.ResetGameState();
g_GameState->ImportPersistentOptions(sysOpts); g_GameState->ImportPersistentOptions(sysOpts);
g_GameState->SetGameOptions(gameOpts); g_GameState->SetGameOptions(gameOpts);
g_GameState->GetPlayerState()->SetIsFusionEnabled(g_GameState->SystemOptions().GetPlayerHasFusion()); g_GameState->GetPlayerState()->SetIsFusionEnabled(g_GameState->SystemOptions().GetPlayerFusionSuitActive());
} }
void CMain::InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr) void CMain::InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr)
@ -130,10 +130,10 @@ void CMain::LoadAudio()
void CMain::StreamNewGameState(CBitStreamReader& r, u32 idx) void CMain::StreamNewGameState(CBitStreamReader& r, u32 idx)
{ {
bool fusionBackup = g_GameState->SystemOptions().GetPlayerHasFusion(); bool fusionBackup = g_GameState->SystemOptions().GetPlayerFusionSuitActive();
x128_globalObjects.x134_gameState = std::make_unique<CGameState>(r, idx); x128_globalObjects.x134_gameState = std::make_unique<CGameState>(r, idx);
g_GameState = x128_globalObjects.x134_gameState.get(); g_GameState = x128_globalObjects.x134_gameState.get();
g_GameState->SystemOptions().SetPlayerHasFusion(fusionBackup); g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionBackup);
g_GameState->GetPlayerState()->SetIsFusionEnabled(fusionBackup); g_GameState->GetPlayerState()->SetIsFusionEnabled(fusionBackup);
g_GameState->HintOptions().SetNextHintTime(); g_GameState->HintOptions().SetNextHintTime();
} }