531 lines
15 KiB
C++
531 lines
15 KiB
C++
#include "Frontend/Store/PauseStoreMenu.h"
|
|
#include "Frontend/Store/StoreUIChannel.h"
|
|
|
|
|
|
#include "Frontend/ButtonEnum.h"
|
|
#include "Frontend/PauseMenu.h"
|
|
#include "frontend/Store/StoreScreenMgr.h"
|
|
#include "network/Live/livemanager.h"
|
|
#include "network/NetworkInterface.h"
|
|
#include "Network/Sessions/NetworkSession.h"
|
|
#include "rline/rlgamerinfo.h"
|
|
#include "Stats/MoneyInterface.h"
|
|
#include "net/nethardware.h"
|
|
|
|
|
|
FRONTEND_STORE_OPTIMISATIONS()
|
|
|
|
XPARAM(leavempforstore);
|
|
|
|
const unsigned int STORE_UNAVAILABLE_DISPLAY_FRAME_THRESHOLD = 90;
|
|
|
|
CPauseStoreMenu::CPauseStoreMenu( CMenuScreen& owner ): CMenuBase(owner),
|
|
m_storeState(STATE_NONE),
|
|
m_StoreSigninFrameCount(0),
|
|
m_WaitingForLoginScreenReturn(false),
|
|
m_WaitingForLoginScreenEntrance(false),
|
|
m_bIsDisplayingNews(false),
|
|
m_bStoryTextPosted(false)
|
|
{
|
|
|
|
}
|
|
|
|
CPauseStoreMenu::~CPauseStoreMenu()
|
|
{
|
|
|
|
}
|
|
|
|
void CPauseStoreMenu::Init()
|
|
{
|
|
m_WaitingForLoginScreenReturn = false;
|
|
m_WaitingForLoginScreenEntrance = false;
|
|
m_StoreSigninFrameCount = 0;
|
|
}
|
|
|
|
void CPauseStoreMenu::Update()
|
|
{
|
|
CMenuBase::Update();
|
|
|
|
|
|
if ( m_WaitingForLoginScreenEntrance && CLiveManager::IsSystemUiShowing() )
|
|
{
|
|
m_WaitingForLoginScreenEntrance = false;
|
|
m_WaitingForLoginScreenReturn = true;
|
|
|
|
}
|
|
else if ( m_WaitingForLoginScreenReturn && !CLiveManager::IsSystemUiShowing())
|
|
{
|
|
m_WaitingForLoginScreenReturn = false;
|
|
|
|
if( CPauseMenu::IsStoreAvailable() && !CLiveManager::GetCommerceMgr().IsThinDataPopulationInProgress() )
|
|
{
|
|
//We close the pause menu immediately unless we are in an MP game AND the leave mp for store param is set
|
|
bool closePauseMenuImmediately = !(NetworkInterface::IsGameInProgress() && PARAM_leavempforstore.Get());
|
|
if (closePauseMenuImmediately)
|
|
{
|
|
CPauseMenu::TriggerStore();
|
|
}
|
|
else
|
|
{
|
|
cStoreScreenMgr::RequestMPStore();
|
|
|
|
//Lock the store screen early to avoid glitches when leaving the session.
|
|
CPauseMenu::TogglePauseRenderPhases(false, OWNER_STORE, __FUNCTION__ );
|
|
}
|
|
}
|
|
}
|
|
|
|
//We use this to stop flickers of unavailability, and a visible progression of states on sign in.
|
|
if ( CPauseMenu::IsStoreAvailable() )
|
|
{
|
|
m_StoreSigninFrameCount = 0;
|
|
|
|
// If we are displaying news, let's check for any updates
|
|
if( m_bIsDisplayingNews)
|
|
{
|
|
CNetworkPauseMenuNewsController& newsController = CNetworkPauseMenuNewsController::Get();
|
|
if(newsController.IsPendingStoryReady())
|
|
{
|
|
PostStoreStory(newsController.GetPendingStory(), true);
|
|
UpdateStoreColumnScroll(newsController.GetNumStories(), newsController.GetPendingStoryIndex());
|
|
CNetworkPauseMenuNewsController::Get().MarkPendingStoryAsShown();
|
|
m_bStoryTextPosted = false;
|
|
}
|
|
else if(!m_bStoryTextPosted && newsController.IsPendingStoryDataRcvd())
|
|
{
|
|
PostStoreStory(newsController.GetPendingStory(), false);
|
|
UpdateStoreColumnScroll(newsController.GetNumStories(), newsController.GetPendingStoryIndex());
|
|
m_bStoryTextPosted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//We use this point to delay the DC message after sign in. Hopefully I can get a more reliable method to check if sign in is in progress.
|
|
if (m_StoreSigninFrameCount > 0)
|
|
{
|
|
m_StoreSigninFrameCount--;
|
|
}
|
|
|
|
if (IsNotConnected())
|
|
{
|
|
m_StoreSigninFrameCount = STORE_UNAVAILABLE_DISPLAY_FRAME_THRESHOLD;
|
|
}
|
|
|
|
|
|
if(m_storeState != GetStoreState())
|
|
{
|
|
Populate(MENU_UNIQUE_ID_STORE); // We don't want to do this every frame, only when the state has changed
|
|
CPauseMenu::RedrawInstructionalButtons();
|
|
}
|
|
|
|
if(CPauseMenu::DynamicMenuExists() &&
|
|
CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage().IsActive() &&
|
|
CLiveManager::GetInviteMgr().HasPendingAcceptedInvite())
|
|
{
|
|
// If we've started an invite let's kill the warning screen
|
|
CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage().Clear();
|
|
}
|
|
}
|
|
|
|
// void CPauseStoreMenu::Render(const PauseMenuRenderDataExtra* renderData)
|
|
// {
|
|
// CMenuBase::Render(renderData);
|
|
// }
|
|
|
|
bool CPauseStoreMenu::UpdateInput( s32 sInput )
|
|
{
|
|
if ( cStoreScreenMgr::IsPendingNetworkShutdownToOpen() )
|
|
{
|
|
//Dont allow the screen to exit if we are trying to leave a network session and open the store.
|
|
return true;
|
|
}
|
|
|
|
|
|
//BIG HONKING NOTE OF FUTURE PROTECTION-NESS! WHEN THIS MENU PANEL IS PRETTIED UP THE FUNCTIONALITY
|
|
//HERE NEEDS TO BE PRESERVED LEST WE ANGER THE QA ELDER ONES WITH TRC BREACHES.
|
|
//(That's right. Lovecraftian warnings.)
|
|
if( sInput == PAD_CROSS )
|
|
{
|
|
|
|
#if !RSG_ORBIS // B*1817634 - Cannot show Sign-in UI on PS4
|
|
if ( !CLiveManager::IsOnline() )
|
|
{
|
|
CLiveManager::ShowSigninUi();
|
|
m_WaitingForLoginScreenEntrance = true;
|
|
}
|
|
else
|
|
#endif
|
|
if (
|
|
#if !RSG_PC
|
|
(NetworkInterface::IsGameInProgress() && CNetwork::GetNetworkSession().IsActivitySession()) ||
|
|
#endif
|
|
!CPauseMenu::IsStoreAvailable())
|
|
{
|
|
//We do not open the store in this case
|
|
}
|
|
else if (CPauseMenu::IsStoreAvailable() && !CLiveManager::GetCommerceMgr().IsThinDataPopulationInProgress())
|
|
{
|
|
const rlGamerInfo* pGamerInfo = NetworkInterface::GetActiveGamerInfo();
|
|
if (!rlGamerInfo::HasStorePrivileges(pGamerInfo->GetLocalIndex()))
|
|
{
|
|
//Display the warning screen
|
|
DisplayUnderageWarning();
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
atString baseCat("TOP_DEFAULT");
|
|
cStoreScreenMgr::SetBaseCategory(baseCat);
|
|
|
|
//We no longer leave the game to access the store in NG.
|
|
//We close the pause menu immediately unless we are in an MP game AND the leave mp for store param is set
|
|
bool closePauseMenuImmediately = !(NetworkInterface::IsGameInProgress() && PARAM_leavempforstore.Get());
|
|
if (closePauseMenuImmediately)
|
|
{
|
|
CPauseMenu::TriggerStore();
|
|
}
|
|
else
|
|
{
|
|
//We populate here for MP since a lot of data is lost during the session exit.
|
|
cStoreScreenMgr::PopulateDisplayValues();
|
|
DisplayLeaveSessionWarning();
|
|
}
|
|
|
|
CPauseMenu::PlaySound("SELECT");
|
|
|
|
return true;
|
|
}
|
|
else if(!CPauseMenu::IsStoreAvailable())
|
|
{
|
|
// Display Warning
|
|
DisplayStoreUnavailableWarning();
|
|
}
|
|
}
|
|
|
|
if ( sInput == PAD_CIRCLE && cStoreScreenMgr::IsPendingNetworkShutdownToOpen() )
|
|
{
|
|
//Dont allow the screen to exit if we are trying to leave a network session and open the store.
|
|
return true;
|
|
}
|
|
|
|
if (SUIContexts::IsActive("STORE_CanScroll") && m_bIsDisplayingNews)
|
|
{
|
|
if( CPauseMenu::CheckInput(FRONTEND_INPUT_RUP, true))
|
|
{
|
|
CNetworkPauseMenuNewsController::Get().RequestStory(-1);
|
|
ShowColumnWarning(PM_COLUMN_LEFT, 3, "");
|
|
CScaleformMenuHelper::SET_BUSY_SPINNER(PM_COLUMN_MIDDLE, true);
|
|
}
|
|
else if( CPauseMenu::CheckInput(FRONTEND_INPUT_RDOWN, true))
|
|
{
|
|
CNetworkPauseMenuNewsController::Get().RequestStory(1);
|
|
ShowColumnWarning(PM_COLUMN_LEFT, 3, "");
|
|
CScaleformMenuHelper::SET_BUSY_SPINNER(PM_COLUMN_MIDDLE, true);
|
|
}
|
|
}
|
|
|
|
return CMenuBase::UpdateInput( sInput );
|
|
}
|
|
|
|
bool CPauseStoreMenu::Populate(MenuScreenId newScreenId)
|
|
{
|
|
bool bResult = false;
|
|
|
|
bool showAcceptButton = true;
|
|
|
|
if(newScreenId.GetValue() == MENU_UNIQUE_ID_STORE)
|
|
{
|
|
m_storeState = GetStoreState();
|
|
|
|
switch(m_storeState)
|
|
{
|
|
case STATE_DISCONNECTED:
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "NOT_CONNECTED", "WARNING_NOT_CONNECTED_TITLE");
|
|
#if !__XENON
|
|
showAcceptButton = false;
|
|
#endif
|
|
break;
|
|
case STATE_UNDERAGE:
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "HUD_PERM", "CWS_WARNING");
|
|
break;
|
|
case STATE_NOCONNECTION:
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "HUD_NONETWORK", "CWS_WARNING");
|
|
#if !RSG_PC // if no connection, we'll bring up the sign-in page that will say "retry connection" ...so need accept for that
|
|
showAcceptButton = false;
|
|
#endif
|
|
break;
|
|
#if RSG_ORBIS
|
|
case STATE_NP_UNAVAILABLE:
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, CPauseMenu::GetOfflineReasonAsLocKey(), "CWS_WARNING");
|
|
break;
|
|
#endif // RSG_ORBIS
|
|
case STATE_UNAVAILABLE_MP:
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "STORE_UNAVAIL_MP", "WARNING_STORE_UNAVAIL_TITLE");
|
|
showAcceptButton = false;
|
|
break;
|
|
case STATE_UNAVAILABLE:
|
|
#if __XENON
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "SCLB_NO_ROS", "WARNING_STORE_UNAVAIL_TITLE");
|
|
#else
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "STORE_UNAVAIL", "WARNING_STORE_UNAVAIL_TITLE");
|
|
#endif
|
|
showAcceptButton = false;
|
|
break;
|
|
case STATE_NONE:
|
|
default:
|
|
bResult = PopulateStoreNews();
|
|
break;
|
|
}
|
|
|
|
if (m_storeState != STATE_NONE)
|
|
{
|
|
bResult = false;
|
|
m_bIsDisplayingNews = false;
|
|
#if RSG_ORBIS
|
|
showAcceptButton = false; // Orbis only shows accept button when everything is fine. so override any other prev logic
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
if (showAcceptButton)
|
|
{
|
|
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
|
|
}
|
|
else
|
|
{
|
|
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
|
|
}
|
|
|
|
|
|
return bResult;
|
|
}
|
|
|
|
eStoreState CPauseStoreMenu::GetStoreState()
|
|
{
|
|
eStoreState storeState = STATE_NONE;
|
|
|
|
if (IsLinkNotConnected())
|
|
{
|
|
storeState = STATE_NOCONNECTION;
|
|
}
|
|
else if(IsNotConnected())
|
|
{
|
|
#if RSG_ORBIS
|
|
const rlGamerInfo* pGamerInfo = NetworkInterface::GetActiveGamerInfo();
|
|
if( !g_rlNp.GetNpAuth().IsNpAvailable( pGamerInfo->GetLocalIndex() ) )
|
|
{
|
|
storeState = STATE_NP_UNAVAILABLE;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
storeState = STATE_DISCONNECTED;
|
|
}
|
|
}
|
|
else if(IsStoreUnavailableMP())
|
|
{
|
|
storeState = STATE_UNAVAILABLE_MP;
|
|
}
|
|
else if(IsStoreUnavailable())
|
|
{
|
|
//We do this to account for log in time.
|
|
if (m_StoreSigninFrameCount > 0)
|
|
{
|
|
storeState = STATE_DISCONNECTED;
|
|
}
|
|
else
|
|
{
|
|
storeState = STATE_UNAVAILABLE;
|
|
}
|
|
|
|
}
|
|
|
|
else if(CLiveManager::CheckIsAgeRestricted())
|
|
{
|
|
storeState = STATE_UNDERAGE;
|
|
}
|
|
|
|
return storeState;
|
|
}
|
|
|
|
bool CPauseStoreMenu::IsLinkNotConnected()
|
|
{
|
|
#if RSG_PC
|
|
// just check against not connected... can't be running without a SC account on PC
|
|
// this function overrides IsNotConnected in conditions so use here so rest of code works
|
|
return IsNotConnected();
|
|
#else
|
|
return !netHardware::IsLinkConnected();
|
|
#endif
|
|
}
|
|
|
|
bool CPauseStoreMenu::IsNotConnected()
|
|
{
|
|
return !CLiveManager::IsOnline();
|
|
}
|
|
|
|
bool CPauseStoreMenu::IsStoreUnavailableMP()
|
|
{
|
|
// we're happy opening the store on PC, as it's on the SCUI menu
|
|
#if RSG_PC
|
|
return false;
|
|
#else
|
|
return NetworkInterface::IsGameInProgress() && CNetwork::GetNetworkSession().IsActivitySession();
|
|
#endif
|
|
}
|
|
|
|
bool CPauseStoreMenu::IsStoreUnavailable()
|
|
{
|
|
#if !RSG_PC
|
|
// B*2413863 - moved this cloud save check to general unavailable, to display the correct generic "try again later" string
|
|
if (NetworkInterface::IsNetworkOpen())
|
|
{
|
|
if (!MoneyInterface::SavegameCanBuyCashProducts())
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return !CPauseMenu::IsStoreAvailable();
|
|
}
|
|
|
|
bool CPauseStoreMenu::PopulateStoreNews()
|
|
{
|
|
CNetworkPauseMenuNewsController& newsController = CNetworkPauseMenuNewsController::Get();
|
|
|
|
if(!m_bIsDisplayingNews && newsController.InitControl(NEWS_TYPE_STORE_HASH))
|
|
{
|
|
int iNumStories = newsController.GetNumStories();
|
|
if(iNumStories > 1)
|
|
{
|
|
if(!SUIContexts::IsActive("STORE_CanScroll"))
|
|
{
|
|
SUIContexts::Activate("STORE_CanScroll");
|
|
CPauseMenu::RedrawInstructionalButtons();
|
|
}
|
|
UpdateStoreColumnScroll(iNumStories, newsController.GetPendingStoryIndex());
|
|
}
|
|
|
|
m_bIsDisplayingNews = true;
|
|
ShowColumnWarning(PM_COLUMN_LEFT, 3, "");
|
|
CScaleformMenuHelper::SET_BUSY_SPINNER(PM_COLUMN_MIDDLE, true);
|
|
}
|
|
else
|
|
{
|
|
ShowColumnWarning_Loc(PM_COLUMN_LEFT, 3, "", "CMRC_STORE_OPEN");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CPauseStoreMenu::PostStoreStory(CNetworkSCNewsStoryRequest* pNewsItem, bool bUpdateTexture)
|
|
{
|
|
CScaleformMenuHelper::SET_BUSY_SPINNER(PM_COLUMN_MIDDLE_RIGHT, false);
|
|
|
|
if(bUpdateTexture)
|
|
{
|
|
ShowColumnWarning(PM_COLUMN_LEFT, 3, pNewsItem->GetContent(), pNewsItem->GetHeadline(), 0, pNewsItem->GetTxdName(), pNewsItem->GetTxdName(), IMG_ALIGN_RIGHT);
|
|
}
|
|
else
|
|
{
|
|
ShowColumnWarning(PM_COLUMN_LEFT, 3, pNewsItem->GetContent(), pNewsItem->GetHeadline(), 0, "", "", IMG_ALIGN_RIGHT);
|
|
}
|
|
|
|
CScaleformMenuHelper::SET_BUSY_SPINNER(PM_COLUMN_MIDDLE, false);
|
|
|
|
}
|
|
|
|
void CPauseStoreMenu::UpdateStoreColumnScroll(int iNumStories, int iSelectedStory)
|
|
{
|
|
char pszCaption[64] = {0};
|
|
CNumberWithinMessage pArrayOfNumbers[2];
|
|
pArrayOfNumbers[0].Set(iSelectedStory+1);
|
|
pArrayOfNumbers[1].Set(iNumStories);
|
|
if ( iNumStories > 1 )
|
|
{
|
|
CMessages::InsertNumbersAndSubStringsIntoString(TheText.Get("NEWS_NUM_STORIES"),pArrayOfNumbers,2,NULL,0,pszCaption,64);
|
|
CScaleformMenuHelper::SET_COLUMN_SCROLL(PM_COLUMN_LEFT, pszCaption);
|
|
}
|
|
|
|
}
|
|
|
|
void CPauseStoreMenu::LoseFocus()
|
|
{
|
|
uiDebugf3("CPauseStoreMenu::LoseFocus");
|
|
SUIContexts::Deactivate("STORE_CanScroll");
|
|
m_bIsDisplayingNews = false;
|
|
|
|
// Cleanup Newswire
|
|
CNetworkPauseMenuNewsController::Get().Reset();
|
|
}
|
|
|
|
|
|
void CPauseStoreMenu::DisplayUnderageWarning()
|
|
{
|
|
#if RSG_DURANGO
|
|
// Display the Xbox system UI telling the user they can't access the store.
|
|
uiVerifyf(
|
|
CLiveManager::ResolvePlatformPrivilege(
|
|
NetworkInterface::GetLocalGamerIndex(),
|
|
rlPrivileges::PrivilegeTypes::PRIVILEGE_PURCHASE_CONTENT,
|
|
true),
|
|
"CLiveManager::ResolvePlatformPrivilege with attemptResolution = true failed, so the system UI won't be shown");
|
|
#else
|
|
CWarningMessage& rMessage = CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage();
|
|
CWarningMessage::Data messageData;
|
|
|
|
messageData.m_TextLabelBody = "HUD_AGERES";
|
|
messageData.m_iFlags = FE_WARNING_OK;
|
|
messageData.m_acceptPressed = datCallback(MFA(CMenuScreen::BackOutOfWarningMessageToContextMenu), (datBase*)&m_Owner);
|
|
|
|
rMessage.SetMessage(messageData);
|
|
#endif
|
|
}
|
|
|
|
void CPauseStoreMenu::DisplayLeaveSessionWarning()
|
|
{
|
|
CWarningMessage& rMessage = CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage();
|
|
CWarningMessage::Data messageData;
|
|
messageData.m_TextLabelBody = "GOTO_STORE_CONFIRM";
|
|
messageData.m_TextLabelSubtext = "PM_QUIT_WARN11";
|
|
messageData.m_iFlags = FE_WARNING_YES_NO;
|
|
messageData.m_acceptPressed = datCallback(MFA(CPauseStoreMenu::ConfirmDestructiveActionCallback), (datBase*)&m_Owner);
|
|
messageData.m_declinePressed = datCallback(MFA(CMenuScreen::BackOutOfWarningMessageToContextMenu), (datBase*)&m_Owner);
|
|
|
|
rMessage.SetMessage(messageData);
|
|
}
|
|
|
|
void CPauseStoreMenu::DisplayStoreUnavailableWarning()
|
|
{
|
|
CWarningMessage& rMessage = CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage();
|
|
CWarningMessage::Data messageData;
|
|
|
|
#if __XENON || RSG_DURANGO
|
|
if ( !CLiveManager::IsSignedIn() || CLiveManager::IsOnline() )
|
|
{
|
|
messageData.m_TextLabelBody = "STORE_UNAVAIL";
|
|
}
|
|
else
|
|
{
|
|
messageData.m_TextLabelBody = "SCLB_NO_ROS";
|
|
}
|
|
#else
|
|
messageData.m_TextLabelBody = "STORE_UNAVAIL";
|
|
#endif
|
|
|
|
|
|
messageData.m_iFlags = FE_WARNING_OK;
|
|
messageData.m_acceptPressed = datCallback(MFA(CWarningMessage::Clear), &CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage());
|
|
|
|
rMessage.SetMessage(messageData);
|
|
}
|
|
|
|
void CPauseStoreMenu::ConfirmDestructiveActionCallback()
|
|
{
|
|
// remove the warning message
|
|
CPauseMenu::GetDynamicPauseMenu()->GetErrorMessage().Clear();
|
|
CPauseMenu::TriggerStore(true);
|
|
//cStoreScreenMgr::RequestMPStore();
|
|
}
|