diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Common/XUI | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Common/XUI')
176 files changed, 39352 insertions, 0 deletions
diff --git a/Minecraft.Client/Common/XUI/SlotProgressControl.cpp b/Minecraft.Client/Common/XUI/SlotProgressControl.cpp new file mode 100644 index 00000000..91f362a3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/SlotProgressControl.cpp @@ -0,0 +1,88 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\Slot.h" +#include "..\..\..\Minecraft.World\ItemInstance.h" + +#include "SlotItemControlBase.h" +#include "SlotProgressControl.h" + +int SlotProgressControl::GetValue() +{ + int value = 0; + + HXUIOBJ hVisual, hParent; + this->GetParent( &hVisual ); + XuiElementGetParent( hVisual, &hParent); + + void* pvUserData; + XuiElementGetUserData( hParent, &pvUserData ); + + if( pvUserData != NULL ) + { + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>(); + + if( pUserDataContainer->slot != NULL ) + { + item = pUserDataContainer->slot->getItem(); + } + else + { + item = pUserDataContainer->item; + } + + if( item != NULL ) + { + // TODO Should use getDamage instead even though it returns the same value + if( item->isDamaged() ) + value = item->getDamageValue(); + else + value = 0; + } + } + else + { + LPCWSTR name; + XuiElementGetId( hParent, &name ); + + OutputDebugStringW( name ); + OutputDebugString( "\n" ); + } + + return value; +} + +void SlotProgressControl::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = 0; + + HXUIOBJ hVisual, hParent; + this->GetParent( &hVisual ); + XuiElementGetParent( hVisual, &hParent); + + void* pvUserData; + XuiElementGetUserData( hParent, &pvUserData ); + + if( pvUserData != NULL ) + { + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>(); + + if( pUserDataContainer->slot != NULL ) + { + item = pUserDataContainer->slot->getItem(); + } + else + { + item = pUserDataContainer->item; + } + + if( item != NULL ) + { + *pnRangeMax = item->getMaxDamage(); + } + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/SlotProgressControl.h b/Minecraft.Client/Common/XUI/SlotProgressControl.h new file mode 100644 index 00000000..fb5ddcc1 --- /dev/null +++ b/Minecraft.Client/Common/XUI/SlotProgressControl.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ProgressControlBase.h" + +class SlotProgressControl : public ProgressControlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( SlotProgressControl, L"SlotProgressControl", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_BasePlayer.cpp b/Minecraft.Client/Common/XUI/XUI_BasePlayer.cpp new file mode 100644 index 00000000..21348070 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_BasePlayer.cpp @@ -0,0 +1,9 @@ +#include "stdafx.h" +#include <assert.h> +#include "XUI_BasePlayer.h" + +HRESULT CXuiSceneBasePlayer::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + return S_OK; +} + diff --git a/Minecraft.Client/Common/XUI/XUI_BasePlayer.h b/Minecraft.Client/Common/XUI/XUI_BasePlayer.h new file mode 100644 index 00000000..fd777e6a --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_BasePlayer.h @@ -0,0 +1,13 @@ +#pragma once + +class CXuiSceneBasePlayer : public CXuiSceneImpl +{ + +protected: + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneBasePlayer, L"CXuiSceneBasePlayer", XUI_CLASS_SCENE ) +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Chat.cpp b/Minecraft.Client/Common/XUI/XUI_Chat.cpp new file mode 100644 index 00000000..3e3faa77 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Chat.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "XUI_Chat.h" +#include "..\..\Minecraft.h" +#include "..\..\Gui.h" + +HRESULT CScene_Chat::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + this->SetTimer(0,100); + + XuiElementGetPosition(m_hObj,&m_OriginalPosition); + + return S_OK; +} + +HRESULT CScene_Chat::OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + Gui *pGui = pMinecraft->gui; + + //DWORD messagesToDisplay = min( CHAT_LINES_COUNT, pGui->getMessagesCount(m_iPad) ); + for( unsigned int i = 0; i < CHAT_LINES_COUNT; ++i ) + { + float opacity = pGui->getOpacity(m_iPad, i); + if( opacity > 0 ) + { + m_Backgrounds[i].SetOpacity(opacity); + m_Labels[i].SetOpacity(opacity); + m_Labels[i].SetText( pGui->getMessage(m_iPad,i).c_str() ); + } + else + { + m_Backgrounds[i].SetOpacity(0); + m_Labels[i].SetOpacity(0); + } + } + if(pMinecraft->localplayers[m_iPad]!= NULL) + { + m_Jukebox.SetText( pGui->getJukeboxMessage(m_iPad).c_str() ); + m_Jukebox.SetOpacity( pGui->getJukeboxOpacity(m_iPad) ); + } + return S_OK; +} + +HRESULT CScene_Chat::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + + app.ReloadChatScene(m_iPad, bJoining); + + return S_OK; +} + +HRESULT CScene_Chat::OffsetTextPosition( float xOffset, float yOffset /*= 0.0f*/ ) +{ + D3DXVECTOR3 vPos; + float fWidth, fHeight; + XuiElementGetBounds( m_Backgrounds[0], &fWidth, &fHeight ); + for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i) + { + XuiElementGetPosition( m_Labels[i], &vPos ); + vPos.x = xOffset; + vPos.y += yOffset; + XuiElementSetPosition( m_Labels[i], &vPos ); + XuiElementSetBounds( m_Labels[i], fWidth - xOffset, fHeight ); + } + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Chat.h b/Minecraft.Client/Common/XUI/XUI_Chat.h new file mode 100644 index 00000000..d685e587 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Chat.h @@ -0,0 +1,59 @@ +#pragma once +#include "../media/xuiscene_chat.h" +#include "XUI_CustomMessages.h" + +#define CHAT_LINES_COUNT 10 + +class CScene_Chat : public CXuiSceneImpl +{ + +protected: + CXuiControl m_Labels[CHAT_LINES_COUNT]; + CXuiControl m_Backgrounds[CHAT_LINES_COUNT]; + CXuiControl m_Jukebox; + + D3DXVECTOR3 m_OriginalPosition; + int m_iPad; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiLabel1, m_Labels[0]) + MAP_CONTROL(IDC_XuiLabel2, m_Labels[1]) + MAP_CONTROL(IDC_XuiLabel3, m_Labels[2]) + MAP_CONTROL(IDC_XuiLabel4, m_Labels[3]) + MAP_CONTROL(IDC_XuiLabel5, m_Labels[4]) + MAP_CONTROL(IDC_XuiLabel6, m_Labels[5]) + MAP_CONTROL(IDC_XuiLabel7, m_Labels[6]) + MAP_CONTROL(IDC_XuiLabel8, m_Labels[7]) + MAP_CONTROL(IDC_XuiLabel9, m_Labels[8]) + MAP_CONTROL(IDC_XuiLabel10, m_Labels[9]) + MAP_CONTROL(IDC_XuiBack1, m_Backgrounds[0]) + MAP_CONTROL(IDC_XuiBack2, m_Backgrounds[1]) + MAP_CONTROL(IDC_XuiBack3, m_Backgrounds[2]) + MAP_CONTROL(IDC_XuiBack4, m_Backgrounds[3]) + MAP_CONTROL(IDC_XuiBack5, m_Backgrounds[4]) + MAP_CONTROL(IDC_XuiBack6, m_Backgrounds[5]) + MAP_CONTROL(IDC_XuiBack7, m_Backgrounds[6]) + MAP_CONTROL(IDC_XuiBack8, m_Backgrounds[7]) + MAP_CONTROL(IDC_XuiBack9, m_Backgrounds[8]) + MAP_CONTROL(IDC_XuiBack10, m_Backgrounds[9]) + MAP_CONTROL(IDC_XuiLabelJukebox, m_Jukebox) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Chat, L"CScene_Chat", XUI_CLASS_SCENE ) + + HRESULT OffsetTextPosition( float xOffset, float yOffset = 0.0f ); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.cpp b/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.cpp new file mode 100644 index 00000000..9a82a7b3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.cpp @@ -0,0 +1,216 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\..\Minecraft.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_ConnectingProgress::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + ConnectionProgressParams *param = (ConnectionProgressParams *)pInitData->pvInitData; + m_iPad = param->iPad; + MapChildControls(); + + if( param->stringId >= 0 ) + { + m_title.SetText( app.GetString( param->stringId ) ); + } + else + { + m_title.SetText( L"" ); + } + + m_buttonConfirm.SetText( app.GetString( IDS_CONFIRM_OK ) ); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + } + + CXuiSceneBase::ShowBackground( m_iPad, TRUE ); + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + + m_showTooltips = param->showTooltips; + if( param->showTooltips ) + ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_CANCEL_JOIN, -1, -1 ); + else + ui.SetTooltips( m_iPad, -1 ); + + m_runFailTimer = param->setFailTimer; + m_timerTime = param->timerTime; + + return S_OK; +} + +// The framework calls this handler when the object is to be destroyed. +HRESULT CScene_ConnectingProgress::OnDestroy() +{ + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_ConnectingProgress::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_ConnectingProgress::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed == m_buttonConfirm) + { + if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() ) + { + // The connection failed if we see the button, so the temp player should be removed and the viewports updated again + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->removeLocalPlayerIdx(m_iPad); + } + else + { + app.NavigateToHomeMenu(); + //app.NavigateBack( ProfileManager.GetPrimaryPad() ); + } + } + + return S_OK; +} + +HRESULT CScene_ConnectingProgress::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if( m_showTooltips ) + { + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + if (pInputData->dwKeyCode == VK_PAD_B) + { + // Cancel the join + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->removeLocalPlayerIdx(m_iPad); + rfHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_ConnectingProgress::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + // This gets called every frame, so use it to update our two text boxes + + return S_OK; +} + +HRESULT CScene_ConnectingProgress::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(m_runFailTimer) XuiSetTimer(m_hObj,0,m_timerTime); + if( pTransition->dwTransType == XUI_TRANSITION_FROM ) + { + XuiKillTimer(m_hObj,0); + } + + return S_OK; +} + +HRESULT CScene_ConnectingProgress::OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + // are we being destroyed? If so, don't do anything + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) + { + return S_OK; + } + + if( pTransition->dwTransType == XUI_TRANSITION_TO ) + { + if(m_runFailTimer) XuiSetTimer(m_hObj,0,m_timerTime); + } + + return S_OK; +} + +HRESULT CScene_ConnectingProgress::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // Check if the connection failed + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if( pMinecraft->m_connectionFailed[m_iPad] || !g_NetworkManager.IsInSession() ) + { + app.RemoveBackScene(m_iPad); + + // 4J-PB - timers auto repeat, so kill it + XuiKillTimer(m_hObj,0); + + int exitReasonStringId; + switch(pMinecraft->m_connectionFailedReason[m_iPad]) + { + case DisconnectPacket::eDisconnect_LoginTooLong: + exitReasonStringId = IDS_DISCONNECTED_LOGIN_TOO_LONG; + break; + case DisconnectPacket::eDisconnect_ServerFull: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + break; + case DisconnectPacket::eDisconnect_Kicked: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + case DisconnectPacket::eDisconnect_NoUGC_AllLocal: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + break; + case DisconnectPacket::eDisconnect_NoUGC_Single_Local: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + break; + case DisconnectPacket::eDisconnect_NoUGC_Remote: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; + break; + case DisconnectPacket::eDisconnect_NoFlying: + exitReasonStringId = IDS_DISCONNECTED_FLYING; + break; + case DisconnectPacket::eDisconnect_Quitting: + exitReasonStringId = IDS_DISCONNECTED_SERVER_QUIT; + break; + case DisconnectPacket::eDisconnect_OutdatedServer: + exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; + break; + case DisconnectPacket::eDisconnect_OutdatedClient: + exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; + break; + default: + exitReasonStringId = IDS_CONNECTION_LOST_SERVER; + break; + } + + if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() ) + { + m_buttonConfirm.SetShow(TRUE); + m_buttonConfirm.SetFocus(m_iPad); + + // Set text + m_title.SetText( app.GetString( IDS_CONNECTION_FAILED ) ); + m_status.SetText( app.GetString( exitReasonStringId ) ); + } + else + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; +#ifdef _XBOX + StorageManager.RequestMessageBox( IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); +#endif + exitReasonStringId = -1; + + //app.NavigateToHomeMenu(); + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); + } + } + + return S_OK; +} diff --git a/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.h b/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.h new file mode 100644 index 00000000..360ca0b0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_ConnectingProgress.h @@ -0,0 +1,55 @@ +#pragma once +#include "../media/xuiscene_connectingprogress.h" + +class CScene_ConnectingProgress : public CXuiSceneImpl +{ +private: + int m_iPad; + bool m_runFailTimer; + int m_timerTime; + bool m_showTooltips; +protected: + // Control and Element wrapper objects. + CXuiControl m_title, m_status, m_buttonConfirm; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_TRANSITION_START( OnTransitionStart ) + XUI_ON_XM_TRANSITION_END( OnTransitionEnd ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Title, m_title) + MAP_CONTROL(IDC_Status, m_status) + MAP_CONTROL(IDC_ButtonConfirm, m_buttonConfirm) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_ConnectingProgress, L"CScene_ConnectingProgress", XUI_CLASS_SCENE ) + +private: + bool m_threadCompleted; + D3DXVECTOR3 m_OriginalPosition; + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.cpp b/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.cpp new file mode 100644 index 00000000..0096da44 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.cpp @@ -0,0 +1,98 @@ +#include "stdafx.h" +#include "XUI_Control_ComboBox.h" +#include "..\Xbox_App.h" + +HRESULT CXuiControl4JComboBox::OnInit(XUIMessageInit *pInitData, BOOL& bHandled) +{ + m_ListData.nItems=0; + m_ListData.pItems=NULL; + + return S_OK; +} + +void CXuiControl4JComboBox::SetData(LIST_ITEM_INFO *pItems,int iCount) +{ + CXuiControl4JComboBox *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + + // copy the data in + pThis->m_ListData.pItems= new LIST_ITEM_INFO [iCount] ; + memcpy(pThis->m_ListData.pItems,pItems,sizeof(LIST_ITEM_INFO)*iCount); + pThis->m_ListData.nItems=iCount; + + //InsertItems( 0, iCount ); +} + +int CXuiControl4JComboBox::GetSelectedIndex() +{ + return XuiListGetCurSel(GetListObject(),NULL); +} + +// Gets called every frame +HRESULT CXuiControl4JComboBox::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled) +{ + if( ( 0 == pGetSourceTextData->iData ) && ( ( pGetSourceTextData->bItemData ) ) ) + { + pGetSourceTextData->szText = + m_ListData.pItems[pGetSourceTextData->iItem].pwszText; + bHandled = TRUE; + } + return S_OK; +} + +HRESULT CXuiControl4JComboBox::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData,BOOL& bHandled) +{ + pGetItemCountData->cItems = m_ListData.nItems; + bHandled = TRUE; + return S_OK; +} + +HRESULT CXuiControl4JComboBox::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + return S_OK; + + //if( ( 0 == pGetSourceImageData->iData ) && ( pGetSourceImageData->bItemData ) ) + //{ + // // Check for a brush + + // if(m_ListData.pItems[pGetSourceImageData->iItem].hXuiBrush!=NULL) + // { + // pGetSourceImageData->hBrush=m_ListData.pItems[pGetSourceImageData->iItem].hXuiBrush; + // } + // else + // { + // pGetSourceImageData->szPath = + // m_ListData.pItems[pGetSourceImageData->iItem].pwszImage; + // } + // bHandled = TRUE; + //} + //return S_OK; +} + +HRESULT CXuiControl4JComboBox::OnGetItemEnable(XUIMessageGetItemEnable *pGetItemEnableData,BOOL& bHandled) +{ + if(m_ListData.pItems!=NULL && m_ListData.nItems!=0) + { + pGetItemEnableData->bEnabled = + m_ListData.pItems[pGetItemEnableData->iItem].fEnabled; + } + bHandled = TRUE; + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CXuiControl4JComboBox::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + CScene_Base::HandleKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==GetValueObject()) + { + XuiElementSetShow(GetListObject(),TRUE); + XuiElementSetFocus(GetListObject()); + rfHandled = TRUE; + } + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.h b/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.h new file mode 100644 index 00000000..28b61187 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Control_ComboBox.h @@ -0,0 +1,53 @@ +#pragma once + +class CXuiControl4JComboBox : public CXuiComboBoxImpl +{ +public: + + // Information for one list item. + typedef struct _LIST_ITEM_INFO + { + LPCWSTR pwszText; + LPCWSTR pwszImage; + HXUIBRUSH hXuiBrush; + BOOL fChecked; + BOOL fEnabled; + } + LIST_ITEM_INFO; + + // List data. + typedef struct _tagListData + { + int nItems; + LIST_ITEM_INFO *pItems; + } + LIST_DATA; + + LIST_DATA m_ListData; + XUI_IMPLEMENT_CLASS(CXuiControl4JComboBox, L"CXuiControl4JComboBox", XUI_CLASS_COMBOBOX); + + void SetData(_LIST_ITEM_INFO *pItems,int iCount); + int GetSelectedIndex(); + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_GET_ITEMENABLE(OnGetItemEnable) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + + XUI_END_MSG_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnGetItemEnable(XUIMessageGetItemEnable *pGetItemEnableData,BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Controls.h b/Minecraft.Client/Common/XUI/XUI_Controls.h new file mode 100644 index 00000000..c1376ec0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Controls.h @@ -0,0 +1,26 @@ +#pragma once + +#include "XUI_Ctrl_4JEdit.h" +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_Ctrl_4JList.h" +#include "XUI_Ctrl_BrewProgress.h" +#include "XUI_Ctrl_BubblesProgress.h" +#include "XUI_Ctrl_BurnProgress.h" +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "XUI_Ctrl_EnchantButton.h" +#include "XUI_Ctrl_EnchantmentBook.h" +#include "XUI_Ctrl_EnchantmentButtonText.h" +#include "XUI_Ctrl_FireProgress.h" +#include "XUI_Ctrl_LoadingProgress.h" +#include "XUI_Ctrl_MinecraftPlayer.h" +#include "XUI_Ctrl_MinecraftSkinPreview.h" +#include "XUI_Ctrl_MinecraftSlot.h" +#include "XUI_Ctrl_MobEffect.h" +#include "XUI_Ctrl_PassthroughList.h" +#include "XUI_Ctrl_ProgressCtrlBase.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_Ctrl_SlotItem.h" +#include "XUI_Ctrl_SlotItemCtrlBase.h" +#include "XUI_Ctrl_SlotItemListItem.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Ctrl_SplashPulser.h"
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.cpp new file mode 100644 index 00000000..cc3afeca --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.cpp @@ -0,0 +1,200 @@ +#include "stdafx.h" +#include "XUI_Ctrl_4JEdit.h" + + + +HRESULT CXuiCtrl4JEdit::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + // set a limit for the text box + m_uTextLimit=XUI_4JEDIT_MAX_CHARS-1; + XuiEditSetTextLimit(m_hObj,m_uTextLimit); + // Find the text limit. (Add one for NULL terminator) + //m_uTextLimit = min( XuiEditGetTextLimit(m_hObj) + 1, XUI_4JEDIT_MAX_CHARS); + + ZeroMemory( wchText , sizeof(WCHAR)*(m_uTextLimit+1) ); + + m_bReadOnly = false; + m_uiTitle = 0; + m_uiText =0; + m_eKeyboardMode=C_4JInput::EKeyboardMode_Default; + return hr; +} + + +HRESULT CXuiCtrl4JEdit::SetTextLimit(int iLimit) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + if(iLimit<XUI_4JEDIT_MAX_CHARS) + { + pThis->m_uTextLimit=iLimit; + XuiEditSetTextLimit(pThis->m_hObj,iLimit); + ZeroMemory( pThis->wchText , sizeof(WCHAR)*XUI_4JEDIT_MAX_CHARS ); + } + return S_OK; +} +HRESULT CXuiCtrl4JEdit::SetCaretPosition(int iPos) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + XuiEditSetCaretPosition(pThis->m_hObj,iPos); + return S_OK; +} + +HRESULT CXuiCtrl4JEdit::SetTitleAndText(unsigned int uiTitle, unsigned int uiText) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + pThis->m_uiTitle=uiTitle; + pThis->m_uiText=uiText; + + return S_OK; +} + +HRESULT CXuiCtrl4JEdit::SetReadOnly(bool bReadOnly) +{ + // Attempt to make the change on the actual original version of this object that XUI made itself, rather + // than the copy we make ourselves and then map to it, which shares the same handle + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + pThis->m_bReadOnly = bReadOnly; + + return S_OK; +} + +HRESULT CXuiCtrl4JEdit::SetKeyboardType(C_4JInput::EKeyboardMode eKeyboardMode) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + pThis->m_eKeyboardMode= eKeyboardMode; + return S_OK; +} + +// HRESULT CXuiCtrl4JEdit::SetIPMode(bool bIPMode) +// { +// // Attempt to make the change on the actual original version of this object that XUI made itself, rather +// // than the copy we make ourselves and then map to it, which shares the same handle +// CXuiCtrl4JEdit *pThis; +// HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); +// if (FAILED(hr)) +// return hr; +// pThis->m_bIPMode= bIPMode; +// +// return S_OK; +// } + +// HRESULT CXuiCtrl4JEdit::SetExtendedMode(bool bExtendedMode) +// { +// // Attempt to make the change on the actual original version of this object that XUI made itself, rather +// // than the copy we make ourselves and then map to it, which shares the same handle +// CXuiCtrl4JEdit *pThis; +// HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); +// if (FAILED(hr)) +// return hr; +// pThis->m_bExtendedMode= bExtendedMode; +// +// return S_OK; +// } + +HRESULT CXuiCtrl4JEdit::OnChar(XUIMessageChar* pInputData, BOOL& rfHandled) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + HXUIOBJ hBaseObj; + + // need to send the key down to the base object, so that when we notify the parent, the edit control has been updated with the right text + hr=XuiGetBaseObject(pThis->m_hObj,&hBaseObj); + + XUIMessage xuiMsg; + XUIMessageChar xuiMsgChar; + XuiMessageChar( &xuiMsg, &xuiMsgChar, pInputData->wch, pInputData->dwFlags, pInputData->UserIndex ); + // Send the XM_CHAR message. + XuiSendMessage( hBaseObj, &xuiMsg ); + + rfHandled = TRUE; + SendNotifyValueChanged((int)pInputData->wch); + + return hr; +} + +HRESULT CXuiCtrl4JEdit::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + //HRESULT hr = S_OK; + + if( pThis->m_bReadOnly ) return hr; + + // Find the text limit. (Add one for NULL terminator) + //m_uTextLimit = min( XuiEditGetTextLimit(m_hObj) + 1, XUI_4JEDIT_MAX_CHARS); + + if((((pInputData->dwKeyCode == VK_PAD_A) && (pInputData->wch == 0)) || (pInputData->dwKeyCode == VK_PAD_START)) && !(pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT)) + { + pThis->RequestKeyboard(pInputData->UserIndex); + rfHandled = TRUE; + } + + return hr; +} + +void CXuiCtrl4JEdit::RequestKeyboard(int iPad) +{ + InputManager.RequestKeyboard(m_uiTitle,GetText(),m_uiText,iPad,wchText,m_uTextLimit+1,&CXuiCtrl4JEdit::KeyboardReturned,this,m_eKeyboardMode,app.GetStringTable()); +} + + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrl4JEdit::SendNotifyValueChanged(int iValue) +{ + CXuiCtrl4JEdit *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + HXUIOBJ hParent; + //HRESULT hr=S_OK; + XUIMessage msg; + XUINotify msgNotify; + XUINotifyValueChanged msgNotifyValueChanged; + + XuiElementGetParent(pThis->m_hObj, &hParent); + XuiNotifyValueChanged(&msg, &msgNotify, &msgNotifyValueChanged, XuiGetOuter(pThis->m_hObj), iValue); + XuiBubbleMessage(XuiGetOuter(hParent), &msg); + + return hr; +} + +int CXuiCtrl4JEdit::KeyboardReturned(void *pParam,bool bSet) +{ + CXuiCtrl4JEdit* pClass = (CXuiCtrl4JEdit*)pParam; + HRESULT hr = S_OK; + + if(bSet) + { + pClass->SetText(pClass->wchText); + // need to move the caret to the end of the newly set text + XuiEditSetCaretPosition(pClass->m_hObj, (int)wcsnlen(pClass->wchText, 50)); + pClass->SendNotifyValueChanged(10); // 10 for a return + } + + return hr; +} diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.h new file mode 100644 index 00000000..f6899d19 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.h @@ -0,0 +1,44 @@ +#pragma once + +#include <XuiApp.h> + +#define XUI_4JEDIT_MAX_CHARS 61 + +class CXuiCtrl4JEdit : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrl4JEdit, L"CXuiCtrl4JEdit", XUI_CLASS_EDIT) + +protected: + + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_CHAR(OnChar) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnChar(XUIMessageChar* pInputData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); +public: + HRESULT SetReadOnly(bool bReadOnly); +// HRESULT SetIPMode(bool bIPMode); +// HRESULT SetExtendedMode(bool bExtendedMode); + HRESULT SetKeyboardType(C_4JInput::EKeyboardMode eKeyboardMode); + HRESULT SetTextLimit(int iLimit); + HRESULT SetCaretPosition(int iPos); + HRESULT SetTitleAndText(unsigned int uiTitle, unsigned int uiText); + + void RequestKeyboard(int iPad); +protected: + bool m_bReadOnly; + C_4JInput::EKeyboardMode m_eKeyboardMode; + unsigned int m_uiTitle,m_uiText; + +private: + static int KeyboardReturned(void *pParam,bool bSet); + HRESULT SendNotifyValueChanged(int); + WCHAR wchText[XUI_4JEDIT_MAX_CHARS]; + unsigned int m_uTextLimit; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.cpp new file mode 100644 index 00000000..8895b60e --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.cpp @@ -0,0 +1,61 @@ +#include "stdafx.h" +#include "XUI_Ctrl_4JIcon.h" + +HRESULT CXuiCtrl4JIcon::OnInit(XUIMessageInit *pInitData, BOOL& bHandled) +{ + m_hBrush=NULL; + return S_OK; +} + +HRESULT CXuiCtrl4JIcon::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + XUIMessage Message; + XUIMessageGetSourceImage MsgGetImage; + HRESULT hr; + HXUIOBJ hObj; + + if(m_hBrush) + { + pGetSourceImageData->hBrush = m_hBrush; + bHandled = TRUE; + } + else + { + XuiMessageGetSourceImage(&Message, &MsgGetImage, pGetSourceImageData->iItem, pGetSourceImageData->iData, TRUE); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + + if (Message.bHandled) + { + pGetSourceImageData->hBrush = MsgGetImage.hBrush; + bHandled = TRUE; + } + } + } + return S_OK; +} + +HRESULT CXuiCtrl4JIcon::UseBrush(HXUIBRUSH hBrush) +{ + if( m_hBrush ) + { + XuiDestroyBrush( m_hBrush ); + } + m_hBrush = hBrush; + return XuiControlSetImageBrush(m_hObj,hBrush); +} + +HRESULT CXuiCtrl4JIcon::OnDestroy() +{ + + if( m_hBrush ) + { + XuiDestroyBrush( m_hBrush ); + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.h new file mode 100644 index 00000000..d99f0c55 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.h @@ -0,0 +1,25 @@ +#pragma once + + +class CXuiCtrl4JIcon : public CXuiControlImpl +{ +public: + + XUI_IMPLEMENT_CLASS(CXuiCtrl4JIcon, L"CXuiCtrl4JIcon", XUI_CLASS_LABEL); + HRESULT UseBrush(HXUIBRUSH hBrush); + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_END_MSG_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnDestroy(); + + HXUIBRUSH m_hBrush; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.cpp new file mode 100644 index 00000000..60c32909 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.cpp @@ -0,0 +1,405 @@ +#include "stdafx.h" +#include "XUI_Ctrl_4JList.h" + +static bool TimeSortFn(const void *a, const void *b); + +HRESULT CXuiCtrl4JList::OnInit(XUIMessageInit *pInitData, BOOL& bHandled) +{ + InitializeCriticalSection(&m_AccessListData); + + m_hSelectionChangedHandlerObj = NULL; + + return S_OK; +} + +void CXuiCtrl4JList::AddData( const LIST_ITEM_INFO& ItemInfo , int iSortListFromIndex, int iSortFunction) +{ + // need to allocate memory for the structure and its strings + // and remap the string pointers + DWORD dwBytes=0; + DWORD dwLen1=0; + DWORD dwLen2=0; + + if(ItemInfo.pwszText) + { + dwLen1=(int)wcslen(ItemInfo.pwszText)*sizeof(WCHAR); + dwBytes+=dwLen1+sizeof(WCHAR); + } + + if(ItemInfo.pwszImage) + { + dwLen2=(int)(wcslen(ItemInfo.pwszImage))*sizeof(WCHAR); + dwBytes+=dwLen2+sizeof(WCHAR); + } + + dwBytes+=sizeof( LIST_ITEM_INFO ); + LIST_ITEM_INFO *pItemInfo = (LIST_ITEM_INFO *)new BYTE[dwBytes]; + ZeroMemory(pItemInfo,dwBytes); + + XMemCpy( pItemInfo, &ItemInfo, sizeof( LIST_ITEM_INFO ) ); + if(dwLen1!=0) + { + XMemCpy( &pItemInfo[1], ItemInfo.pwszText, dwLen1 ); + pItemInfo->pwszText=(LPCWSTR)&pItemInfo[1]; + if(dwLen2!=0) + { + BYTE *pwszImage = ((BYTE *)&pItemInfo[1])+dwLen1+sizeof(WCHAR); + XMemCpy( pwszImage, ItemInfo.pwszImage, dwLen2 ); + pItemInfo->pwszImage=(LPCWSTR)pwszImage; + } + } + else if(dwLen2!=0) + { + XMemCpy( &pItemInfo[1], ItemInfo.pwszImage, dwLen2 ); + pItemInfo->pwszImage=(LPCWSTR)&pItemInfo[1]; + } + + EnterCriticalSection(&m_AccessListData); + + // need to remember the original index of this addition before it gets sorted - this will get used to load the game + if(iSortListFromIndex!=-1) + { + pItemInfo->iIndex=(int)m_vListData.size()-iSortListFromIndex; + } + else + { + pItemInfo->iIndex=(int)m_vListData.size(); + } + + // added to force a sort order for DLC + //pItemInfo->iSortIndex=iSortIndex; + + m_vListData.push_back(pItemInfo); + +#ifdef _DEBUG + + int iCount=0; + for (AUTO_VAR(it, m_vListData.begin()); it != m_vListData.end(); it++) + { + PLIST_ITEM_INFO pInfo=(PLIST_ITEM_INFO)*it; + app.DebugPrintf("%d. ",iCount++); + OutputDebugStringW(pInfo->pwszText); + app.DebugPrintf(" - %d\n",pInfo->iSortIndex); + + } +#endif + + + if(iSortListFromIndex!=-1) + { + switch(iSortFunction) + { + case eSortList_Date: + // sort from the index passed (to leave create world and tutorial in the saves list) + sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::TimeSortFn); + break; + case eSortList_Alphabetical: + // alphabetical sort + sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::AlphabeticSortFn); + break; + case eSortList_Index: + sort(m_vListData.begin()+iSortListFromIndex, m_vListData.end(),CXuiCtrl4JList::IndexSortFn); + break; + } + } + LeaveCriticalSection(&m_AccessListData); +// #ifdef _DEBUG +// +// iCount=0; +// for (AUTO_VAR(it, m_vListData.begin()); it != m_vListData.end(); it++) +// { +// PLIST_ITEM_INFO pInfo=(PLIST_ITEM_INFO)*it; +// app.DebugPrintf("After Sort - %d. ",iCount++); +// OutputDebugStringW(pInfo->pwszText); +// app.DebugPrintf(" - %d\n",pInfo->iSortIndex); +// +// } +// #endif + InsertItems( 0, 1 ); +} + +void CXuiCtrl4JList::RemoveAllData( ) +{ + EnterCriticalSection(&m_AccessListData); + + int iSize=(int)m_vListData.size(); + for(int i=0;i<iSize;i++) + { + LIST_ITEM_INFO *pBack = m_vListData.back(); + if( pBack->hXuiBrush ) + { + XuiDestroyBrush(pBack->hXuiBrush); + } + m_vListData.pop_back(); + DeleteItems( 0, 1 ); + } + + LeaveCriticalSection(&m_AccessListData); +} + +void CXuiCtrl4JList::SelectByUserData(int iData) +{ + for(unsigned int i = 0; i < m_vListData.size(); ++i) + { + if(m_vListData.at(i)->iData == iData) + { + SetCurSel(i); + SetTopItem(i); // scroll the item into view if it's not visible + break; + } + } +} + +int CXuiCtrl4JList::GetIndexByUserData(int iData) +{ + for(unsigned int i = 0; i < m_vListData.size(); ++i) + { + if(m_vListData.at(i)->iData == iData) + { + return i; + } + } + return 0; +} + +CXuiCtrl4JList::LIST_ITEM_INFO& CXuiCtrl4JList::GetData(DWORD dw) +{ + return *m_vListData[dw]; +} + +CXuiCtrl4JList::LIST_ITEM_INFO& CXuiCtrl4JList::GetDataiData(int iData) +{ + LIST_ITEM_INFO info; + + for(unsigned int i=0;i<m_vListData.size();i++) + { + info=*m_vListData[i]; + if(info.iData==iData) + { + return *m_vListData[i]; + } + } + + return *m_vListData[0]; +} + +CXuiCtrl4JList::LIST_ITEM_INFO& CXuiCtrl4JList::GetData(FILETIME *pFileTime) +{ + LIST_ITEM_INFO info; + + for(unsigned int i=0;i<m_vListData.size();i++) + { + info=*m_vListData[i]; + if((info.fTime.dwHighDateTime==pFileTime->dwHighDateTime)&&(info.fTime.dwLowDateTime==pFileTime->dwLowDateTime)) + { + return *m_vListData[i]; + } + } + + return *m_vListData[0]; +} + +bool CXuiCtrl4JList::TimeSortFn(const void *a, const void *b) +{ + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a; + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; + + if(SaveDetailsA->fTime.dwHighDateTime > SaveDetailsB->fTime.dwHighDateTime) + { + return true; + } + else if(SaveDetailsA->fTime.dwHighDateTime == SaveDetailsB->fTime.dwHighDateTime) + { + if(SaveDetailsA->fTime.dwLowDateTime > SaveDetailsB->fTime.dwLowDateTime) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } + +} + +bool CXuiCtrl4JList::AlphabeticSortFn(const void *a, const void *b) +{ + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a; + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; + + wstring wstr1=SaveDetailsA->pwszText; + wstring wstr2=SaveDetailsB->pwszText; + if(wstr1.compare(wstr2)<0) + { + return true; + } + + return false; +} + +bool CXuiCtrl4JList::IndexSortFn(const void *a, const void *b) +{ + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsA=(CXuiCtrl4JList::LIST_ITEM_INFO *)a; + CXuiCtrl4JList::LIST_ITEM_INFO *SaveDetailsB=(CXuiCtrl4JList::LIST_ITEM_INFO *)b; + + int iA=SaveDetailsA->iSortIndex; + int iB=SaveDetailsB->iSortIndex; + if(iA>iB) + { + return true; + } + + return false; +} + +void CXuiCtrl4JList::UpdateGraphic(int iItem,HXUIBRUSH hXuiBrush ) +{ + // need to update the one with the matching filetime + EnterCriticalSection(&m_AccessListData); + if( GetData(iItem).hXuiBrush ) + { + XuiDestroyBrush( GetData(iItem).hXuiBrush ); + } + GetData(iItem).hXuiBrush=hXuiBrush; + LeaveCriticalSection(&m_AccessListData); +} + +void CXuiCtrl4JList::UpdateText(int iItem,LPCWSTR pwszText ) +{ + // need to update the one with the matching filetime + EnterCriticalSection(&m_AccessListData); + GetData(iItem).pwszText=pwszText; + LeaveCriticalSection(&m_AccessListData); +} + +void CXuiCtrl4JList::UpdateGraphicFromiData(int iData,HXUIBRUSH hXuiBrush ) +{ + // need to update the one with the matching iData + EnterCriticalSection(&m_AccessListData); + if( GetDataiData(iData).hXuiBrush ) + { + XuiDestroyBrush( GetDataiData(iData).hXuiBrush ); + } + GetDataiData(iData).hXuiBrush=hXuiBrush; + LeaveCriticalSection(&m_AccessListData); +} + +void CXuiCtrl4JList::UpdateGraphic(FILETIME *pfTime,HXUIBRUSH hXuiBrush ) +{ + // need to update the one with the matching filetime + EnterCriticalSection(&m_AccessListData); + if( GetData(pfTime).hXuiBrush ) + { + XuiDestroyBrush( GetData(pfTime).hXuiBrush ); + } + GetData(pfTime).hXuiBrush=hXuiBrush; + LeaveCriticalSection(&m_AccessListData); +} + +// Gets called every frame +HRESULT CXuiCtrl4JList::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled) +{ + if( ( 0 == pGetSourceTextData->iData ) && ( ( pGetSourceTextData->bItemData ) ) ) + { + EnterCriticalSection(&m_AccessListData); + pGetSourceTextData->szText = + GetData(pGetSourceTextData->iItem).pwszText; + LeaveCriticalSection(&m_AccessListData); + bHandled = TRUE; + } + return S_OK; +} + +HRESULT CXuiCtrl4JList::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData,BOOL& bHandled) +{ + pGetItemCountData->cItems = (int)m_vListData.size(); + bHandled = TRUE; + return S_OK; +} + +HRESULT CXuiCtrl4JList::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + if( ( 0 == pGetSourceImageData->iData ) && ( pGetSourceImageData->bItemData ) ) + { + // Check for a brush + EnterCriticalSection(&m_AccessListData); + if(GetData(pGetSourceImageData->iItem).hXuiBrush!=NULL) + { + pGetSourceImageData->hBrush=GetData(pGetSourceImageData->iItem).hXuiBrush; + } + else + { + pGetSourceImageData->szPath = + GetData(pGetSourceImageData->iItem).pwszImage; + } + LeaveCriticalSection(&m_AccessListData); + bHandled = TRUE; + } + return S_OK; +} + +HRESULT CXuiCtrl4JList::OnGetItemEnable(XUIMessageGetItemEnable *pGetItemEnableData,BOOL& bHandled) +{ + if(m_vListData.size()!=0) + { + EnterCriticalSection(&m_AccessListData); + pGetItemEnableData->bEnabled = + GetData(pGetItemEnableData->iItem).fEnabled; + LeaveCriticalSection(&m_AccessListData); + } + bHandled = TRUE; + return S_OK; +} + + +HRESULT CXuiCtrl4JList::SetBorder(DWORD dw,BOOL bShow) +{ + CXuiControl Control; + HXUIOBJ hVisual,hBorder; + GetItemControl(dw,&Control); + Control.GetVisual(&hVisual); + XuiElementGetChildById(hVisual,L"Border",&hBorder); + return XuiElementSetShow(hBorder,bShow); +} + +void CXuiCtrl4JList::SetSelectionChangedHandle(HXUIOBJ hObj) +{ + m_hSelectionChangedHandlerObj = hObj; +} + +HRESULT CXuiCtrl4JList::OnDestroy() +{ + DeleteCriticalSection(&m_AccessListData); + + if(m_vListData.size()!=0) + { + for (unsigned i = 0; i < m_vListData.size(); ++i) + { + if( m_vListData[i]->hXuiBrush ) + { + XuiDestroyBrush( m_vListData[i]->hXuiBrush ); + } + delete [] (BYTE *)m_vListData[i]; + } + } + return S_OK; +} + +HRESULT CXuiCtrl4JList::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if(m_hSelectionChangedHandlerObj) + { + XUIMessage xuiMsg; + XUINotify xuiNotify; + XUINotifySelChanged xuiNotifySel; + XuiNotifySelChanged( &xuiMsg, &xuiNotify, &xuiNotifySel, hObjSource, pNotifySelChangedData->iItem, pNotifySelChangedData->iOldItem ); + XuiSendMessage( m_hSelectionChangedHandlerObj, &xuiMsg ); + + bHandled = xuiMsg.bHandled; + } + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.h new file mode 100644 index 00000000..11bdd456 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.h @@ -0,0 +1,78 @@ +#pragma once + + +class CXuiCtrl4JList : public CXuiListImpl +{ +public: + enum + { + eSortList_Date = 0, + eSortList_Alphabetical, + eSortList_Index, + }; + + // Information for one list item. + typedef struct _LIST_ITEM_INFO + { + LPCWSTR pwszText; + LPCWSTR pwszImage; + HXUIBRUSH hXuiBrush; + BOOL fChecked; + BOOL fEnabled; + bool bIsDamaged; // damaged save + FILETIME fTime; + int iData; // user data + int iIndex; // used for internal list sorting + int iSortIndex; // used to force an order for DLC + } + LIST_ITEM_INFO,*PLIST_ITEM_INFO; + + typedef std::vector <PLIST_ITEM_INFO> LISTITEMINFOARRAY; + + XUI_IMPLEMENT_CLASS(CXuiCtrl4JList, L"CXuiCtrl4JList", XUI_CLASS_LIST); + + void AddData( const LIST_ITEM_INFO& ItemInfo , int iSortListFromIndex=-1, int iSortFunction=CXuiCtrl4JList::eSortList_Date); + void RemoveAllData( ); + void UpdateText(int iItem,LPCWSTR pwszText ); + void SelectByUserData(int iData); + int GetIndexByUserData(int iData); + + void UpdateGraphic(int iItem,HXUIBRUSH hXuiBrush ); + void UpdateGraphic(FILETIME *pfTime,HXUIBRUSH hXuiBrush ); + void UpdateGraphicFromiData(int iData,HXUIBRUSH hXuiBrush ); + LIST_ITEM_INFO& GetData(DWORD dw); + LIST_ITEM_INFO& GetData(FILETIME *pFileTime); + LIST_ITEM_INFO& GetDataiData(int iData); + HRESULT SetBorder(DWORD dw,BOOL bShow); // for a highlight around the current selected item in the controls layout + void SetSelectionChangedHandle(HXUIOBJ hObj); +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_GET_ITEMENABLE(OnGetItemEnable) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_END_MSG_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnGetItemEnable(XUIMessageGetItemEnable *pGetItemEnableData,BOOL& bHandled); + HRESULT OnDestroy(); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + + LISTITEMINFOARRAY m_vListData; + CRITICAL_SECTION m_AccessListData; + +private: + static bool AlphabeticSortFn(const void *a, const void *b); + static bool TimeSortFn(const void *a, const void *b); + static bool IndexSortFn(const void *a, const void *b); + + HXUIOBJ m_hSelectionChangedHandlerObj; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.cpp new file mode 100644 index 00000000..074b7300 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.cpp @@ -0,0 +1,27 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\..\..\Minecraft.World\SharedConstants.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.alchemy.h" +#include "XUI_Ctrl_BrewProgress.h" + +int CXuiCtrlBrewProgress::GetValue() +{ + void* pvUserData; + this->GetUserData( &pvUserData ); + + if( pvUserData != NULL ) + { + BrewingStandTileEntity *pBrewingStandTileEntity = (BrewingStandTileEntity *)pvUserData; + + return pBrewingStandTileEntity->getBrewTime(); + } + + return 0; +} + +void CXuiCtrlBrewProgress::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = PotionBrewing::BREWING_TIME_SECONDS * SharedConstants::TICKS_PER_SECOND; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.h new file mode 100644 index 00000000..2f057a76 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.h @@ -0,0 +1,19 @@ +#pragma once +using namespace std; + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +class CXuiCtrlBrewProgress : public CXuiCtrlProgressCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlBrewProgress, L"CXuiCtrlBrewProgress", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.cpp new file mode 100644 index 00000000..cc5d996f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.cpp @@ -0,0 +1,52 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "XUI_Ctrl_BubblesProgress.h" + +int CXuiCtrlBubblesProgress::GetValue() +{ + void* pvUserData; + this->GetUserData( &pvUserData ); + + if( pvUserData != NULL ) + { + BrewingStandTileEntity *pBrewingStandTileEntity = (BrewingStandTileEntity *)pvUserData; + + int value = 0; + int bubbleStep = (pBrewingStandTileEntity->getBrewTime() / 2) % 7; + switch (bubbleStep) + { + case 0: + value = 0; + break; + case 6: + value = 5; + break; + case 5: + value = 10; + break; + case 4: + value = 15; + break; + case 3: + value = 20; + break; + case 2: + value = 25; + break; + case 1: + value = 30; + break; + } + + return value; + } + + return 0; +} + +void CXuiCtrlBubblesProgress::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = 30; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.h new file mode 100644 index 00000000..4950cf72 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.h @@ -0,0 +1,19 @@ +#pragma once +using namespace std; + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +class CXuiCtrlBubblesProgress : public CXuiCtrlProgressCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlBubblesProgress, L"CXuiCtrlBubblesProgress", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.cpp new file mode 100644 index 00000000..8e514094 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\FurnaceMenu.h" +#include "..\..\..\Minecraft.World\FurnaceTileEntity.h" +#include "XUI_Scene_Furnace.h" +#include "XUI_Ctrl_BurnProgress.h" + +int CXuiCtrlBurnProgress::GetValue() +{ + void* pvUserData; + this->GetUserData( &pvUserData ); + + if( pvUserData != NULL ) + { + FurnaceTileEntity *pFurnaceTileEntity = (FurnaceTileEntity *)pvUserData; + + // TODO This param is a magic number in Java but we should really define it somewhere with a name + // I think it is the number of states of the progress display (ie the max value) + return pFurnaceTileEntity->getBurnProgress( 24 ); + } + + return 0; +} + +void CXuiCtrlBurnProgress::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = 24; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.h new file mode 100644 index 00000000..1c403e32 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.h @@ -0,0 +1,19 @@ +#pragma once +using namespace std; + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +class CXuiCtrlBurnProgress : public CXuiCtrlProgressCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlBurnProgress, L"CXuiCtrlBurnProgress", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.cpp new file mode 100644 index 00000000..82b6c3ed --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.cpp @@ -0,0 +1,123 @@ +#include "stdafx.h" + +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSlot class +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +CXuiCtrlCraftIngredientSlot::CXuiCtrlCraftIngredientSlot() +{ + m_iID=0; + m_Desc=NULL; + m_isFoil = false; + m_isDirty = false; + m_item = nullptr; +} + + + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlCraftIngredientSlot::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + return hr; +} +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlCraftIngredientSlot::OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) +{ + if( m_iID != 0 || m_item != NULL ) + { + pData->item = m_item; + pData->iItemBitField = MAKE_SLOTDISPLAY_ITEM_BITMASK(m_iID,m_iAuxVal,m_isFoil); + pData->iDataBitField = MAKE_SLOTDISPLAY_DATA_BITMASK(m_iPad, m_uiAlpha,m_bDecorations,m_iCount,m_iScale,0); + } + else + { + pData->iDataBitField = 0; + pData->szPath = L""; + } + pData->bDirty = m_isDirty ? TRUE : FALSE; + m_isDirty = false; + + bHandled = TRUE; + return S_OK; +} + +HRESULT CXuiCtrlCraftIngredientSlot::OnGetSourceText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled) +{ + pGetSourceTextData->szText=m_Desc; + bHandled = TRUE; + + return S_OK; +} + +void CXuiCtrlCraftIngredientSlot::SetRedBox(BOOL bVal) +{ + HRESULT hr=S_OK; + + HXUIOBJ hObj,hObjChild; + hr=GetVisual(&hObj); + XuiElementGetChildById(hObj,L"BoxRed",&hObjChild); + XuiElementSetShow(hObjChild,bVal); + XuiElementGetChildById(hObj,L"Exclaim",&hObjChild); + XuiElementSetShow(hObjChild,bVal); +} + +void CXuiCtrlCraftIngredientSlot::SetIcon(int iPad, int iId,int iAuxVal, int iCount, int iScale, unsigned int uiAlpha,bool bDecorations,bool isFoil, BOOL bShow) +{ + m_item = nullptr; + m_iID=iId; + m_iAuxVal=iAuxVal; + + // 4J Stu - For clocks and compasses we set the aux value to a special one that signals we should use a default texture + // rather than the dynamic one for the player + // not right... auxvals for diggables are damage values, can be a lot higher + if( (m_iAuxVal & 0xFF) == 0xFF && !( iId == Item::clock_Id || iId == Item::compass_Id ) ) // 4J Stu - If the aux value is set to match any + m_iAuxVal = 0; + + // if the count comes in as 0, make it 1 + m_iCount=iCount==0?1:iCount; + m_iScale=iScale; + m_uiAlpha=uiAlpha; + m_bDecorations=bDecorations; + m_isFoil = isFoil; + + m_iPad = iPad; + m_isDirty = true; + + XuiElementSetShow(m_hObj,bShow); +} + +void CXuiCtrlCraftIngredientSlot::SetIcon(int iPad, shared_ptr<ItemInstance> item, int iScale, unsigned int uiAlpha,bool bDecorations, BOOL bShow) +{ + if(item == NULL) SetIcon(iPad, 0,0,0,0,0,false,false,bShow); + else + { + m_item = item; + m_iID = item->id; + m_iScale = iScale; + m_uiAlpha = uiAlpha; + m_bDecorations = bDecorations; + + m_iPad = iPad; + m_isDirty = true; + + XuiElementSetShow(m_hObj,bShow); + } +} + +void CXuiCtrlCraftIngredientSlot::SetDescription(LPCWSTR Desc) +{ + HRESULT hr=S_OK; + + HXUIOBJ hObj,hObjChild; + hr=GetVisual(&hObj); + XuiElementGetChildById(hObj,L"text_name",&hObjChild); + XuiControlSetText(hObjChild,Desc); + XuiElementSetShow(hObjChild,Desc==NULL?FALSE:TRUE); + m_Desc=Desc; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.h new file mode 100644 index 00000000..5cf7a7f4 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.h @@ -0,0 +1,45 @@ +#pragma once + +#include <string> +#include <XuiApp.h> + + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSlot class +//----------------------------------------------------------------------------- +class CXuiCtrlCraftIngredientSlot : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlCraftIngredientSlot, L"CXuiCtrlCraftIngredientSlot", XUI_CLASS_LABEL) + + CXuiCtrlCraftIngredientSlot(); + virtual ~CXuiCtrlCraftIngredientSlot() { }; + void SetRedBox(BOOL bVal); + void SetIcon(int iPad, int iId,int iAuxVal, int iCount, int iScale, unsigned int uiAlpha, bool bDecorations, bool isFoil = false, BOOL bShow=TRUE); + void SetIcon(int iPad, shared_ptr<ItemInstance> item, int iScale, unsigned int uiAlpha,bool bDecorations, BOOL bShow=TRUE); + void SetDescription(LPCWSTR Desc); +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GETSLOTITEM_MESSAGE(OnCustomMessage_GetSlotItem) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceText) + XUI_END_MSG_MAP() + + HRESULT OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled); + HRESULT OnGetSourceText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + +private: + shared_ptr<ItemInstance> m_item; + int m_iID; + int m_iAuxVal; + int m_iCount; + int m_iScale; + unsigned int m_uiAlpha; + int m_iPad; + bool m_bDecorations; + bool m_isFoil; + LPCWSTR m_Desc; + bool m_isDirty; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.cpp new file mode 100644 index 00000000..dfb9b5ca --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.cpp @@ -0,0 +1,90 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\Font.h" +#include "..\..\Lighting.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "XUI_Scene_Enchant.h" +#include "XUI_Ctrl_EnchantButton.h" + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlEnchantmentButton::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; + + HXUIOBJ parent = m_hObj; + HXUICLASS hcInventoryClass = XuiFindClass( L"CXuiSceneEnchant" ); + HXUICLASS currentClass; + + do + { + XuiElementGetParent(parent,&parent); + currentClass = XuiGetObjectClass( parent ); + } while (parent != NULL && !XuiClassDerivesFrom( currentClass, hcInventoryClass ) ); + + assert( parent != NULL ); + + VOID *pObj; + XuiObjectFromHandle( parent, &pObj ); + m_containerScene = (CXuiSceneEnchant *)pObj; + + m_index = 0; + m_lastCost = 0; + m_iPad = 0; + m_costString = L""; + + return hr; +} + +void CXuiCtrlEnchantmentButton::SetData(int iPad, int index) +{ + m_iPad = iPad; + m_index = index; +} + +HRESULT CXuiCtrlEnchantmentButton::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + EnchantmentMenu *menu = m_containerScene->getMenu(); + + int cost = menu->costs[m_index]; + + if(cost != m_lastCost) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(cost > pMinecraft->localplayers[m_iPad]->experienceLevel && !pMinecraft->localplayers[m_iPad]->abilities.instabuild) + { + // Dark background + SetEnable(FALSE); + } + else + { + // Light background and focus background + SetEnable(TRUE); + } + m_costString = _toString<int>(cost); + m_lastCost = cost; + } + if(cost == 0) + { + // Dark background + SetEnable(FALSE); + pGetSourceTextData->bDisplay = FALSE; + } + else + { + pGetSourceTextData->szText = m_costString.c_str(); + pGetSourceTextData->bDisplay = TRUE; + } + + bHandled = TRUE; + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.h new file mode 100644 index 00000000..0b414d69 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.h @@ -0,0 +1,33 @@ +#pragma once + +class CXuiSceneEnchant; + +class CXuiCtrlEnchantmentButton : public CXuiControlImpl +{ + friend class CXuiCtrlEnchantmentButtonText; +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlEnchantmentButton, L"CXuiCtrlEnchantmentButton", XUI_CLASS_CONTROL) + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + +public: + void SetData(int iPad, int index); + +private: + int m_iPad; + int m_index; + int m_lastCost; + wstring m_costString; + CXuiSceneEnchant *m_containerScene; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.cpp new file mode 100644 index 00000000..8a56a0ea --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.cpp @@ -0,0 +1,346 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" + +#include "..\..\Minecraft.h" +#include "..\..\ScreenSizeCalculator.h" +#include "..\..\TileEntityRenderDispatcher.h" +#include "..\..\EnchantTableRenderer.h" +#include "..\..\Lighting.h" +#include "..\..\LocalPlayer.h" + +#include "XUI_Scene_Enchant.h" + +#include "XUI_Ctrl_EnchantmentBook.h" +#include "..\..\BookModel.h" +#include "..\..\Options.h" + +//----------------------------------------------------------------------------- +// CXuiCtrlEnchantmentBook class +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +CXuiCtrlEnchantmentBook::CXuiCtrlEnchantmentBook() : + m_bDirty(FALSE), + m_fScale(1.0f), + m_fAlpha(1.0f) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; + + model = NULL; + + time = 0; + flip = oFlip = flipT = flipA = 0.0f; + open = oOpen = 0.0f; +} + +CXuiCtrlEnchantmentBook::~CXuiCtrlEnchantmentBook() +{ + //if(model != NULL) delete model; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlEnchantmentBook::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + HXUIOBJ parent = m_hObj; + HXUICLASS hcInventoryClass = XuiFindClass( L"CXuiSceneEnchant" ); + HXUICLASS currentClass; + + do + { + XuiElementGetParent(parent,&parent); + currentClass = XuiGetObjectClass( parent ); + } while (parent != NULL && !XuiClassDerivesFrom( currentClass, hcInventoryClass ) ); + + assert( parent != NULL ); + + VOID *pObj; + XuiObjectFromHandle( parent, &pObj ); + m_containerScene = (CXuiSceneEnchant *)pObj; + + last = nullptr; + + m_iPad = m_containerScene->getPad(); + + return hr; +} + +HRESULT CXuiCtrlEnchantmentBook::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ +#ifdef _XBOX + HXUIDC hDC = pRenderData->hDC; + + // build and render with the game call + + RenderManager.Set_matrixDirty(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + float alpha = 1.0f; + //GetOpacity( &alpha ); + + + D3DXMATRIX matrix; + GetFullXForm(&matrix); + + float bwidth,bheight; + GetBounds(&bwidth,&bheight); + + glColor4f(1, 1, 1, alpha); + + // Annoyingly, XUI renders everything to a z of 0 so if we want to render anything that needs the z-buffer on top of it, then we need to clear it. + // Clear just the region required for this control. + D3DRECT clearRect; + clearRect.x1 = (int)(matrix._41) - 2; + clearRect.y1 = (int)(matrix._42) - 2; + clearRect.x2 = (int)(matrix._41 + ( bwidth * matrix._11 )) + 2; + clearRect.y2 = (int)(matrix._42 + ( bheight * matrix._22 )) + 2; + + RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &clearRect); + + glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_fRawWidth, m_fRawHeight, 0, 1000, 3000); + //gluPerspective(90, (float) (320 / 240.0f), 0.5f, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + float xo = ( (matrix._41 + ( (bwidth*matrix._11)/2) ) / m_fScreenWidth ) * m_fRawWidth; + float yo = ( (matrix._42 + ((bheight*matrix._22)/2) ) / m_fScreenHeight ) * m_fRawHeight; + + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + glPushMatrix(); + glTranslatef(xo, yo, 50.0f); + float ss; + + // Base scale on height of this control + // Potentially we might want separate x & y scales here + ss = ( ( (bheight*matrix._22) / m_fScreenHeight ) * m_fRawHeight ) * 1.5f; + + glScalef(-ss, ss, ss); + //glRotatef(180, 0, 0, 1); + + glRotatef(45 + 90, 0, 1, 0); + Lighting::turnOn(); + glRotatef(-45 - 90, 0, 1, 0); + + //float sss = 4; + + //glTranslatef(0, 3.3f, -16); + //glScalef(sss, sss, sss); + + int tex = pMinecraft->textures->loadTexture(TN_ITEM_BOOK); // 4J was L"/1_2_2/item/book.png" + pMinecraft->textures->bind(tex); + + glRotatef(20, 1, 0, 0); + + float a = 1; + float o = oOpen + (open - oOpen) * a; + glTranslatef((1 - o) * 0.2f, (1 - o) * 0.1f, (1 - o) * 0.25f); + glRotatef(-(1 - o) * 90 - 90, 0, 1, 0); + glRotatef(180, 1, 0, 0); + + float ff1 = oFlip + (flip - oFlip) * a + 0.25f; + float ff2 = oFlip + (flip - oFlip) * a + 0.75f; + ff1 = (ff1 - floor(ff1)) * 1.6f - 0.3f; + ff2 = (ff2 - floor(ff2)) * 1.6f - 0.3f; + + if (ff1 < 0) ff1 = 0; + if (ff2 < 0) ff2 = 0; + if (ff1 > 1) ff1 = 1; + if (ff2 > 1) ff2 = 1; + + glEnable(GL_CULL_FACE); + + if(model == NULL) + { + // Share the model the the EnchantTableRenderer + + EnchantTableRenderer *etr = (EnchantTableRenderer*)TileEntityRenderDispatcher::instance->getRenderer(eTYPE_ENCHANTMENTTABLEENTITY); + if(etr != NULL) + { + model = etr->bookModel; + } + else + { + model = new BookModel(); + } + } + + model->render(NULL, 0, ff1, ff2, o, 0, 1 / 16.0f,true); + glDisable(GL_CULL_FACE); + + glPopMatrix(); + Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); + + XuiRenderRestoreState(hDC); + + tickBook(); + + bHandled = TRUE; + +#endif + return S_OK; +} + +//HRESULT CXuiCtrlEnchantmentBook::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +//{ +// HXUIDC hDC = pRenderData->hDC; +// +// RenderManager.Set_matrixDirty(); +// +// Minecraft *minecraft = Minecraft::GetInstance(); +// +// // 4J JEV: Inputs in the java, dunno what they are. +// float a = 1; +// +// D3DXMATRIX matrix; +// CXuiControl xuiControl(m_hObj); +// xuiControl.GetFullXForm(&matrix); +// float bwidth,bheight; +// xuiControl.GetBounds(&bwidth,&bheight); +// +// D3DXVECTOR3 vec, vecP, vecPP; +// xuiControl.GetPosition(&vec); +// +// CXuiElement parent, scene; +// xuiControl.GetParent(&parent); +// parent.GetPosition(&vecP); +// parent.GetParent(&scene); +// scene.GetPosition(&vecPP); +// +// float xo = ( (matrix._41 + ( (bwidth*matrix._11)/2) ) / m_fScreenWidth ) * m_fRawWidth; +// float yo = ( (matrix._42 + (bheight*matrix._22) ) / m_fScreenHeight ) * m_fRawHeight; +// +// glColor4f(1, 1, 1, 1); +// +// glPushMatrix(); +// glMatrixMode(GL_PROJECTION); +// glPushMatrix(); +// glLoadIdentity(); +// +// ScreenSizeCalculator ssc = ScreenSizeCalculator(minecraft->options, minecraft->width, minecraft->height); +// +// //glViewport((int) (ssc.getWidth() - 320) / 2 * ssc.scale, (int) (ssc.getHeight() - 240) / 2 * ssc.scale, (int) (320 * ssc.scale), (int) (240 * ssc.scale)); +// +// // 4J JEV: Trying to position it within the XUI element +// float xPos, yPos; +// xPos = (vec.x + vecP.x + vecPP.x) / (minecraft->width/2); xPos = xPos - 1; xPos = 2*xPos/3; +// yPos = (vec.y + vecP.y + vecPP.y) / (minecraft->height/2); yPos = 1 - yPos; yPos = 2*yPos/3; +// glTranslatef(xPos, yPos, 0); +// +// gluPerspective(90, (float) (320 / 240.0f), 9, 80); +// +// float sss = 1; +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// Lighting::turnOn(); +// +// glTranslatef(0, 3.3f, -16); +// glScalef(sss, sss, sss); +// +// float ss = 5; +// +// glScalef(ss, ss, ss); +// glRotatef(180, 0, 0, 1); +// +// int tex = minecraft->textures->loadTexture(TN_ITEM_BOOK); // 4J was L"/1_2_2/item/book.png" +// minecraft->textures->bind(tex); +// +// glRotatef(20, 1, 0, 0); +// +// float o = oOpen + (open - oOpen) * a; +// glTranslatef((1 - o) * 0.2f, (1 - o) * 0.1f, (1 - o) * 0.25f); +// glRotatef(-(1 - o) * 90 - 90, 0, 1, 0); +// glRotatef(180, 1, 0, 0); +// +// float ff1 = oFlip + (flip - oFlip) * a + 0.25f; +// float ff2 = oFlip + (flip - oFlip) * a + 0.75f; +// ff1 = (ff1 - floor(ff1)) * 1.6f - 0.3f; +// ff2 = (ff2 - floor(ff2)) * 1.6f - 0.3f; +// +// if (ff1 < 0) ff1 = 0; +// if (ff2 < 0) ff2 = 0; +// if (ff1 > 1) ff1 = 1; +// if (ff2 > 1) ff2 = 1; +// +// glEnable(GL_RESCALE_NORMAL); +// +// model.render(NULL, 0, ff1, ff2, o, 0, 1 / 16.0f,true); +// +// glDisable(GL_RESCALE_NORMAL); +// Lighting::turnOff(); +// glMatrixMode(GL_PROJECTION); +// //glViewport(0, 0, minecraft->width, minecraft->height); +// glPopMatrix(); +// glMatrixMode(GL_MODELVIEW); +// glPopMatrix(); +// +// Lighting::turnOff(); +// glColor4f(1, 1, 1, 1); +// +// XuiRenderRestoreState(hDC); +// +// tickBook(); +// +// bHandled = TRUE; +// +// return S_OK; +//} + +void CXuiCtrlEnchantmentBook::tickBook() +{ + EnchantmentMenu *menu = m_containerScene->getMenu(); + shared_ptr<ItemInstance> current = menu->getSlot(0)->getItem(); + if (!ItemInstance::matches(current, last)) + { + last = current; + + do + { + flipT += random.nextInt(4) - random.nextInt(4); + } while (flip <= flipT + 1 && flip >= flipT - 1); + } + + time++; + oFlip = flip; + oOpen = open; + + bool shouldBeOpen = false; + for (int i = 0; i < 3; i++) + { + if (menu->costs[i] != 0) + { + shouldBeOpen = true; + } + } + + if (shouldBeOpen) open += 0.2f; + else open -= 0.2f; + if (open < 0) open = 0; + if (open > 1) open = 1; + + + float diff = (flipT - flip) * 0.4f; + float max = 0.2f; + if (diff < -max) diff = -max; + if (diff > +max) diff = +max; + flipA += (diff - flipA) * 0.9f; + + flip = flip + flipA; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.h new file mode 100644 index 00000000..93da0768 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.h @@ -0,0 +1,51 @@ +#pragma once +#include "..\..\..\Minecraft.World\Random.h" + +using namespace std; + +class CXuiSceneEnchant; +class BookModel; + +//----------------------------------------------------------------------------- +// CXuiCtrlEnchantPanel class +//----------------------------------------------------------------------------- +class CXuiCtrlEnchantmentBook : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlEnchantmentBook, L"CXuiCtrlEnchantmentBook", XUI_CLASS_LABEL) + + CXuiCtrlEnchantmentBook(); + virtual ~CXuiCtrlEnchantmentBook(); + + void setChanged(); + void setOpen(bool); + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + BookModel *model; + Random random; + + // 4J JEV: Book animation variables. + int time; + float flip, oFlip, flipT, flipA; + float open, oOpen; + + BOOL m_bDirty; + float m_fScale,m_fAlpha; + int m_iPad; + CXuiSceneEnchant *m_containerScene; + shared_ptr<ItemInstance> last; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; + + void tickBook(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.cpp new file mode 100644 index 00000000..702ef15d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.cpp @@ -0,0 +1,185 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\Font.h" +#include "..\..\Lighting.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "XUI_Scene_Enchant.h" +#include "XUI_Ctrl_EnchantButton.h" +#include "XUI_Ctrl_EnchantmentButtonText.h" +#include "..\..\Minecraft.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" + +#include <iostream> +#include <string> +#include <sstream> +#include <algorithm> +#include <iterator> + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlEnchantmentButtonText::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; + + HXUIOBJ parent = m_hObj; + HXUICLASS hcInventoryClass = XuiFindClass( L"CXuiCtrlEnchantmentButton" ); + HXUICLASS currentClass; + + do + { + XuiElementGetParent(parent,&parent); + currentClass = XuiGetObjectClass( parent ); + } while (parent != NULL && !XuiClassDerivesFrom( currentClass, hcInventoryClass ) ); + + assert( parent != NULL ); + + VOID *pObj; + XuiObjectFromHandle( parent, &pObj ); + m_parentControl = (CXuiCtrlEnchantmentButton *)pObj; + + m_lastCost = 0; + m_enchantmentString = L""; + + m_textColour = app.GetHTMLColour(eTextColor_Enchant); + m_textFocusColour = app.GetHTMLColour(eTextColor_EnchantFocus); + m_textDisabledColour = app.GetHTMLColour(eTextColor_EnchantDisabled); + + return hr; +} + +HRESULT CXuiCtrlEnchantmentButtonText::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ + HXUIDC hDC = pRenderData->hDC; + CXuiControl xuiControl(m_hObj); + + // build and render with the game call + + RenderManager.Set_matrixDirty(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + D3DXMATRIX matrix; + xuiControl.GetFullXForm(&matrix); + float bwidth,bheight; + xuiControl.GetBounds(&bwidth,&bheight); + + // Annoyingly, XUI renders everything to a z of 0 so if we want to render anything that needs the z-buffer on top of it, then we need to clear it. + // Clear just the region required for this control. + D3DRECT clearRect; + clearRect.x1 = (int)(matrix._41) - 2; + clearRect.y1 = (int)(matrix._42) - 2; + clearRect.x2 = (int)(matrix._41 + ( bwidth * matrix._11 )) + 2; + clearRect.y2 = (int)(matrix._42 + ( bheight * matrix._22 )) + 2; + + RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &clearRect); + // glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_fScreenWidth, m_fScreenHeight, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + + glEnable(GL_RESCALE_NORMAL); + glPushMatrix(); + glRotatef(120, 1, 0, 0); + //Lighting::turnOnGui(); + glPopMatrix(); + + + + EnchantmentMenu *menu = m_parentControl->m_containerScene->getMenu(); + + float xo = matrix._41; + float yo = matrix._42; + glTranslatef(xo, yo, 50.0f); + + float ss = 1; + + if(!m_parentControl->m_containerScene->m_bSplitscreen) + { + ss = 2; + } + + glScalef(ss, ss, ss); + + int cost = menu->costs[m_parentControl->m_index]; + + if(cost != m_lastCost) + { + m_lastCost = cost; + m_enchantmentString = EnchantmentNames::instance.getRandomName(); + } + + glColor4f(1, 1, 1, 1); + if (cost != 0) + { + wstring line = _toString<int>(cost); + Font *font = pMinecraft->altFont; + //int col = 0x685E4A; + unsigned int col = m_textColour; + if (pMinecraft->localplayers[m_parentControl->m_iPad]->experienceLevel < cost && !pMinecraft->localplayers[m_parentControl->m_iPad]->abilities.instabuild) + { + col = m_textDisabledColour; + font->drawWordWrap(m_enchantmentString, 0, 0, bwidth/ss, col, bheight/ss); + font = pMinecraft->font; + //col = (0x80ff20 & 0xfefefe) >> 1; + //font->drawShadow(line, (bwidth - font->width(line))/ss, 7, col); + } + else + { + if (m_parentControl->HasFocus()) + { + //col = 0xffff80; + col = m_textFocusColour; + } + font->drawWordWrap(m_enchantmentString, 0, 0, bwidth/ss, col, bheight/ss); + font = pMinecraft->font; + //col = 0x80ff20; + //font->drawShadow(line, (bwidth - font->width(line))/ss, 7, col); + } + } + else + { + } + + //Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); + + XuiRenderRestoreState(hDC); + + bHandled = TRUE; + + return S_OK; +} + +CXuiCtrlEnchantmentButtonText::EnchantmentNames CXuiCtrlEnchantmentButtonText::EnchantmentNames::instance; + +CXuiCtrlEnchantmentButtonText::EnchantmentNames::EnchantmentNames() +{ + wstring allWords = L"the elder scrolls klaatu berata niktu xyzzy bless curse light darkness fire air earth water hot dry cold wet ignite snuff embiggen twist shorten stretch fiddle destroy imbue galvanize enchant free limited range of towards inside sphere cube self other ball mental physical grow shrink demon elemental spirit animal creature beast humanoid undead fresh stale "; + std::wistringstream iss(allWords); + std::copy(std::istream_iterator< std::wstring, wchar_t, std::char_traits<wchar_t> >(iss), std::istream_iterator< std::wstring, wchar_t, std::char_traits<wchar_t> >(),std::back_inserter(words)); +} + +wstring CXuiCtrlEnchantmentButtonText::EnchantmentNames::getRandomName() +{ + int wordCount = random.nextInt(2) + 3; + wstring word = L""; + for (int i = 0; i < wordCount; i++) + { + if (i > 0) word += L" "; + word += words[random.nextInt(words.size())]; + } + return word; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.h new file mode 100644 index 00000000..c28b29ed --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.h @@ -0,0 +1,45 @@ +#pragma once + +class CXuiSceneEnchant; + +class CXuiCtrlEnchantmentButtonText : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlEnchantmentButtonText, L"CXuiCtrlEnchantmentButtonText", XUI_CLASS_CONTROL) + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + CXuiCtrlEnchantmentButton *m_parentControl; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; + + int m_lastCost; + wstring m_enchantmentString; + + unsigned int m_textColour, m_textFocusColour, m_textDisabledColour; + + class EnchantmentNames + { + public: + static EnchantmentNames instance; + + private: + Random random; + vector<wstring> words; + + EnchantmentNames(); + + public: + wstring getRandomName(); + }; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.cpp new file mode 100644 index 00000000..b125af39 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\FurnaceMenu.h" +#include "..\..\..\Minecraft.World\FurnaceTileEntity.h" +#include "XUI_Scene_Furnace.h" +#include "XUI_Ctrl_FireProgress.h" + +int CXuiCtrlFireProgress::GetValue() +{ + void* pvUserData; + this->GetUserData( &pvUserData ); + + if( pvUserData != NULL ) + { + FurnaceTileEntity *pFurnaceTileEntity = (FurnaceTileEntity *)pvUserData; + + // TODO This param is a magic number in Java but we should really define it somewhere with a name + // I think it is the number of states of the progress display (ie the max value) + return pFurnaceTileEntity->getLitProgress( 12 ); + } + + return 0; +} + +void CXuiCtrlFireProgress::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = 12; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.h new file mode 100644 index 00000000..595072ef --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.h @@ -0,0 +1,19 @@ +#pragma once +using namespace std; + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +class CXuiCtrlFireProgress : public CXuiCtrlProgressCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlFireProgress, L"CXuiCtrlFireProgress", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.cpp new file mode 100644 index 00000000..3bb33440 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" + +#include "XUI_Ctrl_LoadingProgress.h" +#include "..\..\Minecraft.h" +#include "..\..\ProgressRenderer.h" + +int CXuiCtrlLoadingProgress::GetValue() +{ + int currentValue = 0; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + currentValue = pMinecraft->progressRenderer->getCurrentPercent(); + //printf("About to render progress of %d\n", currentValue); + return currentValue; +} + +void CXuiCtrlLoadingProgress::GetRange(int *pnRangeMin, int *pnRangeMax) +{ + *pnRangeMin = 0; + *pnRangeMax = 100; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.h new file mode 100644 index 00000000..623393bd --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.h @@ -0,0 +1,18 @@ +#pragma once + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +class CXuiCtrlLoadingProgress : public CXuiCtrlProgressCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlLoadingProgress, L"CXuiCtrlLoadingProgress", XUI_CLASS_PROGRESSBAR ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + virtual int GetValue(); + virtual void GetRange(int *pnRangeMin, int *pnRangeMax); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.cpp new file mode 100644 index 00000000..02ee7c93 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.cpp @@ -0,0 +1,190 @@ +#include "stdafx.h" +#include "..\..\Minecraft.h" +#include "..\..\ScreenSizeCalculator.h" +#include "..\..\EntityRenderDispatcher.h" +#include "..\..\Lighting.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "XUI_Ctrl_MinecraftPlayer.h" +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_Scene_Inventory.h" +#include "..\..\Options.h" + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftPlayer class +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +CXuiCtrlMinecraftPlayer::CXuiCtrlMinecraftPlayer() : + m_bDirty(FALSE), + m_fScale(1.0f), + m_fAlpha(1.0f) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlMinecraftPlayer::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + HXUIOBJ parent = m_hObj; + HXUICLASS hcInventoryClass = XuiFindClass( L"CXuiSceneInventory" ); + HXUICLASS currentClass; + + do + { + XuiElementGetParent(parent,&parent); + currentClass = XuiGetObjectClass( parent ); + } while (parent != NULL && !XuiClassDerivesFrom( currentClass, hcInventoryClass ) ); + + assert( parent != NULL ); + + VOID *pObj; + XuiObjectFromHandle( parent, &pObj ); + m_containerScene = (CXuiSceneInventory *)pObj; + + m_iPad = m_containerScene->getPad(); + + return hr; +} + +HRESULT CXuiCtrlMinecraftPlayer::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ +#ifdef _XBOX + HXUIDC hDC = pRenderData->hDC; + + // build and render with the game call + + RenderManager.Set_matrixDirty(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + glColor4f(1, 1, 1, 1); + glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_fRawWidth, m_fRawHeight, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + + D3DXMATRIX matrix; + CXuiControl xuiControl(m_hObj); + xuiControl.GetFullXForm(&matrix); + float bwidth,bheight; + xuiControl.GetBounds(&bwidth,&bheight); + + float xo = ( (matrix._41 + ( (bwidth*matrix._11)/2) ) / m_fScreenWidth ) * m_fRawWidth; + float yo = ( (matrix._42 + (bheight*matrix._22) ) / m_fScreenHeight ) * m_fRawHeight; + + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + glPushMatrix(); + glTranslatef(xo, yo - 3.5f, 50.0f); + float ss;// = 26; + + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + ss = 24; + } + else + { + if(app.GetLocalPlayerCount()>1) + { + ss = 13; + } + else + { + ss = 26; + } + } + // Base scale on height of this control + // Potentially we might want separate x & y scales here + //ss = ( ( bheight / m_fScreenHeight ) * m_fRawHeight ); + // For testing split screen - this scale is correct for 4 player split screen + + // how many local players do we have? +// int iPlayerC=0; +// +// for(int i=0;i<XUSER_MAX_COUNT;i++) +// { +// if(pMinecraft->localplayers[i] != NULL) +// { +// iPlayerC++; +// } +// } +// +// switch(iPlayerC) +// { +// case 1: +// break; +// case 2: +// case 3: +// case 4: +// ss *= 0.5f; +// break; +// } + + glScalef(-ss, ss, ss); + glRotatef(180, 0, 0, 1); + + float oybr = pMinecraft->localplayers[m_iPad]->yBodyRot; + float oyr = pMinecraft->localplayers[m_iPad]->yRot; + float oxr = pMinecraft->localplayers[m_iPad]->xRot; + float oyhr = pMinecraft->localplayers[m_iPad]->yHeadRot; + + D3DXVECTOR3 pointerPosition = m_containerScene->GetCursorScreenPosition(); + //printf("Pointer screen position is x:%f, y:%f, z:%f\n",pointerPosition.x, pointerPosition.y, pointerPosition.z); + + float xd = ( matrix._41 + ( (bwidth*matrix._11)/2) ) - pointerPosition.x; + + // Need to base Y on head position, not centre of mass + float yd = ( matrix._42 + ( (bheight*matrix._22) / 2) - 40 ) - pointerPosition.y; + + glRotatef(45 + 90, 0, 1, 0); + Lighting::turnOn(); + glRotatef(-45 - 90, 0, 1, 0); + + glRotatef(-(float) atan(yd / 40.0f) * 20, 1, 0, 0); + + pMinecraft->localplayers[m_iPad]->yBodyRot = (float) atan(xd / 40.0f) * 20; + pMinecraft->localplayers[m_iPad]->yRot = (float) atan(xd / 40.0f) * 40; + pMinecraft->localplayers[m_iPad]->xRot = -(float) atan(yd / 40.0f) * 20; + pMinecraft->localplayers[m_iPad]->yHeadRot = pMinecraft->localplayers[m_iPad]->yRot; + //pMinecraft->localplayers[m_iPad]->glow = 1; + glTranslatef(0, pMinecraft->localplayers[m_iPad]->heightOffset, 0); + EntityRenderDispatcher::instance->playerRotY = 180; + + // 4J Stu - Turning on hideGui while we do this stops the name rendering in split-screen + bool wasHidingGui = pMinecraft->options->hideGui; + pMinecraft->options->hideGui = true; + EntityRenderDispatcher::instance->render(pMinecraft->localplayers[m_iPad], 0, 0, 0, 0, 1,false,false); + pMinecraft->options->hideGui = wasHidingGui; + //pMinecraft->localplayers[m_iPad]->glow = 0; + + pMinecraft->localplayers[m_iPad]->yBodyRot = oybr; + pMinecraft->localplayers[m_iPad]->yRot = oyr; + pMinecraft->localplayers[m_iPad]->xRot = oxr; + pMinecraft->localplayers[m_iPad]->yHeadRot = oyhr; + glPopMatrix(); + Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); + + XuiRenderRestoreState(hDC); + + bHandled = TRUE; +#endif + return S_OK; + +} + + + diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.h new file mode 100644 index 00000000..fa28d6b8 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.h @@ -0,0 +1,42 @@ +#pragma once + +#include <string> +#include <XuiApp.h> + +using namespace std; + +class TileRenderer; +class ItemRenderer; +class CXuiSceneInventory; + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftPlayer class +//----------------------------------------------------------------------------- +class CXuiCtrlMinecraftPlayer : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlMinecraftPlayer, L"CXuiCtrlMinecraftPlayer", XUI_CLASS_LABEL) + + CXuiCtrlMinecraftPlayer(); + virtual ~CXuiCtrlMinecraftPlayer() { }; + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + BOOL m_bDirty; + float m_fScale,m_fAlpha; + int m_iPad; + CXuiSceneInventory *m_containerScene; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.cpp new file mode 100644 index 00000000..80750deb --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.cpp @@ -0,0 +1,551 @@ +#include "stdafx.h" +#include "..\..\Minecraft.h" +#include "..\..\ScreenSizeCalculator.h" +#include "..\..\EntityRenderDispatcher.h" +#include "..\..\PlayerRenderer.h" +#include "..\..\HumanoidModel.h" +#include "..\..\Lighting.h" +#include "..\..\..\Minecraft.World\Class.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "XUI_Ctrl_MinecraftSkinPreview.h" +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_Scene_Inventory.h" +#include "..\..\Options.h" +#include "..\..\stubs.h" +#include "..\..\ModelPart.h" + +//#define SKIN_PREVIEW_BOB_ANIM +#define SKIN_PREVIEW_WALKING_ANIM + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSkinPreview class +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +CXuiCtrlMinecraftSkinPreview::CXuiCtrlMinecraftSkinPreview() : + m_bDirty(FALSE), + m_fScale(1.0f), + m_fAlpha(1.0f) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; + + m_customTextureUrl = L"default"; + m_backupTexture = TN_MOB_CHAR; + m_capeTextureUrl = L""; + + m_yRot = 0; + m_xRot = 0; + + m_swingTime = 0.0f; + m_bobTick = 0.0f; + m_walkAnimSpeedO = 0.0f; + m_walkAnimSpeed = 0.0f; + m_walkAnimPos = 0.0f; + + m_bAutoRotate = false; + m_bRotatingLeft = false; + + m_incXRot = false; + m_decXRot = false; + m_incYRot = false; + m_decYRot = false; + + m_currentAnimation = e_SkinPreviewAnimation_Walking; + + m_fTargetRotation = 0.0f; + m_fOriginalRotation = 0.0f; + m_framesAnimatingRotation = 0; + m_bAnimatingToFacing = false; + m_pvAdditionalModelParts=NULL; + m_uiAnimOverrideBitmask=0L; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlMinecraftSkinPreview::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + + return hr; +} + +void CXuiCtrlMinecraftSkinPreview::SetTexture(const wstring &url, TEXTURE_NAME backupTexture) +{ + m_customTextureUrl = url; + m_backupTexture = backupTexture; + + unsigned int uiAnimOverrideBitmask = Player::getSkinAnimOverrideBitmask( app.getSkinIdFromPath(m_customTextureUrl) ); + + if(app.GetGameSettings(eGameSetting_CustomSkinAnim)==0 ) + { + // We have a force animation for some skins (claptrap) + // 4J-PB - treat all the eAnim_Disable flags as a force anim + + if((uiAnimOverrideBitmask & HumanoidModel::m_staticBitmaskIgnorePlayerCustomAnimSetting)!=0) + { + m_uiAnimOverrideBitmask=uiAnimOverrideBitmask; + } + else + { + m_uiAnimOverrideBitmask=0; + } + } + else + { + m_uiAnimOverrideBitmask = uiAnimOverrideBitmask; + } + + app.DebugPrintf("+++ SetTexture - %d, %8x\n",app.getSkinIdFromPath(m_customTextureUrl)&0xFFFFFFF,m_uiAnimOverrideBitmask); + m_pvAdditionalModelParts=app.GetAdditionalModelParts(app.getSkinIdFromPath(m_customTextureUrl)); +} + +void CXuiCtrlMinecraftSkinPreview::SetFacing(ESkinPreviewFacing facing, bool bAnimate /*= false*/) +{ + switch(facing) + { + case e_SkinPreviewFacing_Forward: + m_fTargetRotation = 0; + m_bRotatingLeft = true; + break; + case e_SkinPreviewFacing_Left: + m_fTargetRotation = LOOK_LEFT_EXTENT; + m_bRotatingLeft = false; + break; + case e_SkinPreviewFacing_Right: + m_fTargetRotation = LOOK_RIGHT_EXTENT; + m_bRotatingLeft = true; + break; + } + + if(!bAnimate) + { + m_yRot = m_fTargetRotation; + m_bAnimatingToFacing = false; + } + else + { + m_fOriginalRotation = m_yRot; + m_bAnimatingToFacing = true; + m_framesAnimatingRotation = 0; + } +} + +void CXuiCtrlMinecraftSkinPreview::CycleNextAnimation() +{ + m_currentAnimation = (ESkinPreviewAnimations)(m_currentAnimation + 1); + if(m_currentAnimation >= e_SkinPreviewAnimation_Count) m_currentAnimation = e_SkinPreviewAnimation_Walking; + + m_swingTime = 0.0f; +} + +void CXuiCtrlMinecraftSkinPreview::CyclePreviousAnimation() +{ + m_currentAnimation = (ESkinPreviewAnimations)(m_currentAnimation - 1); + if(m_currentAnimation < e_SkinPreviewAnimation_Walking) m_currentAnimation = (ESkinPreviewAnimations)(e_SkinPreviewAnimation_Count - 1); + + m_swingTime = 0.0f; +} + +HRESULT CXuiCtrlMinecraftSkinPreview::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ + if( m_bAnimatingToFacing ) + { + ++m_framesAnimatingRotation; + m_yRot = m_fOriginalRotation + m_framesAnimatingRotation * ( (m_fTargetRotation - m_fOriginalRotation) / CHANGING_SKIN_FRAMES ); + + //if(m_framesAnimatingRotation == CHANGING_SKIN_FRAMES) m_bAnimatingToFacing = false; + } + else + { + if( m_incXRot ) IncrementXRotation(); + if( m_decXRot ) DecrementXRotation(); + if( m_incYRot ) IncrementYRotation(); + if( m_decYRot ) DecrementYRotation(); + + if(m_bAutoRotate) + { + ++m_rotateTick; + + if(m_rotateTick%4==0) + { + if(m_yRot >= LOOK_LEFT_EXTENT) + { + m_bRotatingLeft = false; + } + else if(m_yRot <= LOOK_RIGHT_EXTENT) + { + m_bRotatingLeft = true; + } + + if(m_bRotatingLeft) + { + IncrementYRotation(); + } + else + { + DecrementYRotation(); + } + } + } + } + + HXUIDC hDC = pRenderData->hDC; + + // build and render with the game call + + RenderManager.Set_matrixDirty(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + float alpha = 1.0f; + //GetOpacity( &alpha ); + + glColor4f(1, 1, 1, alpha); + glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_fRawWidth, m_fRawHeight, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + + D3DXMATRIX matrix; + GetFullXForm(&matrix); + float bwidth,bheight; + GetBounds(&bwidth,&bheight); + + float xo = ( (matrix._41 + ( (bwidth*matrix._11)/2) ) / m_fScreenWidth ) * m_fRawWidth; + float yo = ( (matrix._42 + (bheight*matrix._22) ) / m_fScreenHeight ) * m_fRawHeight; + + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + glPushMatrix(); + glTranslatef(xo, yo - 3.5f, 50.0f); + float ss; + + // Base scale on height of this control + // Potentially we might want separate x & y scales here + ss = ( ( (bheight*matrix._22) / m_fScreenHeight ) * m_fRawHeight )/2; + + glScalef(-ss, ss, ss); + glRotatef(180, 0, 0, 1); + + //glRotatef(45 + 90, 0, 1, 0); + Lighting::turnOn(); + //glRotatef(-45 - 90, 0, 1, 0); + + glRotatef(-(float)m_xRot, 1, 0, 0); + + // 4J Stu - Turning on hideGui while we do this stops the name rendering in split-screen + bool wasHidingGui = pMinecraft->options->hideGui; + pMinecraft->options->hideGui = true; + + //EntityRenderDispatcher::instance->render(pMinecraft->localplayers[0], 0, 0, 0, 0, 1); + EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER); + if (renderer != NULL) + { + // 4J-PB - any additional parts to turn on for this player (skin dependent) + //vector<ModelPart *> *pAdditionalModelParts=mob->GetAdditionalModelParts(); + + if(m_pvAdditionalModelParts && m_pvAdditionalModelParts->size()!=0) + { + for(AUTO_VAR(it, m_pvAdditionalModelParts->begin()); it != m_pvAdditionalModelParts->end(); ++it) + { + ModelPart *pModelPart=*it; + + pModelPart->visible=true; + } + } + + render(renderer,0,0,0,0,1); + //renderer->postRender(entity, x, y, z, rot, a); + + // hide the additional parts + if(m_pvAdditionalModelParts && m_pvAdditionalModelParts->size()!=0) + { + for(AUTO_VAR(it, m_pvAdditionalModelParts->begin()); it != m_pvAdditionalModelParts->end(); ++it) + { + ModelPart *pModelPart=*it; + + pModelPart->visible=false; + } + } + } + + pMinecraft->options->hideGui = wasHidingGui; + + glPopMatrix(); + Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); + + XuiRenderRestoreState(hDC); + + bHandled = TRUE; + + return S_OK; +} + +// 4J Stu - Modified version of MobRenderer::render that does not require an actual entity +void CXuiCtrlMinecraftSkinPreview::render(EntityRenderer *renderer, double x, double y, double z, float rot, float a) +{ + glPushMatrix(); + glDisable(GL_CULL_FACE); + + HumanoidModel *model = (HumanoidModel *)renderer->getModel(); + + //getAttackAnim(mob, a); + //if (armor != NULL) armor->attackTime = model->attackTime; + //model->riding = mob->isRiding(); + //if (armor != NULL) armor->riding = model->riding; + + // 4J Stu - Remember to reset these values once the rendering is done if you add another one + model->attackTime = 0; + model->sneaking = false; + model->holdingRightHand = false; + model->holdingLeftHand = false; + model->idle = false; + model->eating = false; + model->eating_swing = 0; + model->eating_t = 0; + model->young = false; + model->riding = false; + + model->m_uiAnimOverrideBitmask = m_uiAnimOverrideBitmask; + + if( !m_bAnimatingToFacing ) + { + switch( m_currentAnimation ) + { + case e_SkinPreviewAnimation_Sneaking: + model->sneaking = true; + break; + case e_SkinPreviewAnimation_Attacking: + model->holdingRightHand = true; + m_swingTime++; + if (m_swingTime >= (Player::SWING_DURATION * 3) ) + { + m_swingTime = 0; + } + model->attackTime = m_swingTime / (float) (Player::SWING_DURATION * 3); + break; + default: + break; + }; + } + + + float bodyRot = m_yRot; //(mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a); + float headRot = m_yRot; //(mob->yRotO + (mob->yRot - mob->yRotO) * a); + float headRotx = 0; //(mob->xRotO + (mob->xRot - mob->xRotO) * a); + + //setupPosition(mob, x, y, z); + // is equivalent to + glTranslatef((float) x, (float) y, (float) z); + + //float bob = getBob(mob, a); +#ifdef SKIN_PREVIEW_BOB_ANIM + float bob = (m_bobTick + a)/2; + + ++m_bobTick; + if(m_bobTick>=360*2) m_bobTick = 0; +#else + float bob = 0.0f; +#endif + + //setupRotations(mob, bob, bodyRot, a); + // is equivalent to + glRotatef(180 - bodyRot, 0, 1, 0); + + float _scale = 1 / 16.0f; + glEnable(GL_RESCALE_NORMAL); + glScalef(-1, -1, 1); + + //scale(mob, a); + // is equivalent to + float s = 15 / 16.0f; + glScalef(s, s, s); + + glTranslatef(0, -24 * _scale - 0.125f / 16.0f, 0); + +#ifdef SKIN_PREVIEW_WALKING_ANIM + m_walkAnimSpeedO = m_walkAnimSpeed; + m_walkAnimSpeed += (0.1f - m_walkAnimSpeed) * 0.4f; + m_walkAnimPos += m_walkAnimSpeed; + float ws = m_walkAnimSpeedO + (m_walkAnimSpeed - m_walkAnimSpeedO) * a; + float wp = m_walkAnimPos - m_walkAnimSpeed * (1 - a); +#else + float ws = 0; + float wp = 0; +#endif + + if (ws > 1) ws = 1; + + MemSect(31); + bindTexture(m_customTextureUrl, m_backupTexture); + MemSect(0); + glEnable(GL_ALPHA_TEST); + + //model->prepareMobModel(mob, wp, ws, a); + model->render(nullptr, wp, ws, bob, headRot - bodyRot, headRotx, _scale, true); + /*for (int i = 0; i < MAX_ARMOR_LAYERS; i++) + { + if (prepareArmor(mob, i, a)) + { + armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, true); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + } + }*/ + + //additionalRendering(mob, a); + if (bindTexture(m_capeTextureUrl, L"" )) + { + glPushMatrix(); + glTranslatef(0, 0, 2 / 16.0f); + + double xd = 0;//(mob->xCloakO + (mob->xCloak - mob->xCloakO) * a) - (mob->xo + (mob->x - mob->xo) * a); + double yd = 0;//(mob->yCloakO + (mob->yCloak - mob->yCloakO) * a) - (mob->yo + (mob->y - mob->yo) * a); + double zd = 0;//(mob->zCloakO + (mob->zCloak - mob->zCloakO) * a) - (mob->zo + (mob->z - mob->zo) * a); + + float yr = 1;//mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a; + + double xa = sin(yr * PI / 180); + double za = -cos(yr * PI / 180); + + float flap = (float) yd * 10; + if (flap < -6) flap = -6; + if (flap > 32) flap = 32; + float lean = (float) (xd * xa + zd * za) * 100; + float lean2 = (float) (xd * za - zd * xa) * 100; + if (lean < 0) lean = 0; + + //float pow = 1;//mob->oBob + (bob - mob->oBob) * a; + + flap += 1;//sin((mob->walkDistO + (mob->walkDist - mob->walkDistO) * a) * 6) * 32 * pow; + if (model->sneaking) + { + flap += 25; + } + + glRotatef(6.0f + lean / 2 + flap, 1, 0, 0); + glRotatef(lean2 / 2, 0, 0, 1); + glRotatef(-lean2 / 2, 0, 1, 0); + glRotatef(180, 0, 1, 0); + model->renderCloak(1 / 16.0f,true); + glPopMatrix(); + } + /* + float br = mob->getBrightness(a); + int overlayColor = getOverlayColor(mob, br, a); + + if (((overlayColor >> 24) & 0xff) > 0 || mob->hurtTime > 0 || mob->deathTime > 0) + { + glDisable(GL_TEXTURE_2D); + glDisable(GL_ALPHA_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_EQUAL); + + // 4J - changed these renders to not use the compiled version of their models, because otherwise the render states set + // about (in particular the depth & alpha test) don't work with our command buffer versions + if (mob->hurtTime > 0 || mob->deathTime > 0) + { + glColor4f(br, 0, 0, 0.4f); + model->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false); + for (int i = 0; i < MAX_ARMOR_LAYERS; i++) + { + if (prepareArmorOverlay(mob, i, a)) + { + glColor4f(br, 0, 0, 0.4f); + armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false); + } + } + } + + if (((overlayColor >> 24) & 0xff) > 0) + { + float r = ((overlayColor >> 16) & 0xff) / 255.0f; + float g = ((overlayColor >> 8) & 0xff) / 255.0f; + float b = ((overlayColor) & 0xff) / 255.0f; + float aa = ((overlayColor >> 24) & 0xff) / 255.0f; + glColor4f(r, g, b, aa); + model->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false); + for (int i = 0; i < MAX_ARMOR_LAYERS; i++) + { + if (prepareArmorOverlay(mob, i, a)) + { + glColor4f(r, g, b, aa); + armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false); + } + } + } + + glDepthFunc(GL_LEQUAL); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glEnable(GL_TEXTURE_2D); + } + */ + glDisable(GL_RESCALE_NORMAL); + + glEnable(GL_CULL_FACE); + + glPopMatrix(); + + MemSect(31); + //renderName(mob, x, y, z); + MemSect(0); + + // Reset the model values to stop the changes we made here affecting anything in game (like the player hand render) + model->attackTime = 0; + model->sneaking = false; + model->holdingRightHand = false; + model->holdingLeftHand = false; +} + +bool CXuiCtrlMinecraftSkinPreview::bindTexture(const wstring& urlTexture, int backupTexture) +{ + Textures *t = Minecraft::GetInstance()->textures; + + // 4J-PB - no http textures on the xbox, mem textures instead + + //int id = t->loadHttpTexture(urlTexture, backupTexture); + int id = t->loadMemTexture(urlTexture, backupTexture); + + if (id >= 0) + { + t->bind(id); + return true; + } + else + { + return false; + } +} + +bool CXuiCtrlMinecraftSkinPreview::bindTexture(const wstring& urlTexture, const wstring& backupTexture) +{ + Textures *t = Minecraft::GetInstance()->textures; + + // 4J-PB - no http textures on the xbox, mem textures instead + + //int id = t->loadHttpTexture(urlTexture, backupTexture); + int id = t->loadMemTexture(urlTexture, backupTexture); + + if (id >= 0) + { + t->bind(id); + return true; + } + else + { + return false; + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.h new file mode 100644 index 00000000..22f4991b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.h @@ -0,0 +1,106 @@ +#pragma once + +#include <string> +#include <XuiApp.h> +#include "..\..\Textures.h" +//#include "..\..\Xbox\DLC\DLCSkinFile.h" +#include "..\..\Model.h" + +using namespace std; + +class EntityRenderer; + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSkinPreview class +//----------------------------------------------------------------------------- +class CXuiCtrlMinecraftSkinPreview : public CXuiControlImpl +{ +private: + static const int LOOK_LEFT_EXTENT = 45; + static const int LOOK_RIGHT_EXTENT = -45; + + static const int CHANGING_SKIN_FRAMES = 15; + + enum ESkinPreviewAnimations + { + e_SkinPreviewAnimation_Walking, + e_SkinPreviewAnimation_Sneaking, + e_SkinPreviewAnimation_Attacking, + + e_SkinPreviewAnimation_Count, + }; +public: + enum ESkinPreviewFacing + { + e_SkinPreviewFacing_Forward, + e_SkinPreviewFacing_Left, + e_SkinPreviewFacing_Right, + }; +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlMinecraftSkinPreview, L"CXuiCtrlMinecraftSkinPreview", XUI_CLASS_LABEL) + + CXuiCtrlMinecraftSkinPreview(); + virtual ~CXuiCtrlMinecraftSkinPreview() { }; + + void SetTexture(const wstring &url, TEXTURE_NAME backupTexture = TN_MOB_CHAR); + void SetCapeTexture(const wstring &url) { m_capeTextureUrl = url; } + void ResetRotation() { m_xRot = 0; m_yRot = 0; } + void IncrementYRotation() { m_yRot = (m_yRot+4); if(m_yRot >= 180) m_yRot = -180; } + void DecrementYRotation() { m_yRot = (m_yRot-4); if(m_yRot <= -180) m_yRot = 180; } + void IncrementXRotation() { m_xRot = (m_xRot+2); if(m_xRot > 22) m_xRot = 22; } + void DecrementXRotation() { m_xRot = (m_xRot-2); if(m_xRot < -22) m_xRot = -22; } + void SetAutoRotate(bool autoRotate) { m_bAutoRotate = autoRotate; } + void SetFacing(ESkinPreviewFacing facing, bool bAnimate = false); + + void CycleNextAnimation(); + void CyclePreviousAnimation(); + + bool m_incXRot, m_decXRot; + bool m_incYRot, m_decYRot; + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + void render(EntityRenderer *renderer, double x, double y, double z, float rot, float a); + bool bindTexture(const wstring& urlTexture, int backupTexture); + bool bindTexture(const wstring& urlTexture, const wstring& backupTexture); + + BOOL m_bDirty; + float m_fScale,m_fAlpha; + + wstring m_customTextureUrl; + TEXTURE_NAME m_backupTexture; + wstring m_capeTextureUrl; + unsigned int m_uiAnimOverrideBitmask; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; + + int m_yRot,m_xRot; + + float m_bobTick; + + float m_walkAnimSpeedO; + float m_walkAnimSpeed; + float m_walkAnimPos; + + bool m_bAutoRotate, m_bRotatingLeft; + BYTE m_rotateTick; + float m_fTargetRotation, m_fOriginalRotation; + int m_framesAnimatingRotation; + bool m_bAnimatingToFacing; + + float m_swingTime; + + ESkinPreviewAnimations m_currentAnimation; + //vector<Model::SKIN_BOX *> *m_pvAdditionalBoxes; + vector<ModelPart *> *m_pvAdditionalModelParts; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.cpp new file mode 100644 index 00000000..84273eb5 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.cpp @@ -0,0 +1,356 @@ +#include "stdafx.h" + +#include "..\..\ItemRenderer.h" +#include "..\..\GameRenderer.h" +#include "..\..\TileRenderer.h" +#include "..\..\Lighting.h" +#include "..\..\ScreenSizeCalculator.h" +#include "..\..\LocalPlayer.h" +#include "..\..\..\Minecraft.World\ItemInstance.h" +#include "..\..\..\Minecraft.World\Item.h" +#include "..\..\..\Minecraft.World\Tile.h" +#include "XUI_Ctrl_MinecraftSlot.h" + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSlot class +//----------------------------------------------------------------------------- + +// The xzp path icons for the leaderboard + +LPCWSTR CXuiCtrlMinecraftSlot::xzpIcons[15]= +{ + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Skeleton.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Creeper.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_SpiderJockey.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Spider.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Zombie.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_ZombiePigman.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Swam.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Walked.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Fallen.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Portal.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Climbed.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Ghast.png", + L"Graphics\\Leaderboard\\LeaderBoard_Icon_Slime.png", + L"Graphics\\CraftIcons\\icon_structures.png", + L"Graphics\\CraftIcons\\icon_tools.png", +}; + + + +//----------------------------------------------------------------------------- +CXuiCtrlMinecraftSlot::CXuiCtrlMinecraftSlot() : + //m_hBrush(NULL), + m_bDirty(FALSE), + m_iPassThroughDataAssociation(0), + m_iPassThroughIdAssociation(0), + m_fScale(1.0f), + m_fAlpha(1.0f), + m_iID(0), + m_iCount(0), + m_iAuxVal(0), + m_bDecorations(false), + m_isFoil(false), + m_popTime(0) +{ + m_pItemRenderer = new ItemRenderer(); + m_item = nullptr; + + m_bScreenWidthSetup = false; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + if(pMinecraft != NULL) + { + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_bScreenWidthSetup = true; + } +} + +CXuiCtrlMinecraftSlot::~CXuiCtrlMinecraftSlot() +{ + delete m_pItemRenderer; +} + +VOID CXuiCtrlMinecraftSlot::SetPassThroughDataAssociation(unsigned int iID, unsigned int iData) +{ + m_item = nullptr; + m_iPassThroughIdAssociation = iID; + m_iPassThroughDataAssociation = iData; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlMinecraftSlot::OnGetSourceImage(XUIMessageGetSourceImage* pData, BOOL& rfHandled) +{ + XUIMessage Message; + CustomMessage_GetSlotItem_Struct MsgGetSlotItem; + HRESULT hr; + HXUIOBJ hObj; + + CustomMessage_GetSlotItem(&Message, &MsgGetSlotItem, m_iPassThroughIdAssociation, m_iPassThroughDataAssociation); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + + if(hr == XUI_ERR_SOURCEDATA_ITEM) + { + // Go up the parent chain one more + HXUIOBJ hParent; + hr = XuiElementGetParent(hObj,&hParent); + hr = XuiBubbleMessage(hParent, &Message); + } + + if (Message.bHandled) + { + pData->szPath = MsgGetSlotItem.szPath; + pData->bDirty = MsgGetSlotItem.bDirty; + + if(MsgGetSlotItem.item != NULL) + { + m_item = MsgGetSlotItem.item; + m_iID = m_item->id; + m_iPad = GET_SLOTDISPLAY_USERINDEX_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + m_fAlpha = ((float)GET_SLOTDISPLAY_ALPHA_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField))/31.0f; + m_bDecorations = GET_SLOTDISPLAY_DECORATIONS_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + m_fScale = ((float)GET_SLOTDISPLAY_SCALE_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField))/10.0f; + } + else + { + m_iID = GET_SLOTDISPLAY_ID_FROM_ITEM_BITMASK(MsgGetSlotItem.iItemBitField); + + // if the id is greater than or equal to 32000, then it's an xzp icon, not a game icon + if(m_iID<32000) + { + // 4J Stu - Some parent controls may overide this, others will leave it as what we passed in + + m_iPad = GET_SLOTDISPLAY_USERINDEX_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + m_fAlpha = ((float)GET_SLOTDISPLAY_ALPHA_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField))/31.0f; + m_bDecorations = GET_SLOTDISPLAY_DECORATIONS_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + m_iCount = GET_SLOTDISPLAY_COUNT_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + m_fScale = ((float)GET_SLOTDISPLAY_SCALE_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField))/10.0f; + m_popTime = GET_SLOTDISPLAY_POPTIME_FROM_DATA_BITMASK(MsgGetSlotItem.iDataBitField); + + m_iAuxVal = GET_SLOTDISPLAY_AUXVAL_FROM_ITEM_BITMASK(MsgGetSlotItem.iItemBitField); + + //m_iID = iID; + + m_isFoil = GET_SLOTDISPLAY_FOIL_FROM_ITEM_BITMASK(MsgGetSlotItem.iItemBitField); + } + else + { + pData->szPath = xzpIcons[m_iID-32000]; + } + + if(m_item != NULL && (m_item->id != m_iID || m_item->getAuxValue() != m_iAuxVal || m_item->GetCount() != m_iCount) ) m_item = nullptr; + } + + + rfHandled = TRUE; + return hr; + } + else + { + pData->szPath = L""; + } + } + + pData->bDirty = m_bDirty; + m_bDirty = FALSE; + rfHandled = TRUE; + return S_OK; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlMinecraftSlot::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + //DWORD dwPropId; + HRESULT hr=S_OK; + return hr; +} + +//----------------------------------------------------------------------------- + +HRESULT CXuiCtrlMinecraftSlot::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ + // Force an update of the id + XUIMessage Message; + XUIMessageGetSourceImage MsgGetImage; + HRESULT hr; + XuiMessageGetSourceImage(&Message, &MsgGetImage, m_iPassThroughIdAssociation, m_iPassThroughDataAssociation, FALSE); + hr = XuiSendMessage(m_hObj, &Message); + + // We cannot have an Item with id 0 + if(m_item != NULL || (m_iID > 0 && m_iID<32000) ) + { + HXUIDC hDC = pRenderData->hDC; + CXuiControl xuiControl(m_hObj); + if(m_item == NULL) m_item = shared_ptr<ItemInstance>( new ItemInstance(m_iID, m_iCount, m_iAuxVal) ); + + // build and render with the game call + + RenderManager.Set_matrixDirty(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + D3DXMATRIX matrix; + xuiControl.GetFullXForm(&matrix); + float bwidth,bheight; + xuiControl.GetBounds(&bwidth,&bheight); + + float x = matrix._41; + float y = matrix._42; + + // Base scale on height of this control, compared to height of what the item renderer normally renders (16 pixels high). Potentially + // we might want separate x & y scales here + + float scaleX = bwidth / 16.0f; + float scaleY = bheight / 16.0f; + + // apply any scale in the matrix too + scaleX *= matrix._11; + scaleY *= matrix._22; + + // Annoyingly, XUI renders everything to a z of 0 so if we want to render anything that needs the z-buffer on top of it, then we need to clear it. + // Clear just the region required for this control. + D3DRECT clearRect; + clearRect.x1 = (int)(matrix._41) - 2; + clearRect.y1 = (int)(matrix._42) - 2; + clearRect.x2 = (int)(matrix._41 + ( bwidth * matrix._11 )) + 2; + clearRect.y2 = (int)(matrix._42 + ( bheight * matrix._22 )) + 2; + + if(!m_bScreenWidthSetup) + { + Minecraft *pMinecraft=Minecraft::GetInstance(); + if(pMinecraft != NULL) + { + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_bScreenWidthSetup = true; + } + } + + RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &clearRect); + // glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_fScreenWidth, m_fScreenHeight, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + + + glEnable(GL_RESCALE_NORMAL); + glPushMatrix(); + glRotatef(120, 1, 0, 0); + Lighting::turnOn(); + glPopMatrix(); + + + + //Make sure that pMinecraft->player is the correct player so that player specific rendering + // eg clock and compass, are rendered correctly + shared_ptr<MultiplayerLocalPlayer> oldPlayer = pMinecraft->player; + + if( m_iPad >= 0 && m_iPad < XUSER_MAX_COUNT ) pMinecraft->player = pMinecraft->localplayers[m_iPad]; + + float pop = m_popTime; + if (pop > 0) + { + glPushMatrix(); + float squeeze = 1 + pop / (float) Inventory::POP_TIME_DURATION; + float sx = x; + float sy = y; + float sxoffs = 8 * scaleX; + float syoffs = 12 * scaleY; + glTranslatef((float)(sx + sxoffs), (float)(sy + syoffs), 0); + glScalef(1 / squeeze, (squeeze + 1) / 2, 1); + glTranslatef((float)-(sx + sxoffs), (float)-(sy + syoffs), 0); + } + + m_pItemRenderer->renderAndDecorateItem(pMinecraft->font, pMinecraft->textures, m_item, x, y,scaleX,scaleY,m_fAlpha,m_isFoil,false); + + if (pop > 0) + { + glPopMatrix(); + } + + if(m_bDecorations) + { + if((scaleX!=1.0f) ||(scaleY!=1.0f)) + { + glPushMatrix(); + glScalef(scaleX, scaleY, 1.0f); + int iX= (int)(0.5f+((float)x)/scaleX); + int iY= (int)(0.5f+((float)y)/scaleY); + + m_pItemRenderer->renderGuiItemDecorations(pMinecraft->font, pMinecraft->textures, m_item, iX, iY, m_fAlpha); + glPopMatrix(); + } + else + { + m_pItemRenderer->renderGuiItemDecorations(pMinecraft->font, pMinecraft->textures, m_item, (int)x, (int)y, m_fAlpha); + } + } + + pMinecraft->player = oldPlayer; + + Lighting::turnOff(); + glDisable(GL_RESCALE_NORMAL); + + XuiRenderRestoreState(hDC); + + bHandled = TRUE; + } + return S_OK; +} + + +void CXuiCtrlMinecraftSlot::SetIcon(int iPad, int iId,int iAuxVal, int iCount, int iScale, unsigned int uiAlpha,bool bDecorations,BOOL bShow, bool isFoil) +{ + m_item = nullptr; + m_iID=iId; + m_iAuxVal=iAuxVal; + + // aux value for diggers can go as high as 1561 + //const _Tier *_Tier::DIAMOND = new _Tier(3, 1561, 8, 3); // + // setMaxDamage(tier->getUses()); + + // int ItemInstance::getDamageValue() + // { + // return auxValue; + // } + + + if( (m_iAuxVal & 0xFF) == 0xFF) // 4J Stu - If the aux value is set to match any + m_iAuxVal = 0; + + m_iCount=iCount; + m_fScale = (float)(iScale)/10.0f; + //m_uiAlpha=uiAlpha; + m_fAlpha =((float)(uiAlpha)) / 255.0f; + m_bDecorations = bDecorations; + // mif(bDecorations) m_iDecorations=1; + // else m_iDecorations=0; + + m_iPad = iPad; + + m_isFoil = isFoil; + + XuiElementSetShow(m_hObj,bShow); +} + +void CXuiCtrlMinecraftSlot::SetIcon(int iPad, shared_ptr<ItemInstance> item, int iScale, unsigned int uiAlpha,bool bDecorations, BOOL bShow) +{ + m_item = item; + m_isFoil = item->isFoil(); + m_iPad = iPad; + m_fScale = (float)(iScale)/10.0f; + m_fAlpha =((float)(uiAlpha)) / 31; + m_bDecorations = bDecorations; + m_bDirty = TRUE; + XuiElementSetShow(m_hObj,bShow); +} diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.h new file mode 100644 index 00000000..5dafec53 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.h @@ -0,0 +1,59 @@ +#pragma once + +#include <string> +#include <XuiApp.h> + +using namespace std; + +class TileRenderer; +class ItemRenderer; + +//----------------------------------------------------------------------------- +// CXuiCtrlMinecraftSlot class +//----------------------------------------------------------------------------- +class CXuiCtrlMinecraftSlot : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlMinecraftSlot, L"CXuiCtrlMinecraftSlot", XUI_CLASS_LABEL) + + VOID SetPassThroughDataAssociation(unsigned int iID, unsigned int iData); + CXuiCtrlMinecraftSlot(); + virtual ~CXuiCtrlMinecraftSlot(); + + void renderGuiItem(Font *font, Textures *textures,ItemInstance *item, int x, int y); + void RenderItem(); + void SetIcon(int iPad, int iId,int iAuxVal, int iCount, int iScale, unsigned int uiAlpha,bool bDecorations,BOOL bShow, bool isFoil); + void SetIcon(int iPad, shared_ptr<ItemInstance> item, int iScale, unsigned int uiAlpha,bool bDecorations, BOOL bShow=TRUE); + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceImage) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnGetSourceImage(XUIMessageGetSourceImage* pData, BOOL& rfHandled); + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + shared_ptr<ItemInstance> m_item; + BOOL m_bDirty; + INT m_iPassThroughDataAssociation; + INT m_iPassThroughIdAssociation; + float m_fScale,m_fAlpha; + int m_iPad; + int m_iID; + int m_iCount; + int m_iAuxVal; + bool m_bDecorations; + bool m_isFoil; + int m_popTime; + + bool m_bScreenWidthSetup; + float m_fScreenWidth,m_fScreenHeight; + ItemRenderer *m_pItemRenderer; + + static LPCWSTR xzpIcons[15]; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.cpp new file mode 100644 index 00000000..23b22573 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "XUI_Ctrl_MobEffect.h" + +LPCWSTR CXuiCtrlMobEffect::iconFrameNames[MobEffect::e_MobEffectIcon_COUNT]= +{ + L"Normal", + L"Blindness", + L"Fire_Resistance", + L"Haste", + L"Hunger", + L"Invisibility", + L"Jump_Boost", + L"Mining_Fatigue", + L"Nausea", + L"Night_Vision", + L"Poison", + L"Regeneration", + L"Resistance", + L"Slowness", + L"Speed", + L"Strength", + L"Water_Breathing", + L"Weakness", +}; + +HRESULT CXuiCtrlMobEffect::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + m_icon = MobEffect::e_MobEffectIcon_None; + m_name = L""; + m_duration = L""; + return S_OK; +} + +HRESULT CXuiCtrlMobEffect::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + if( pGetSourceTextData->iData == 1 ) + { + pGetSourceTextData->szText = m_name.c_str(); + pGetSourceTextData->bDisplay = TRUE; + + if(FAILED(PlayVisualRange(iconFrameNames[m_icon],NULL,iconFrameNames[m_icon]))) + { + PlayVisualRange(L"Normal",NULL,L"Normal"); + } + + bHandled = TRUE; + } + else if( pGetSourceTextData->iData == 2 ) + { + pGetSourceTextData->szText = m_duration.c_str(); + pGetSourceTextData->bDisplay = TRUE; + + bHandled = TRUE; + } + return S_OK; +} + +void CXuiCtrlMobEffect::setIcon(MobEffect::EMobEffectIcon icon) +{ + m_icon = icon; +} + +void CXuiCtrlMobEffect::setName(const wstring &name) +{ + m_name = name; +} + +void CXuiCtrlMobEffect::setDuration(const wstring &duration) +{ + m_duration = duration; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.h new file mode 100644 index 00000000..c43e7fe9 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.h @@ -0,0 +1,31 @@ +#pragma once +using namespace std; + +#include "..\..\..\Minecraft.World\MobEffect.h" + +class CXuiCtrlMobEffect : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlMobEffect, L"CXuiCtrlMobEffect", XUI_CLASS_CONTROL) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + +public: + void setIcon(MobEffect::EMobEffectIcon icon); + void setName(const wstring &name); + void setDuration(const wstring &duration); + +private: + MobEffect::EMobEffectIcon m_icon; + wstring m_name; + wstring m_duration; + + static LPCWSTR iconFrameNames[MobEffect::e_MobEffectIcon_COUNT]; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_PassThroughList.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_PassThroughList.cpp new file mode 100644 index 00000000..d00762b8 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_PassThroughList.cpp @@ -0,0 +1,109 @@ +#include "stdafx.h" +#include "XUI_Ctrl_PassThroughList.h" + +HRESULT CXuiCtrlPassThroughList::OnInit(XUIMessageInit *pInitData, BOOL& bHandled) +{ + return S_OK; +} + +HRESULT CXuiCtrlPassThroughList::OnKeyDown(XUIMessageInput* pInputData, BOOL& bHandled) +{ + XUIMessage message; + XUIMessageInput messageInput; + HRESULT hr; + HXUIOBJ hObj; + + XuiMessageInput( &message, &messageInput, XUI_KEYDOWN, pInputData->dwKeyCode, pInputData->wch, pInputData->dwFlags, pInputData->UserIndex ); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &message); + + if (message.bHandled) + { + bHandled = TRUE; + } + } + + return S_OK; +} + +// Gets called every frame +HRESULT CXuiCtrlPassThroughList::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled) +{ + XUIMessage Message; + XUIMessageGetSourceText MsgGetText; + HRESULT hr; + HXUIOBJ hObj; + + + XuiMessageGetSourceText(&Message, &MsgGetText, pGetSourceTextData->iItem, pGetSourceTextData->iData, pGetSourceTextData->bItemData); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + + if (Message.bHandled) + { + pGetSourceTextData->szText = MsgGetText.szText; + bHandled = TRUE; + } + } + return S_OK; +} + +// Gets called every frame +HRESULT CXuiCtrlPassThroughList::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + XUIMessage Message; + XUIMessageGetSourceImage MsgGetImage; + HRESULT hr; + HXUIOBJ hObj; + + + XuiMessageGetSourceImage(&Message, &MsgGetImage, pGetSourceImageData->iItem, pGetSourceImageData->iData, pGetSourceImageData->bItemData); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + + if (Message.bHandled) + { + pGetSourceImageData->szPath = MsgGetImage.szPath; + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CXuiCtrlPassThroughList::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData,BOOL& bHandled) +{ + XUIMessage Message; + XUIMessageGetItemCount MsgGetItemCountAll; + HRESULT hr; + HXUIOBJ hObj; + + + XuiMessageGetItemCount(&Message, &MsgGetItemCountAll, XUI_ITEMCOUNT_ALL); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + + if (Message.bHandled) + { + pGetItemCountData->cItems = MsgGetItemCountAll.cItems; + bHandled = TRUE; + } + } + bHandled = TRUE; + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_PassthroughList.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_PassthroughList.h new file mode 100644 index 00000000..9e2c1bdf --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_PassthroughList.h @@ -0,0 +1,28 @@ +#pragma once + +// 4J Stu - A list control that responds by sending the message to it's parent and +// returning what the parent returns + +class CXuiCtrlPassThroughList : public CXuiListImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlPassThroughList, L"CXuiCtrlPassThroughList", XUI_CLASS_LIST); +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_END_MSG_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& bHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.cpp new file mode 100644 index 00000000..6d1c4ce7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.cpp @@ -0,0 +1,22 @@ +#include "stdafx.h" + +#include "XUI_Ctrl_ProgressCtrlBase.h" + +HRESULT CXuiCtrlProgressCtrlBase::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + // The Xui backend calls GetSourceDataText every frame to get the text for the indexed label + // We don't want to change the label, but take this opportunity to send out a message to ourself + // to update the value of the progress bar + this->SetValue( GetValue() ); + + int min, max; + this->GetRange( &min, &max ); + this->SetRange( min, max ); + + pGetSourceTextData->szText = L""; + pGetSourceTextData->bDisplay = FALSE; + + bHandled = TRUE; + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.h new file mode 100644 index 00000000..7a4302d3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.h @@ -0,0 +1,11 @@ +#pragma once + +class CXuiCtrlProgressCtrlBase : public CXuiProgressBar, public CXuiElementImplBase +{ +public: + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + + // Override these in the derived classes to return the values to be displayed on the control + virtual int GetValue() = 0; + virtual void GetRange(int *pnRangeMin, int *pnRangeMax) = 0; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.cpp new file mode 100644 index 00000000..a4e9f6be --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.cpp @@ -0,0 +1,174 @@ +#include "stdafx.h" +#include "XUI_Ctrl_SliderWrapper.h" + +#define NO_SOUND_TIMER 0 + +HRESULT CXuiCtrlSliderWrapper::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + VOID *pObj; + HXUIOBJ hObjChild; + + XuiElementGetChildById(m_hObj,L"FocusSink",&hObjChild); + XuiObjectFromHandle( hObjChild, &pObj ); + m_pFocusSink = (CXuiControl *)pObj; + + XuiElementGetChildById(m_hObj,L"XuiSlider",&hObjChild); + XuiObjectFromHandle( hObjChild, &pObj ); + m_pSlider = (CXuiSlider *)pObj; + + m_sliderActive = false; + m_bDisplayVal=true; + m_bPlaySound=false; // make this false to avoid a sound being played in the first setting of the slider value in a scene + XuiSetTimer( m_hObj,NO_SOUND_TIMER,50); + bHandled = TRUE; + return S_OK; +} + +HRESULT CXuiCtrlSliderWrapper::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + +// switch(pInputData->dwKeyCode) +// { + +// case VK_PAD_A: +// // 4J-PB - IGNORE ! +// if(m_sliderActive) +// { +// m_pFocusSink->SetFocus(pInputData->UserIndex); +// m_sliderActive = false; +// } +// else +// { +// m_pSlider->SetFocus(pInputData->UserIndex); +// m_sliderActive = true; +// } +// rfHandled = TRUE; +// +// break; +// default: +// m_pSlider->SetFocus(pInputData->UserIndex); +// m_sliderActive = false; +// break; +// +// } +// + return S_OK; +} + +HRESULT CXuiCtrlSliderWrapper::OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) +{ + XUIMessage Message; + XUINotify Notify; + XUINotifyValueChanged MsgValueChanged; + HRESULT hr; + HXUIOBJ hObj; + + if(m_bPlaySound) + { + m_bPlaySound=false; + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + XuiSetTimer( m_hObj,NO_SOUND_TIMER,150); + } + + //app.DebugPrintf("Slider val changed - %d\n",pValueChangedData->nValue); + + XuiNotifyValueChanged(&Message,&Notify,&MsgValueChanged,hObjSource,pValueChangedData->nValue); + + hr = GetParent(&hObj); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(hObj, &Message); + rfHandled = TRUE; + } + return S_OK; +} + + +HRESULT CXuiCtrlSliderWrapper::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==NO_SOUND_TIMER) + { + XuiKillTimer(m_hObj,NO_SOUND_TIMER); + m_bPlaySound=true; + } + + return S_OK; +} + +HRESULT CXuiCtrlSliderWrapper::SetValue( int nValue ) +{ + CXuiCtrlSliderWrapper *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + pThis->m_pSlider->SetValue(nValue); + return S_OK; +} + +HRESULT CXuiCtrlSliderWrapper::SetValueDisplay( BOOL bShow ) +{ + CXuiCtrlSliderWrapper *pThis; + HXUIOBJ hVisual,hText; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + hr=XuiControlGetVisual(pThis->m_pSlider->m_hObj,&hVisual); + hr=XuiElementGetChildById(hVisual,L"Text_Value",&hText); + + if(hText!=NULL) + { + XuiElementSetShow(hText,bShow); + } + + return S_OK; +} + +LPCWSTR CXuiCtrlSliderWrapper::GetText( ) +{ + CXuiCtrlSliderWrapper *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return NULL; + return pThis->m_pSlider->GetText(); + //return S_OK; +} + +HRESULT CXuiCtrlSliderWrapper::SetText(LPCWSTR text , int iDataAssoc) +{ + CXuiCtrlSliderWrapper *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + // if there's a data assoc value, find the right control for it + if(iDataAssoc!=0) + { + + } + + pThis->m_pSlider->SetText(text); + return hr; +} + +HXUIOBJ CXuiCtrlSliderWrapper::GetSlider() +{ + CXuiCtrlSliderWrapper *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return NULL; + return pThis->m_pSlider->m_hObj; +} + +HRESULT CXuiCtrlSliderWrapper::SetRange( int nRangeMin, int nRangeMax) +{ + CXuiCtrlSliderWrapper *pThis; + HRESULT hr = XuiObjectFromHandle(m_hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + pThis->m_pSlider->SetRange(nRangeMin, nRangeMax); + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.h new file mode 100644 index 00000000..03659fca --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.h @@ -0,0 +1,38 @@ +#pragma once + +class CXuiCtrlSliderWrapper : public CXuiSceneImpl +{ +private: + CXuiSlider *m_pSlider; + CXuiControl *m_pFocusSink; + bool m_sliderActive; + bool m_bDisplayVal; + bool m_bPlaySound; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_END_MSG_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlSliderWrapper, L"CXuiCtrlSliderWrapper", XUI_CLASS_SCENE ) + + HRESULT SetValue( int nValue ); + HXUIOBJ GetSlider(); + HRESULT SetRange( int nRangeMin, int nRangeMax); + LPCWSTR GetText( ); + HRESULT SetText(LPCWSTR text, int iDataAssoc=0 ); + HRESULT SetValueDisplay( BOOL bShow ); + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItem.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItem.h new file mode 100644 index 00000000..1fad4a34 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItem.h @@ -0,0 +1,37 @@ +#pragma once +#include "XUI_Ctrl_SlotItemCtrlBase.h" + +class CXuiCtrlSlotItem : public CXuiControlImpl, public CXuiCtrlSlotItemCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlSlotItem, L"CXuiCtrlSlotItem", XUI_CLASS_CONTROL ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_GETSLOTITEM_MESSAGE(OnCustomMessage_GetSlotItem) + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_END_MSG_MAP() + + using CXuiCtrlSlotItemCtrlBase::OnInit; + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& bHandled) { return this->OnInit( m_hObj, pInitData, bHandled ); }; + + using CXuiCtrlSlotItemCtrlBase::OnDestroy; + HRESULT OnDestroy() { return this->OnDestroy( m_hObj ); }; + + using CXuiCtrlSlotItemCtrlBase::OnCustomMessage_GetSlotItem; + HRESULT OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) { return this->OnCustomMessage_GetSlotItem( m_hObj, pData, bHandled ); }; + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + using CXuiCtrlSlotItemCtrlBase::OnControlNavigate; + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) { return this->OnControlNavigate( m_hObj, pControlNavigateData, bHandled ); }; + + using CXuiCtrlSlotItemCtrlBase::OnKeyDown; + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) { return this->OnKeyDown( m_hObj, pInputData, bHandled ); }; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.cpp new file mode 100644 index 00000000..87abbcd3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.cpp @@ -0,0 +1,392 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Slot.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\Minecraft.h" + +#include "XUI_Ctrl_SlotItemCtrlBase.h" + +HRESULT CXuiCtrlSlotItemCtrlBase::OnInit( HXUIOBJ hObj, XUIMessageInit* pInitData, BOOL& bHandled ) +{ + HRESULT hr = S_OK; + SlotControlUserDataContainer* pvUserData = new SlotControlUserDataContainer(); + hr = XuiElementSetUserData(hObj, (void *)pvUserData ); + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + m_bSkipDefaultNavigation = false; + + return hr; +} + +HRESULT CXuiCtrlSlotItemCtrlBase::OnDestroy( HXUIOBJ hObj ) +{ + HRESULT hr = S_OK; + void* pvUserData; + hr = XuiElementGetUserData( hObj, &pvUserData ); + + if( pvUserData != NULL ) + { + delete pvUserData; + } + + return hr; +} + +HRESULT CXuiCtrlSlotItemCtrlBase::OnCustomMessage_GetSlotItem(HXUIOBJ hObj, CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) +{ + shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>(); + + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + if( pUserDataContainer->slot != NULL ) + { + item = pUserDataContainer->slot->getItem(); + } + else if(pUserDataContainer->m_iPad >= 0 && pUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad] ); + if(player != NULL) item = player->inventory->getCarried(); + } + + if( item != NULL ) + { + pData->item = item; + pData->iItemBitField = MAKE_SLOTDISPLAY_ITEM_BITMASK(item->id,item->getAuxValue(),item->isFoil()); + //int iAuxVal=item->getAuxValue(); + //int iCount = item->GetCount(); + // 8 bits - alpha + // 1 bit - decorations on + // 11 bits - auxval + // 6 bits - count + // 6 bits - scale + pData->iDataBitField = MAKE_SLOTDISPLAY_DATA_BITMASK(pUserDataContainer->m_iPad, (int)(31*pUserDataContainer->m_fAlpha),true,item->GetCount(),7,item->popTime); + } + else + { + //pGetSourceImageData->iData = 0; + pData->szPath = L""; + } + + bHandled = TRUE; + + return S_OK; +} + +void CXuiCtrlSlotItemCtrlBase::SetSlot( HXUIOBJ hObj, Slot* slot ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + pUserDataContainer->slot = slot; +} + +void CXuiCtrlSlotItemCtrlBase::SetUserIndex( HXUIOBJ hObj, int iPad ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + pUserDataContainer->m_iPad = iPad; +} + +void CXuiCtrlSlotItemCtrlBase::SetAlpha( HXUIOBJ hObj, float fAlpha ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + pUserDataContainer->m_fAlpha = fAlpha; +} + +bool CXuiCtrlSlotItemCtrlBase::isEmpty( HXUIOBJ hObj ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + if(pUserDataContainer->slot != NULL) + { + return !pUserDataContainer->slot->hasItem(); + } + else if(pUserDataContainer->m_iPad >= 0 && pUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad] ); + if(player != NULL) return player->inventory->getCarried() == NULL; + + } + return true; +} + +wstring CXuiCtrlSlotItemCtrlBase::GetItemDescription( HXUIOBJ hObj, vector<wstring> &unformattedStrings ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + if(pUserDataContainer->slot != NULL) + { + wstring desc = L""; + vector<wstring> *strings = pUserDataContainer->slot->getItem()->getHoverText(Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad], false, unformattedStrings); + bool firstLine = true; + for(AUTO_VAR(it, strings->begin()); it != strings->end(); ++it) + { + wstring thisString = *it; + if(!firstLine) + { + desc.append( L"<br />" ); + } + else + { + firstLine = false; + wchar_t formatted[256]; + eMinecraftColour rarityColour = pUserDataContainer->slot->getItem()->getRarity()->color; + int colour = app.GetHTMLColour(rarityColour); + + if(pUserDataContainer->slot->getItem()->hasCustomHoverName()) + { + colour = app.GetHTMLColour(eTextColor_RenamedItemTitle); + } + + swprintf(formatted, 256, L"<font color=\"#%08x\">%s</font>",colour,thisString.c_str()); + thisString = formatted; + } + desc.append( thisString ); + } + strings->clear(); + delete strings; + return desc;//app.GetString( pUserDataContainer->slot->getItem()->getDescriptionId() ); + } + else if(pUserDataContainer->m_iPad >= 0 && pUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad] ); + if(player != NULL) + { + shared_ptr<ItemInstance> item = player->inventory->getCarried(); + if(item != NULL) return app.GetString( item->getDescriptionId() ); + } + + } + return L""; +} + +shared_ptr<ItemInstance> CXuiCtrlSlotItemCtrlBase::getItemInstance( HXUIOBJ hObj ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + if(pUserDataContainer->slot != NULL) + { + return pUserDataContainer->slot->getItem(); + } + else if(pUserDataContainer->m_iPad >= 0 && pUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad] ); + if(player != NULL) return player->inventory->getCarried(); + + } + return nullptr; +} + +Slot *CXuiCtrlSlotItemCtrlBase::getSlot( HXUIOBJ hObj ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + return pUserDataContainer->slot; +} + +HRESULT CXuiCtrlSlotItemCtrlBase::OnKeyDown(HXUIOBJ hObj, XUIMessageInput *pInputData, BOOL& bHandled) +{ + if( pInputData->dwKeyCode == VK_PAD_DPAD_LEFT || + pInputData->dwKeyCode == VK_PAD_DPAD_RIGHT || + pInputData->dwKeyCode == VK_PAD_DPAD_UP || + pInputData->dwKeyCode == VK_PAD_DPAD_DOWN || + pInputData->dwKeyCode == VK_PAD_LTRIGGER || + pInputData->dwKeyCode == VK_PAD_RTRIGGER) + { + HXUIOBJ parent; + HRESULT hr; + hr = XuiElementGetParent( hObj, &parent ); + + XUIMessage message; + XUIMessageInput messageInput; + + XuiMessageInput( &message, &messageInput, XUI_KEYDOWN, pInputData->dwKeyCode, pInputData->wch, pInputData->dwFlags, pInputData->UserIndex ); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(parent, &message); + + if (message.bHandled) + { + bHandled = TRUE; + } + } + } + + return S_OK; +} + +// 4J WESTY : Pointer Prototype : Added to support prototype only. +HRESULT CXuiCtrlSlotItemCtrlBase::OnControlNavigate( HXUIOBJ hObj, XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // Skip default navigation behaviour when navigation is by pointer. + if ( m_bSkipDefaultNavigation ) + { + pControlNavigateData->bSkipNavigate = TRUE; + bHandled = TRUE; + } + return S_OK; +} + +// 4J WESTY : Pointer Prototype : Added to support prototype only. +int CXuiCtrlSlotItemCtrlBase::GetObjectCount( HXUIOBJ hObj ) +{ + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + int iCount = 0; + + if(pUserDataContainer->slot != NULL) + { + if ( pUserDataContainer->slot->hasItem() ) + { + iCount = pUserDataContainer->slot->getItem()->GetCount(); + } + } + else if(pUserDataContainer->m_iPad >= 0 && pUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pUserDataContainer->m_iPad] ); + if(player != NULL && player->inventory->getCarried() != NULL) + { + iCount = player->inventory->getCarried()->count; + } + + } + return iCount; +} + + +// 4J WESTY : Pointer Prototype : Added to support prototype only. +bool CXuiCtrlSlotItemCtrlBase::IsSameItemAs( HXUIOBJ hThisObj, HXUIOBJ hOtherObj ) +{ + bool bThisItemExists = false; + int iThisID = 0; + int iThisAux = 0; + + bool bOtherItemExists = false; + int iOtherID = 0; + int iOtherAux = 0; + + bool bStackedByData = false; + + // Get the info on this item. + void* pvThisUserData; + XuiElementGetUserData( hThisObj, &pvThisUserData ); + SlotControlUserDataContainer* pThisUserDataContainer = (SlotControlUserDataContainer*)pvThisUserData; + + if(pThisUserDataContainer->slot != NULL) + { + if ( pThisUserDataContainer->slot->hasItem() ) + { + iThisID = pThisUserDataContainer->slot->getItem()->id; + iThisAux = pThisUserDataContainer->slot->getItem()->getAuxValue(); + bThisItemExists = true; + bStackedByData = pThisUserDataContainer->slot->getItem()->isStackedByData(); + } + } + else if(pThisUserDataContainer->m_iPad >= 0 && pThisUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pThisUserDataContainer->m_iPad] ); + if(player != NULL && player->inventory->getCarried() != NULL) + { + iThisID = player->inventory->getCarried()->id; + iThisAux = player->inventory->getCarried()->getAuxValue(); + bThisItemExists = true; + bStackedByData = player->inventory->getCarried()->isStackedByData(); + } + + } + + // Get the info on other item. + void* pvOtherUserData; + XuiElementGetUserData( hOtherObj, &pvOtherUserData ); + SlotControlUserDataContainer* pOtherUserDataContainer = (SlotControlUserDataContainer*)pvOtherUserData; + + if(pOtherUserDataContainer->slot != NULL) + { + if ( pOtherUserDataContainer->slot->hasItem() ) + { + iOtherID = pOtherUserDataContainer->slot->getItem()->id; + iOtherAux = pOtherUserDataContainer->slot->getItem()->getAuxValue(); + bOtherItemExists = true; + } + } + else if(pOtherUserDataContainer->m_iPad >= 0 && pOtherUserDataContainer->m_iPad < XUSER_MAX_COUNT) + { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( Minecraft::GetInstance()->localplayers[pOtherUserDataContainer->m_iPad] ); + if(player != NULL && player->inventory->getCarried() != NULL) + { + iOtherID = player->inventory->getCarried()->id; + iOtherAux = player->inventory->getCarried()->getAuxValue(); + bOtherItemExists = true; + } + + } + + if ( bThisItemExists && bOtherItemExists ) + { + return ( ( iThisID == iOtherID ) && ( (bStackedByData && iThisAux == iOtherAux) || !bStackedByData ) ); + } + else + { + return false; + } +} + +// 4J WESTY : Pointer Prototype : Added to support prototype only. +// Returns number of items that can still be stacked into this slot. +int CXuiCtrlSlotItemCtrlBase::GetEmptyStackSpace( HXUIOBJ hObj ) +{ + int iResult = 0; + + void* pvUserData; + XuiElementGetUserData( hObj, &pvUserData ); + SlotControlUserDataContainer* pUserDataContainer = (SlotControlUserDataContainer*)pvUserData; + + int iCount = 0; + int iMaxStackSize = 0; + bool bStackable = false; + + if(pUserDataContainer->slot != NULL) + { + if ( pUserDataContainer->slot->hasItem() ) + { + bStackable = pUserDataContainer->slot->getItem()->isStackable(); + if ( bStackable ) + { + iCount = pUserDataContainer->slot->getItem()->GetCount(); + iMaxStackSize = min(pUserDataContainer->slot->getItem()->getMaxStackSize(), pUserDataContainer->slot->getMaxStackSize() ); + + iResult = iMaxStackSize - iCount; + + if(iResult < 0 ) iResult = 0; + } + } + } + + return iResult; +} + diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.h new file mode 100644 index 00000000..2fd21749 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.h @@ -0,0 +1,78 @@ +#pragma once +using namespace std; + +class Slot; +class ItemInstance; + +#include "XUI_CustomMessages.h" + +class SlotControlUserDataContainer +{ +public: + SlotControlUserDataContainer() : slot( NULL ), hProgressBar( NULL ), m_iPad( -1 ), m_fAlpha(1.0f) {}; + Slot* slot; + HXUIOBJ hProgressBar; + float m_fAlpha; + int m_iPad; +}; + +// The base class for all controls with the "ItemButton" visual +// This could be a list item or just a button. +// We need this class to be able to easily access all the parts of the visual + +class CXuiCtrlSlotItemCtrlBase +{ +private: + // 4J WESTY : Pointer Prototype : Added to support prototype only. + BOOL m_bSkipDefaultNavigation; + +public: + // We define a lot of functions as virtual. These should be implemented to call the protected version by + // passing in the HXUIOBJ of the control as the first parameter. We do not have access to that normally + // due to the inheritance structure + virtual HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) = 0; + + virtual HRESULT OnDestroy() = 0; + + virtual HRESULT OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) = 0; + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + virtual HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) = 0; + + virtual HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) = 0; + + void SetSlot( HXUIOBJ hObj, Slot* slot ); + void SetAlpha( HXUIOBJ hObj, float fAlpha ); + void SetUserIndex( HXUIOBJ hObj, int iPad ); + + bool isEmpty( HXUIOBJ hObj ); + + wstring GetItemDescription( HXUIOBJ hObj, vector<wstring> &unformattedStrings ); + + shared_ptr<ItemInstance> getItemInstance( HXUIOBJ hObj ); + Slot *getSlot( HXUIOBJ hObj ); + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + int GetObjectCount( HXUIOBJ hObj ); + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + void SetSkipsDefaultNavigation( BOOL bSkipDefaultNavigation ) { m_bSkipDefaultNavigation = bSkipDefaultNavigation; } + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + int GetEmptyStackSpace( HXUIOBJ hObj ); // Returns number of items that can still be stacked into this slot. + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + bool IsSameItemAs( HXUIOBJ hThisObj, HXUIOBJ hOtherObj ); + +protected: + HRESULT OnInit( HXUIOBJ hObj, XUIMessageInit* pInitData, BOOL& bHandled ); + + HRESULT OnDestroy( HXUIOBJ hObj ); + + HRESULT OnCustomMessage_GetSlotItem(HXUIOBJ hObj, CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled); + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + HRESULT OnControlNavigate(HXUIOBJ hObj, XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + + HRESULT OnKeyDown(HXUIOBJ hObj, XUIMessageInput *pInputData, BOOL& bHandled); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemListItem.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemListItem.h new file mode 100644 index 00000000..bee1b93f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemListItem.h @@ -0,0 +1,38 @@ +#pragma once + +#include "XUI_Ctrl_SlotItemCtrlBase.h" + +class CXuiCtrlSlotItemListItem : public CXuiListItemImpl, public CXuiCtrlSlotItemCtrlBase +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlSlotItemListItem, L"CXuiCtrlSlotItemListItem", XUI_CLASS_LISTITEM ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_GETSLOTITEM_MESSAGE(OnCustomMessage_GetSlotItem) + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_END_MSG_MAP() + + using CXuiCtrlSlotItemCtrlBase::OnInit; + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& bHandled) { return this->OnInit( m_hObj, pInitData, bHandled ); }; + + using CXuiCtrlSlotItemCtrlBase::OnDestroy; + HRESULT OnDestroy() { return this->OnDestroy( m_hObj ); }; + + using CXuiCtrlSlotItemCtrlBase::OnCustomMessage_GetSlotItem; + HRESULT OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) { return this->OnCustomMessage_GetSlotItem( m_hObj, pData, bHandled ); }; + + // 4J WESTY : Pointer Prototype : Added to support prototype only. + using CXuiCtrlSlotItemCtrlBase::OnControlNavigate; + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) { return this->OnControlNavigate( m_hObj, pControlNavigateData, bHandled ); } + + using CXuiCtrlSlotItemCtrlBase::OnKeyDown; + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) { return this->OnKeyDown( m_hObj, pInputData, bHandled ); }; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.cpp new file mode 100644 index 00000000..7e51c885 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.cpp @@ -0,0 +1,231 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\AbstractContainerMenu.h" + +#include "XUI_Ctrl_SlotItemListItem.h" +#include "XUI_Ctrl_SlotList.h" + + +//-------------------------------------------------------------------------------------- +// Name: CXuiCtrlSlotList::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiCtrlSlotList::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + slotCount = 0; + + return S_OK; +} + +HRESULT CXuiCtrlSlotList::OnDestroy() +{ + return S_OK; +} + +HRESULT CXuiCtrlSlotList::OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) +{ + if( pInputData->dwKeyCode == VK_PAD_DPAD_LEFT || + pInputData->dwKeyCode == VK_PAD_DPAD_RIGHT || + pInputData->dwKeyCode == VK_PAD_DPAD_UP || + pInputData->dwKeyCode == VK_PAD_DPAD_DOWN || + pInputData->dwKeyCode == VK_PAD_LTRIGGER || + pInputData->dwKeyCode == VK_PAD_RTRIGGER) + { + HXUIOBJ parent; + HRESULT hr; + hr = XuiElementGetParent( m_hObj, &parent ); + + XUIMessage message; + XUIMessageInput messageInput; + + XuiMessageInput( &message, &messageInput, XUI_KEYDOWN, pInputData->dwKeyCode, pInputData->wch, pInputData->dwFlags, pInputData->UserIndex ); + + if (HRESULT_SUCCEEDED(hr)) + { + hr = XuiBubbleMessage(parent, &message); + + if (message.bHandled) + { + bHandled = TRUE; + } + } + } + + return S_OK; +} + +void CXuiCtrlSlotList::SetData(int m_iPad, AbstractContainerMenu* menu, int rows, int columns, int startIndex /*= 0*/, int endIndex /*= 0*/) +{ + assert( startIndex >= 0 && startIndex < menu->getSize() ); + assert( endIndex <= menu->getSize() ); + + if( startIndex < 0 ) + { + startIndex = 0; + } + else if( startIndex > menu->getSize() ) + { + startIndex = menu->getSize(); + } + + if( endIndex == 0 ) + { + endIndex = startIndex + (rows * columns); + } + + if( endIndex > menu->getSize() ) + { + endIndex = menu->getSize(); + } + + if( startIndex > endIndex ) + { + endIndex = startIndex; + } + + assert( (rows * columns) == (endIndex - startIndex) ); + + this->rows = rows; + this->columns = columns; + + this->startIndex = startIndex; + + this->slotCount = rows * columns; + + InsertItems( 0, slotCount ); + + for(int i = 0; i < slotCount; i++) + { + CXuiCtrlSlotItemListItem* slotControl; + GetCXuiCtrlSlotItem(i, &slotControl); + + slotControl->SetSlot( slotControl->m_hObj, menu->getSlot( i + startIndex ) ); + + slotControl->SetUserIndex( slotControl->m_hObj, m_iPad ); + + slotControl = NULL; + } +} + +HRESULT CXuiCtrlSlotList::OnGetItemCountAll( XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled ) +{ + // We don't need to look at the type of request. The message map + // has already filtered out a request to retrieve all items. + pGetItemCountData->cItems = slotCount; + bHandled = TRUE; + + return( S_OK ); +} + +HRESULT CXuiCtrlSlotList::OnGetItemCountMaxLines( XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled ) +{ + // We don't need to look at the type of request. The message map + // has already filtered out a request to retrieve max lines. + pGetItemCountData->cItems = rows; + bHandled = TRUE; + + return( S_OK ); +} + +HRESULT CXuiCtrlSlotList::OnGetItemCountMaxPerLine( XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled ) +{ + // We don't need to look at the type of request. The message map + // has already filtered out a request to retrieve max per line. + pGetItemCountData->cItems = columns; + bHandled = TRUE; + + return( S_OK ); +} + +int CXuiCtrlSlotList::GetCurrentColumn() +{ + int currentItemIndex = GetCurSel(); + + return currentItemIndex % columns; +} + +int CXuiCtrlSlotList::GetCurrentRow() +{ + int currentItemIndex = GetCurSel(); + + return (currentItemIndex/columns) % rows; +} + +// Return the index in the menu object +int CXuiCtrlSlotList::GetCurrentIndex() +{ + int currentSelected = GetCurSel(); + return currentSelected + this->startIndex; +} + +void CXuiCtrlSlotList::SetCurrentSlot(int row, int column) +{ + if( row >= rows ) + { + row = rows - 1; + } + else if ( row < 0 ) + { + row = 0; + } + if( column >= columns ) + { + column = columns - 1; + } + else if ( column < 0 ) + { + column = 0; + } + int newSlot = ( row * columns ) + column; + SetCurSel( newSlot ); +} + +void CXuiCtrlSlotList::SetEntrySlot(int row, int column, XUI_CONTROL_NAVIGATE direction) +{ + // The direction is the direction in which we are leaving the previous control to get to here + // So a Navigate up means we want to start at the bottom of ourself + switch( direction ) + { + case XUI_CONTROL_NAVIGATE_UP: + { + row = rows - 1; + break; + } + case XUI_CONTROL_NAVIGATE_DOWN: + { + row = 0; + break; + } + case XUI_CONTROL_NAVIGATE_LEFT: + case XUI_CONTROL_NAVIGATE_TABBACKWARD: + { + column = columns - 1; + break; + } + case XUI_CONTROL_NAVIGATE_RIGHT: + case XUI_CONTROL_NAVIGATE_TABFORWARD: + { + column = 0; + break; + } + } + SetCurrentSlot( row, column ); +} + +void CXuiCtrlSlotList::Clicked() +{ + CXuiCtrlSlotItemListItem* slot; + GetCXuiCtrlSlotItem( GetCurSel() , &slot); + + // To get the press animation + slot->Press(); +} + +void CXuiCtrlSlotList::GetCXuiCtrlSlotItem(int itemIndex, CXuiCtrlSlotItemListItem** CXuiCtrlSlotItem) +{ + HXUIOBJ itemControl = this->GetItemControl(itemIndex); + VOID *pObj; + XuiObjectFromHandle( itemControl, &pObj ); + *CXuiCtrlSlotItem = (CXuiCtrlSlotItemListItem *)pObj; +} + diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.h new file mode 100644 index 00000000..d428ab14 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.h @@ -0,0 +1,73 @@ +#pragma once + +// Sig: HRESULT OnGetItemCountMaxLines(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +#define XUI_ON_XM_GET_ITEMCOUNT_MAX_LINES(MemberFunc)\ + if (pMessage->dwMessage == XM_GET_ITEMCOUNT && ((XUIMessageGetItemCount *) pMessage->pvData)->nType == XUI_ITEMCOUNT_MAX_LINES)\ + {\ + XUIMessageGetItemCount *pData = (XUIMessageGetItemCount *) pMessage->pvData;\ + return MemberFunc(pData, pMessage->bHandled);\ + } + +// Sig: HRESULT OnGetItemCountMaxPerLine(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +#define XUI_ON_XM_GET_ITEMCOUNT_MAX_PER_LINE(MemberFunc)\ + if (pMessage->dwMessage == XM_GET_ITEMCOUNT && ((XUIMessageGetItemCount *) pMessage->pvData)->nType == XUI_ITEMCOUNT_MAX_PER_LINE)\ + {\ + XUIMessageGetItemCount *pData = (XUIMessageGetItemCount *) pMessage->pvData;\ + return MemberFunc(pData, pMessage->bHandled);\ + } + +class AbstractContainerMenu; +class SlotListItemControl; +class CXuiCtrlSlotItemListItem; + +class CXuiCtrlSlotList : public CXuiListImpl +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiCtrlSlotList, L"CXuiCtrlSlotList", XUI_CLASS_LIST ) + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_GET_ITEMCOUNT_ALL( OnGetItemCountAll ) + XUI_ON_XM_GET_ITEMCOUNT_MAX_LINES(OnGetItemCountMaxLines) + XUI_ON_XM_GET_ITEMCOUNT_MAX_PER_LINE(OnGetItemCountMaxPerLine) + XUI_END_MSG_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnGetItemCountAll( XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled ); + HRESULT OnGetItemCountMaxLines(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnGetItemCountMaxPerLine(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +public: + void SetData(int m_iPad, AbstractContainerMenu* menu, int rows, int columns, int startIndex = 0, int endIndex = 0); + + int GetRows() { return rows; }; + int GetColumns() { return columns; }; + int GetCurrentColumn(); + int GetCurrentRow(); + + int GetCurrentIndex(); + + void SetCurrentSlot(int row, int column); + void SetEntrySlot(int row, int column, XUI_CONTROL_NAVIGATE direction); + + void Clicked(); + + // 4J WESTY : Pointer Prototype : Made public. + void GetCXuiCtrlSlotItem(int itemIndex, CXuiCtrlSlotItemListItem** CXuiCtrlSlotItem); + +private: + int slotCount; + int rows; + int columns; + int startIndex; + + // 4J WESTY : Pointer Prototype : Made public. + //void GetCXuiCtrlSlotItem(int itemIndex, CXuiCtrlSlotItemListItem** CXuiCtrlSlotItem); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.cpp b/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.cpp new file mode 100644 index 00000000..2e971710 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.cpp @@ -0,0 +1,94 @@ +#include "stdafx.h" +#include "..\..\Minecraft.h" +#include "..\..\ScreenSizeCalculator.h" +#include "..\..\Lighting.h" +#include "XUI_Ctrl_SplashPulser.h" +#include "..\..\Font.h" +#include "..\..\..\Minecraft.World\Mth.h" +#include "..\..\..\Minecraft.World\System.h" + +//----------------------------------------------------------------------------- +// CXuiCtrlSplashPulser class +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +CXuiCtrlSplashPulser::CXuiCtrlSplashPulser() : + m_bDirty(FALSE), + m_fScale(1.0f), + m_fAlpha(1.0f) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys); + m_fScreenWidth=(float)pMinecraft->width_phys; + m_fRawWidth=(float)ssc.rawWidth; + m_fScreenHeight=(float)pMinecraft->height_phys; + m_fRawHeight=(float)ssc.rawHeight; +} + +//----------------------------------------------------------------------------- +HRESULT CXuiCtrlSplashPulser::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled) +{ + HRESULT hr=S_OK; + return hr; +} + +HRESULT CXuiCtrlSplashPulser::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled ) +{ +#ifdef _XBOX + HXUIDC hDC = pRenderData->hDC; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + Font *font = pMinecraft->font; + + wstring splash( GetText() ); + + // build and render with the game call + + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + + RenderManager.Set_matrixDirty(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 1280.0f, 720.0f, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + glColor4f(1.0f,1.0f,1.0f,1.0f); + + glPushMatrix(); + + D3DXMATRIX matrix; + CXuiControl xuiControl(m_hObj); + xuiControl.GetFullXForm(&matrix); + float bwidth,bheight; + xuiControl.GetBounds(&bwidth,&bheight); + + float xo = (matrix._41 + (bwidth*matrix._11)/2 ); + float yo = (matrix._42 + (bheight*matrix._22) ); + glTranslatef(xo, yo, 0); + + glRotatef(-17, 0, 0, 1); + float sss = 1.8f - Mth::abs(Mth::sin(System::currentTimeMillis() % 1000 / 1000.0f * PI * 2) * 0.1f); + sss*=(m_fScreenWidth/m_fRawWidth); + + sss = sss * 100 / (font->width(splash) + 8 * 4); + glScalef(sss, sss, sss); + //drawCenteredString(font, splash, 0, -8, 0xffff00); + font->drawShadow(splash, 0 - (font->width(splash)) / 2, -8, 0xffff00); + glPopMatrix(); + + glDisable(GL_RESCALE_NORMAL); + + glEnable(GL_DEPTH_TEST); + + XuiRenderRestoreState(hDC); + + bHandled = TRUE; +#endif + return S_OK; +} + + + diff --git a/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.h b/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.h new file mode 100644 index 00000000..504cf4c5 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.h @@ -0,0 +1,36 @@ +#pragma once + +#include <string> +#include <XuiApp.h> + +using namespace std; + +//----------------------------------------------------------------------------- +// CXuiCtrlSplashPulser class +//----------------------------------------------------------------------------- +class CXuiCtrlSplashPulser : public CXuiControlImpl +{ +public: + XUI_IMPLEMENT_CLASS(CXuiCtrlSplashPulser, L"CXuiCtrlSplashPulser", XUI_CLASS_LABEL) + + CXuiCtrlSplashPulser(); + virtual ~CXuiCtrlSplashPulser() { }; + +protected: + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT(OnInit) + XUI_ON_XM_RENDER(OnRender) + XUI_END_MSG_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& rfHandled); + HRESULT OnRender(XUIMessageRender *pRenderData, BOOL &rfHandled); + +private: + BOOL m_bDirty; + float m_fScale,m_fAlpha; + + float m_fScreenWidth,m_fScreenHeight; + float m_fRawWidth,m_fRawHeight; + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_CustomMessages.h b/Minecraft.Client/Common/XUI/XUI_CustomMessages.h new file mode 100644 index 00000000..888f8ad0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_CustomMessages.h @@ -0,0 +1,193 @@ +#pragma once + +#define XM_SPLITSCREENPLAYER_MESSAGE XM_USER +#define XM_FONTRENDERERCHANGE_MESSAGE XM_USER + 1 +#define XM_DLCMOUNTED_MESSAGE XM_USER + 2 +#define XM_BASE_POSITION_CHANGED_MESSAGE XM_USER + 3 +#define XM_DLCSINSTALLED_MESSAGE XM_USER + 4 +#define XM_INVENTORYUPDATED_MESSAGE XM_USER + 5 +#define XM_TMS_DLCFILE_RETRIEVED_MESSAGE XM_USER + 6 +#define XM_TMS_BANFILE_RETRIEVED_MESSAGE XM_USER + 7 +#define XM_TMS_ALLFILES_RETRIEVED_MESSAGE XM_USER + 8 +#define XM_CUSTOMTICKSCENE_MESSAGE XM_USER + 9 +#define XM_GETSLOTITEM_MESSAGE XM_USER + 10 + +typedef struct +{ + shared_ptr<ItemInstance> item; + + // Legacy values for compatibility + int iDataBitField; + int iItemBitField; + LPCWSTR szPath; + BOOL bDirty; +} +CustomMessage_GetSlotItem_Struct; + + +// Define the prototype for your handler function +// Sig: HRESULT OnCustomMessage_GetSlotItem(CustomMessage_GetSlotItem_Struct *pData, BOOL& bHandled) + +// Define the message map macro +#define XUI_ON_XM_GETSLOTITEM_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_GETSLOTITEM_MESSAGE)\ +{\ + CustomMessage_GetSlotItem_Struct *pData = (CustomMessage_GetSlotItem_Struct *) pMessage->pvData;\ + return MemberFunc(pData, pMessage->bHandled);\ +} + +static __declspec(noinline) void CustomMessage_GetSlotItem(XUIMessage *pMsg, CustomMessage_GetSlotItem_Struct* pData, int iDataBitField, int iItemBitField) +{ + XuiMessage(pMsg,XM_GETSLOTITEM_MESSAGE); + _XuiMessageExtra(pMsg,(XUIMessageData*) pData, sizeof(*pData)); + pData->item = nullptr; + pData->iDataBitField = iDataBitField; + pData->iItemBitField = iItemBitField; + pData->szPath = NULL; + pData->bDirty = false; +} + +typedef struct +{ + bool bJoining; // if you're not joining, your leaving +} +CustomMessage_Splitscreenplayer_Struct; + + +// Define the prototype for your handler function +// Sig: HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) + +// Define the message map macro +#define XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_SPLITSCREENPLAYER_MESSAGE)\ +{\ + CustomMessage_Splitscreenplayer_Struct *pData = (CustomMessage_Splitscreenplayer_Struct *) pMessage->pvData;\ + return MemberFunc(pData->bJoining, pMessage->bHandled);\ +} + +static __declspec(noinline) void CustomMessage_Splitscreenplayer(XUIMessage *pMsg, CustomMessage_Splitscreenplayer_Struct* pData, bool bJoining) +{ + XuiMessage(pMsg,XM_SPLITSCREENPLAYER_MESSAGE); + _XuiMessageExtra(pMsg,(XUIMessageData*) pData, sizeof(*pData)); + pData->bJoining = bJoining; +} + +// Define the prototype for your handler function +// Sig: HRESULT OnFontRendererChange() + +// Define the message map macro +#define XUI_ON_XM_FONTRENDERERCHANGE_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_FONTRENDERERCHANGE_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_FontRendererChange(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_FONTRENDERERCHANGE_MESSAGE); +} + +// Define the prototype for your handler function +// Sig: HRESULT OnDLCMounted() + +// Define the message map macro +#define XUI_ON_XM_DLCLOADED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_DLCMOUNTED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_DLCMountingComplete(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_DLCMOUNTED_MESSAGE); +} + +// Define the prototype for your handler function +// Sig: HRESULT OnBasePositionChanged() + +// Define the message map macro +#define XUI_ON_XM_BASE_POSITION_CHANGED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_BASE_POSITION_CHANGED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_BasePositionChanged(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_BASE_POSITION_CHANGED_MESSAGE); +} + +// the prototype for your handler function +// Sig: HRESULT OnDLCInstalled() + +// Define the message map macro +#define XUI_ON_XM_DLCINSTALLED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_DLCSINSTALLED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_DLCInstalled(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_DLCSINSTALLED_MESSAGE); +} + +// the prototype for your handler function +// Sig: HRESULT OnCustomMessage_InventoryUpdated() + +// Define the message map macro +#define XUI_ON_XM_INVENTORYUPDATED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_INVENTORYUPDATED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_InventoryUpdated(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_INVENTORYUPDATED_MESSAGE); +} + +// the prototype for your handler function +// Sig: HRESULT OnCustomMessage_() + +// Define the message map macro +#define XUI_ON_XM_TMS_DLCFILE_RETRIEVED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_TMS_DLCFILE_RETRIEVED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_TMS_DLCFileRetrieved(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_TMS_DLCFILE_RETRIEVED_MESSAGE); +} + +// the prototype for your handler function +// Sig: HRESULT OnCustomMessage_() + +// Define the message map macro +#define XUI_ON_XM_TMS_BANFILE_RETRIEVED_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_TMS_BANFILE_RETRIEVED_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_TMS_BanFileRetrieved(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_TMS_BANFILE_RETRIEVED_MESSAGE); +} + +// Define the prototype for your handler function +// Sig: HRESULT OnCustomMessage_TickScene() + +// Define the message map macro +#define XUI_ON_XM_CUSTOMTICKSCENE_MESSAGE(MemberFunc)\ + if (pMessage->dwMessage == XM_CUSTOMTICKSCENE_MESSAGE)\ +{\ + return MemberFunc();\ +} + +static __declspec(noinline) void CustomMessage_TickScene(XUIMessage *pMsg) +{ + XuiMessage(pMsg,XM_CUSTOMTICKSCENE_MESSAGE); +} diff --git a/Minecraft.Client/Common/XUI/XUI_DLCOffers.cpp b/Minecraft.Client/Common/XUI/XUI_DLCOffers.cpp new file mode 100644 index 00000000..bd05ca14 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DLCOffers.cpp @@ -0,0 +1,886 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\..\..\Minecraft.World\ByteArrayInputStream.h" +#include "..\..\..\Minecraft.World\BufferedReader.h" +#include "..\..\..\Minecraft.World\InputStreamReader.h" +#include "..\..\..\Minecraft.World\ArrayWithLength.h" +#include <assert.h> +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_DLCOffers.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#ifdef _XBOX +#include <xavatar.h> +#endif + +#define TIMER_ID_NETWORK_CONNECTION 1 +#define TIMER_ID_NAVIGATE_BACK 2 +// Constants + +//const wstring CScene_DLCOffers::DEFAULT_BANNER = L"Graphics/banner.png"; + +// DLC Main + +HRESULT CScene_DLCMain::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + iPad = *(int *) pInitData->pvInitData; + + MapChildControls(); + + app.SetTickTMSDLCFiles(true); + + XuiControlSetText(xList,app.GetString(IDS_DOWNLOADABLE_CONTENT_OFFERS)); + + //if(app.GetTMSDLCInfoRead()) + { + m_Timer.SetShow(FALSE); + m_bIgnoreInput=false; + + VOID *pObj; + XuiObjectFromHandle( xList, &pObj ); + list = (CXuiCtrl4JList *) pObj; + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK ); + + CXuiCtrl4JList::LIST_ITEM_INFO *pListInfo = new CXuiCtrl4JList::LIST_ITEM_INFO [e_DLC_MAX_MinecraftStore]; + ZeroMemory(pListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)*e_DLC_MAX_MinecraftStore); + + m_bAllDLCContentRetrieved=false; + pListInfo[e_DLC_SkinPack].pwszText = app.GetString(IDS_DLC_MENU_SKINPACKS); + pListInfo[e_DLC_SkinPack].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_SkinPack]); + + pListInfo[e_DLC_TexturePacks].pwszText = app.GetString(IDS_DLC_MENU_TEXTUREPACKS); + pListInfo[e_DLC_TexturePacks].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_TexturePacks]); + + pListInfo[e_DLC_MashupPacks].pwszText = app.GetString(IDS_DLC_MENU_MASHUPPACKS); + pListInfo[e_DLC_MashupPacks].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_MashupPacks]); + + pListInfo[e_DLC_Themes].pwszText = app.GetString(IDS_DLC_MENU_THEMES); + pListInfo[e_DLC_Themes].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_Themes]); + + pListInfo[e_DLC_AvatarItems].pwszText = app.GetString(IDS_DLC_MENU_AVATARITEMS); + pListInfo[e_DLC_AvatarItems].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_AvatarItems]); + + pListInfo[e_DLC_Gamerpics].pwszText = app.GetString(IDS_DLC_MENU_GAMERPICS); + pListInfo[e_DLC_Gamerpics].fEnabled=TRUE; + list->AddData(pListInfo[e_DLC_Gamerpics]); + + app.AddDLCRequest(e_Marketplace_Content); // content is skin packs, texture packs and mash-up packs + app.AddDLCRequest(e_Marketplace_Gamerpics); + app.AddDLCRequest(e_Marketplace_Themes); + app.AddDLCRequest(e_Marketplace_AvatarItems); + + // start retrieving the images needed from TMS + app.AddTMSPPFileTypeRequest(e_DLC_SkinPack); + app.AddTMSPPFileTypeRequest(e_DLC_Gamerpics); + app.AddTMSPPFileTypeRequest(e_DLC_Themes); + app.AddTMSPPFileTypeRequest(e_DLC_AvatarItems); + app.AddTMSPPFileTypeRequest(e_DLC_TexturePacks); + app.AddTMSPPFileTypeRequest(e_DLC_MashupPacks); + } + + XuiElementInitUserFocus(xList, ProfileManager.GetPrimaryPad(), TRUE); + TelemetryManager->RecordMenuShown(iPad, eUIScene_DLCMainMenu, 0); // 4J JEV ? + + return S_OK; +} + +HRESULT CScene_DLCMain::OnDestroy() +{ + return S_OK; +} + +HRESULT CScene_DLCMain::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==TIMER_ID_NETWORK_CONNECTION) + { + if(ProfileManager.GetLiveConnectionStatus()!=XONLINE_S_LOGON_CONNECTION_ESTABLISHED) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + StorageManager.ClearDLCOffers(); + app.ClearAndResetDLCDownloadQueue(); + } + } + else if(pData->nId==TIMER_ID_NAVIGATE_BACK) + { + if(app.CheckTMSDLCCanStop()) + { + XuiKillTimer(m_hObj,TIMER_ID_NAVIGATE_BACK); + app.NavigateBack(XUSER_INDEX_ANY); + } + } + + return S_OK; +} + + +HRESULT CScene_DLCMain::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + app.SetTickTMSDLCFiles(false); + + // set the timer running to navigate back when any tms retrieval has come in + XuiSetTimer(m_hObj,TIMER_ID_NAVIGATE_BACK,50); + m_bIgnoreInput=true; + m_Timer.SetShow(TRUE); + //app.NavigateBack(XUSER_INDEX_ANY); + rfHandled = TRUE; + + break; + } + + return S_OK; +} + +HRESULT CScene_DLCMain::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==xList) + { + int iIndex; + CXuiControl pItem; + iIndex=xList.GetCurSel(&pItem); + + DLCOffersParam *param = new DLCOffersParam(); + param->iPad = iPad; + param->iType = iIndex; + + // promote the DLC content request type + app.AddDLCRequest((eDLCMarketplaceType)iIndex, true); + app.NavigateToScene(iPad,eUIScene_DLCOffersMenu, param); + } + return S_OK; +} + +HRESULT CScene_DLCMain::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK ); + + return S_OK; +} + +// DLC OFFERS + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_DLCOffers::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + DLCOffersParam *param = (DLCOffersParam *) pInitData->pvInitData; + m_iPad = param->iPad; + m_iType = param->iType; + m_iOfferC = app.GetDLCOffersCount(); + m_bIsFemale = false; + m_pNoImageFor_DLC=NULL; + bNoDLCToDisplay=true; + //hCostText=NULL; + + + // 4J JEV: Deleting this here seems simpler. + delete param; + + // If this is the avatar items, we need to init the avatar system to allow us to find out what the player avatar gender is (since we should only display tshirts etc with the right gender) + // The init reserves 3MB of memory, so we shut down on leaving this. + if(m_iType==e_DLC_AvatarItems) + { + XAVATAR_METADATA AvatarMetadata; + HRESULT hRes; + + + hRes=XAvatarInitialize(XAVATAR_COORDINATE_SYSTEM_LEFT_HANDED,0,0,0,NULL); + + // get the avatar gender + hRes=XAvatarGetMetadataLocalUser(m_iPad,&AvatarMetadata,NULL); + + m_bIsFemale= (XAVATAR_BODY_TYPE_FEMALE == XAvatarMetadataGetBodyType(&AvatarMetadata)); + // shutdown the avatar system + + XAvatarShutdown(); + } + + m_bIsSD=!RenderManager.IsHiDef() && !RenderManager.IsWidescreen(); + + MapChildControls(); + + XuiControlSetText(m_List,app.GetString(IDS_DOWNLOADABLE_CONTENT_OFFERS)); + + m_bIgnorePress=true; + + VOID *pObj; + m_hXuiBrush=NULL; + + XuiObjectFromHandle( m_List, &pObj ); + m_pOffersList = (CXuiCtrl4JList *)pObj; + m_bAllDLCContentRetrieved=false; + + XuiElementInitUserFocus(m_hObj,ProfileManager.GetPrimaryPad(),TRUE); + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_DLCOffersMenu, 0); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1,IDS_TOOLTIPS_BACK); + + // Disable the price tag display + m_PriceTag.SetShow(FALSE); + + // If we don't yet have this DLC, we need to display a timer + m_bDLCRequiredIsRetrieved=false; + + // Is the DLC we're looking for available? + if(!m_bDLCRequiredIsRetrieved) + { + if(app.DLCContentRetrieved((eDLCMarketplaceType)m_iType)) + { + m_bDLCRequiredIsRetrieved=true; + + // Retrieve the info + GetDLCInfo(app.GetDLCOffersCount(), false); + m_bIgnorePress=false; + } + } + + XuiSetTimer(m_hObj,TIMER_ID_NETWORK_CONNECTION,50); + + return S_OK; +} + +HRESULT CScene_DLCOffers::GetDLCInfo( int iOfferC, bool bUpdateOnly ) +{ + CXuiCtrl4JList::LIST_ITEM_INFO *pListInfo=NULL; + //XMARKETPLACE_CONTENTOFFER_INFO xOffer; + XMARKETPLACE_CURRENCY_CONTENTOFFER_INFO xOffer; + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + ZeroMemory(szResourceLocator,sizeof(WCHAR)*LOCATOR_SIZE); + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + int iCount=0; + + if(bUpdateOnly) // Just update the info on the current list + { + for(int i=0;i<iOfferC;i++) + { + xOffer = StorageManager.GetOffer(i); + // Check that this is in the list of known DLC + DLC_INFO *pDLC=app.GetDLCInfoForFullOfferID(xOffer.qwOfferID); + if(pDLC==NULL) + { + // try the trial version + pDLC=app.GetDLCInfoForTrialOfferID(xOffer.qwOfferID); + } + + if(pDLC==NULL) + { + // skip this one +#ifdef _DEBUG + app.DebugPrintf("Unknown offer - "); + OutputDebugStringW(xOffer.wszOfferName); + app.DebugPrintf("\n"); +#endif + continue; + } + + // If the item has a gender, then skip ones that are the other gender + if((pDLC->iGender==1) && (m_bIsFemale==true)) + { + app.DebugPrintf("Wrong gender\n"); + continue; + } + + // can't trust the offer type - partnernet is giving avatar items the CONTENT type + //if(Offer.dwOfferType==app.GetDLCContentType((eDLCContentType)m_iType)) + if(pDLC->eDLCType==(eDLCContentType)m_iType) + { + if(xOffer.fUserHasPurchased) + { + HXUIBRUSH hBrush; + + if(RenderManager.IsHiDef() || RenderManager.IsWidescreen()) + { + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/DLC_Tick.png"); + XuiCreateTextureBrush(szResourceLocator,&hBrush); + } + else + { + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/DLC_TickSmall.png"); + XuiCreateTextureBrush(szResourceLocator,&hBrush); + } + m_pOffersList->UpdateGraphic(i,hBrush ); + } + + iCount++; + } + } + + if(iCount>0) + { + bNoDLCToDisplay=false; + } + } + else + { + if(iOfferC!=0) + { + pListInfo = new CXuiCtrl4JList::LIST_ITEM_INFO [iOfferC]; + ZeroMemory(pListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)*iOfferC); + } + + for(int i = 0; i < iOfferC; i++) + { + xOffer = StorageManager.GetOffer(i); + + // Check that this is in the list of known DLC + DLC_INFO *pDLC=app.GetDLCInfoForFullOfferID(xOffer.qwOfferID); + if(pDLC==NULL) + { + // try the trial version + pDLC=app.GetDLCInfoForTrialOfferID(xOffer.qwOfferID); + } + + if(pDLC==NULL) + { + // skip this one +#ifdef _DEBUG + app.DebugPrintf("Unknown offer - "); + OutputDebugStringW(xOffer.wszOfferName); + app.DebugPrintf("\n"); +#endif + continue; + } + + // can't trust the offer type - partnernet is giving avatar items the CONTENT type + //if(Offer.dwOfferType==app.GetDLCContentType((eDLCContentType)m_iType)) + if(pDLC->eDLCType==(eDLCContentType)m_iType) + { + wstring wstrTemp=xOffer.wszOfferName; + + // If the string starts with Minecraft, removed that + + // Bug 49249 - JPN: Code Defect: Missing Text: String 'Minecraft' is missing in contents download screen. + // Looks like we shouldn't be removing this text for Japanese, and probably Chinese & Korean + + DWORD dwLanguage = XGetLanguage( ); + switch(dwLanguage) + { + case XC_LANGUAGE_KOREAN: + case XC_LANGUAGE_JAPANESE: + case XC_LANGUAGE_TCHINESE: + pListInfo[iCount].pwszText = xOffer.wszOfferName; + break; + default: + if(wstrTemp.compare(0,10,L"Minecraft ")==0) + { + pListInfo[iCount].pwszText = &xOffer.wszOfferName[10]; + } + else + { + pListInfo[iCount].pwszText = xOffer.wszOfferName; + } + break; + } + + pListInfo[iCount].fEnabled=TRUE; + + // store the offer index + pListInfo[iCount].iData=i; + pListInfo[iCount].iSortIndex=(int)pDLC->uiSortIndex; +#ifdef _DEBUG + app.DebugPrintf("Adding "); + OutputDebugStringW(pListInfo[iCount].pwszText); + app.DebugPrintf(" at %d\n",i); +#endif + + m_pOffersList->AddData(pListInfo[iCount],0,CXuiCtrl4JList::eSortList_Index); + //offerIndexes.push_back(i); + + if(xOffer.fUserHasPurchased) + { + HXUIBRUSH hBrush; + + if(RenderManager.IsHiDef() || RenderManager.IsWidescreen()) + { + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/DLC_Tick.png"); + XuiCreateTextureBrush(szResourceLocator,&hBrush); + } + else + { + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/DLC_TickSmall.png"); + XuiCreateTextureBrush(szResourceLocator,&hBrush); + } + m_pOffersList->UpdateGraphicFromiData(i,hBrush); + } + + /** 4J JEV: + * We've filtered results out from the list, need to keep track + * of the 'actual' list index. + */ + iCount++; + } + } + + // Check if there is nothing to display, and display the default "nothing available at this time" + if(iCount>0) + { + bNoDLCToDisplay=false; + } + } + + // turn off the timer display + m_Timer.SetShow(FALSE); + if(iCount!=0) + { + // get the right index for the first list item - it will have been re-sorted internally in the list + int iIndex=0; + xOffer=StorageManager.GetOffer(m_pOffersList->GetData(iIndex).iData); + m_pOffersList->SetCurSelVisible(0); + + DLC_INFO *dlc = app.GetDLCInfoForFullOfferID(xOffer.qwOfferID); + if (dlc != NULL) + { + BYTE *pData=NULL; + UINT uiSize=0; + DWORD dwSize=0; + + WCHAR *cString = dlc->wchBanner; + // is the file in the TMS XZP? + int iIndex = app.GetLocalTMSFileIndex(cString, true); + + if(iIndex!=-1) + { + // it's in the xzp + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + } + app.LoadLocalTMSFile(cString); + XuiCreateTextureBrushFromMemory(app.TMSFileA[iIndex].pbData,app.TMSFileA[iIndex].uiSize,&m_hXuiBrush); + } + else + { + bool bPresent = app.IsFileInMemoryTextures(cString); + if (!bPresent) + { + // Image has not come in yet + // Set the item monitored in the timer, so we can set the image when it comes in + m_pNoImageFor_DLC=dlc; + } + else + { + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + } + app.GetMemFileDetails(cString,&pData,&dwSize); + XuiCreateTextureBrushFromMemory(pData,dwSize,&m_hXuiBrush); + } + } + } + + wchar_t formatting[40]; + wstring wstrTemp = xOffer.wszSellText; + swprintf(formatting, 40, L"<font size=\"%d\">", m_bIsSD?12:14); + wstrTemp = formatting + wstrTemp; + + m_SellText.SetText(wstrTemp.c_str()); + m_SellText.SetShow(TRUE); + + // set the price info + m_PriceTag.SetShow(TRUE); +// swprintf(formatting, 40, L"%d",xOffer.dwPointsPrice); +// wstrTemp=wstring(formatting); +// m_PriceTag.SetText(wstrTemp.c_str()); + m_PriceTag.SetText(xOffer.wszCurrencyPrice); + + XuiElementSetShow(m_List,TRUE); + XuiElementSetFocus(m_List); + + UpdateTooltips(xOffer); + } + else if(bNoDLCToDisplay) + { + // set the default text + + wchar_t formatting[40]; + wstring wstrTemp = app.GetString(IDS_NO_DLCOFFERS); + swprintf(formatting, 40, L"<font size=\"%d\">", m_bIsSD?12:14); + wstrTemp = formatting + wstrTemp; + + m_SellText.SetText(wstrTemp.c_str()); + m_SellText.SetShow(TRUE); + } + return S_OK; +} + +HRESULT CScene_DLCOffers::OnDestroy() +{ + // 4J-PB - don't cancel the DLC anymore + //StorageManager.CancelGetDLCOffers(); + + // clear out any TMS images loaded from the XZP + app.FreeLocalTMSFiles(eTMSFileType_MinecraftStore); + return S_OK; +} + + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_DLCOffers::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnorePress) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_List) + { + CXuiControl pItem; + int iIndex; + CXuiCtrl4JList::LIST_ITEM_INFO ItemInfo; + // get the selected item + iIndex=m_List.GetCurSel(&pItem); + ItemInfo=m_pOffersList->GetData(iIndex); + + ULONGLONG ullIndexA[1]; + + // check if it's already installed + // if(StorageManager.GetOffer(iIndex).fUserHasPurchased) + // { + // + // } + // else + // if it's already been purchased, we need to let the user download it anyway + { + ullIndexA[0]=StorageManager.GetOffer(ItemInfo.iData).qwOfferID; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + + return S_OK; +} + +HRESULT CScene_DLCOffers::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + // Fix for Compliance fail - + // On a functional console, the game must not enter an extended unresponsive state, cause unintentional loss of player data, crash, or cause an unintended reboot of the machine. + + //if(m_bIgnorePress) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(XUSER_INDEX_ANY); + rfHandled = TRUE; + + break; + + case VK_PAD_RTHUMB_DOWN: + { + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_SellText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_SellText.m_hObj,1); + } + } + break; + case VK_PAD_RTHUMB_UP: + { + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_SellText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_SellText.m_hObj,-1); + } + } + break; + } + + return S_OK; +} + + +HRESULT CScene_DLCOffers::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + // re-enable button presses + m_bIgnorePress=false; + + return S_OK; +} + +//void CScene_DLCOffers::UpdateTooltips(XMARKETPLACE_CONTENTOFFER_INFO& xOffer) +void CScene_DLCOffers::UpdateTooltips(XMARKETPLACE_CURRENCY_CONTENTOFFER_INFO& xOffer) +{ + // if the current offer hasn't been purchased already, check if there's a trial version available + if(xOffer.fUserHasPurchased==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_INSTALL,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_REINSTALL,IDS_TOOLTIPS_BACK); + } +} + + +HRESULT CScene_DLCOffers::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + if( pGetSourceImageData->bItemData ) + { + pGetSourceImageData->hBrush = m_hXuiBrush; + + bHandled = TRUE; + } + return S_OK; +} + +HRESULT CScene_DLCOffers::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + //int index = pNotifySelChangedData->iItem; + // reset the image monitor, but not for the first selection + if(pNotifySelChangedData->iOldItem!=-1) + { + m_pNoImageFor_DLC=NULL; + } + + if (m_List.TreeHasFocus())// && offerIndexes.size() > index) + { + CXuiControl pItem; + int iIndex; + CXuiCtrl4JList::LIST_ITEM_INFO ItemInfo; + // get the selected item + iIndex=m_List.GetCurSel(&pItem); + ItemInfo=m_pOffersList->GetData(iIndex); + +// XMARKETPLACE_CONTENTOFFER_INFO xOffer= +// StorageManager.GetOffer(ItemInfo.iData); + XMARKETPLACE_CURRENCY_CONTENTOFFER_INFO xOffer= + StorageManager.GetOffer(ItemInfo.iData); + + + wchar_t formatting[40]; + wstring wstrTemp=xOffer.wszSellText; + swprintf(formatting, 40, L"<font size=\"%d\">",m_bIsSD?12:14); + wstrTemp = wstring(formatting) + wstrTemp; + + m_SellText.SetText(wstrTemp.c_str()); + + // set the price info + m_PriceTag.SetShow(TRUE); +// swprintf(formatting, 40, L"%d",xOffer.dwPointsPrice); +// wstrTemp=wstring(formatting); +// m_PriceTag.SetText(wstrTemp.c_str()); + m_PriceTag.SetText(xOffer.wszCurrencyPrice); + + DLC_INFO *dlc = app.GetDLCInfoForTrialOfferID(xOffer.qwOfferID); + if(dlc==NULL) + { + dlc = app.GetDLCInfoForFullOfferID(xOffer.qwOfferID); + } + + if (dlc != NULL) + { + BYTE *pImage=NULL; + UINT uiSize=0; + DWORD dwSize=0; + + WCHAR *cString = dlc->wchBanner; + + int iIndex = app.GetLocalTMSFileIndex(cString,true); + + if(iIndex!=-1) + { + // it's in the xzp + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + } + app.LoadLocalTMSFile(cString); + XuiCreateTextureBrushFromMemory(app.TMSFileA[iIndex].pbData,app.TMSFileA[iIndex].uiSize,&m_hXuiBrush); + } + else + { + bool bPresent = app.IsFileInMemoryTextures(cString); + if (!bPresent) + { + // Image has not come in yet + // Set the item monitored in the timer, so we can set the image when it comes in + m_pNoImageFor_DLC=dlc; + + // promote it to the top of the queue of images to be retrieved + // We can't trust the dwContentCategory from partnernet - it has avatar items as content instead of avatars + app.AddTMSPPFileTypeRequest(dlc->eDLCType,true); + } + else + { + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + } + app.GetMemFileDetails(cString,&pImage,&dwSize); + XuiCreateTextureBrushFromMemory(pImage,dwSize,&m_hXuiBrush); + } + } + } + else + { + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + + m_hXuiBrush=NULL; + } + } + + UpdateTooltips(xOffer); + } + else + { + m_SellText.SetText(L""); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_ACCEPT ,IDS_TOOLTIPS_BACK); + } + return S_OK; +} + + +HRESULT CScene_DLCOffers::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + // check the ethernet status - if it's disconnected, exit the xui + + if(ProfileManager.GetLiveConnectionStatus()!=XONLINE_S_LOGON_CONNECTION_ESTABLISHED) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + m_pOffersList->RemoveAllData(); + m_iOfferC=0; + StorageManager.ClearDLCOffers(); + app.ClearAndResetDLCDownloadQueue(); + + StorageManager.RequestMessageBox(IDS_CONNECTION_LOST, IDS_CONNECTION_LOST_LIVE, uiIDA, 1, ProfileManager.GetPrimaryPad(),&CConsoleMinecraftApp::EthernetDisconnectReturned,this, app.GetStringTable()); + } + + // Is the DLC we're looking for available? + if(!m_bDLCRequiredIsRetrieved) + { + if(app.DLCContentRetrieved((eDLCMarketplaceType)m_iType)) + { + m_bDLCRequiredIsRetrieved=true; + + // Retrieve the info + GetDLCInfo(app.GetDLCOffersCount(), false); + m_bIgnorePress=false; + } + } + + // Check for any TMS image we're waiting for + if(m_pNoImageFor_DLC!=NULL) + { + // Is it present now? + WCHAR *cString = m_pNoImageFor_DLC->wchBanner; + + bool bPresent = app.IsFileInMemoryTextures(cString); + + if(bPresent) + { + BYTE *pImage=NULL; + DWORD dwSize=0; + + if(m_hXuiBrush!=NULL) + { + XuiDestroyBrush(m_hXuiBrush); + // clear the TMS XZP vector memory + //app.FreeLocalTMSFiles(); + } + app.GetMemFileDetails(cString,&pImage,&dwSize); + XuiCreateTextureBrushFromMemory(pImage,dwSize,&m_hXuiBrush); + m_pNoImageFor_DLC=NULL; + } + } + + return S_OK; +} + +// int CScene_DLCOffers::EthernetDisconnectReturned(void *pParam,int iPad,const C4JStorage::EMessageResult) +// { +// CConsoleMinecraftApp* pApp = (CConsoleMinecraftApp*)pParam; +// +// pApp->NavigateBack(XUSER_INDEX_ANY); +// +// return 0; +// } + +HRESULT CScene_DLCOffers::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed - need to re-run the GetDLC + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1, IDS_TOOLTIPS_BACK); + m_bIgnorePress=true; + m_pOffersList->RemoveAllData(); + m_iOfferC=0; + + // Update the dlc info + StorageManager.ClearDLCOffers(); + app.ClearAndResetDLCDownloadQueue(); + + // order these requests so the current DLC comes in first + switch(m_iType) + { + case e_DLC_Gamerpics: + app.AddDLCRequest(e_Marketplace_Gamerpics); + app.AddDLCRequest(e_Marketplace_Content); + app.AddDLCRequest(e_Marketplace_Themes); + app.AddDLCRequest(e_Marketplace_AvatarItems); + break; + case e_DLC_Themes: + app.AddDLCRequest(e_Marketplace_Themes); + app.AddDLCRequest(e_Marketplace_Content); + app.AddDLCRequest(e_Marketplace_Gamerpics); + app.AddDLCRequest(e_Marketplace_AvatarItems); + break; + case e_DLC_AvatarItems: + app.AddDLCRequest(e_Marketplace_AvatarItems); + app.AddDLCRequest(e_Marketplace_Content); + app.AddDLCRequest(e_Marketplace_Themes); + app.AddDLCRequest(e_Marketplace_Gamerpics); + break; + default: + app.AddDLCRequest(e_Marketplace_Content); + app.AddDLCRequest(e_Marketplace_Gamerpics); + app.AddDLCRequest(e_Marketplace_Themes); + app.AddDLCRequest(e_Marketplace_AvatarItems); + break; + } + + m_Timer.SetShow(TRUE); + m_bDLCRequiredIsRetrieved=false; + + return S_OK; +} diff --git a/Minecraft.Client/Common/XUI/XUI_DLCOffers.h b/Minecraft.Client/Common/XUI/XUI_DLCOffers.h new file mode 100644 index 00000000..412446d0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DLCOffers.h @@ -0,0 +1,136 @@ +#pragma once + +#include "../media\xuiscene_DLCOffers.h" +#include "../media\xuiscene_DLCMain.h" + + +#include "XUI_CustomMessages.h" +#include "XUI_Ctrl_4JList.h" +#include "XUI_Ctrl_4JIcon.h" +//#include "XUI_Ctrl_DLCPrice.h" + +class CXuiCtrl4JList; +class CScene_DLCOffers; +class CXuiCtrlDLCPrice; + +class CScene_DLCMain : public CXuiSceneImpl +{ + // Xui Elements + CXuiList xList; + CXuiCtrl4JList *list; + CXuiControl m_Timer; + + // Misc + int iPad, iOfferC; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiOffersList, xList) + MAP_CONTROL(IDC_Timer, m_Timer) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + +public: + XUI_IMPLEMENT_CLASS( CScene_DLCMain, L"CScene_DLCMain", XUI_CLASS_SCENE ) + +private: + bool m_bAllDLCContentRetrieved; + bool m_bIgnoreInput; +}; + +class CScene_DLCOffers : public CXuiSceneImpl +{ +protected: + //static const wstring DEFAULT_BANNER; + + // Control and Element wrapper objects. + CXuiList m_List; + CXuiCtrl4JList *m_pOffersList; + CXuiImageElement m_Banner; + CXuiCtrl4JIcon m_TMSImage; + CXuiHtmlControl m_SellText; + CXuiControl m_PriceTag; + CXuiControl m_Timer; + HXUIBRUSH m_hXuiBrush; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_GET_SOURCE_IMAGE( OnGetSourceDataImage ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiOffersList, m_List) + MAP_CONTROL(IDC_XuiHTMLSellText, m_SellText) + MAP_CONTROL(IDC_XuiDLCPriceTag, m_PriceTag) + MAP_CONTROL(IDC_XuiDLCBanner, m_TMSImage) + MAP_CONTROL(IDC_Timer, m_Timer) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnDestroy(); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + + HRESULT GetDLCInfo( int iOfferC, bool bUpdateOnly=false ); + + //static int EthernetDisconnectReturned(void *pParam,int iPad,const C4JStorage::EMessageResult); + static int TMSReadCallback(void *pParam,int iPad,bool bResult); + + //void UpdateTooltips(XMARKETPLACE_CONTENTOFFER_INFO& xOffer); + void UpdateTooltips(XMARKETPLACE_CURRENCY_CONTENTOFFER_INFO& xOffer); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DLCOffers, L"CScene_DLCOffers", XUI_CLASS_SCENE ) + + typedef struct _DLCOffer + { + int iOfferC; + } + DLCOffer; + +private: + + //vector<int> offerIndexes; + CScene_DLCMain *pMain; + bool m_bIgnorePress; + int m_iPad; + int m_iOfferC; + int m_iType; + bool m_bIsSD; + bool m_bAllDLCContentRetrieved; + bool m_bDLCRequiredIsRetrieved; + bool m_bIsFemale; // to only show the correct gender type offers for avatars + DLC_INFO *m_pNoImageFor_DLC; + bool bNoDLCToDisplay; // to display a default "No DLC available at this time" + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Death.cpp b/Minecraft.Client/Common/XUI/XUI_Death.cpp new file mode 100644 index 00000000..83275c14 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Death.cpp @@ -0,0 +1,242 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_Death.h" +#include <assert.h> +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\..\Minecraft.Client\StatsCounter.h" +#include "..\..\..\Minecraft.World\Entity.h" +#include "..\..\..\Minecraft.Client\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\Level.h" +#include "..\..\..\Minecraft.World\ChunkSource.h" +#include "..\..\..\Minecraft.Client\ProgressRenderer.h" +#include "..\..\..\Minecraft.Client\GameRenderer.h" +#include "..\..\..\Minecraft.Client\LevelRenderer.h" +#include "..\..\..\Minecraft.World\Pos.h" +#include "..\..\..\Minecraft.World\Dimension.h" +#include "..\..\Minecraft.h" +#include "..\..\Options.h" +#include "..\..\LocalPlayer.h" +#include "..\..\..\Minecraft.World\compression.h" +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Death::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + m_bIgnoreInput = false; + + MapChildControls(); + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + XuiControlSetText(m_Title,app.GetString(IDS_YOU_DIED)); + XuiControlSetText(m_Buttons[BUTTON_DEATH_RESPAWN],app.GetString(IDS_RESPAWN)); + XuiControlSetText(m_Buttons[BUTTON_DEATH_EXITGAME],app.GetString(IDS_EXIT_GAME)); + + // Display the tooltips + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT); + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_Death::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if( hObjSource == m_Scene ) + { + /*int curSel = m_List.GetCurSel(); + + // Set the locale with the current language. + XuiSetLocale( Languages[curSel].pszLanguagePath ); + + // Apply the locale to the main scene. + XuiApplyLocale( m_hObj, NULL ); + + // Update the text for the current value. + m_Value.SetText( m_List.GetText( curSel ) );*/ + + + + bHandled = TRUE; + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Death::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + + while((uiButtonCounter<BUTTONS_DEATH_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // Determine which button was pressed, + // and call the appropriate function. + switch(uiButtonCounter) + { + case BUTTON_DEATH_EXITGAME: + { + // 4J-PB - fix for #8333 - BLOCKER: If player decides to exit game, then cancels the exit player becomes stuck at game over screen + //m_bIgnoreInput = true; + // Check if it's the trial version + if(ProfileManager.IsFullVersion()) + { + UINT uiIDA[3]; + + // is it the primary player exiting? + if(pNotifyPressData->UserIndex==ProfileManager.GetPrimaryPad()) + { + int playTime = -1; + if( pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL ) + { + playTime = (int)pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer(); + } + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Failed); + + if(StorageManager.GetSaveDisabled()) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + else + { + if( g_NetworkManager.IsHost() ) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameSaveDialogReturned,this, app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + } + } + else + { + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Failed); + + // just exit the player + app.SetAction(pNotifyPressData->UserIndex,eAppAction_ExitPlayer); + } + } + else + { + // is it the primary player exiting? + if(pNotifyPressData->UserIndex==ProfileManager.GetPrimaryPad()) + { + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Failed); + + // adjust the trial time played + CXuiSceneBase::ReduceTrialTimerValue(); + + // exit the level + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + else + { + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Failed); + + // just exit the player + app.SetAction(pNotifyPressData->UserIndex,eAppAction_ExitPlayer); + } + } + } + break; + case BUTTON_DEATH_RESPAWN: + { + m_bIgnoreInput = true; + app.SetAction(pNotifyPressData->UserIndex,eAppAction_Respawn); + } + + break; + default: + break; + } + + + + return S_OK; +} + +HRESULT CScene_Death::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_ESCAPE: + + // kill the crafting xui + // 4J Stu - No back out, must choose + //app.CloseXuiScenes(); + + rfHandled = TRUE; + + break; + } + + return S_OK; +} + +int CScene_Death::RespawnThreadProc( void* lpParameter ) +{ + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + size_t iPad=(size_t)lpParameter; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + pMinecraft->localplayers[iPad]->respawn(); + + app.SetGameStarted(true); + pMinecraft->gameRenderer->EnableUpdateThread(); + + // If we are online, then we should wait here until the respawn is done + // If we are offline, this should release straight away + //WaitForSingleObject( pMinecraft->m_hPlayerRespawned, INFINITE ); + while(pMinecraft->localplayers[iPad]->GetPlayerRespawned()==false) + { + Sleep(50); + } + + return S_OK; +} + +HRESULT CScene_Death::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Death.h b/Minecraft.Client/Common/XUI/XUI_Death.h new file mode 100644 index 00000000..62d37d0d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Death.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../media/xuiscene_Death.h" +#include "XUI_CustomMessages.h" + +#define BUTTON_DEATH_RESPAWN 0 +#define BUTTON_DEATH_EXITGAME 1 +#define BUTTONS_DEATH_MAX BUTTON_DEATH_EXITGAME + 1 + + + +class CScene_Death : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiScene m_Scene; + CXuiControl m_Buttons[BUTTONS_DEATH_MAX]; + CXuiControl m_Title; + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Respawn, m_Buttons[BUTTON_DEATH_RESPAWN]) + MAP_CONTROL(IDC_ExitGame, m_Buttons[BUTTON_DEATH_EXITGAME]) + MAP_CONTROL(IDC_Title, m_Title) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Death, L"CScene_Death", XUI_CLASS_SCENE ) + + static int RespawnThreadProc( void* lpParameter ); +private: + bool m_bIgnoreInput; + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Debug.h b/Minecraft.Client/Common/XUI/XUI_Debug.h new file mode 100644 index 00000000..1fa6d3c8 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Debug.h @@ -0,0 +1,53 @@ +#pragma once + +#include "../media/xuiscene_debug.h" + +class CScene_Debug : public CXuiSceneImpl +{ + protected: + + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_CONTROL_NAVIGATE(OnControlNavigate) + XUI_END_MSG_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); +public: + + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Debug, L"CScene_Debug", XUI_CLASS_SCENE ) + +private: + + typedef struct + { + HXUIOBJ hXuiObj; + VOID *pvData; + } + DEBUGDATA; + + + static LPCWSTR m_DebugCheckboxTextA[eDebugSetting_Max+1]; + static LPCWSTR m_DebugButtonTextA[eDebugButton_Max+1]; + int m_iTotalCheckboxElements; + int m_iTotalButtonElements; + DEBUGDATA *m_DebugCheckboxDataA; + DEBUGDATA *m_DebugButtonDataA; + int m_iCurrentCheckboxElement; + int m_iCurrentButtonElement; + int m_iPad; + bool m_bOnCheckboxes; // for navigations +}; diff --git a/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.cpp b/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.cpp new file mode 100644 index 00000000..56b41267 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.cpp @@ -0,0 +1,118 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\ClientConnection.h" +#include "..\..\Common\GameRules\ConsoleGameRules.h" +#include "XUI_DebugItemEditor.h" + +#ifdef _DEBUG_MENUS_ENABLED +HRESULT CScene_DebugItemEditor::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + MapChildControls(); + + ItemEditorInput *initData = (ItemEditorInput *)pInitData->pvInitData; + m_iPad = initData->iPad; + m_slot = initData->slot; + m_menu = initData->menu; + if(m_slot != NULL) m_item = m_slot->getItem(); + + if(m_item!=NULL) + { + m_icon->SetIcon(m_iPad, m_item->id,m_item->getAuxValue(),m_item->count,10,31,false,m_item->isFoil()); + m_itemName.SetText( app.GetString( Item::items[m_item->id]->getDescriptionId(m_item) ) ); + + m_itemId .SetText( _toString<int>(m_item->id).c_str() ); + m_itemAuxValue .SetText( _toString<int>(m_item->getAuxValue()).c_str() ); + m_itemCount .SetText( _toString<int>(m_item->count).c_str() ); + m_item4JData .SetText( _toString<int>(m_item->get4JData()).c_str() ); + } + + m_itemId .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_itemAuxValue .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_itemCount .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_item4JData .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + + m_generatedXml.SetText( CollectItemRuleDefinition::generateXml(m_item).c_str() ); + + delete initData; + + return S_OK; +} + +HRESULT CScene_DebugItemEditor::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_PAD_BACK: + // We need to send a packet to the server to update it's representation of this item + if(m_slot != NULL && m_menu != NULL) + { + m_slot->set(m_item); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> player = pMinecraft->localplayers[m_iPad]; + if(player != NULL && player->connection) player->connection->send( shared_ptr<ContainerSetSlotPacket>( new ContainerSetSlotPacket(m_menu->containerId, m_slot->index, m_item) ) ); + } + // kill the crafting xui + app.NavigateBack(m_iPad); + + rfHandled = TRUE; + + break; + + } + + return S_OK; +} + +HRESULT CScene_DebugItemEditor::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled) +{ + if(m_item == NULL) m_item = shared_ptr<ItemInstance>( new ItemInstance(0,1,0) ); + if(hObjSource == m_itemId) + { + int id = 0; + wstring value = m_itemId.GetText(); + if(!value.empty()) id = _fromString<int>( value ); + + // TODO Proper validation of the valid item ids + if(id > 0 && Item::items[id] != NULL) m_item->id = id; + } + else if(hObjSource == m_itemAuxValue) + { + int auxVal = 0; + wstring value = m_itemAuxValue.GetText(); + if(!value.empty()) auxVal = _fromString<int>( value ); + if(auxVal >= 0) m_item->setAuxValue( auxVal ); + } + else if(hObjSource == m_itemCount) + { + int count = 0; + wstring value = m_itemCount.GetText(); + if(!value.empty()) count = _fromString<int>( value ); + if(count > 0 && count <= Item::items[m_item->id]->getMaxStackSize()) m_item->count = count; + } + else if(hObjSource == m_item4JData) + { + int data = 0; + wstring value = m_item4JData.GetText(); + if(!value.empty()) data = _fromString<int>( value ); + m_item->set4JData(data); + } + + m_icon->SetIcon(m_iPad, m_item->id,m_item->getAuxValue(),m_item->count,10,31,false,m_item->isFoil()); + + m_itemName.SetText( app.GetString( Item::items[m_item->id]->getDescriptionId(m_item) ) ); + + m_generatedXml.SetText( CollectItemRuleDefinition::generateXml(m_item).c_str() ); + return S_OK; +} +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.h b/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.h new file mode 100644 index 00000000..2e2f5b5a --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugItemEditor.h @@ -0,0 +1,57 @@ +#pragma once +using namespace std; +#include "../media/xuiscene_debug_item_editor.h" + +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "XUI_Ctrl_4JEdit.h" +#include "..\..\..\Minecraft.World\ItemInstance.h" + +class CScene_DebugItemEditor : public CXuiSceneImpl +{ +#ifdef _DEBUG_MENUS_ENABLED +public: + typedef struct _ItemEditorInput + { + int iPad; + Slot *slot; + AbstractContainerMenu *menu; + } ItemEditorInput; +private: + int m_iPad; + shared_ptr<ItemInstance> m_item; + Slot *m_slot; + AbstractContainerMenu *m_menu; + + CXuiCtrlCraftIngredientSlot *m_icon; + CXuiControl m_generatedXml, m_itemName; + CXuiCtrl4JEdit m_itemId, m_itemAuxValue, m_itemCount, m_item4JData; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_itemId, m_itemId) + MAP_CONTROL(IDC_itemAuxValue, m_itemAuxValue) + MAP_CONTROL(IDC_itemCount, m_itemCount) + MAP_CONTROL(IDC_item4JData, m_item4JData) + MAP_OVERRIDE(IDC_icon, m_icon) + MAP_CONTROL(IDC_ruleXml, m_generatedXml) + MAP_CONTROL(IDC_itemName, m_itemName) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DebugItemEditor, L"CScene_DebugItemEditor", XUI_CLASS_SCENE ) +#endif +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugOverlay.cpp b/Minecraft.Client/Common/XUI/XUI_DebugOverlay.cpp new file mode 100644 index 00000000..a23e97b7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugOverlay.cpp @@ -0,0 +1,391 @@ +#include "stdafx.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\MultiplayerLevel.h" +#include "..\..\GameMode.h" +#include "..\..\SurvivalMode.h" +#include "..\..\CreativeMode.h" +#include "ClientConnection.h" +#include "MultiPlayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\ArrayWithLength.h" +#include "..\..\..\Minecraft.World\com.mojang.nbt.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.animal.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.monster.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.saveddata.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.storage.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.storage.h" +#include "..\..\..\Minecraft.World\InputOutputStream.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.enchantment.h" +#include "XUI_DebugOverlay.h" +#include "..\..\..\Minecraft.Client\GameRenderer.h" +#include "..\..\MinecraftServer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\..\Minecraft.World\net.minecraft.commands.common.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileOriginal.h" + +#ifdef _DEBUG_MENUS_ENABLED +HRESULT CScene_DebugOverlay::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + MapChildControls(); + + m_items.InsertItems( 0, 512 ); + + for(unsigned int i = 0; i < Item::items.length; ++i) + { + if(Item::items[i] != NULL) + { + //m_items.InsertItems(m_items.GetItemCount(),1); + m_itemIds.push_back(i); + m_items.SetText( m_itemIds.size() - 1, app.GetString( Item::items[i]->getDescriptionId() ) ); + } + } + + m_enchantments.InsertItems( 0, Enchantment::validEnchantments.size() ); + for(unsigned int i = 0; i < Enchantment::validEnchantments.size(); ++i ) + { + Enchantment *ench = Enchantment::validEnchantments.at(i); + + m_enchantmentIds.push_back(ench->id); + m_enchantments.SetText( i, app.GetString( ench->getDescriptionId() ) ); + } + + m_mobs.InsertItems( 0, 21 ); + + m_mobs.SetText( m_mobFactories.size(), L"Chicken" ); + m_mobFactories.push_back(eTYPE_CHICKEN); + m_mobs.SetText( m_mobFactories.size(), L"Cow" ); + m_mobFactories.push_back(eTYPE_COW); + m_mobs.SetText( m_mobFactories.size(), L"Pig" ); + m_mobFactories.push_back(eTYPE_PIG); + m_mobs.SetText( m_mobFactories.size(), L"Sheep" ); + m_mobFactories.push_back(eTYPE_SHEEP); + m_mobs.SetText( m_mobFactories.size(), L"Squid" ); + m_mobFactories.push_back(eTYPE_SQUID); + m_mobs.SetText( m_mobFactories.size(), L"Wolf" ); + m_mobFactories.push_back(eTYPE_WOLF); + m_mobs.SetText( m_mobFactories.size(), L"Creeper" ); + m_mobFactories.push_back(eTYPE_CREEPER); + m_mobs.SetText( m_mobFactories.size(), L"Ghast" ); + m_mobFactories.push_back(eTYPE_GHAST); + m_mobs.SetText( m_mobFactories.size(), L"Pig Zombie" ); + m_mobFactories.push_back(eTYPE_PIGZOMBIE); + m_mobs.SetText( m_mobFactories.size(), L"Skeleton" ); + m_mobFactories.push_back(eTYPE_SKELETON); + m_mobs.SetText( m_mobFactories.size(), L"Slime" ); + m_mobFactories.push_back(eTYPE_SLIME); + m_mobs.SetText( m_mobFactories.size(), L"Spider" ); + m_mobFactories.push_back(eTYPE_SPIDER); + m_mobs.SetText( m_mobFactories.size(), L"Zombie" ); + m_mobFactories.push_back(eTYPE_ZOMBIE); + m_mobs.SetText( m_mobFactories.size(), L"Enderman" ); + m_mobFactories.push_back(eTYPE_ENDERMAN); + m_mobs.SetText( m_mobFactories.size(), L"Silverfish" ); + m_mobFactories.push_back(eTYPE_SILVERFISH); + m_mobs.SetText( m_mobFactories.size(), L"Cave Spider" ); + m_mobFactories.push_back(eTYPE_CAVESPIDER); + m_mobs.SetText( m_mobFactories.size(), L"Mooshroom" ); + m_mobFactories.push_back(eTYPE_MUSHROOMCOW); + m_mobs.SetText( m_mobFactories.size(), L"Snow Golem" ); + m_mobFactories.push_back(eTYPE_SNOWMAN); + m_mobs.SetText( m_mobFactories.size(), L"Ender Dragon" ); + m_mobFactories.push_back(eTYPE_ENDERDRAGON); + m_mobs.SetText( m_mobFactories.size(), L"Blaze" ); + m_mobFactories.push_back(eTYPE_BLAZE); + m_mobs.SetText( m_mobFactories.size(), L"Magma Cube" ); + m_mobFactories.push_back(eTYPE_LAVASLIME); + + + Minecraft *pMinecraft = Minecraft::GetInstance(); + m_setTime.SetValue( pMinecraft->level->getLevelData()->getTime() % 24000 ); + m_setFov.SetValue( (int)pMinecraft->gameRenderer->GetFovVal()); + + XuiSetTimer(m_hObj,0,DEBUG_OVERLAY_UPDATE_TIME_PERIOD); + + bHandled = TRUE; + return S_OK; +} + +// Handler for the XM_NOTIFY message +HRESULT CScene_DebugOverlay::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int nIndex; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if ( hObjPressed == m_items ) + { + nIndex = m_items.GetCurSel(); + if(nIndex<m_itemIds.size()) + { + int id = m_itemIds[nIndex]; + //app.SetXuiServerAction(pNotifyPressData->UserIndex, eXuiServerAction_DropItem, (void *)id); + ClientConnection *conn = Minecraft::GetInstance()->getConnection(ProfileManager.GetPrimaryPad()); + conn->send( GiveItemCommand::preparePacket(dynamic_pointer_cast<Player>(Minecraft::GetInstance()->localplayers[ProfileManager.GetPrimaryPad()]), id) ); + } + } + else if ( hObjPressed == m_mobs ) + { + nIndex = m_mobs.GetCurSel(); + if(nIndex<m_mobFactories.size()) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_SpawnMob,(void *)m_mobFactories[nIndex]); + } + } + else if ( hObjPressed == m_enchantments ) + { + nIndex = m_enchantments.GetCurSel(); + ClientConnection *conn = Minecraft::GetInstance()->getConnection(ProfileManager.GetPrimaryPad()); + conn->send( EnchantItemCommand::preparePacket(dynamic_pointer_cast<Player>(Minecraft::GetInstance()->localplayers[ProfileManager.GetPrimaryPad()]), m_enchantmentIds[nIndex]) ); + } + /*else if( hObjPressed == m_saveToDisc ) // 4J-JEV: Doesn't look like we use this debug option anymore. + { +#ifndef _CONTENT_PACKAGE + pMinecraft->level->save(true, NULL); + + int radius; + m_chunkRadius.GetValue(&radius); + if( radius > 0 ) + { + SaveLimitedFile(radius); + } + else + { + pMinecraft->level->getLevelStorage()->getSaveFile()->DebugFlushToFile(); + } +#endif + }*/ + else if( hObjPressed == m_createSchematic ) + { +#ifndef _CONTENT_PACKAGE + // load from the .xzp file + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + HXUIOBJ hScene; + HRESULT hr; + //const WCHAR XZP_SEPARATOR = L'#'; + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/"); + hr = XuiSceneCreate(szResourceLocator,app.GetSceneName(eUIScene_DebugCreateSchematic,false, false), NULL, &hScene); + this->NavigateForward(hScene); + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DebugCreateSchematic); +#endif + } + else if ( hObjPressed == m_setCamera ) + { +#ifndef _CONTENT_PACKAGE + // load from the .xzp file + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + HXUIOBJ hScene; + HRESULT hr; + //const WCHAR XZP_SEPARATOR = L'#'; + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/"); + hr = XuiSceneCreate(szResourceLocator,app.GetSceneName(eUIScene_DebugSetCamera, false, false), NULL, &hScene); + this->NavigateForward(hScene); + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DebugCreateSchematic); +#endif + } + else if( hObjPressed == m_toggleRain ) + { + //app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_ToggleRain); + ClientConnection *conn = Minecraft::GetInstance()->getConnection(ProfileManager.GetPrimaryPad()); + conn->send( ToggleDownfallCommand::preparePacket() ); + } + else if( hObjPressed == m_toggleThunder ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_ToggleThunder); + } + else if( hObjPressed == m_resetTutorial ) + { + Tutorial::debugResetPlayerSavedProgress( ProfileManager.GetPrimaryPad() ); + } + else if( hObjPressed == m_setDay ) + { + ClientConnection *conn = Minecraft::GetInstance()->getConnection(ProfileManager.GetPrimaryPad()); + conn->send( TimeCommand::preparePacket(false) ); + } + else if( hObjPressed == m_setNight ) + { + ClientConnection *conn = Minecraft::GetInstance()->getConnection(ProfileManager.GetPrimaryPad()); + conn->send( TimeCommand::preparePacket(true) ); + } + + rfHandled = TRUE; + return S_OK; +} + +HRESULT CScene_DebugOverlay::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_PAD_BACK: + + // kill the crafting xui + app.EnableDebugOverlay(false,pInputData->UserIndex); + + rfHandled = TRUE; + + break; + + } + + return S_OK; +} + +HRESULT CScene_DebugOverlay::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled) +{ + if( hObjSource == m_setTime ) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + + // Need to set the time on both levels to stop the flickering as the local level + // tries to predict the time + // Only works if we are on the host machine, but shouldn't break if not + MinecraftServer::SetTime(pNotifyValueChangedData->nValue); + pMinecraft->level->getLevelData()->setTime(pNotifyValueChangedData->nValue); + } + if( hObjSource == m_setFov ) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->gameRenderer->SetFovVal((float)pNotifyValueChangedData->nValue); + } + return S_OK; +} + +HRESULT CScene_DebugOverlay::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft->level != NULL) + { + m_setTime.SetValue( pMinecraft->level->getLevelData()->getTime() % 24000 ); + m_setFov.SetValue( (int)pMinecraft->gameRenderer->GetFovVal()); + } + return S_OK; +} + +void CScene_DebugOverlay::SetSpawnToPlayerPos() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + pMinecraft->level->getLevelData()->setXSpawn((int)pMinecraft->player->x); + pMinecraft->level->getLevelData()->setYSpawn((int)pMinecraft->player->y); + pMinecraft->level->getLevelData()->setZSpawn((int)pMinecraft->player->z); +} + +#ifndef _CONTENT_PACKAGE +void CScene_DebugOverlay::SaveLimitedFile(int chunkRadius) +{ + unordered_map<File, RegionFile *, FileKeyHash, FileKeyEq> newFileCache; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + ConsoleSaveFile *currentSave = pMinecraft->level->getLevelStorage()->getSaveFile(); + + // With a size of 0 but a value in the data pointer we should create a new save + ConsoleSaveFileOriginal newSave( currentSave->getFilename(), NULL, 0, true ); + + // TODO Make this only happen for the new save + //SetSpawnToPlayerPos(); + FileEntry *origFileEntry = currentSave->createFile( wstring( L"level.dat" ) ); + byteArray levelData( origFileEntry->getFileSize() ); + DWORD bytesRead; + currentSave->setFilePointer(origFileEntry,0,NULL,FILE_BEGIN); + currentSave->readFile( + origFileEntry, + levelData.data, // data buffer + origFileEntry->getFileSize(), // number of bytes to read + &bytesRead // number of bytes read + ); + + FileEntry *newFileEntry = newSave.createFile( wstring( L"level.dat" ) ); + DWORD bytesWritten; + newSave.writeFile( newFileEntry, + levelData.data, // data buffer + origFileEntry->getFileSize(), // number of bytes to write + &bytesWritten // number of bytes written + ); + + int playerChunkX = pMinecraft->player->xChunk; + int playerChunkZ = pMinecraft->player->zChunk; + + for(int xPos = playerChunkX - chunkRadius; xPos < playerChunkX + chunkRadius; ++xPos) + { + for(int zPos = playerChunkZ - chunkRadius; zPos < playerChunkZ + chunkRadius; ++zPos) + { + CompoundTag *chunkData=NULL; + + DataInputStream *is = RegionFileCache::getChunkDataInputStream(currentSave, L"", xPos, zPos); + if (is != NULL) + { + chunkData = NbtIo::read((DataInput *)is); + is->deleteChildStream(); + delete is; + } + app.DebugPrintf("Processing chunk (%d, %d)\n", xPos, zPos); + DataOutputStream *os = getChunkDataOutputStream(newFileCache, &newSave, L"", xPos, zPos); + if(os != NULL) + { + NbtIo::write(chunkData, os); + os->close(); + + // 4J Stu - getChunkDataOutputStream makes a new DataOutputStream that points to a new ChunkBuffer( ByteArrayOutputStream ) + // We should clean these up when we are done + os->deleteChildStream(); + delete os; + } + if(chunkData != NULL) + { + delete chunkData; + } + } + } + + newSave.DebugFlushToFile(); +} +#endif + +RegionFile *CScene_DebugOverlay::getRegionFile(unordered_map<File, RegionFile *, FileKeyHash, FileKeyEq> &newFileCache, ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) // 4J - TODO was synchronized +{ + File file( prefix + wstring(L"r.") + _toString(chunkX>>5) + L"." + _toString(chunkZ>>5) + L".mcr" ); + + RegionFile *ref = NULL; + AUTO_VAR(it, newFileCache.find(file)); + if( it != newFileCache.end() ) + ref = it->second; + + // 4J Jev, put back in. + if (ref != NULL) + { + return ref; + } + + RegionFile *reg = new RegionFile(saveFile, &file); + newFileCache[file] = reg; // 4J - this was originally a softReferenc + return reg; +} + +DataOutputStream *CScene_DebugOverlay::getChunkDataOutputStream(unordered_map<File, RegionFile *, FileKeyHash, FileKeyEq> &newFileCache, ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) +{ + RegionFile *r = getRegionFile(newFileCache, saveFile, prefix, chunkX, chunkZ); + return r->getChunkDataOutputStream(chunkX & 31, chunkZ & 31); +} +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugOverlay.h b/Minecraft.Client/Common/XUI/XUI_DebugOverlay.h new file mode 100644 index 00000000..ed5f85c2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugOverlay.h @@ -0,0 +1,72 @@ +#pragma once +using namespace std; +#include "../media/xuiscene_debugoverlay.h" + +#define DEBUG_OVERLAY_UPDATE_TIME_PERIOD 10000 + +class RegionFile; +class DataOutputStream; +class ConsoleSaveFile; +#include "..\..\..\Minecraft.World\File.h" +#include "..\..\..\Minecraft.World\Entity.h" + +class CScene_DebugOverlay : public CXuiSceneImpl +{ +#ifdef _DEBUG_MENUS_ENABLED +private: + CXuiList m_items, m_mobs, m_enchantments; + CXuiControl m_resetTutorial, m_createSchematic, m_toggleRain, m_toggleThunder, m_setCamera; + CXuiControl m_setDay, m_setNight; + CXuiSlider m_chunkRadius, m_setTime,m_setFov; + vector<int> m_itemIds; + vector<eINSTANCEOF> m_mobFactories; + vector<int> m_enchantmentIds; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX( OnNotifyPressEx ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_ChunkRadius, m_chunkRadius) + MAP_CONTROL(IDC_ResetTutorial, m_resetTutorial) + MAP_CONTROL(IDC_CreateSchematic, m_createSchematic) + MAP_CONTROL(IDC_ToggleRain, m_toggleRain) + MAP_CONTROL(IDC_ToggleThunder, m_toggleThunder) + MAP_CONTROL(IDC_SetDay, m_setDay) + MAP_CONTROL(IDC_SetNight, m_setNight) + MAP_CONTROL(IDC_SliderTime, m_setTime) + MAP_CONTROL(IDC_SliderFov, m_setFov) + MAP_CONTROL(IDC_MobList, m_mobs) + MAP_CONTROL(IDC_EnchantmentsList, m_enchantments) + MAP_CONTROL(IDC_ItemsList, m_items) + MAP_CONTROL(IDC_SetCamera, m_setCamera) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DebugOverlay, L"CScene_DebugOverlay", XUI_CLASS_SCENE ) + +private: + void SetSpawnToPlayerPos(); +#ifndef _CONTENT_PACKAGE + void SaveLimitedFile(int chunkRadius); +#endif + RegionFile *getRegionFile(unordered_map<File, RegionFile *, FileKeyHash, FileKeyEq> &newFileCache, ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ); + + DataOutputStream *getChunkDataOutputStream(unordered_map<File, RegionFile *, FileKeyHash, FileKeyEq> &newFileCache, ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ); +#endif +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.cpp b/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.cpp new file mode 100644 index 00000000..66279d1f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.cpp @@ -0,0 +1,178 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XUI_DebugSchematicCreator.h" +#include "..\..\..\Minecraft.World\ChunkSource.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" + +#ifndef _CONTENT_PACKAGE +HRESULT CScene_DebugSchematicCreator::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + MapChildControls(); + + m_startX .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_startY .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_startZ .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_endX .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_endY .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_endZ .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + + m_data = new ConsoleSchematicFile::XboxSchematicInitParam(); + + return S_OK; +} + +HRESULT CScene_DebugSchematicCreator::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if ( hObjPressed == m_createButton ) + { + // We want the start to be even + if(m_data->startX > 0 && m_data->startX%2 != 0) + m_data->startX-=1; + else if(m_data->startX < 0 && m_data->startX%2 !=0) + m_data->startX-=1; + if(m_data->startY < 0) m_data->startY = 0; + else if(m_data->startY > 0 && m_data->startY%2 != 0) + m_data->startY-=1; + if(m_data->startZ > 0 && m_data->startZ%2 != 0) + m_data->startZ-=1; + else if(m_data->startZ < 0 && m_data->startZ%2 !=0) + m_data->startZ-=1; + + // We want the end to be odd to have a total size that is even + if(m_data->endX > 0 && m_data->endX%2 == 0) + m_data->endX+=1; + else if(m_data->endX < 0 && m_data->endX%2 ==0) + m_data->endX+=1; + if(m_data->endY > Level::maxBuildHeight) + m_data->endY = Level::maxBuildHeight; + else if(m_data->endY > 0 && m_data->endY%2 == 0) + m_data->endY+=1; + else if(m_data->endY < 0 && m_data->endY%2 ==0) + m_data->endY+=1; + if(m_data->endZ > 0 && m_data->endZ%2 == 0) + m_data->endZ+=1; + else if(m_data->endZ < 0 && m_data->endZ%2 ==0) + m_data->endZ+=1; + + wstring value = m_name.GetText(); + if(!value.empty()) + { + swprintf(m_data->name,64,L"%ls", value.c_str()); + } + else + { + swprintf(m_data->name,64,L"schematic"); + } + + m_data->bSaveMobs = m_saveMobs.IsChecked(); + +#ifdef _XBOX + if (m_useXboxCompr.IsChecked()) + m_data->compressionType = Compression::eCompressionType_LZXRLE; + else +#endif + m_data->compressionType = Compression::eCompressionType_RLE; + + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_ExportSchematic, (void *)m_data); + + NavigateBack(); + rfHandled = TRUE; + } + return S_OK; +} + +HRESULT CScene_DebugSchematicCreator::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_PAD_BACK: + NavigateBack(); + + rfHandled = TRUE; + + break; + + } + + return S_OK; +} + +HRESULT CScene_DebugSchematicCreator::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled) +{ + if(hObjSource == m_startX) + { + int iVal = 0; + wstring value = m_startX.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->startX = iVal; + } + } + else if(hObjSource == m_startY) + { + int iVal = 0; + wstring value = m_startY.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->startY = iVal; + } + } + else if(hObjSource == m_startZ) + { + int iVal = 0; + wstring value = m_startZ.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->startZ = iVal; + } + } + else if(hObjSource == m_endX) + { + int iVal = 0; + wstring value = m_endX.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->endX = iVal; + } + } + else if(hObjSource == m_endY) + { + int iVal = 0; + wstring value = m_endY.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->endY = iVal; + } + } + else if(hObjSource == m_endZ) + { + int iVal = 0; + wstring value = m_endZ.GetText(); + if(!value.empty()) iVal = _fromString<int>( value ); + + if( iVal >= (LEVEL_MAX_WIDTH * -16) || iVal < (LEVEL_MAX_WIDTH * 16)) + { + m_data->endZ = iVal; + } + } + return S_OK; +} +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.h b/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.h new file mode 100644 index 00000000..b502d110 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.h @@ -0,0 +1,49 @@ +#pragma once +#include "..\Media\xuiscene_debug_schematic_create.h" +#include "XUI_Ctrl_4JEdit.h" +#include "..\..\Common\GameRules\ConsoleSchematicFile.h" + +class CScene_DebugSchematicCreator : public CXuiSceneImpl +{ +#ifndef _CONTENT_PACKAGE +private: + CXuiControl m_createButton; + CXuiCtrl4JEdit m_name, m_startX, m_startY, m_startZ, m_endX, m_endY, m_endZ; + CXuiCheckbox m_saveMobs, m_useXboxCompr; + + ConsoleSchematicFile::XboxSchematicInitParam *m_data; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX( OnNotifyPressEx ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_CreateButton, m_createButton) + MAP_CONTROL(IDC_Name, m_name) + MAP_CONTROL(IDC_StartX, m_startX) + MAP_CONTROL(IDC_StartY, m_startY) + MAP_CONTROL(IDC_StartZ, m_startZ) + MAP_CONTROL(IDC_EndX, m_endX) + MAP_CONTROL(IDC_EndY, m_endY) + MAP_CONTROL(IDC_EndZ, m_endZ) + MAP_CONTROL(IDC_SaveMobs, m_saveMobs) + MAP_CONTROL(IDC_UseXboxCompression, m_useXboxCompr) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DebugSchematicCreator, L"CScene_DebugSchematicCreator", XUI_CLASS_SCENE ) +#endif +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.cpp b/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.cpp new file mode 100644 index 00000000..2227e895 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.cpp @@ -0,0 +1,152 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XUI_DebugSetCamera.h" +#include "..\..\..\Minecraft.World\ChunkSource.h" + +// #include "..\..\Xbox\4JLibs\inc\4J_Input.h" + +#include "..\..\Minecraft.h" +#include "..\..\MultiplayerLocalPlayer.h" + +#ifndef _CONTENT_PACKAGE +HRESULT CScene_DebugSetCamera::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + MapChildControls(); + + m_camX .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_camY .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_camZ .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_yRot .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + m_elevation .SetKeyboardType(C_4JInput::EKeyboardMode_Numeric); + + int playerNo = 0; + currentPosition = new DebugSetCameraPosition(); + + currentPosition->player = playerNo; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + if (pMinecraft != NULL) + { + Vec3 *vec = pMinecraft->localplayers[playerNo]->getPos(1.0); + + currentPosition->m_camX = vec->x; + currentPosition->m_camY = vec->y - 1.62;// pMinecraft->localplayers[playerNo]->getHeadHeight(); + currentPosition->m_camZ = vec->z; + + currentPosition->m_yRot = pMinecraft->localplayers[playerNo]->yRot; + currentPosition->m_elev = pMinecraft->localplayers[playerNo]->xRot; + } + + m_camX.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + m_camY.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + m_camZ.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + m_yRot.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + m_elevation.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + + m_camX.SetText((CONST WCHAR *) _toString<double>(currentPosition->m_camX).c_str()); + m_camY.SetText((CONST WCHAR *) _toString<double>(currentPosition->m_camY + 1.62).c_str()); + m_camZ.SetText((CONST WCHAR *) _toString<double>(currentPosition->m_camZ).c_str()); + + m_yRot.SetText((CONST WCHAR *) _toString<double>(currentPosition->m_yRot).c_str()); + m_elevation.SetText((CONST WCHAR *) _toString<double>(currentPosition->m_elev).c_str()); + + //fpp = new FreezePlayerParam(); + //fpp->player = playerNo; + //fpp->freeze = true; + + //m_lockPlayer.SetCheck( !fpp->freeze ); + + m_lockPlayer.SetCheck( app.GetFreezePlayers() ); + + return S_OK; +} + +HRESULT CScene_DebugSetCamera::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if (hObjPressed == m_teleport) + { + app.SetXuiServerAction( ProfileManager.GetPrimaryPad(), + eXuiServerAction_SetCameraLocation, + (void *)currentPosition); + rfHandled = TRUE; + } + else if (hObjPressed == m_lockPlayer) + { + app.SetFreezePlayers( m_lockPlayer.IsChecked() ); + + rfHandled = TRUE; + } + + return S_OK; +} + +HRESULT CScene_DebugSetCamera::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_PAD_START: + case VK_PAD_BACK: + NavigateBack(); + + //delete currentPosition; + //currentPosition = NULL; + + rfHandled = TRUE; + break; + } + return S_OK; +} + +HRESULT CScene_DebugSetCamera::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled) +{ + + // Text Boxes + if (hObjSource == m_camX) + { + double iVal = 0; + wstring value = m_camX.GetText(); + if(!value.empty()) iVal = _fromString<double>( value ); + currentPosition->m_camX = iVal; + bHandled = TRUE; + } + else if (hObjSource == m_camY) + { + double iVal = 0; + wstring value = m_camY.GetText(); + if(!value.empty()) iVal = _fromString<double>( value ); + currentPosition->m_camY = iVal - 1.62; + bHandled = TRUE; + } + else if (hObjSource == m_camZ) + { + double iVal = 0; + wstring value = m_camZ.GetText(); + if(!value.empty()) iVal = _fromString<double>( value ); + currentPosition->m_camZ = iVal; + bHandled = TRUE; + } + else if (hObjSource == m_yRot) + { + double iVal = 0; + wstring value = m_yRot.GetText(); + if(!value.empty()) iVal = _fromString<double>( value ); + currentPosition->m_yRot = iVal; + bHandled = TRUE; + } + else if (hObjSource == m_elevation) + { + double iVal = 0; + wstring value = m_elevation.GetText(); + if(!value.empty()) iVal = _fromString<double>( value ); + currentPosition->m_elev = iVal; + bHandled = TRUE; + } + + return S_OK; +} +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.h b/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.h new file mode 100644 index 00000000..1bc662e9 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugSetCamera.h @@ -0,0 +1,54 @@ +#pragma once +#include "..\Media\xuiscene_debug_set_camera.h" +#include "XUI_Ctrl_4JEdit.h" +#include "..\..\Common\GameRules\ConsoleSchematicFile.h" + +class CScene_DebugSetCamera : public CXuiSceneImpl +{ +public: + typedef struct _FreezePlayerParam + { + int player; + bool freeze; + } FreezePlayerParam; + +#ifndef _CONTENT_PACKAGE +private: + CXuiCtrl4JEdit m_camX, m_camY, m_camZ, m_yRot, m_elevation; + CXuiCheckbox m_lockPlayer; + CXuiControl m_teleport; + + DebugSetCameraPosition *currentPosition; + FreezePlayerParam *fpp; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX( OnNotifyPressEx ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_CamX, m_camX) + MAP_CONTROL(IDC_CamY, m_camY) + MAP_CONTROL(IDC_CamZ, m_camZ) + MAP_CONTROL(IDC_YRot, m_yRot) + MAP_CONTROL(IDC_Elevation, m_elevation) + MAP_CONTROL(IDC_LockPlayer, m_lockPlayer) + MAP_CONTROL(IDC_Teleport, m_teleport) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged *pNotifyValueChangedData, BOOL &bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DebugSetCamera, L"CScene_DebugSetCamera", XUI_CLASS_SCENE ) +#endif +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugTips.cpp b/Minecraft.Client/Common/XUI/XUI_DebugTips.cpp new file mode 100644 index 00000000..aaa3b06f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugTips.cpp @@ -0,0 +1,73 @@ +#include "stdafx.h" + +#include <assert.h> +#include "XUI_DebugTips.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_DebugTips::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + m_bIgnoreInput = false; + + MapChildControls(); + + // Display the tooltips + //ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT); + // display the next tip + wstring wsText=app.FormatHTMLString(m_iPad,app.GetString(app.GetNextTip())); + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=14><DIV ALIGN=CENTER>",app.GetHTMLColour(eHTMLColor_White)); + wsText= startTags + wsText + L"</DIV>"; + XuiControlSetText(m_tip,wsText.c_str()); + + return S_OK; +} + + +HRESULT CScene_DebugTips::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + //ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + + switch(pInputData->dwKeyCode) + { + case VK_PAD_A: + { + + + // next tip + // display the next tip + wstring wsText=app.FormatHTMLString(m_iPad,app.GetString(app.GetNextTip())); + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=14><DIV ALIGN=CENTER>",app.GetHTMLColour(eHTMLColor_White)); + wsText= startTags + wsText + L"</DIV>"; + XuiControlSetText(m_tip,wsText.c_str()); + + rfHandled = TRUE; + } + break; + + case VK_PAD_B: + case VK_PAD_START: + case VK_ESCAPE: + + app.NavigateBack(m_iPad); + + rfHandled = TRUE; + + break; +#ifndef _CONTENT_PACKAGE + case VK_PAD_LTHUMB_PRESS: +#ifdef _XBOX + app.OverrideFontRenderer(true); +#endif + break; +#endif + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_DebugTips.h b/Minecraft.Client/Common/XUI/XUI_DebugTips.h new file mode 100644 index 00000000..10627d3c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_DebugTips.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../media/xuiscene_DebugTips.h" + + + + +class CScene_DebugTips : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiControl m_tip; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Tip, m_tip) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_DebugTips, L"CScene_DebugTips", XUI_CLASS_SCENE ) + +private: + bool m_bIgnoreInput; + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.cpp b/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.cpp new file mode 100644 index 00000000..f66c0d70 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.cpp @@ -0,0 +1,375 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\..\Minecraft.h" +#include "..\..\ProgressRenderer.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\Common\Tutorial\TutorialMode.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_FullscreenProgress::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + m_buttonConfirm.SetText( app.GetString( IDS_CONFIRM_OK ) ); + + LoadingInputParams *params = (LoadingInputParams *)pInitData->pvInitData; + + m_CompletionData = params->completionData; + m_iPad=params->completionData->iPad; + m_cancelFunc = params->cancelFunc; + m_cancelFuncParam = params->m_cancelFuncParam; + m_completeFunc = params->completeFunc; + m_completeFuncParam = params->m_completeFuncParam; + m_bWasCancelled=false; + + thread = new C4JThread(params->func, params->lpParam, "FullscreenProgress"); + thread->SetProcessor(3); // TODO 4J Stu - Make sure this is a good thread/core to use + + m_threadCompleted = false; + threadStarted = false; + //ResumeThread( thread ); + if( CXuiSceneBase::GetPlayerBasePosition(m_iPad) != CXuiSceneBase::e_BaseScene_Fullscreen && CXuiSceneBase::GetPlayerBasePosition(m_iPad) != CXuiSceneBase::e_BaseScene_NotSet) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, params->completionData->bShowLogo ); + } + + CXuiSceneBase::ShowBackground( m_iPad, params->completionData->bShowBackground ); + ui.SetTooltips( m_iPad, -1, params->cancelText, -1, -1 ); + + // Clear the progress text + Minecraft *pMinecraft=Minecraft::GetInstance(); + pMinecraft->progressRenderer->progressStart(-1); + pMinecraft->progressRenderer->progressStage(-1); + + // set the tip + wstring wsText=app.FormatHTMLString(m_iPad,app.GetString(app.GetNextTip())); + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=14><DIV ALIGN=CENTER>",app.GetHTMLColour(eHTMLColor_White)); + wsText= startTags + wsText + L"</DIV>"; + XuiControlSetText(m_tip, wsText.c_str()); + + m_tip.SetShow( m_CompletionData->bShowTips ); + + return S_OK; +} + +// The framework calls this handler when the object is to be destroyed. +HRESULT CScene_FullscreenProgress::OnDestroy() +{ + if( thread != NULL && thread != INVALID_HANDLE_VALUE ) + delete thread; + + if( m_CompletionData != NULL ) + delete m_CompletionData; + + return S_OK; +} + +HRESULT CScene_FullscreenProgress::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + // 4J-JEV: Fix for Xbox360 #162749 - TU17: Save Upload: Content: UI: Player is presented with non-functional Tooltips after the Upload Save For Xbox One is completed. + if( m_cancelFunc != NULL && !m_threadCompleted ) + { + m_cancelFunc( m_cancelFuncParam ); + m_bWasCancelled=true; + } + break; + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_FullscreenProgress::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_FullscreenProgress::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(m_threadCompleted == true && hObjPressed == m_buttonConfirm) + { + // if there's a complete function, call it + if(m_completeFunc) + { + m_completeFunc(m_completeFuncParam); + } + switch(m_CompletionData->type) + { + case e_ProgressCompletion_NavigateBack: + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, FALSE ); + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, TRUE ); + app.NavigateBack(m_CompletionData->iPad); + // Show the other players scenes + CXuiSceneBase::ShowOtherPlayersBaseScene(m_CompletionData->iPad, true); + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_NavigateBackToScene: + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, FALSE ); + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, TRUE ); + CXuiSceneBase::ShowOtherPlayersBaseScene(m_CompletionData->iPad, true); + // If the pause menu is still active, then navigate back + // Otherwise close everything then navigate forwads to the pause menu + if(app.IsSceneInStack(m_CompletionData->iPad, m_CompletionData->scene)) + { + app.NavigateBack(m_CompletionData->iPad,false, m_CompletionData->scene); + } + else + { + app.CloseXuiScenesAndNavigateToScene(m_CompletionData->iPad,m_CompletionData->scene); + } + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_CloseUIScenes: + app.CloseXuiScenes(m_CompletionData->iPad); + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_CloseAllPlayersUIScenes: + app.CloseAllPlayersXuiScenes(); + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_NavigateToHomeMenu: + app.NavigateToHomeMenu(); + ui.UpdatePlayerBasePositions(); + break; + } + } + + return S_OK; +} + +HRESULT CScene_FullscreenProgress::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + // This gets called every frame, so use it to update our two text boxes + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + int title = pMinecraft->progressRenderer->getCurrentTitle(); + if(title >= 0) + m_title.SetText( app.GetString( title ) ); + else + m_title.SetText( L"" ); + + int status = pMinecraft->progressRenderer->getCurrentStatus(); + if(status >= 0) + m_status.SetText( app.GetString( status ) ); + else + m_status.SetText( L"" ); + + return S_OK; +} + +HRESULT CScene_FullscreenProgress::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(!threadStarted) + { + thread->Run(); + threadStarted = true; + XuiSetTimer(m_hObj,TIMER_FULLSCREEN_PROGRESS,TIMER_FULLSCREEN_PROGRESS_TIME); + XuiSetTimer(m_hObj,TIMER_FULLSCREEN_TIPS,TIMER_FULLSCREEN_TIPS_TIME); + } + return S_OK; +} + +HRESULT CScene_FullscreenProgress::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + int code = thread->GetExitCode(); + DWORD exitcode = *((DWORD *)&code); + + //app.DebugPrintf("CScene_FullscreenProgress Timer %d\n",pTimer->nId); + + if( exitcode != STILL_ACTIVE ) + { + // 4J-PB - need to kill the timers whatever happens + XuiKillTimer(m_hObj,TIMER_FULLSCREEN_PROGRESS); + XuiKillTimer(m_hObj,TIMER_FULLSCREEN_TIPS); + XuiControlSetText(m_tip,L""); + + // hide the tips bar in cause we're waiting for the user to press ok + m_tip.SetShow( FALSE ); + + // If we failed (currently used by network connection thread), navigate back + if( exitcode != S_OK ) + { + if( exitcode == ERROR_CANCELLED ) + { + // Current thread cancelled for whatever reason + // Currently used only for the CConsoleMinecraftApp::RemoteSaveThreadProc thread + // Assume to just ignore this thread as something else is now running that will + // cause another action + } + else + { + /*m_threadCompleted = true; + m_buttonConfirm.SetShow( TRUE ); + m_buttonConfirm.SetFocus( m_CompletionData->iPad ); + m_CompletionData->type = e_ProgressCompletion_NavigateToHomeMenu; + + int exitReasonStringId; + switch( app.GetDisconnectReason() ) + { + default: + exitReasonStringId = IDS_CONNECTION_FAILED; + } + Minecraft *pMinecraft=Minecraft::GetInstance(); + pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId );*/ + //app.NavigateBack(m_CompletionData->iPad); + + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + + app.NavigateToHomeMenu(); + ui.UpdatePlayerBasePositions(); + } + } + else + { + if(( m_CompletionData->bRequiresUserAction == TRUE ) && (!m_bWasCancelled)) + { + m_threadCompleted = true; + m_buttonConfirm.SetShow( TRUE ); + m_buttonConfirm.SetFocus( ProfileManager.GetPrimaryPad() ); + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT, -1, -1, -1 ); + } + else + { + if(m_bWasCancelled) + { + m_threadCompleted = true; + } + app.DebugPrintf("FullScreenProgress complete with action: "); + switch(m_CompletionData->type) + { + case e_ProgressCompletion_AutosaveNavigateBack: + app.DebugPrintf("e_ProgressCompletion_AutosaveNavigateBack\n"); + { + // store these - they get wiped by the destroy caused by navigateback + int iPad=m_CompletionData->iPad; + //bool bAutosaveWasMenuDisplayed=m_CompletionData->bAutosaveWasMenuDisplayed; + CXuiSceneBase::ShowBackground( iPad, FALSE ); + CXuiSceneBase::ShowLogo(iPad, FALSE ); + app.NavigateBack(iPad); + + // 4J Stu - Fix for #65437 - Customer Encountered: Code: Settings: Autosave option doesn't work when the Host goes into idle state during gameplay. + // Autosave obviously cannot occur if an ignore autosave menu is displayed, so even if we navigate back to a scene and not empty + // then we still want to reset this flag which was set true by the navigate to the fullscreen progress + app.SetIgnoreAutosaveMenuDisplayed(iPad, false); + + // the navigate back leaves SetMenuDisplayed as true, but there may not have been a menu up when autosave was kicked off +// if(bAutosaveWasMenuDisplayed==false) +// { +// app.SetMenuDisplayed(iPad,false); +// } + // Show the other players scenes + CXuiSceneBase::ShowOtherPlayersBaseScene(iPad, true); + // This just allows it to be shown + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(true); + ui.UpdatePlayerBasePositions(); + } + break; + + case e_ProgressCompletion_NavigateBack: + app.DebugPrintf("e_ProgressCompletion_NavigateBack\n"); + { + // store these - they get wiped by the destroy caused by navigateback + int iPad=m_CompletionData->iPad; + + CXuiSceneBase::ShowBackground( iPad, FALSE ); + CXuiSceneBase::ShowBackground( iPad, TRUE ); + app.NavigateBack(iPad); + // Show the other players scenes + CXuiSceneBase::ShowOtherPlayersBaseScene(iPad, true); + ui.UpdatePlayerBasePositions(); + } + break; + case e_ProgressCompletion_NavigateBackToScene: + app.DebugPrintf("e_ProgressCompletion_NavigateBackToScene\n"); + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, FALSE ); + CXuiSceneBase::ShowBackground( m_CompletionData->iPad, TRUE ); + CXuiSceneBase::ShowOtherPlayersBaseScene(m_CompletionData->iPad, true); + // If the pause menu is still active, then navigate back + // Otherwise close everything then navigate forwads to the pause menu + if(app.IsSceneInStack(m_CompletionData->iPad, m_CompletionData->scene)) + { + app.NavigateBack(m_CompletionData->iPad,false, m_CompletionData->scene); + } + else + { + app.CloseXuiScenesAndNavigateToScene(m_CompletionData->iPad,m_CompletionData->scene); + } + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_CloseUIScenes: + app.DebugPrintf("e_ProgressCompletion_CloseUIScenes\n"); + app.CloseXuiScenes(m_CompletionData->iPad); + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_CloseAllPlayersUIScenes: + app.DebugPrintf("e_ProgressCompletion_CloseAllPlayersUIScenes\n"); + app.CloseAllPlayersXuiScenes(); + ui.UpdatePlayerBasePositions(); + break; + case e_ProgressCompletion_NavigateToHomeMenu: + app.DebugPrintf("e_ProgressCompletion_NavigateToHomeMenu\n"); + app.NavigateToHomeMenu(); + //ui.UpdatePlayerBasePositions(); + break; + default: + app.DebugPrintf("Default\n"); + break; + } + } + } + } + else + { + switch(pTimer->nId) + { + case TIMER_FULLSCREEN_PROGRESS: + break; + case TIMER_FULLSCREEN_TIPS: + { + // display the next tip + wstring wsText=app.FormatHTMLString(m_iPad,app.GetString(app.GetNextTip())); + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=14><DIV ALIGN=CENTER>",app.GetHTMLColour(eHTMLColor_White)); + wsText= startTags + wsText + L"</DIV>"; + XuiControlSetText(m_tip,wsText.c_str()); + } + break; + } + } + + bHandled = TRUE; + + return( S_OK ); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.h b/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.h new file mode 100644 index 00000000..271a5781 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_FullscreenProgress.h @@ -0,0 +1,68 @@ +#pragma once +#include "../media/xuiscene_fullscreenprogress.h" +#include "..\..\..\Minecraft.World\C4JThread.h" + +#define ERROR_FULLSCREENPROGRESS_ + +class CScene_FullscreenProgress : public CXuiSceneImpl +{ +private: + C4JThread* thread; + bool threadStarted; + UIFullscreenProgressCompletionData *m_CompletionData; + + static const int TIMER_FULLSCREEN_PROGRESS = 0; + static const int TIMER_FULLSCREEN_TIPS = 1; + + static const int TIMER_FULLSCREEN_PROGRESS_TIME = 500; + static const int TIMER_FULLSCREEN_TIPS_TIME = 7000; +protected: + // Control and Element wrapper objects. + CXuiControl m_title, m_status, m_buttonConfirm, m_tip; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_TRANSITION_START( OnTransitionStart ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Title, m_title) + MAP_CONTROL(IDC_Tip, m_tip) + MAP_CONTROL(IDC_Status, m_status) + MAP_CONTROL(IDC_ButtonConfirm, m_buttonConfirm) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_FullscreenProgress, L"CScene_FullscreenProgress", XUI_CLASS_SCENE ) + +private: + bool m_threadCompleted; + int m_iPad; + void (*m_cancelFunc)(LPVOID param); + void (*m_completeFunc)(LPVOID param); + LPVOID m_cancelFuncParam; + LPVOID m_completeFuncParam; + D3DXVECTOR3 m_OriginalPosition; + bool m_bWasCancelled; + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_HUD.cpp b/Minecraft.Client/Common/XUI/XUI_HUD.cpp new file mode 100644 index 00000000..286f06a7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HUD.cpp @@ -0,0 +1,464 @@ +#include "stdafx.h" +#include "XUI_HUD.h" +#include "..\..\Minecraft.h" +#include "..\..\Gui.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\Random.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.effect.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.material.h" + +HRESULT CXuiSceneHud::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + XuiElementGetPosition(m_hObj,&m_OriginalPosition); + + m_tickCount = 0; + + return S_OK; +} + +HRESULT CXuiSceneHud::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + + app.ReloadHudScene(m_iPad, bJoining); + + return S_OK; +} + +HRESULT CXuiSceneHud::OnCustomMessage_TickScene() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft->localplayers[m_iPad] == NULL || pMinecraft->localgameModes[m_iPad] == NULL) return S_OK; + + ++m_tickCount; + + int iGuiScale; + + if(pMinecraft->localplayers[m_iPad]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + iGuiScale=app.GetGameSettings(m_iPad,eGameSetting_UISize); + } + else + { + iGuiScale=app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen); + } + + int startFrame = 0; + switch(iGuiScale) + { + case 0: + XuiElementFindNamedFrame(m_hObj, L"ScaleSmall", &startFrame); + break; + case 1: + XuiElementFindNamedFrame(m_hObj, L"Normal", &startFrame); + break; + case 2: + XuiElementFindNamedFrame(m_hObj, L"ScaleLarge", &startFrame); + break; + } + if(startFrame >= 0) XuiElementPlayTimeline( m_hObj, startFrame, startFrame, startFrame, FALSE, TRUE); + + // Move the whole hud group if we are not in fullscreen + if(pMinecraft->localplayers[m_iPad]->m_iScreenSection != C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + int iTooltipsYOffset = 0; + // if tooltips are off, set the y offset to zero + if(app.GetGameSettings(m_iPad,eGameSetting_Tooltips)==0) + { + switch(iGuiScale) + { + case 0: + iTooltipsYOffset=28;//screenHeight/10; + break; + case 2: + iTooltipsYOffset=28;//screenHeight/10; + break; + case 1: + default: + iTooltipsYOffset=28;//screenHeight/10; + break; + } + } + + float fHeight, fWidth; + GetBounds(&fWidth, &fHeight); + + int iSafezoneYHalf = 0; + switch(pMinecraft->localplayers[m_iPad]->m_iScreenSection) + { + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + iSafezoneYHalf = -fHeight/10;// 5% (need to treat the whole screen is 2x this screen) + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + iSafezoneYHalf = (fHeight/2)-(fHeight/10);// 5% (need to treat the whole screen is 2x this screen) + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: + iSafezoneYHalf = (fHeight/2)-(fHeight/10);// 5% (need to treat the whole screen is 2x this screen) + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + iSafezoneYHalf = -fHeight/10; // 5% (the whole screen is 2x this screen) + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + iSafezoneYHalf = -fHeight/10; // 5% (the whole screen is 2x this screen) + break; + }; + + D3DXVECTOR3 pos; + m_hudGroup.GetPosition(&pos); + pos.y = iTooltipsYOffset + iSafezoneYHalf; + m_hudGroup.SetPosition(&pos); + } + + // Update inventory + float opacity = 1.0f; + GetOpacity(&opacity); + int selected = pMinecraft->localplayers[m_iPad]->inventory->selected; + for(unsigned int j = 0; j < 9; ++j) + { + m_hotbarIcon[j]->SetSlot(m_hotbarIcon[j]->m_hObj,pMinecraft->localplayers[m_iPad]->inventoryMenu->getSlot(InventoryMenu::USE_ROW_SLOT_START + j)); + m_hotbarIcon[j]->SetUserIndex(m_hotbarIcon[j]->m_hObj, m_iPad ); + + if(j == selected) + { + m_hotbarIcon[j]->SetEnable(FALSE); //Makes the selected overlay display + } + else + { + m_hotbarIcon[j]->SetEnable(TRUE); //Hides the selected overlay display + } + + m_hotbarIcon[j]->SetAlpha( m_hotbarIcon[j]->m_hObj, opacity ); + } + + // Update xp progress + if (pMinecraft->localgameModes[m_iPad]->canHurtPlayer()) + { + int xpNeededForNextLevel = pMinecraft->localplayers[m_iPad]->getXpNeededForNextLevel(); + int progress = (int)(pMinecraft->localplayers[m_iPad]->experienceProgress *xpNeededForNextLevel); + + m_ExperienceProgress.SetShow(TRUE); + m_ExperienceProgress.SetRange(0,xpNeededForNextLevel); + m_ExperienceProgress.SetValue(progress); + } + else + { + m_ExperienceProgress.SetShow(FALSE); + } + + // Update xp level + if (pMinecraft->localgameModes[m_iPad]->hasExperience() && pMinecraft->localplayers[m_iPad]->experienceLevel > 0) + { + m_xpLevel.SetShow(TRUE); + + wchar_t formatted[10]; + swprintf(formatted, 10, L"%d",pMinecraft->localplayers[m_iPad]->experienceLevel); + + m_xpLevel.SetText(formatted); + } + else + { + m_xpLevel.SetShow(FALSE); + } + + if (pMinecraft->localgameModes[m_iPad]->canHurtPlayer()) + { + m_random.setSeed(m_tickCount * 312871); + + // Update health + int heartOffsetIndex = -1; + if (pMinecraft->localplayers[m_iPad]->hasEffect(MobEffect::regeneration)) + { + heartOffsetIndex = m_tickCount % 25; + } + + bool blink = pMinecraft->localplayers[m_iPad]->invulnerableTime / 3 % 2 == 1; + if (pMinecraft->localplayers[m_iPad]->invulnerableTime < 10) blink = false; + int iHealth = pMinecraft->localplayers[m_iPad]->getHealth(); + int iLastHealth = pMinecraft->localplayers[m_iPad]->lastHealth; + bool bHasPoison = pMinecraft->localplayers[m_iPad]->hasEffect(MobEffect::poison); + for (int icon = 0; icon < Player::MAX_HEALTH / 2; icon++) + { + if(blink) + { + if (icon * 2 + 1 < iLastHealth || icon * 2 + 1 < iHealth) + { + // Full + if(bHasPoison) + { + m_healthIcon[icon].PlayVisualRange(L"FullPoisonFlash",NULL,L"FullPoisonFlash"); + } + else + { + m_healthIcon[icon].PlayVisualRange(L"FullFlash",NULL,L"FullFlash"); + } + } + else if (icon * 2 + 1 == iLastHealth || icon * 2 + 1 == iHealth) + { + // Half + if(bHasPoison) + { + m_healthIcon[icon].PlayVisualRange(L"HalfPoisonFlash",NULL,L"HalfPoisonFlash"); + } + else + { + m_healthIcon[icon].PlayVisualRange(L"HalfFlash",NULL,L"HalfFlash"); + } + } + else + { + // Empty + m_healthIcon[icon].PlayVisualRange(L"NormalFlash",NULL,L"NormalFlash"); + } + } + else + { + if (icon * 2 + 1 < iHealth) + { + // Full + if(bHasPoison) + { + m_healthIcon[icon].PlayVisualRange(L"FullPoison",NULL,L"FullPoison"); + } + else + { + m_healthIcon[icon].PlayVisualRange(L"Full",NULL,L"Full"); + } + } + else if (icon * 2 + 1 == iHealth) + { + // Half + if(bHasPoison) + { + m_healthIcon[icon].PlayVisualRange(L"HalfPoison",NULL,L"HalfPoison"); + } + else + { + m_healthIcon[icon].PlayVisualRange(L"Half",NULL,L"Half"); + } + } + else + { + // Empty + m_healthIcon[icon].PlayVisualRange(L"Normal",NULL,L"Normal"); + } + } + + float yo = 0; + if (iHealth <= 4) + { + yo = (float)m_random.nextInt(2) * (iGuiScale+1); + } + if (icon == heartOffsetIndex) + { + yo = -2.0f * (iGuiScale+1); + } + + D3DXVECTOR3 pos; + m_healthIcon[icon].GetPosition(&pos); + // TODO - 4J Stu - This should be scaled based on gui scale and overall size (ie full, split or 480) + pos.y = yo; + m_healthIcon[icon].SetPosition(&pos); + + } + + // Update food + bool foodBlink = false; + FoodData *foodData = pMinecraft->localplayers[m_iPad]->getFoodData(); + int food = foodData->getFoodLevel(); + int oldFood = foodData->getLastFoodLevel(); + bool hasHungerEffect = pMinecraft->localplayers[m_iPad]->hasEffect(MobEffect::hunger); + int saturationLevel = pMinecraft->localplayers[m_iPad]->getFoodData()->getSaturationLevel(); + for (int icon = 0; icon < 10; icon++) + { + if(foodBlink) + { + if (icon * 2 + 1 < oldFood || icon * 2 + 1 < food) + { + // Full + if(hasHungerEffect) + { + m_foodIcon[icon].PlayVisualRange(L"FullPoisonFlash",NULL,L"FullPoisonFlash"); + } + else + { + m_foodIcon[icon].PlayVisualRange(L"FullFlash",NULL,L"FullFlash"); + } + } + else if (icon * 2 + 1 == oldFood || icon * 2 + 1 == food) + { + // Half + if(hasHungerEffect) + { + m_foodIcon[icon].PlayVisualRange(L"HalfPoisonFlash",NULL,L"HalfPoisonFlash"); + } + else + { + m_foodIcon[icon].PlayVisualRange(L"HalfFlash",NULL,L"HalfFlash"); + } + } + else + { + // Empty + m_foodIcon[icon].PlayVisualRange(L"NormalFlash",NULL,L"NormalFlash"); + } + } + else + { + if (icon * 2 + 1 < food) + { + // Full + if(hasHungerEffect) + { + m_foodIcon[icon].PlayVisualRange(L"FullPoison",NULL,L"FullPoison"); + } + else + { + m_foodIcon[icon].PlayVisualRange(L"Full",NULL,L"Full"); + } + } + else if (icon * 2 + 1 == food) + { + // Half + if(hasHungerEffect) + { + m_foodIcon[icon].PlayVisualRange(L"HalfPoison",NULL,L"HalfPoison"); + } + else + { + m_foodIcon[icon].PlayVisualRange(L"Half",NULL,L"Half"); + } + } + else + { + // Empty + if(hasHungerEffect) + { + m_foodIcon[icon].PlayVisualRange(L"NormalPoison",NULL,L"NormalPoison"); + } + else + { + m_foodIcon[icon].PlayVisualRange(L"Normal",NULL,L"Normal"); + } + } + } + + + float yo = 0; + if (saturationLevel <= 0) + { + if ((m_tickCount % (food * 3 + 1)) == 0) + { + yo = (float)(m_random.nextInt(3) - 1) * (iGuiScale+1); + } + } + + D3DXVECTOR3 pos; + m_foodIcon[icon].GetPosition(&pos); + // TODO - 4J Stu - This should be scaled based on gui scale and overall size (ie full, split or 480) + pos.y = yo; + m_foodIcon[icon].SetPosition(&pos); + } + + // Update armour + int armor = pMinecraft->localplayers[m_iPad]->getArmorValue(); + if(armor > 0) + { + m_armourGroup.SetShow(TRUE); + for (int icon = 0; icon < 10; icon++) + { + if (icon * 2 + 1 < armor) m_armourIcon[icon].PlayVisualRange(L"Full",NULL,L"Full"); + else if (icon * 2 + 1 == armor) m_armourIcon[icon].PlayVisualRange(L"Half",NULL,L"Half"); + else if (icon * 2 + 1 > armor) m_armourIcon[icon].PlayVisualRange(L"Normal",NULL,L"Normal"); + } + } + else + { + m_armourGroup.SetShow(FALSE); + } + + // Update air + if (pMinecraft->localplayers[m_iPad]->isUnderLiquid(Material::water)) + { + m_airGroup.SetShow(TRUE); + int count = (int) ceil((pMinecraft->localplayers[m_iPad]->getAirSupply() - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY); + int extra = (int) ceil((pMinecraft->localplayers[m_iPad]->getAirSupply()) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count; + for (int icon = 0; icon < 10; icon++) + { + // Air bubbles + if (icon < count) + { + m_airIcon[icon].SetShow(TRUE); + m_airIcon[icon].PlayVisualRange(L"Bubble",NULL,L"Bubble"); + } + else if(icon < count + extra) + { + m_airIcon[icon].SetShow(TRUE); + m_airIcon[icon].PlayVisualRange(L"Pop",NULL,L"Pop"); + } + else m_airIcon[icon].SetShow(FALSE); + } + } + else + { + m_airGroup.SetShow(FALSE); + } + } + else + { + m_healthGroup.SetShow(FALSE); + m_foodGroup.SetShow(FALSE); + m_armourGroup.SetShow(FALSE); + m_airGroup.SetShow(FALSE); + } + return S_OK; +} + +HRESULT CXuiSceneHud::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + bool bPauseMenuDisplayed=false; + bool bInGame=(Minecraft::GetInstance()->level!=NULL); + // ignore this if we have menus up - they'll deal with it + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + if(app.IsPauseMenuDisplayed(i)) + { + bPauseMenuDisplayed=true; + break; + } + } + + if(bInGame && !bPauseMenuDisplayed) + { + app.StartInstallDLCProcess(ProfileManager.GetPrimaryPad()); + } + + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + + +HRESULT CXuiSceneHud::OnCustomMessage_DLCMountingComplete() +{ + // A join from invite may have installed the trial pack during the game. + // Need to switch to the texture pack if it's not being used yet, and turn off background downloads + + // what texture pack are we using? + // TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + // if(tPack->getDLCParentPackId()!=app.GetRequiredTexturePackID()) + // { + // app.DebugPrintf("DLC install finished, and the game is using a texture pack that isn't the required one\n"); + // } + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_HUD.h b/Minecraft.Client/Common/XUI/XUI_HUD.h new file mode 100644 index 00000000..1bf6bcbf --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HUD.h @@ -0,0 +1,129 @@ +#pragma once +#include "../media/xuiscene_hud.h" +#include "XUI_CustomMessages.h" + +#define CHAT_LINES_COUNT 10 + +class CXuiSceneHud : public CXuiSceneImpl +{ +private: + Random m_random; + int m_tickCount; + +protected: + CXuiControl m_hudHolder; // Contains the HUD group to enable moving all elements together + CXuiControl m_hudGroup; // Contains all the HUD elements except crosshair, in a group that scales + CXuiControl m_hudScaleGroup; // Contains all the HUD elements except crosshair + CXuiControl m_hotbarGroup; + CXuiCtrlSlotItem *m_hotbarIcon[9]; + CXuiProgressBar m_ExperienceProgress; + CXuiControl m_healthGroup; + CXuiControl m_healthIcon[10]; + CXuiControl m_armourGroup; + CXuiControl m_armourIcon[10]; + CXuiControl m_foodGroup; + CXuiControl m_foodIcon[10]; + CXuiControl m_airGroup; + CXuiControl m_airIcon[10]; + CXuiControl m_xpLevel; + + D3DXVECTOR3 m_OriginalPosition; + int m_iPad; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_CUSTOMTICKSCENE_MESSAGE(OnCustomMessage_TickScene) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_HudHolder, m_hudHolder) + BEGIN_MAP_CHILD_CONTROLS(m_hudHolder) + MAP_CONTROL(IDC_HudGroup, m_hudGroup) + BEGIN_MAP_CHILD_CONTROLS(m_hudGroup) + MAP_CONTROL(IDC_HudScaleGroup, m_hudScaleGroup) + BEGIN_MAP_CHILD_CONTROLS(m_hudScaleGroup) + MAP_CONTROL(IDC_Hotbar, m_hotbarGroup) + BEGIN_MAP_CHILD_CONTROLS(m_hotbarGroup) + MAP_OVERRIDE(IDC_Inventory1, m_hotbarIcon[0]) + MAP_OVERRIDE(IDC_Inventory2, m_hotbarIcon[1]) + MAP_OVERRIDE(IDC_Inventory3, m_hotbarIcon[2]) + MAP_OVERRIDE(IDC_Inventory4, m_hotbarIcon[3]) + MAP_OVERRIDE(IDC_Inventory5, m_hotbarIcon[4]) + MAP_OVERRIDE(IDC_Inventory6, m_hotbarIcon[5]) + MAP_OVERRIDE(IDC_Inventory7, m_hotbarIcon[6]) + MAP_OVERRIDE(IDC_Inventory8, m_hotbarIcon[7]) + MAP_OVERRIDE(IDC_Inventory9, m_hotbarIcon[8]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_ExperienceProgress, m_ExperienceProgress) + MAP_CONTROL(IDC_Health, m_healthGroup) + BEGIN_MAP_CHILD_CONTROLS(m_healthGroup) + MAP_CONTROL(IDC_Health0, m_healthIcon[0]) + MAP_CONTROL(IDC_Health1, m_healthIcon[1]) + MAP_CONTROL(IDC_Health2, m_healthIcon[2]) + MAP_CONTROL(IDC_Health3, m_healthIcon[3]) + MAP_CONTROL(IDC_Health4, m_healthIcon[4]) + MAP_CONTROL(IDC_Health5, m_healthIcon[5]) + MAP_CONTROL(IDC_Health6, m_healthIcon[6]) + MAP_CONTROL(IDC_Health7, m_healthIcon[7]) + MAP_CONTROL(IDC_Health8, m_healthIcon[8]) + MAP_CONTROL(IDC_Health9, m_healthIcon[9]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Armour, m_armourGroup) + BEGIN_MAP_CHILD_CONTROLS(m_armourGroup) + MAP_CONTROL(IDC_Armour0, m_armourIcon[0]) + MAP_CONTROL(IDC_Armour1, m_armourIcon[1]) + MAP_CONTROL(IDC_Armour2, m_armourIcon[2]) + MAP_CONTROL(IDC_Armour3, m_armourIcon[3]) + MAP_CONTROL(IDC_Armour4, m_armourIcon[4]) + MAP_CONTROL(IDC_Armour5, m_armourIcon[5]) + MAP_CONTROL(IDC_Armour6, m_armourIcon[6]) + MAP_CONTROL(IDC_Armour7, m_armourIcon[7]) + MAP_CONTROL(IDC_Armour8, m_armourIcon[8]) + MAP_CONTROL(IDC_Armour9, m_armourIcon[9]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Food, m_foodGroup) + BEGIN_MAP_CHILD_CONTROLS(m_foodGroup) + MAP_CONTROL(IDC_Food0, m_foodIcon[0]) + MAP_CONTROL(IDC_Food1, m_foodIcon[1]) + MAP_CONTROL(IDC_Food2, m_foodIcon[2]) + MAP_CONTROL(IDC_Food3, m_foodIcon[3]) + MAP_CONTROL(IDC_Food4, m_foodIcon[4]) + MAP_CONTROL(IDC_Food5, m_foodIcon[5]) + MAP_CONTROL(IDC_Food6, m_foodIcon[6]) + MAP_CONTROL(IDC_Food7, m_foodIcon[7]) + MAP_CONTROL(IDC_Food8, m_foodIcon[8]) + MAP_CONTROL(IDC_Food9, m_foodIcon[9]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Air, m_airGroup) + BEGIN_MAP_CHILD_CONTROLS(m_airGroup) + MAP_CONTROL(IDC_Air0, m_airIcon[0]) + MAP_CONTROL(IDC_Air1, m_airIcon[1]) + MAP_CONTROL(IDC_Air2, m_airIcon[2]) + MAP_CONTROL(IDC_Air3, m_airIcon[3]) + MAP_CONTROL(IDC_Air4, m_airIcon[4]) + MAP_CONTROL(IDC_Air5, m_airIcon[5]) + MAP_CONTROL(IDC_Air6, m_airIcon[6]) + MAP_CONTROL(IDC_Air7, m_airIcon[7]) + MAP_CONTROL(IDC_Air8, m_airIcon[8]) + MAP_CONTROL(IDC_Air9, m_airIcon[9]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_XPLevel, m_xpLevel) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnCustomMessage_TickScene(); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneHud, L"CXuiSceneHud", XUI_CLASS_SCENE ) +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.cpp b/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.cpp new file mode 100644 index 00000000..9ba49e9d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.cpp @@ -0,0 +1,462 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_HelpAndOptions.h" + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_HelpAndOptions::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + MapChildControls(); + XuiControlSetText(m_Buttons[BUTTON_HAO_CHANGESKIN],app.GetString(IDS_CHANGE_SKIN)); + XuiControlSetText(m_Buttons[BUTTON_HAO_HOWTOPLAY],app.GetString(IDS_HOW_TO_PLAY)); + XuiControlSetText(m_Buttons[BUTTON_HAO_CONTROLS],app.GetString(IDS_CONTROLS)); + XuiControlSetText(m_Buttons[BUTTON_HAO_SETTINGS],app.GetString(IDS_SETTINGS)); + XuiControlSetText(m_Buttons[BUTTON_HAO_CREDITS],app.GetString(IDS_CREDITS)); + XuiControlSetText(m_Buttons[BUTTON_HAO_REINSTALL],app.GetString(IDS_REINSTALL_CONTENT)); + XuiControlSetText(m_Buttons[BUTTON_HAO_DEBUG],app.GetString(IDS_DEBUG_SETTINGS)); + + //if(app.GetTMSDLCInfoRead()) + { + m_Timer.SetShow(FALSE); + m_bIgnoreInput=false; + + #ifndef _FINAL_BUILD + if(!app.DebugSettingsOn()) + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(FALSE); + } + else + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(TRUE); + + } + #endif + + // 4J-PB - do not need a storage device to see this menu - just need one when you choose to re-install them + + // any content to be re-installed? + if(m_iPad==ProfileManager.GetPrimaryPad() && bNotInGame) + { + // We should show the reinstall menu + app.DebugPrintf("Reinstall Menu required...\n"); + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(TRUE); + } + else + { + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(FALSE); + } + + if(app.GetLocalPlayerCount()>1) + { + // no credits in splitscreen + D3DXVECTOR3 vec; + + m_Buttons[BUTTON_HAO_CREDITS].GetPosition(&vec); + + m_Buttons[BUTTON_HAO_CREDITS].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_CREDITS].SetShow(FALSE); + + m_Buttons[BUTTON_HAO_REINSTALL].SetPosition(&vec); + + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + + if(ProfileManager.GetPrimaryPad()!=m_iPad) + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(FALSE); + } + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + // Display the tooltips + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + + if(!ProfileManager.IsFullVersion() )//|| ProfileManager.IsGuest(m_iPad)) + { + // disable save button + m_Buttons[BUTTON_HAO_CHANGESKIN].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_CHANGESKIN].EnableInput(FALSE); + // set the focus to the second button + + XuiElementSetUserFocus(m_Buttons[BUTTON_HAO_HOWTOPLAY].m_hObj, m_iPad); + } + } + /*else + { + m_bIgnoreInput=true; + m_Timer.SetShow(TRUE); + + // hide all the buttons + for(int i=0;i<BUTTONS_HAO_MAX;i++) + { + m_Buttons[i].SetEnable(FALSE); + m_Buttons[i].SetShow(FALSE); + } + + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1,-1); + } + else + { + ui.SetTooltips( m_iPad, -1,-1); + } + }*/ + return S_OK; +} + +/*HRESULT CScene_HelpAndOptions::OnTMSDLCFileRetrieved( ) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + m_Timer.SetShow(FALSE); + m_bIgnoreInput=false; + + // show all the buttons - except the debug settings and reinstall content + m_Buttons[BUTTON_HAO_CHANGESKIN].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_CHANGESKIN].SetShow(TRUE); + m_Buttons[BUTTON_HAO_HOWTOPLAY].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_HOWTOPLAY].SetShow(TRUE); + m_Buttons[BUTTON_HAO_CONTROLS].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_CONTROLS].SetShow(TRUE); + m_Buttons[BUTTON_HAO_SETTINGS].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_SETTINGS].SetShow(TRUE); + m_Buttons[BUTTON_HAO_CREDITS].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_CREDITS].SetShow(TRUE); + + + +#ifndef _FINAL_BUILD + if(!app.DebugSettingsOn()) + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(FALSE); + } + else + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(TRUE); + + } +#endif + + // 4J-PB - do not need a storage device to see this menu - just need one when you choose to re-install them + + // any content to be re-installed? + if(m_iPad==ProfileManager.GetPrimaryPad() && bNotInGame) + { + // We should show the reinstall menu + app.DebugPrintf("Reinstall Menu required...\n"); + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(TRUE); + } + else + { + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(FALSE); + } + + if(app.GetLocalPlayerCount()>1) + { + // no credits in splitscreen + D3DXVECTOR3 vec; + + m_Buttons[BUTTON_HAO_CREDITS].GetPosition(&vec); + + m_Buttons[BUTTON_HAO_CREDITS].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_CREDITS].SetShow(FALSE); + + m_Buttons[BUTTON_HAO_REINSTALL].SetPosition(&vec); + + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + + if(ProfileManager.GetPrimaryPad()!=m_iPad) + { + m_Buttons[BUTTON_HAO_DEBUG].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_DEBUG].SetShow(FALSE); + } + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + // Display the tooltips + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + + if(!ProfileManager.IsFullVersion() )//|| ProfileManager.IsGuest(m_iPad)) + { + // disable save button + m_Buttons[BUTTON_HAO_CHANGESKIN].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_CHANGESKIN].EnableInput(FALSE); + // set the focus to the second button + + XuiElementSetUserFocus(m_Buttons[BUTTON_HAO_HOWTOPLAY].m_hObj, m_iPad); + } + else + { + XuiElementSetUserFocus(m_Buttons[BUTTON_HAO_CHANGESKIN].m_hObj, m_iPad); + } + return S_OK; +}*/ + +HRESULT CScene_HelpAndOptions::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_HelpAndOptions::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + + while((uiButtonCounter<BUTTONS_HAO_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + // Determine which button was pressed, + // and call the appropriate function. + + switch(uiButtonCounter) + { + case BUTTON_HAO_HOWTOPLAY: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_HowToPlayMenu); + break; + case BUTTON_HAO_CONTROLS: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_ControlsMenu); + break; + case BUTTON_HAO_SETTINGS: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsMenu); + break; + case BUTTON_HAO_CHANGESKIN: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SkinSelectMenu); + break; + case BUTTON_HAO_CREDITS: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_Credits); + break; + + case BUTTON_HAO_REINSTALL: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_ReinstallMenu); + break; + + case BUTTON_HAO_DEBUG: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_DebugOptions); + break; + + default: + break; + } + + return S_OK; +} + +HRESULT CScene_HelpAndOptions::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // ignore a held down key to avoid skipping this scene if the user changes a setting and presses B for slightly too long + if((pInputData->dwFlags&XUI_INPUT_FLAG_REPEAT)&&(pInputData->dwKeyCode==VK_PAD_B)) + { + return S_OK; + } + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + BYTE userIndex = pInputData->UserIndex; + if( !app.IsPauseMenuDisplayed(userIndex) ) + { + // If we are not from a pause menu, then we are from the main menu + userIndex = XUSER_INDEX_ANY; + } + + app.NavigateBack(userIndex); + rfHandled = TRUE; + + break; + } + + return S_OK; +} + +HRESULT CScene_HelpAndOptions::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + + if(m_iPad==ProfileManager.GetPrimaryPad() )//&& + // StorageManager.GetSaveDeviceSelected(m_iPad) && + // !StorageManager.GetSaveDisabled() && +// ( ProfileManager.IsAwardsFlagSet(m_iPad,eAward_mine100Blocks) || +// ProfileManager.IsAwardsFlagSet(m_iPad,eAward_kill10Creepers) || +// ProfileManager.IsAwardsFlagSet(m_iPad,eAward_eatPorkChop) || +// ProfileManager.IsAwardsFlagSet(m_iPad,eAward_play100Days) || +// ProfileManager.IsAwardsFlagSet(m_iPad,eAward_arrowKillCreeper) || +// ProfileManager.IsAwardsFlagSet(m_iPad,eAward_socialPost)) ) + { + // We should show the reinstall menu + app.DebugPrintf("Reinstall Menu required...\n"); + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(TRUE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(TRUE); + } + else + { + m_Buttons[BUTTON_HAO_REINSTALL].SetEnable(FALSE); + m_Buttons[BUTTON_HAO_REINSTALL].SetShow(FALSE); + } + + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + if(app.GetLocalPlayerCount()>1) + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + + +// int CScene_HelpAndOptions::ResetDefaultsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +// { +// CScene_HelpAndOptions* pClass = (CScene_HelpAndOptions*)pParam; +// +// // results switched for this dialog +// if(result==C4JStorage::EMessage_ResultDecline) +// { +// app.SetDefaultOptions(ProfileManager.GetDashboardProfileSettings(pClass->m_iPad),pClass->m_iPad); +// // if the profile data has been changed, then force a profile write +// // It seems we're allowed to break the 5 minute rule if it's the result of a user action +// app.CheckGameSettingsChanged(true,iPad); +// } +// return 0; +// } + +HRESULT CScene_HelpAndOptions::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + XUIRect xuiRect; + HXUIOBJ visual=NULL; + HXUIOBJ text; + float fMaxTextLen=0.0f; + float fTextVisualLen; + float fMaxButton; + float fWidth,fHeight; + + HRESULT hr=XuiControlGetVisual(m_Buttons[0].m_hObj,&visual); + hr=XuiElementGetChildById(visual,L"text_Label",&text); + hr=XuiElementGetBounds(text,&fTextVisualLen,&fHeight); + m_Buttons[0].GetBounds(&fMaxButton,&fHeight); + + + for(int i=0;i<BUTTONS_HAO_MAX;i++) + { + hr=XuiTextPresenterMeasureText(text, m_Buttons[i].GetText(), &xuiRect); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + } + + if(fTextVisualLen<fMaxTextLen) + { + D3DXVECTOR3 vec; + + // centre is vec.x+(fWidth/2) + for(int i=0;i<BUTTONS_HAO_MAX;i++) + { + // need to resize and reposition the buttons + m_Buttons[i].GetPosition(&vec); + m_Buttons[i].GetBounds(&fWidth,&fHeight); + vec.x= vec.x+(fWidth/2.0f)-(fMaxTextLen/2.0f); + + m_Buttons[i].SetPosition(&vec); + m_Buttons[i].SetBounds(fMaxButton+fMaxTextLen-fTextVisualLen,fHeight); + } + } + } + + return S_OK; +} + + +HRESULT CScene_HelpAndOptions::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,false); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.h b/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.h new file mode 100644 index 00000000..9ece2cd9 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpAndOptions.h @@ -0,0 +1,70 @@ +#pragma once + +#include "../media/xuiscene_helpandoptions.h" +#include "XUI_CustomMessages.h" + +#define BUTTON_HAO_CHANGESKIN 0 +#define BUTTON_HAO_HOWTOPLAY 1 +#define BUTTON_HAO_CONTROLS 2 +#define BUTTON_HAO_SETTINGS 3 +#define BUTTON_HAO_CREDITS 4 +#define BUTTON_HAO_REINSTALL 5 +#define BUTTON_HAO_DEBUG 6 +#define BUTTONS_HAO_MAX BUTTON_HAO_DEBUG + 1 + + + +class CScene_HelpAndOptions : public CXuiSceneImpl +{ +protected: + // Control and Element wrapper objects. + CXuiScene m_Scene; + CXuiControl m_Buttons[BUTTONS_HAO_MAX]; + CXuiElement m_Background; + CXuiControl m_Timer; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + //XUI_ON_XM_TMS_DLCFILE_RETRIEVED_MESSAGE(OnTMSDLCFileRetrieved) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiButton1, m_Buttons[BUTTON_HAO_CHANGESKIN]) + MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_HAO_HOWTOPLAY ]) + MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_HAO_CONTROLS ]) + MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_HAO_SETTINGS ]) + MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_HAO_CREDITS]) + MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_HAO_REINSTALL]) + MAP_CONTROL(IDC_XuiButton7, m_Buttons[BUTTON_HAO_DEBUG]) + MAP_CONTROL(IDC_Timer, m_Timer) + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + //HRESULT OnTMSDLCFileRetrieved( ); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_HelpAndOptions, L"CScene_HelpAndOptions", XUI_CLASS_SCENE ) + +private: + + int m_iPad; + bool m_bIgnoreInput; + D3DXVECTOR3 m_OriginalPosition; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_HelpControls.cpp b/Minecraft.Client/Common/XUI/XUI_HelpControls.cpp new file mode 100644 index 00000000..e7a8b0ca --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpControls.cpp @@ -0,0 +1,566 @@ +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_HelpControls.h" +#include "XUI_Ctrl_4JList.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\LevelData.h" +#include "..\..\MultiplayerLocalPlayer.h" + +#define ALIGN_START 0 +#define ALIGN_END 1 +typedef struct +{ + WCHAR wchName[20]; + int iAlign; + D3DXVECTOR3 vPos; +} +CONTROLDETAILS; + +LPCWSTR CScene_Controls::m_LayoutNameA[3]= +{ + L"1", + L"2", + L"3", +}; +CONTROLDETAILS controlDetailsA[MAX_CONTROLS]= +{ + { + L"FigA",ALIGN_END // _360_JOY_BUTTON_A + }, + { + L"FigB",ALIGN_END // _360_JOY_BUTTON_B + }, + { + L"FigX",ALIGN_END // _360_JOY_BUTTON_X + }, + { + L"FigY",ALIGN_END // _360_JOY_BUTTON_Y + }, + { + L"FigStart",ALIGN_END // _360_JOY_BUTTON_START + }, + { + L"FigBack",ALIGN_START // _360_JOY_BUTTON_BACK + }, + { + L"FigRB",ALIGN_END // _360_JOY_BUTTON_RB + }, + { + L"FigLB",ALIGN_START // _360_JOY_BUTTON_LB + }, + { + L"FigRStickButton",ALIGN_END // _360_JOY_BUTTON_RTHUMB + }, + { + L"FigLStickButton",ALIGN_START // _360_JOY_BUTTON_LTHUMB + }, + // Move + { + L"FigRStick",ALIGN_END // _360_JOY_BUTTON_RSTICK_RIGHT + }, + // Look + { + L"FigLStick",ALIGN_START // _360_JOY_BUTTON_LSTICK_RIGHT + }, + { + L"FigRT",ALIGN_END // RT + }, + { + L"FigLT",ALIGN_START // LT + }, + { + L"FigDpadR",ALIGN_START // DpadR + }, + { + L"FigDpadL",ALIGN_START // DpadL + }, + { + L"FigDpad",ALIGN_START // DpadL + }, + +}; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Controls::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + XuiControlSetText(m_SouthPaw,app.GetString(IDS_SOUTHPAW)); + XuiControlSetText(m_InvertLook,app.GetString(IDS_INVERT_LOOK)); + + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + bool bSplitscreen=(app.GetLocalPlayerCount()>1); + m_iCurrentTextIndex=0; + m_bCreativeMode = !bNotInGame && Minecraft::GetInstance()->localplayers[m_iPad] && Minecraft::GetInstance()->localplayers[m_iPad]->abilities.mayfly; + + if(!bNotInGame) + { + // disable the build ver display + m_BuildVer.SetShow(FALSE); + } + + if(bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,32.0f); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + m_iSchemeTextA[0]=IDS_CONTROLS_SCHEME0; + m_iSchemeTextA[1]=IDS_CONTROLS_SCHEME1; + m_iSchemeTextA[2]=IDS_CONTROLS_SCHEME2; + + // get the figures + HXUIOBJ hObj; + HRESULT hr; + + // turn off all the figures to start with + for(int i=0;i<MAX_CONTROLS;i++) + { + m_FigA[i].GetChildById(controlDetailsA[i].wchName,&hObj); + hr=XuiElementGetPosition(hObj,&controlDetailsA[i].vPos); + if(controlDetailsA[i].iAlign==ALIGN_END) + { + float fW,fH; + hr=XuiElementGetBounds(hObj,&fW,&fH); + controlDetailsA[i].vPos.x+=fW; + controlDetailsA[i].vPos.y+=fH; + } + + // if we're in splitscreen, half all the numbers + if(bSplitscreen) + { + controlDetailsA[i].vPos.x/=2.0f; + controlDetailsA[i].vPos.y/=2.0f; + } + m_FigA[i].SetShow(FALSE); + m_TextPresenterA[i] = NULL; + } + + // fill out the layouts list + VOID *pObj; + XuiObjectFromHandle( m_SchemeList, &pObj ); + m_pLayoutList = (CXuiCtrl4JList *)pObj; + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo[3]; + ZeroMemory(ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)*3); + + for(int i=0;i<3;i++) + { + ListInfo[i].pwszText=m_LayoutNameA[i]; + ListInfo[i].hXuiBrush=NULL; + ListInfo[i].fEnabled=TRUE; + m_pLayoutList->AddData(ListInfo[i]); + } + + m_bIgnoreNotifies=true; + m_bIgnoreNotifies=false; + int iSelected=app.GetGameSettings(m_iPad,eGameSetting_ControlScheme); + XuiControlSetText(m_SchemeList,app.GetString(IDS_CONTROLS_LAYOUT)); + hr=m_pLayoutList->SetCurSelVisible(iSelected); + m_iCurrentNavigatedControlsLayout=iSelected; + + LPWSTR layoutString = new wchar_t[ 128 ]; + swprintf( layoutString, 128, L"%ls : %ls", app.GetString( IDS_CURRENT_LAYOUT ),app.GetString(m_iSchemeTextA[iSelected])); + XuiControlSetText(m_CurrentLayout,layoutString); + + //PositionAllText(m_iPad); + + swprintf( layoutString, 128, L"%ls%ls", VER_PRODUCTVERSION_STR_W,app.DLCInstallProcessCompleted()?L"_DLC":L" "); + + m_BuildVer.SetText(layoutString); + delete [] layoutString; + + // Set check box initial states. + BOOL bInvertLook = app.GetGameSettings(m_iPad,eGameSetting_ControlInvertLook); + m_InvertLook.SetCheck( bInvertLook ); + + BOOL bSouthPaw = app.GetGameSettings(m_iPad,eGameSetting_ControlSouthPaw); + m_SouthPaw.SetCheck( bSouthPaw ); + + return S_OK; +} + + + +HRESULT CScene_Controls::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + int iSelected=app.GetGameSettings(m_iPad,eGameSetting_ControlScheme); + // and update the highlight on the current selection + m_pLayoutList->SetBorder(iSelected,TRUE); + + PositionAllText(m_iPad); + } + + return S_OK; +} + +void CScene_Controls::PositionAllText(int iPad) +{ + // turn off all the figures to start with + for(int i=0;i<MAX_CONTROLS;i++) + { + m_FigA[i].SetShow(FALSE); + } + + m_iCurrentTextIndex=0; + if(m_bCreativeMode) + { + PositionText(iPad,IDS_CONTROLS_JUMPFLY,MINECRAFT_ACTION_JUMP); + } + else + { + PositionText(iPad,IDS_CONTROLS_JUMP,MINECRAFT_ACTION_JUMP); + } + PositionText(iPad,IDS_CONTROLS_INVENTORY,MINECRAFT_ACTION_INVENTORY); + PositionText(iPad,IDS_CONTROLS_PAUSE,MINECRAFT_ACTION_PAUSEMENU); + if(m_bCreativeMode) + { + PositionText(iPad,IDS_CONTROLS_SNEAKFLY,MINECRAFT_ACTION_SNEAK_TOGGLE); + } + else + { + PositionText(iPad,IDS_CONTROLS_SNEAK,MINECRAFT_ACTION_SNEAK_TOGGLE); + } + PositionText(iPad,IDS_CONTROLS_USE,MINECRAFT_ACTION_USE); + PositionText(iPad,IDS_CONTROLS_ACTION,MINECRAFT_ACTION_ACTION); + PositionText(iPad,IDS_CONTROLS_HELDITEM,MINECRAFT_ACTION_RIGHT_SCROLL); + PositionText(iPad,IDS_CONTROLS_HELDITEM,MINECRAFT_ACTION_LEFT_SCROLL); + PositionText(iPad,IDS_CONTROLS_DROP,MINECRAFT_ACTION_DROP); + PositionText(iPad,IDS_CONTROLS_CRAFTING,MINECRAFT_ACTION_CRAFTING); + + PositionText(iPad,IDS_CONTROLS_THIRDPERSON,MINECRAFT_ACTION_RENDER_THIRD_PERSON); + PositionText(iPad,IDS_CONTROLS_PLAYERS,MINECRAFT_ACTION_GAME_INFO); + + // Swap for southpaw. + if ( app.GetGameSettings(m_iPad,eGameSetting_ControlSouthPaw) ) + { + // Move + PositionText(iPad,IDS_CONTROLS_LOOK,MINECRAFT_ACTION_RIGHT); + // Look + PositionText(iPad,IDS_CONTROLS_MOVE,MINECRAFT_ACTION_LOOK_RIGHT); + } + else // Normal right handed. + { + // Move + PositionText(iPad,IDS_CONTROLS_MOVE,MINECRAFT_ACTION_RIGHT); + // Look + PositionText(iPad,IDS_CONTROLS_LOOK,MINECRAFT_ACTION_LOOK_RIGHT); + } + + // If we're in controls mode 1, and creative mode show the dpad for Creative Mode + if(m_bCreativeMode && (m_iCurrentNavigatedControlsLayout==0)) + { + PositionTextDirect(iPad,IDS_CONTROLS_DPAD,16,true); + } + else + { + PositionTextDirect(iPad,IDS_CONTROLS_DPAD,16,false); + } +} + +HRESULT CScene_Controls::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + + app.CheckGameSettingsChanged(true,pInputData->UserIndex); + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +void CScene_Controls::PositionText(int iPad,int iTextID, unsigned char ucAction) +{ + // position the text depending on the control id + //int iTextWidth; + XUIRect xuiRect; + LPCWSTR pwchText; + D3DXVECTOR3 vpos,vScale; + HXUIOBJ hFigGroup; + unsigned int uiVal=InputManager.GetGameJoypadMaps(m_iCurrentNavigatedControlsLayout,ucAction); + + // get the visual of the fig group and use any scaling in it to adjust the text positions + XuiElementGetChildById(m_hObj,L"FigGroup",&hFigGroup); + XuiElementGetScale(hFigGroup,&vScale); + + // check the width of the control with the text set in it + if(m_TextPresenterA[m_iCurrentTextIndex]==NULL) + { + HXUIOBJ hObj=NULL; + HRESULT hr=XuiControlGetVisual(m_TextA[m_iCurrentTextIndex].m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"Text",&m_TextPresenterA[m_iCurrentTextIndex]); + } + + pwchText=app.GetString(iTextID); + HRESULT hr=XuiTextPresenterMeasureText(m_TextPresenterA[m_iCurrentTextIndex], pwchText, &xuiRect); + m_TextA[m_iCurrentTextIndex].SetBounds(xuiRect.right,xuiRect.bottom); + + int iControlDetailsIndex=0; + switch(uiVal) + { + case _360_JOY_BUTTON_A: + iControlDetailsIndex=0; + break; + case _360_JOY_BUTTON_B: + iControlDetailsIndex=1; + break; + case _360_JOY_BUTTON_X: + iControlDetailsIndex=2; + break; + case _360_JOY_BUTTON_Y: + iControlDetailsIndex=3; + break; + case _360_JOY_BUTTON_START: + iControlDetailsIndex=4; + break; + case _360_JOY_BUTTON_BACK: + iControlDetailsIndex=5; + break; + case _360_JOY_BUTTON_RB: + iControlDetailsIndex=6; + break; + case _360_JOY_BUTTON_LB: + iControlDetailsIndex=7; + break; + case _360_JOY_BUTTON_RTHUMB: + iControlDetailsIndex=8; + break; + case _360_JOY_BUTTON_LTHUMB: + iControlDetailsIndex=9; + break; + // Look + case _360_JOY_BUTTON_RSTICK_RIGHT: + iControlDetailsIndex=10; + break; + // Move + case _360_JOY_BUTTON_LSTICK_RIGHT: + iControlDetailsIndex=11; + break; + case _360_JOY_BUTTON_RT: + iControlDetailsIndex=12; + break; + // Move + case _360_JOY_BUTTON_LT: + iControlDetailsIndex=13; + break; + case _360_JOY_BUTTON_DPAD_RIGHT: + iControlDetailsIndex=14; + break; + case _360_JOY_BUTTON_DPAD_LEFT: + iControlDetailsIndex=15; + break; + } + + hr=m_FigA[iControlDetailsIndex].SetShow(TRUE); + // position the control depending on the text width + + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + // 480 mode - we need to scale the text positions + if(controlDetailsA[iControlDetailsIndex].iAlign==ALIGN_END) + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x + 5.0f)* vScale.x; + } + else + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x - 5.0f)* vScale.x - xuiRect.right; + } + + vpos.y=(controlDetailsA[iControlDetailsIndex].vPos.y * vScale.y) - (xuiRect.bottom/2.0f); + } + else + { + if(controlDetailsA[iControlDetailsIndex].iAlign==ALIGN_END) + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x + 5.0f); + } + else + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x - 5.0f) - xuiRect.right; + } + + vpos.y=(controlDetailsA[iControlDetailsIndex].vPos.y ) - (xuiRect.bottom/2.0f); + } + + vpos.x=floor(vpos.x); + vpos.y=floor(vpos.y); + vpos.z=0.0f; + + m_TextA[m_iCurrentTextIndex].SetPosition(&vpos); + m_TextA[m_iCurrentTextIndex].SetText(pwchText); + m_TextA[m_iCurrentTextIndex].SetShow(TRUE); + m_iCurrentTextIndex++; +} + +void CScene_Controls::PositionTextDirect(int iPad,int iTextID, int iControlDetailsIndex, bool bShow) +{ + // position the text depending on the control id + //int iTextWidth; + XUIRect xuiRect; + LPCWSTR pwchText; + D3DXVECTOR3 vpos,vScale; + HXUIOBJ hFigGroup; + + if(bShow==false) + { + m_TextA[m_iCurrentTextIndex++].SetShow(FALSE); + return; + } + // get the visual of the fig group and use any scaling in it to adjust the text positions + XuiElementGetChildById(m_hObj,L"FigGroup",&hFigGroup); + XuiElementGetScale(hFigGroup,&vScale); + + // check the width of the control with the text set in it + if(m_TextPresenterA[m_iCurrentTextIndex]==NULL) + { + HXUIOBJ hObj=NULL; + HRESULT hr=XuiControlGetVisual(m_TextA[m_iCurrentTextIndex].m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"Text",&m_TextPresenterA[m_iCurrentTextIndex]); + } + + pwchText=app.GetString(iTextID); + HRESULT hr=XuiTextPresenterMeasureText(m_TextPresenterA[m_iCurrentTextIndex], pwchText, &xuiRect); + m_TextA[m_iCurrentTextIndex].SetBounds(xuiRect.right,xuiRect.bottom); + + + + hr=m_FigA[iControlDetailsIndex].SetShow(TRUE); + // position the control depending on the text width + + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + // 480 mode - we need to scale the text positions + if(controlDetailsA[iControlDetailsIndex].iAlign==ALIGN_END) + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x + 5.0f)* vScale.x; + } + else + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x - 5.0f)* vScale.x - xuiRect.right; + } + + vpos.y=(controlDetailsA[iControlDetailsIndex].vPos.y * vScale.y) - (xuiRect.bottom/2.0f); + } + else + { + if(controlDetailsA[iControlDetailsIndex].iAlign==ALIGN_END) + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x + 5.0f); + } + else + { + vpos.x=(controlDetailsA[iControlDetailsIndex].vPos.x - 5.0f) - xuiRect.right; + } + + vpos.y=(controlDetailsA[iControlDetailsIndex].vPos.y ) - (xuiRect.bottom/2.0f); + } + + vpos.x=floor(vpos.x); + vpos.y=floor(vpos.y); + vpos.z=0.0f; + + m_TextA[m_iCurrentTextIndex].SetPosition(&vpos); + m_TextA[m_iCurrentTextIndex].SetText(pwchText); + m_TextA[m_iCurrentTextIndex].SetShow(TRUE); + m_iCurrentTextIndex++; +} + +HRESULT CScene_Controls::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if( ( !m_bIgnoreNotifies )&&( hObjSource==m_pLayoutList->m_hObj ) ) + { + m_iCurrentNavigatedControlsLayout=pNotifySelChangedData->iItem; + PositionAllText(m_iPad); + } + if(pNotifySelChangedData->iOldItem!=-1 && hObjSource==m_SchemeList ) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + return S_OK; +} + + + + +HRESULT CScene_Controls::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + // Handle check box changes. + if ( hObjPressed == m_InvertLook.m_hObj ) + { + BOOL bIsChecked = m_InvertLook.IsChecked(); + app.SetGameSettings(m_iPad,eGameSetting_ControlInvertLook,(unsigned char)( bIsChecked ) ); + } + else if ( hObjPressed == m_SouthPaw.m_hObj ) + { + BOOL bIsChecked = m_SouthPaw.IsChecked(); + app.SetGameSettings(m_iPad,eGameSetting_ControlSouthPaw,(unsigned char)( bIsChecked ) ); + PositionAllText(m_iPad); + } + else if( hObjPressed == m_SchemeList) + { + // check what's been selected + app.SetGameSettings(m_iPad,eGameSetting_ControlScheme,(unsigned char)m_SchemeList.GetCurSel()); + LPWSTR layoutString = new wchar_t[ 128 ]; + swprintf( layoutString, 128, L"%ls : %ls", app.GetString( IDS_CURRENT_LAYOUT ),app.GetString(m_iSchemeTextA[m_SchemeList.GetCurSel()]) ); + + XuiControlSetText(m_CurrentLayout,layoutString); + delete [] layoutString; + // and update the highlight on the current selection + for(int i=0;i<m_pLayoutList->GetItemCount();i++) + { + m_pLayoutList->SetBorder(i,FALSE); + } + m_pLayoutList->SetBorder(m_SchemeList.GetCurSel(),TRUE); + } + return S_OK; +} + +HRESULT CScene_Controls::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,32.0f); +} diff --git a/Minecraft.Client/Common/XUI/XUI_HelpControls.h b/Minecraft.Client/Common/XUI/XUI_HelpControls.h new file mode 100644 index 00000000..4d14953b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpControls.h @@ -0,0 +1,115 @@ +#pragma once + +#include "../media/xuiscene_controls.h" +#include "XUI_CustomMessages.h" + +class CXuiCtrl4JList; + + + +#define MAX_CONTROLS 17 +class CScene_Controls : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiControl m_TextA[MAX_CONTROLS]; + HXUIOBJ m_TextPresenterA[MAX_CONTROLS]; + CXuiElement m_FigA[MAX_CONTROLS]; + CXuiList m_SchemeList; + CXuiElement m_Group; + CXuiControl m_BuildVer; + CXuiControl m_CurrentLayout; + CXuiCheckbox m_InvertLook; + CXuiCheckbox m_SouthPaw; + static LPCWSTR m_LayoutNameA[3]; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_SchemeList, m_SchemeList) + MAP_CONTROL(IDC_CurrentLayout, m_CurrentLayout) + + MAP_CONTROL(IDC_XuiBuildVer, m_BuildVer) + MAP_CONTROL(IDC_XuiLabel1, m_TextA[0]) + MAP_CONTROL(IDC_XuiLabel2, m_TextA[1]) + MAP_CONTROL(IDC_XuiLabel3, m_TextA[2]) + MAP_CONTROL(IDC_XuiLabel4, m_TextA[3]) + MAP_CONTROL(IDC_XuiLabel5, m_TextA[4]) + MAP_CONTROL(IDC_XuiLabel6, m_TextA[5]) + MAP_CONTROL(IDC_XuiLabel7, m_TextA[6]) + MAP_CONTROL(IDC_XuiLabel8, m_TextA[7]) + MAP_CONTROL(IDC_XuiLabel9, m_TextA[8]) + MAP_CONTROL(IDC_XuiLabel10, m_TextA[9]) + MAP_CONTROL(IDC_XuiLabel11, m_TextA[10]) + MAP_CONTROL(IDC_XuiLabel12, m_TextA[11]) + MAP_CONTROL(IDC_XuiLabel13, m_TextA[12]) + MAP_CONTROL(IDC_XuiLabel14, m_TextA[13]) + MAP_CONTROL(IDC_XuiLabel15, m_TextA[14]) + MAP_CONTROL(IDC_XuiLabel16, m_TextA[15]) + MAP_CONTROL(IDC_XuiLabel17, m_TextA[16]) + MAP_CONTROL(IDC_FigGroup, m_Group) + MAP_CONTROL(IDC_InvertLook, m_InvertLook) + MAP_CONTROL(IDC_SouthPaw, m_SouthPaw) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_A, m_FigA[0]) + MAP_CONTROL(IDC_B, m_FigA[1]) + MAP_CONTROL(IDC_X, m_FigA[2]) + MAP_CONTROL(IDC_Y, m_FigA[3]) + MAP_CONTROL(IDC_Start, m_FigA[4]) + MAP_CONTROL(IDC_Back, m_FigA[5]) + MAP_CONTROL(IDC_RB, m_FigA[6]) + MAP_CONTROL(IDC_LB, m_FigA[7]) + MAP_CONTROL(IDC_RStickButton, m_FigA[8]) + MAP_CONTROL(IDC_LStickButton, m_FigA[9]) + MAP_CONTROL(IDC_RStick, m_FigA[10]) + MAP_CONTROL(IDC_LStick, m_FigA[11]) + MAP_CONTROL(IDC_RT, m_FigA[12]) + MAP_CONTROL(IDC_LT, m_FigA[13]) + MAP_CONTROL(IDC_DpadR, m_FigA[14]) + MAP_CONTROL(IDC_DpadL, m_FigA[15]) + MAP_CONTROL(IDC_Dpad, m_FigA[16]) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + + + void PositionText(int iPad,int iTextID, unsigned char ucAction); + void PositionTextDirect(int iPad,int iTextID, int iControlDetailsIndex, bool bShow); + void PositionAllText(int iPad); + + + int m_iCurrentTextIndex; + int m_iCurrentNavigatedControlsLayout; + int m_iSchemeTextA[3]; + int m_nItems; + int m_iPad; + CXuiCtrl4JList *m_pLayoutList; + bool m_bIgnoreNotifies; + D3DXVECTOR3 m_OriginalPosition; + bool m_bCreativeMode; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Controls, L"CScene_Controls", XUI_CLASS_SCENE ) + + + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_HelpCredits.cpp b/Minecraft.Client/Common/XUI/XUI_HelpCredits.cpp new file mode 100644 index 00000000..4a6ce55f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpCredits.cpp @@ -0,0 +1,688 @@ +#include "stdafx.h" +#include <assert.h> +#include "XUI_HelpCredits.h" + +SCreditTextItemDef CScene_Credits::gs_aCreditDefs[MAX_CREDIT_STRINGS] = +{ + { L"MOJANG", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_ORIGINALDESIGN, NO_TRANSLATED_STRING,eLargeText }, + { L"Markus Persson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_PMPROD, NO_TRANSLATED_STRING,eLargeText }, + { L"Daniel Kaplan", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_RESTOFMOJANG, NO_TRANSLATED_STRING,eMediumText }, + { L"%s", IDS_CREDITS_LEADPC, NO_TRANSLATED_STRING,eLargeText }, + { L"Jens Bergensten", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_JON_KAGSTROM, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_CEO, NO_TRANSLATED_STRING,eLargeText }, + { L"Carl Manneh", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_DOF, NO_TRANSLATED_STRING,eLargeText }, + { L"Lydia Winters", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_WCW, NO_TRANSLATED_STRING,eLargeText }, + { L"Karin Severinsson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_CUSTOMERSUPPORT, NO_TRANSLATED_STRING,eLargeText }, + { L"Marc Watson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_DESPROG, NO_TRANSLATED_STRING,eLargeText }, + { L"Aron Nieminen", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_CHIEFARCHITECT, NO_TRANSLATED_STRING,eLargeText }, + { L"Daniel Frisk", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_CODENINJA, NO_TRANSLATED_STRING,eLargeText }, + { L"%s", IDS_CREDITS_TOBIAS_MOLLSTAM, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_OFFICEDJ, NO_TRANSLATED_STRING,eLargeText }, + { L"Kristoffer Jelbring", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_DEVELOPER, NO_TRANSLATED_STRING,eLargeText }, + { L"Leonard Axelsson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_BULLYCOORD, NO_TRANSLATED_STRING,eLargeText }, + { L"Jakob Porser", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_ARTDEVELOPER, NO_TRANSLATED_STRING,eLargeText }, + { L"Junkboy", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_EXPLODANIM, NO_TRANSLATED_STRING,eLargeText }, + { L"Mattis Grahm", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_CONCEPTART, NO_TRANSLATED_STRING,eLargeText }, + { L"Henrik Petterson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_CRUNCHER, NO_TRANSLATED_STRING,eLargeText }, + { L"Patrick Geuder", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_MUSICANDSOUNDS, NO_TRANSLATED_STRING,eLargeText }, + { L"Daniel Rosenfeld (C418)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"4J Studios", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"%s", IDS_CREDITS_PROGRAMMING, NO_TRANSLATED_STRING,eLargeText }, + { L"Paddy Burns", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Richard Reavy", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Stuart Ross", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"James Vaughan", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Mark Hughes", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Thomas Kronberg", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ian le Bruce", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Andy West", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Gordon McLean", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_ART, NO_TRANSLATED_STRING,eLargeText }, + { L"David Keningale", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Pat McGovern", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Alan Redmond", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Julian Laing", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Caitlin Goodale", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Scott Sutherland", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Reeves", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kate Wright", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michael Hansen", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kate Flavell", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Donald Robertson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jamie Keddie", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Thomas Naylor", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Brian Lindsay", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Hannah Watts", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Rebecca O'Neil", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_QA, NO_TRANSLATED_STRING,eLargeText }, + { L"Steven Gary Woodward", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Richard Black", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"George Vaughan", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_SPECIALTHANKS, NO_TRANSLATED_STRING,eLargeText }, + { L"Chris van der Kuyl", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Roni Percy", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Anne Clarke", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Anthony Kent", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Microsoft Studios", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + + { L"Xbox LIVE Arcade Team", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_LEADPRODUCER, NO_TRANSLATED_STRING,eLargeText }, + { L"Roger Carpenter", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_PRODUCER, NO_TRANSLATED_STRING,eLargeText }, + { L"Stuart Platt", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Riccardo Lenzi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_LEADTESTER, NO_TRANSLATED_STRING,eLargeText }, + { L"Bill Brown (Insight Global)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Brandon McCurry (Insight Global)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Hakim Ronaque, Joe Dunavant", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Paul Loynd, Jeffery Stephens", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Rial Lerum (Xtreme Consulting Group Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_DESIGNTEAM, NO_TRANSLATED_STRING,eLargeText }, + { L"Craig Leigh", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_DEVELOPMENTTEAM, NO_TRANSLATED_STRING,eLargeText }, + { L"Scott Guest", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jeff \"Dextor\" Blazier", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Yukie Yamaguchi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jason Hewitt", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_RELEASEMANAGEMENT, NO_TRANSLATED_STRING,eLargeText }, + { L"Josh Mulanax", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Shogo Ishii (TekSystems)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tyler Keenan (Xtreme Consulting Group Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Joshua Bullard (TekSystems)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_EXECPRODUCER, NO_TRANSLATED_STRING,eLargeText }, + { L"Mark Coates", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Avi Ben-Menahem", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Earnest Yuen", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_XBLADIRECTOR, NO_TRANSLATED_STRING,eLargeText }, + { L"Ted Woolsey", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_BIZDEV, NO_TRANSLATED_STRING,eLargeText }, + { L"Cherie Lutz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Peter Zetterberg", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_PORTFOLIODIRECTOR, NO_TRANSLATED_STRING,eLargeText }, + { L"Chris Charla", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_PRODUCTMANAGER, NO_TRANSLATED_STRING,eLargeText }, + { L"Daniel McConnell", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_MARKETING, NO_TRANSLATED_STRING,eLargeText }, + { L"Brandon Wells", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michael Wolf", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"John Dongelmans", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_COMMUNITYMANAGER, NO_TRANSLATED_STRING,eLargeText }, + { L"Alex Hebert", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_REDMONDLOC, NO_TRANSLATED_STRING,eLargeText }, + { L"Zeb Wedell", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Gabriella Mittiga (Pactera)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Scott Fielding (Global Studio Consulting)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Yong Zhao (Hisoft Envisage Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Shogo Ishii (Insight Global)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_EUROPELOC, NO_TRANSLATED_STRING,eLargeText }, + { L"Gerard Dunne", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ricardo Cordoba", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Magali Lucchini", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Malika Kherfi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Lizzy Untermann", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ian Walsh", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Alfonsina Mossello (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marika Mauri (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Nobuhiro Izumisawa (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Sebastien Faucon (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jose Manuel Martinez (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Montse Garcia (Keywords International Ltd)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_ASIALOC, NO_TRANSLATED_STRING,eLargeText }, + { L"Takashi Sasaki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Changseon Ha", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Shinya Muto (Zip Global Corporation)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Hiroshi Hosoda (Zip Global Corporation)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Natsuko Kudo (Zip Global Corporation)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Yong-Hong Park (Zip Global Corporation)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Yuko Yoshida (Zip Global Corporation)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_USERRESEARCH, NO_TRANSLATED_STRING,eLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"User Research Lead", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Tim Nichols", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"User Research Engineer", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Michael Medlock", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kristie Fisher", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_MGSCENTRAL, NO_TRANSLATED_STRING,eLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"Test Team Lead", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Dan Smith", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_MILESTONEACCEPT, NO_TRANSLATED_STRING,eLargeText }, + { L"Justin Davis (VMC)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Microsoft Studios Sentient Development Team", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Ellery Charlson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Frank Klier", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jason Ronald", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Cullen Waters", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Steve Jackson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Barath Vasudevan", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Derek Mantey", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Henry Sterchi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Scott Fintel", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Soren Hannibal Nielsen", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Meetali Goel (Aditi)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Uladzimir Sadouski (Volt)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_SPECIALTHANKS, NO_TRANSLATED_STRING,eLargeText }, + { L"Brianna Witherspoon (Nytec Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jim Pekola (Xtreme Consulting Group Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Henry", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Matt Golz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Gaffney (Volt)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jared Barnhill (Aditi)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Laura Hawkins", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"2nd Cavalry", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"GTO Bug Bash Team", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Oliver Miyashita", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kevin Salcedo", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Nick Bodenham", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Giggins", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ben Board", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Peter Choi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Andy Su (CompuCom Systems Inc.)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"David Boker ", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Josh Bliggenstorfer", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Paul Amer", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Louise Smith", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Karin Behland (Aquent LLC)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"John Bruno", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Phil Spencer", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"John Smith", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Christi Davisson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jacob Farley (Aditi)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chad Stringer (Collabera)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Rick Rispoli (Collabera)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Test by Experis", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"%s", IDS_CREDITS_TESTMANAGER, NO_TRANSLATED_STRING,eLargeText }, + { L"Matt Brown", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Gavin Kennedy", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_SRTESTLEAD, NO_TRANSLATED_STRING,eLargeText }, + { L"Lloyd Bell", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tim Attuquayefio", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_TESTLEAD, NO_TRANSLATED_STRING,eLargeText }, + { L"Byron R. Monzon", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marta Alombro", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_SDET, NO_TRANSLATED_STRING,eLargeText }, + { L"Valeriy Novytskyy", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_PROJECT, NO_TRANSLATED_STRING,eLargeText }, + { L"Allyson Burk", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"David Scott", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"John Shearer", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_ADDITIONALSTE, NO_TRANSLATED_STRING,eLargeText }, + { L"Chris Merritt", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kimberlee Lyles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Eric Ranz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Russ Allen", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_TESTASSOCIATES, NO_TRANSLATED_STRING,eLargeText }, + { L"Michael Arvat", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Josh Breese", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"April Culberson", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jason Fox", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Clayton K. Hopper", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Matthew Howells", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Alan Hume", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jacob Martin", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kevin Lourigan", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tyler Lovemark", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_RISE_LUGO, NO_TRANSLATED_STRING,eSmallText }, + { L"Ryan Naegeli", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Isaac Price", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Masha Reutovski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Brad Shockey", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jonathan Tote", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marc Williams", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Gillian Williams", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jeffrey Woito", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tyler Young", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jae Yslas", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Amanda Swalling", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ben Dienes", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Kent", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Dustin Lukas", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Emily Lovering", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Nick Fowler", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + // EVEN MORE CREDITS + { L"Test by Lionbridge", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"%s", IDS_CREDITS_TESTMANAGER, NO_TRANSLATED_STRING,eLargeText }, + { L"Blazej Zawadzki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"David Hickey", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_TESTLEAD, NO_TRANSLATED_STRING,eLargeText }, + { L"Jakub Garwacki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kamil Lahti", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Mariusz Gelnicki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Karol Falak", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Lukasz Watroba", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_PROJECT, NO_TRANSLATED_STRING,eLargeText }, + { L"Artur Grochowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Grzegorz Kohorewicz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Lukasz Derewonko", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Celej", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Senior Test Engineers", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Jakub Rybacki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Mateusz Szymanski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Arkadiusz Szczytowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Rafal Rawski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + + { L"%s", IDS_CREDITS_TESTASSOCIATES, NO_TRANSLATED_STRING,eLargeText }, + { L"Adrian Klepacki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Arkadiusz Kala", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Arkadiusz Sykula", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Bartlomiej Kmita", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jakub Malinowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jan Prejs", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Maciej Urlo", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Maciej Wygoda", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marcin Piasecki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marcin Piotrowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marek Latacz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Biernat", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Krupinski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Warchal", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Wascinski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Zbrzezniak", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Milosz Maciejewicz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Przemyslaw Malinowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tomasz Dabrowicz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tomasz Trzebiatowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + + { L"Adam Bogucki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Aleksander Pietraszak", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Arkadiusz Szczytowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Blazej Kohorewicz", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Damian Mielnik", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Dariusz Nowakowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Dominik Rzeznicki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jacek Piotrowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jakub Rybacki", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jakub Wozniakowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jaroslaw Radzio", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kamil Dabrowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Kamil Kaczor", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Karolina Szymanska", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Konrad Mady", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Krzysztof Galazka", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ludwik Miszta", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Lukasz Kwiatkowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Marcin Krzysiak", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Mateusz Szymanski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Maslany", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michal Nyszka", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Norbert Jankowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Piotr Daszewski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Radoslaw Kozlowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Tomasz Kalowski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"%s", IDS_CREDITS_SPECIALTHANKS, NO_TRANSLATED_STRING,eLargeText }, + { L"Adam Keating", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jerzy Tyminski", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Paulina Sliwinska", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Sean Kellogg", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + + { L"Test by Shield", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eExtraLargeText }, + { L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line + { L"GTO Shared Service Test Manager", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Natahri Felton", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Shield Test Lead", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Matt Giddings", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Shield IT Support", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"David Grant (Compucom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Primary Team", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eLargeText }, + { L"Alex Chen (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Alex Hunte (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Brian Boye (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Bridgette Cummins (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Chris Carleson (Volt)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Christopher Hermey (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"David Hendrickson (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Ioana Preda (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Jessica Jenkins (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Johnathan Ochs (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Michael Upham (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Nicholas Johansson (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Nicholas Starner (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Torr Vickers (Volt)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + { L"Victoria Bruder (CompuCom Systems Inc)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, + +}; + +// Table tells us how many text elements of each type are available in the scene. +static const int gs_aNumTextElements[ eNumTextTypes ] = +{ + 3, // CScene_Credits::eExtraLargeText + 5, // CScene_Credits::eLargeText + 5, // CScene_Credits::eMediumText + 15 // CScene_Credits::eSmallText +}; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Credits::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + int iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + // if we're not in the game, we need to use basescene 0 + if(Minecraft::GetInstance()->level==NULL) + { + iPad=0; + } + + ui.SetTooltips( iPad, -1, IDS_TOOLTIPS_BACK); + + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + CREDITS_SCREEN_MIN_Y = 200.0f/1.5f; // Y pos at which credits are removed from top of screen. + CREDITS_SCREEN_MAX_Y = 630.0f/1.5f; // Y pos at which credits appear at bottom of screen. + CREDITS_FADE_HEIGHT = 100.0f/1.5f; // Height over which credits fade in or fade out. + gs_aLineSpace[eExtraLargeText]=53.0f; + gs_aLineSpace[eLargeText]=46.0f; + gs_aLineSpace[eMediumText]=40.0f; + gs_aLineSpace[eSmallText]=21.0f; + } + else + { + CREDITS_SCREEN_MIN_Y = 200.0f; // Y pos at which credits are removed from top of screen. + CREDITS_SCREEN_MAX_Y = 630.0f; // Y pos at which credits appear at bottom of screen. + CREDITS_FADE_HEIGHT = 100.0f; // Height over which credits fade in or fade out. + gs_aLineSpace[eExtraLargeText]=80.0f; + gs_aLineSpace[eLargeText]=70.0f; + gs_aLineSpace[eMediumText]=60.0f; + gs_aLineSpace[eSmallText]=32.0f; + } + + + // Init text elements. + int iIDTag = 1; + LPWSTR idString = new wchar_t[ 32 ]; + + for ( int i = 0; i < eNumTextTypes; ++i ) + { + m_aTextTypes[ i ].m_iNextFreeElement = 0; + m_aTextTypes[ i ].m_iNumUsedElements = 0; + m_aTextTypes[ i ].m_iMaxElements = gs_aNumTextElements[ i ]; + m_aTextTypes[ i ].m_appTextElements = new CXuiControl* [ m_aTextTypes[ i ].m_iMaxElements ]; + + for ( int j = 0; j < m_aTextTypes[ i ].m_iMaxElements; ++j ) + { + swprintf( idString, 32, L"XuiText%d", iIDTag ); + ++iIDTag; + + HXUIOBJ text; + GetChildById( idString, &text ); + + VOID* pTextObj; + XuiObjectFromHandle( text, &pTextObj ); + m_aTextTypes[ i ].m_appTextElements[ j ] = (CXuiControl *)pTextObj; + m_aTextTypes[ i ].m_appTextElements[ j ]->SetShow( false ); + } + } + delete [] idString; + + // How many lines of text are in the credits? + + m_iNumTextDefs = MAX_CREDIT_STRINGS;//sizeof( gs_aCreditDefs ) / sizeof( SCreditTextItemDef ); + + // Are there any additional lines needed for the DLC credits? + m_iNumTextDefs+=app.GetDLCCreditsCount(); + + m_iCurrDefIndex = -1; + m_fMoveSinceLastDef = 0.0f; + m_fMoveToNextDef = 0.0f; + + // Add timer to tick credits update at 60Hz + HRESULT timerResult = SetTimer( CREDITS_TICK_TIMER_ID, ( 1000 / 60 ) ); + assert( timerResult == S_OK ); + + return S_OK; +} + +HRESULT CScene_Credits::OnDestroy() +{ + // Free up memory that we allocated. + for ( int i = 0; i < eNumTextTypes; ++i ) + { + delete [] m_aTextTypes[ i ].m_appTextElements; + } + + return S_OK; +} + +HRESULT CScene_Credits::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + + return hr; +} + +HRESULT CScene_Credits::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // ignore any joypads other than the main + BYTE bFocusUser=XuiElementGetFocusUser(pControlNavigateData->hObjSource); + // get the user from the control + /*if(!=ProfileManager.GetLockedProfile()) + { + bHandled=true; + return S_OK; + }*/ + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Credits::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + + return S_OK; +} + + + +HRESULT CScene_Credits::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // Update pointer from stick input on timer. + if ( pTimer->nId == CREDITS_TICK_TIMER_ID ) + { + D3DXVECTOR3 vTextPos; + + // Do we need to spawn a new item? + if ( ( m_iCurrDefIndex == -1 ) || ( m_fMoveSinceLastDef >= m_fMoveToNextDef ) ) + { + const SCreditTextItemDef* pDef; + + // Time to create next text item. + ++m_iCurrDefIndex; + + // Wrap back to start. + if ( m_iCurrDefIndex >= m_iNumTextDefs ) + { + m_iCurrDefIndex = 0; + } + + if(m_iCurrDefIndex >= MAX_CREDIT_STRINGS) + { + // DLC credit + pDef = app.GetDLCCredits(m_iCurrDefIndex-MAX_CREDIT_STRINGS); + } + else + { + // Get text def for this item. + pDef = &( gs_aCreditDefs[ m_iCurrDefIndex ] ); + } + + int iNewTextType = ( int )( pDef->m_eType ); + STextType* pTextType = &( m_aTextTypes[ iNewTextType ] ); + + // Are there any text elements available for this item? + if ( pTextType->m_iNumUsedElements < pTextType->m_iMaxElements ) + { + // Get the correct text element to use. + CXuiControl* pElement = pTextType->m_appTextElements[ pTextType->m_iNextFreeElement ]; + + // Set up the new text element. + if ( pDef->m_iStringID[0] == NO_TRANSLATED_STRING ) + { + pElement->SetText( pDef->m_Text ); + } + else // using additional translated string. + { + LPWSTR creditsString = new wchar_t[ 128 ]; + if(pDef->m_iStringID[1]!=NO_TRANSLATED_STRING) + { + swprintf( creditsString, 128, pDef->m_Text, app.GetString( pDef->m_iStringID[0] ), app.GetString( pDef->m_iStringID[1] ) ); + } + else + { + swprintf( creditsString, 128, pDef->m_Text, app.GetString( pDef->m_iStringID[0] ) ); + } + pElement->SetText( creditsString ); + delete [] creditsString; + } + + pElement->SetShow( true ); + pElement->SetOpacity( 0.0f ); + + pElement->GetPosition( &vTextPos ); + vTextPos.y = CREDITS_SCREEN_MAX_Y; + pElement->SetPosition( &vTextPos ); + + // Set next free element of this type. + ++( pTextType->m_iNextFreeElement ); + + if ( pTextType->m_iNextFreeElement >= pTextType->m_iMaxElements ) + { + pTextType->m_iNextFreeElement = 0; + } + + ++pTextType->m_iNumUsedElements; + + int iNextDef = m_iCurrDefIndex + 1; + if ( iNextDef == m_iNumTextDefs ) + { + // Large space before looping back to start of credits. + m_fMoveToNextDef = 400.0f; + } + else if ( iNextDef < MAX_CREDIT_STRINGS ) + { + // Determine space to next item. + m_fMoveToNextDef = gs_aLineSpace[ gs_aCreditDefs[ iNextDef ].m_eType ]; + } + else + { + // Determine space to next item. + m_fMoveToNextDef = gs_aLineSpace[app.GetDLCCredits(iNextDef-MAX_CREDIT_STRINGS)->m_eType]; + } + + m_fMoveSinceLastDef = 0.0f; + } + } + + // Scroll up every active text element. + for ( int i = 0; i < eNumTextTypes; ++i ) + { + STextType* pTextType = &( m_aTextTypes[ i ] ); + + // Process in reverse order from latest one back (so that we can easily remove oldest if it has scrolled off the top). + int iElementIndex = pTextType->m_iNextFreeElement; + + --iElementIndex; + if ( iElementIndex < 0 ) + { + iElementIndex = pTextType->m_iMaxElements - 1; + } + + // For each element that it is use + for ( int j = 0; j < pTextType->m_iNumUsedElements; ++j ) + { + // Get the actual element. + CXuiControl* pElement = pTextType->m_appTextElements[ iElementIndex ]; + + // Scroll element up. + pElement->GetPosition( &vTextPos ); + vTextPos.y -= 1.0f; + pElement->SetPosition( &vTextPos ); + + // Is it off the top? + if ( vTextPos.y < CREDITS_SCREEN_MIN_Y ) + { + // Remove it. + pElement->SetShow( false ); + --( pTextType->m_iNumUsedElements ); + } + else + { + // Set transparency to fade in at bottom or out at top. + float fOpacity = 1.0f; + if ( vTextPos.y < ( CREDITS_SCREEN_MIN_Y + CREDITS_FADE_HEIGHT ) ) + { + fOpacity = ( vTextPos.y - CREDITS_SCREEN_MIN_Y ) / CREDITS_FADE_HEIGHT; + } + else if ( vTextPos.y > ( CREDITS_SCREEN_MAX_Y - CREDITS_FADE_HEIGHT ) ) + { + fOpacity = ( CREDITS_SCREEN_MAX_Y - vTextPos.y ) / CREDITS_FADE_HEIGHT; + } + pElement->SetOpacity( fOpacity ); + } + + // Determine next element index. + --iElementIndex; + if ( iElementIndex < 0 ) + { + iElementIndex = pTextType->m_iMaxElements - 1; + } + } + } + + m_fMoveSinceLastDef += 1.0f; + + // This message has been dealt with, don't pass it on further. + bHandled = TRUE; + } + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_HelpCredits.h b/Minecraft.Client/Common/XUI/XUI_HelpCredits.h new file mode 100644 index 00000000..e973286e --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpCredits.h @@ -0,0 +1,73 @@ +#pragma once + +#define CREDITS_TICK_TIMER_ID (6) // Arbitrary timer ID used to tick credits for scrolling. + +#define MAX_CREDIT_STRINGS 360 +// 213 + +#include "..\UI\UIStructs.h" + +class CScene_Credits : public CXuiSceneImpl +{ +protected: + // Control and Element wrapper objects. + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_CONTROL_NAVIGATE(OnControlNavigate) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnDestroy(); + +private: + + + struct STextType + { + // Array of pointers to text elements. + CXuiControl** m_appTextElements; + + int m_iNextFreeElement; + int m_iNumUsedElements; + int m_iMaxElements; + }; + + STextType m_aTextTypes[ eNumTextTypes ]; + + int m_iCurrDefIndex; // Index of last created text def. + float m_fMoveSinceLastDef; // How far have credits scrolled since we last created a new text item. + float m_fMoveToNextDef; // How far we need to move before starting next text item. + int m_iNumTextDefs; // Total number of text defs in the credits. + + float CREDITS_SCREEN_MIN_Y;// ( 200.0f ) // Y pos at which credits are removed from top of screen. + float CREDITS_SCREEN_MAX_Y;// ( 630.0f ) // Y pos at which credits appear at bottom of screen. + float CREDITS_FADE_HEIGHT;// ( 100.0f ) // Height over which credits fade in or fade out. + + float gs_aLineSpace[ eNumTextTypes ]; + +public: + static SCreditTextItemDef gs_aCreditDefs[MAX_CREDIT_STRINGS]; + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Credits, L"CScene_Credits", XUI_CLASS_SCENE ) + + + +}; + diff --git a/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.cpp b/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.cpp new file mode 100644 index 00000000..5c750d03 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.cpp @@ -0,0 +1,238 @@ +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_HelpHowToPlay.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" + +static SHowToPlayPageDef gs_aPageDefs[ eHowToPlay_NumPages ] = +{ + { eHowToPlay_WhatsNew, IDS_HOW_TO_PLAY_WHATSNEW, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_WhatsNew + { eHowToPlay_TextBasics, IDS_HOW_TO_PLAY_BASICS, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_Basics + { eHowToPlay_TextMultiplayer, IDS_HOW_TO_PLAY_MULTIPLAYER, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_Multiplayer + { eHowToPlay_TextHUD, IDS_HOW_TO_PLAY_HUD, eHowToPlay_ImageHUD, 0, 0}, // eHowToPlay_HUD + { eHowToPlay_TextCreative, IDS_HOW_TO_PLAY_CREATIVE, eHowToPlay_ImageCreative, eHowToPlay_LabelCreativeInventory, 1}, // eHowToPlay_Creative + { eHowToPlay_TextInventory, IDS_HOW_TO_PLAY_INVENTORY, eHowToPlay_ImageInventory, eHowToPlay_LabelIInventory, 1}, // eHowToPlay_Inventory + { eHowToPlay_TextSmallChest, IDS_HOW_TO_PLAY_CHEST, eHowToPlay_ImageChest, eHowToPlay_LabelSCInventory, 2}, // eHowToPlay_Chest + { eHowToPlay_TextLargeChest, IDS_HOW_TO_PLAY_LARGECHEST, eHowToPlay_ImageLargeChest, eHowToPlay_LabelLCInventory, 2}, // eHowToPlay_LargeChest + { eHowToPlay_TextEnderchest, IDS_HOW_TO_PLAY_ENDERCHEST, eHowToPlay_ImageEnderChest, 0, 0}, // eHowToPlay_EnderChest + { eHowToPlay_TextCrafting, IDS_HOW_TO_PLAY_CRAFTING, eHowToPlay_ImageInventoryCrafting, eHowToPlay_LabelCItem, 3}, // eHowToPlay_InventoryCrafting + { eHowToPlay_TextCraftTable, IDS_HOW_TO_PLAY_CRAFT_TABLE, eHowToPlay_ImageCraftingTable, eHowToPlay_LabelCTItem, 3}, // eHowToPlay_CraftTable + { eHowToPlay_TextFurnace, IDS_HOW_TO_PLAY_FURNACE, eHowToPlay_ImageFurnace, eHowToPlay_LabelFFuel, 4}, // eHowToPlay_Furnace + { eHowToPlay_TextDispenser, IDS_HOW_TO_PLAY_DISPENSER, eHowToPlay_ImageDispenser, eHowToPlay_LabelDText, 2}, // eHowToPlay_Dispenser + { eHowToPlay_TextBrewing, IDS_HOW_TO_PLAY_BREWING, eHowToPlay_ImageBrewing, eHowToPlay_LabelBBrew, 2}, // eHowToPlay_Brewing + { eHowToPlay_TextEnchantment, IDS_HOW_TO_PLAY_ENCHANTMENT, eHowToPlay_ImageEnchantment, eHowToPlay_LabelEEnchant, 2}, // eHowToPlay_Enchantment + { eHowToPlay_TextAnvil, IDS_HOW_TO_PLAY_ANVIL, eHowToPlay_ImageAnvil, eHowToPlay_LabelAnvil_Inventory, 3}, // eHowToPlay_Anvil + { eHowToPlay_TextFarmingAnimals,IDS_HOW_TO_PLAY_FARMANIMALS, eHowToPlay_ImageFarmingAnimals, 0, 0}, // eHowToPlay_Farming + { eHowToPlay_TextBreeding, IDS_HOW_TO_PLAY_BREEDANIMALS, eHowToPlay_ImageBreeding, 0, 0}, // eHowToPlay_Breeding + { eHowToPlay_TextTrading, IDS_HOW_TO_PLAY_TRADING, eHowToPlay_ImageTrading, eHowToPlay_LabelTrading_Inventory, 5}, // eHowToPlay_Trading + { eHowToPlay_TextNetherPortal, IDS_HOW_TO_PLAY_NETHERPORTAL, eHowToPlay_ImageNetherPortal, 0, 0}, // eHowToPlay_NetherPortal + { eHowToPlay_TextTheEnd, IDS_HOW_TO_PLAY_THEEND, eHowToPlay_ImageTheEnd, 0, 0}, // eHowToPlay_TheEnd + { eHowToPlay_TextSocialMedia, IDS_HOW_TO_PLAY_SOCIALMEDIA, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_SocialMedia + { eHowToPlay_TextBanList, IDS_HOW_TO_PLAY_BANLIST, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_BanList + { eHowToPlay_TextHostOptions, IDS_HOW_TO_PLAY_HOSTOPTIONS, eHowToPlay_ImageNone, 0, 0}, // eHowToPlay_HostOptions +}; + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_HowToPlay::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + // Extract pad and required page from init data. We just put the data into the pointer rather than using it as an address. + size_t uiInitData = ( size_t )( pInitData->pvInitData ); + + m_iPad = ( int )( ( short )( uiInitData & 0xFFFF ) ); + EHowToPlayPage eStartPage = ( EHowToPlayPage )( ( uiInitData >> 16 ) & 0xFFF ); // Ignores MSB which is set to 1! + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_HowToPlay, (ETelemetry_HowToPlay_SubMenuId)eStartPage); + + MapChildControls(); + + wstring wsTemp, inventoryString = app.GetString(IDS_INVENTORY); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCTItem],app.GetString(IDS_ITEM_HATCHET_WOOD)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCTGroup],app.GetString(IDS_GROUPNAME_TOOLS)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCTInventory3x3],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCItem],app.GetString(IDS_TILE_WORKBENCH)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCGroup],app.GetString(IDS_GROUPNAME_STRUCTURES)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCInventory2x2],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelFFuel],app.GetString(IDS_FUEL)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelFInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelFIngredient],app.GetString(IDS_INGREDIENT)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelFChest],app.GetString(IDS_FURNACE)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelLCInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelCreativeInventory],app.GetString(IDS_GROUPNAME_BUILDING_BLOCKS)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelLCChest],app.GetString(IDS_CHEST)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelSCInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelSCChest],app.GetString(IDS_CHEST)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelIInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelDInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelDText],app.GetString(IDS_DISPENSER)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelEEnchant],app.GetString(IDS_ENCHANT)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelEInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelBBrew],app.GetString(IDS_BREWING_STAND)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelBInventory],inventoryString.c_str()); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelAnvil_Inventory], inventoryString.c_str()); + + wsTemp = app.GetString(IDS_REPAIR_COST); + wsTemp.replace( wsTemp.find(L"%d"), 2, wstring(L"8") ); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelAnvil_Cost], wsTemp.c_str()); + + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelAnvil_ARepairAndName], app.GetString(IDS_REPAIR_AND_NAME)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelTrading_Inventory], inventoryString.c_str()); + //XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelTrading_Offer2], app.GetString(IDS_ITEM_HATCHET_DIAMOND)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelTrading_Offer1], app.GetString(IDS_ITEM_EMERALD)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelTrading_NeededForTrade], app.GetString(IDS_REQUIRED_ITEMS_FOR_TRADE)); + + wsTemp = app.GetString(IDS_VILLAGER_OFFERS_ITEM); + wsTemp = replaceAll(wsTemp,L"{*VILLAGER_TYPE*}",app.GetString(IDS_VILLAGER_PRIEST)); + wsTemp.replace(wsTemp.find(L"%s"),2, app.GetString(IDS_TILE_LIGHT_GEM)); + XuiControlSetText(m_aLabelControls[ eHowToPlay_LabelTrading_VillagerOffers], wsTemp.c_str()); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + + StartPage( eStartPage ); + + return S_OK; +} + +HRESULT CScene_HowToPlay::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + { + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + } + break; + case VK_PAD_A: + { + // Next page + int iNextPage = ( int )( m_eCurrPage ) + 1; + if ( iNextPage != eHowToPlay_NumPages ) + { + StartPage( ( EHowToPlayPage )( iNextPage ) ); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + rfHandled = TRUE; + } + break; + case VK_PAD_X: + { + // Next page + int iPrevPage = ( int )( m_eCurrPage ) - 1; + if ( iPrevPage >= 0 ) + { + StartPage( ( EHowToPlayPage )( iPrevPage ) ); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + rfHandled = TRUE; + } + break; + } + return S_OK; +} + + +void CScene_HowToPlay::StartPage( EHowToPlayPage ePage ) +{ + int iBaseSceneUser; + // if we're not in the game, we need to use basescene 0 + if(Minecraft::GetInstance()->level==NULL) + { + iBaseSceneUser=DEFAULT_XUI_MENU_USER; + } + else + { + iBaseSceneUser=m_iPad; + } + m_eCurrPage = ePage; + + // Turn off everything. + for ( int i = 0; i < eHowToPlay_NumTexts; ++i ) + { + m_aTextControls[ i ].SetShow( FALSE ); + } + for ( int i = 0; i < eHowToPlay_NumImages; ++i ) + { + m_aImageControls[ i ].SetShow( FALSE ); + } + for ( int i = 0; i < eHowToPlay_NumLabels; ++i ) + { + m_aLabelControls[ i ].SetShow( FALSE ); + } + + // Turn on just what we need for this screen. + SHowToPlayPageDef* pDef = &( gs_aPageDefs[ m_eCurrPage ] ); + + if ( pDef->m_iTextControlIndex != eHowToPlay_TextNone ) + { + // Replace button identifiers in the text with actual button images. + wstring replacedText = app.FormatHTMLString(m_iPad, app.GetString( pDef->m_iTextStringID )); + + // 4J-PB - replace the title with the platform specific title, and the platform name + replacedText = replaceAll(replacedText,L"{*PLATFORM_NAME*}",app.GetString(IDS_PLATFORM_NAME)); + replacedText = replaceAll(replacedText,L"{*BACK_BUTTON*}",app.GetString(IDS_BACK_BUTTON)); + replacedText = replaceAll(replacedText,L"{*DISABLES_ACHIEVEMENTS*}",app.GetString(IDS_HOST_OPTION_DISABLES_ACHIEVEMENTS)); + + // Set the text colour + wstring finalText(replacedText.c_str() ); + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\">",app.GetHTMLColour(eHTMLColor_White)); + finalText = startTags + finalText; + + // Set the text in the xui scene. + m_aTextControls[ pDef->m_iTextControlIndex ].SetText( finalText.c_str() ); + + // Make it visible. + m_aTextControls[ pDef->m_iTextControlIndex ].SetShow( TRUE ); + + XuiElementSetUserFocus(m_aTextControls[ pDef->m_iTextControlIndex ].m_hObj, m_iPad); + } + + if(pDef->m_iLabelCount!=0) + { + for(int i=pDef->m_iLabelStartIndex;i<(pDef->m_iLabelStartIndex+pDef->m_iLabelCount);i++) + { + m_aLabelControls[i].SetShow( TRUE ); + } + } + + if ( pDef->m_iImageControlIndex != eHowToPlay_ImageNone ) + { + m_aImageControls[ pDef->m_iImageControlIndex ].SetShow( TRUE ); + } + + // Tool tips. + int iPage = ( int )( m_eCurrPage ); + if ( iPage == 0 ) + { + // No previous page. + ui.SetTooltips( iBaseSceneUser, IDS_HOW_TO_PLAY_NEXT, IDS_TOOLTIPS_BACK, -1 ); + } + else if ( ( iPage + 1 ) == eHowToPlay_NumPages ) + { + // No next page. + ui.SetTooltips( iBaseSceneUser, -1, IDS_TOOLTIPS_BACK, IDS_HOW_TO_PLAY_PREV ); + } + else + { + ui.SetTooltips( iBaseSceneUser, IDS_HOW_TO_PLAY_NEXT, IDS_TOOLTIPS_BACK, IDS_HOW_TO_PLAY_PREV ); + } + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_HowToPlay, (ETelemetry_HowToPlay_SubMenuId)ePage); +} + +HRESULT CScene_HowToPlay::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} diff --git a/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.h b/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.h new file mode 100644 index 00000000..8a37e925 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.h @@ -0,0 +1,217 @@ +#pragma once + +#include "../media/xuiscene_howtoplay.h" +#include "XUI_CustomMessages.h" + +enum EHowToPlayTextControls +{ + eHowToPlay_TextNone = -1, + eHowToPlay_TextWhatsNew = 0, + eHowToPlay_TextBasics, + eHowToPlay_TextMultiplayer, + eHowToPlay_TextHUD, + eHowToPlay_TextCreative, + eHowToPlay_TextInventory, + eHowToPlay_TextSmallChest, + eHowToPlay_TextLargeChest, + eHowToPlay_TextEnderchest, + eHowToPlay_TextCrafting, + eHowToPlay_TextCraftTable, + eHowToPlay_TextFurnace, + eHowToPlay_TextDispenser, + eHowToPlay_TextBrewing, + eHowToPlay_TextEnchantment, + eHowToPlay_TextAnvil, + eHowToPlay_TextFarmingAnimals, + eHowToPlay_TextBreeding, + eHowToPlay_TextTrading, + eHowToPlay_TextNetherPortal, + eHowToPlay_TextTheEnd, + eHowToPlay_TextSocialMedia, + eHowToPlay_TextBanList, + eHowToPlay_TextHostOptions, + eHowToPlay_NumTexts +}; + +enum EHowToPlayImageControls +{ + eHowToPlay_ImageNone = -1, + eHowToPlay_ImageHUD = 0, + eHowToPlay_ImageCreative, + eHowToPlay_ImageInventory, + eHowToPlay_ImageChest, + eHowToPlay_ImageLargeChest, + eHowToPlay_ImageEnderChest, + eHowToPlay_ImageInventoryCrafting, + eHowToPlay_ImageCraftingTable, + eHowToPlay_ImageFurnace, + eHowToPlay_ImageDispenser, + eHowToPlay_ImageBrewing, + eHowToPlay_ImageEnchantment, + eHowToPlay_ImageAnvil, + eHowToPlay_ImageFarmingAnimals, + eHowToPlay_ImageBreeding, + eHowToPlay_ImageTrading, + eHowToPlay_ImageNetherPortal, + eHowToPlay_ImageTheEnd, + eHowToPlay_NumImages +}; + +enum EHowToPlayLabelControls +{ + eHowToPlay_LabelNone = -1, + eHowToPlay_LabelIInventory =0, + eHowToPlay_LabelSCInventory , + eHowToPlay_LabelSCChest , + eHowToPlay_LabelLCInventory , + eHowToPlay_LabelLCChest , + eHowToPlay_LabelCItem , + eHowToPlay_LabelCGroup , + eHowToPlay_LabelCInventory2x2 , + eHowToPlay_LabelCTItem , + eHowToPlay_LabelCTGroup , + eHowToPlay_LabelCTInventory3x3 , + eHowToPlay_LabelFFuel , + eHowToPlay_LabelFInventory , + eHowToPlay_LabelFIngredient , + eHowToPlay_LabelFChest , + eHowToPlay_LabelDText , + eHowToPlay_LabelDInventory , + eHowToPlay_LabelCreativeInventory, + eHowToPlay_LabelEEnchant, + eHowToPlay_LabelEInventory, + eHowToPlay_LabelBBrew, + eHowToPlay_LabelBInventory, + eHowToPlay_LabelAnvil_Inventory, + eHowToPlay_LabelAnvil_Cost, + eHowToPlay_LabelAnvil_ARepairAndName, + eHowToPlay_LabelTrading_Inventory, + eHowToPlay_LabelTrading_Offer2, + eHowToPlay_LabelTrading_Offer1, + eHowToPlay_LabelTrading_NeededForTrade, + eHowToPlay_LabelTrading_VillagerOffers, + eHowToPlay_NumLabels +}; + +struct SHowToPlayPageDef +{ + int m_iTextControlIndex; // eHowToPlay_TextNone if not used. + int m_iTextStringID; // -1 if not used. + int m_iImageControlIndex; // eHowToPlay_ImageNone if not used. + int m_iLabelStartIndex; // index of the labels if there are any for the page + int m_iLabelCount; +}; + +class CScene_HowToPlay : public CXuiSceneImpl +{ +protected: + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + EHowToPlayPage m_eCurrPage; + + // Control and Element wrapper objects. + CXuiHtmlElement m_aTextControls[ eHowToPlay_NumTexts ]; + CXuiControl m_aImageControls[ eHowToPlay_NumImages ]; + CXuiControl m_aLabelControls[ eHowToPlay_NumLabels ]; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiHtmlControlMultiplayer, m_aTextControls[ eHowToPlay_TextMultiplayer ] ) + MAP_CONTROL(IDC_XuiHtmlControlBasics, m_aTextControls[ eHowToPlay_TextBasics ] ) + MAP_CONTROL(IDC_XuiHtmlControlHUD, m_aTextControls[ eHowToPlay_TextHUD ] ) + MAP_CONTROL(IDC_XuiHtmlControlCreative, m_aTextControls[ eHowToPlay_TextCreative ] ) + MAP_CONTROL(IDC_XuiHtmlControlInventory, m_aTextControls[ eHowToPlay_TextInventory ] ) + MAP_CONTROL(IDC_XuiHtmlControlChest, m_aTextControls[ eHowToPlay_TextSmallChest ] ) + MAP_CONTROL(IDC_XuiHtmlControlLargeChest, m_aTextControls[ eHowToPlay_TextLargeChest ] ) + MAP_CONTROL(IDC_XuiHtmlControlEnderchest, m_aTextControls[ eHowToPlay_TextEnderchest ] ) + MAP_CONTROL(IDC_XuiHtmlControlCrafting, m_aTextControls[ eHowToPlay_TextCrafting ] ) + MAP_CONTROL(IDC_XuiHtmlControlCraftingTable, m_aTextControls[ eHowToPlay_TextCraftTable ] ) + MAP_CONTROL(IDC_XuiHtmlControlFurnace, m_aTextControls[ eHowToPlay_TextFurnace ] ) + MAP_CONTROL(IDC_XuiHtmlControlDispenser, m_aTextControls[ eHowToPlay_TextDispenser ] ) + MAP_CONTROL(IDC_XuiHtmlControlBrewing, m_aTextControls[ eHowToPlay_TextBrewing ] ) + MAP_CONTROL(IDC_XuiHtmlControlEnchantment, m_aTextControls[ eHowToPlay_TextEnchantment ] ) + MAP_CONTROL(IDC_XuiHtmlControlAnvil, m_aTextControls[ eHowToPlay_TextAnvil ] ) + MAP_CONTROL(IDC_XuiHtmlControlFarmingAnimals, m_aTextControls[ eHowToPlay_TextFarmingAnimals ] ) + MAP_CONTROL(IDC_XuiHtmlControlBreeding, m_aTextControls[ eHowToPlay_TextBreeding ] ) + MAP_CONTROL(IDC_XuiHtmlControlTrading, m_aTextControls[ eHowToPlay_TextTrading ] ) + MAP_CONTROL(IDC_XuiHtmlControlNetherPortal, m_aTextControls[ eHowToPlay_TextNetherPortal ] ) + MAP_CONTROL(IDC_XuiHtmlControlTheEnd, m_aTextControls[ eHowToPlay_TextTheEnd ] ) + MAP_CONTROL(IDC_XuiHtmlControlSocialMedia, m_aTextControls[ eHowToPlay_TextSocialMedia ] ) + MAP_CONTROL(IDC_XuiHtmlControlBanList, m_aTextControls[ eHowToPlay_TextBanList ] ) + MAP_CONTROL(IDC_XuiHtmlControlWhatsNew, m_aTextControls[ eHowToPlay_TextWhatsNew ] ) + MAP_CONTROL(IDC_XuiHtmlControlHostOptions, m_aTextControls[ eHowToPlay_TextHostOptions] ) + + MAP_CONTROL(IDC_XuiImageHUD, m_aImageControls[ eHowToPlay_ImageHUD ] ) + MAP_CONTROL(IDC_XuiImageCreative, m_aImageControls[ eHowToPlay_ImageCreative ] ) + MAP_CONTROL(IDC_XuiImageInventory, m_aImageControls[ eHowToPlay_ImageInventory ] ) + MAP_CONTROL(IDC_XuiImageChest, m_aImageControls[ eHowToPlay_ImageChest ] ) + MAP_CONTROL(IDC_XuiImageLargeChest, m_aImageControls[ eHowToPlay_ImageLargeChest ] ) + MAP_CONTROL(IDC_XuiImageEnderchest, m_aImageControls[ eHowToPlay_ImageEnderChest ] ) + MAP_CONTROL(IDC_XuiImageCrafting, m_aImageControls[ eHowToPlay_ImageInventoryCrafting ] ) + MAP_CONTROL(IDC_XuiImageCraftingTable, m_aImageControls[ eHowToPlay_ImageCraftingTable ] ) + MAP_CONTROL(IDC_XuiImageFurnace, m_aImageControls[ eHowToPlay_ImageFurnace ] ) + MAP_CONTROL(IDC_XuiImageDispenser, m_aImageControls[ eHowToPlay_ImageDispenser ] ) + MAP_CONTROL(IDC_XuiImageBrewing, m_aImageControls[ eHowToPlay_ImageBrewing ] ) + MAP_CONTROL(IDC_XuiImageEnchantment, m_aImageControls[ eHowToPlay_ImageEnchantment ] ) + MAP_CONTROL(IDC_XuiImageAnvil, m_aImageControls[ eHowToPlay_ImageAnvil ] ) + MAP_CONTROL(IDC_XuiImageBreeding, m_aImageControls[ eHowToPlay_ImageBreeding ] ) + MAP_CONTROL(IDC_XuiImageFarmingAnimals, m_aImageControls[ eHowToPlay_ImageFarmingAnimals ] ) + MAP_CONTROL(IDC_XuiImageTrading, m_aImageControls[ eHowToPlay_ImageTrading ] ) + MAP_CONTROL(IDC_XuiImageNetherPortal, m_aImageControls[ eHowToPlay_ImageNetherPortal ] ) + MAP_CONTROL(IDC_XuiImageTheEnd, m_aImageControls[ eHowToPlay_ImageTheEnd ] ) + + MAP_CONTROL(IDC_CTItem, m_aLabelControls[ eHowToPlay_LabelCTItem ] ) + MAP_CONTROL(IDC_CTGroup, m_aLabelControls[ eHowToPlay_LabelCTGroup ] ) + MAP_CONTROL(IDC_CTInventory3x3, m_aLabelControls[ eHowToPlay_LabelCTInventory3x3 ] ) + MAP_CONTROL(IDC_CItem, m_aLabelControls[ eHowToPlay_LabelCItem ] ) + MAP_CONTROL(IDC_CGroup, m_aLabelControls[ eHowToPlay_LabelCGroup ] ) + MAP_CONTROL(IDC_CInventory, m_aLabelControls[ eHowToPlay_LabelCInventory2x2 ] ) + MAP_CONTROL(IDC_FFuel, m_aLabelControls[ eHowToPlay_LabelFFuel ] ) + MAP_CONTROL(IDC_FInventory, m_aLabelControls[ eHowToPlay_LabelFInventory ] ) + MAP_CONTROL(IDC_FIngredient, m_aLabelControls[ eHowToPlay_LabelFIngredient ] ) + MAP_CONTROL(IDC_FChest, m_aLabelControls[ eHowToPlay_LabelFChest ] ) + MAP_CONTROL(IDC_LCInventory, m_aLabelControls[ eHowToPlay_LabelLCInventory ] ) + MAP_CONTROL(IDC_CIGroup, m_aLabelControls[ eHowToPlay_LabelCreativeInventory ] ) + MAP_CONTROL(IDC_LCChest, m_aLabelControls[ eHowToPlay_LabelLCChest ] ) + MAP_CONTROL(IDC_SCInventory, m_aLabelControls[ eHowToPlay_LabelSCInventory ] ) + MAP_CONTROL(IDC_SCChest, m_aLabelControls[ eHowToPlay_LabelSCChest ] ) + MAP_CONTROL(IDC_IInventory, m_aLabelControls[ eHowToPlay_LabelIInventory ] ) + MAP_CONTROL(IDC_DInventory, m_aLabelControls[ eHowToPlay_LabelDInventory ] ) + MAP_CONTROL(IDC_DText, m_aLabelControls[ eHowToPlay_LabelDText ] ) + MAP_CONTROL(IDC_EEnchant, m_aLabelControls[ eHowToPlay_LabelEEnchant ] ) + MAP_CONTROL(IDC_EInventory, m_aLabelControls[ eHowToPlay_LabelEInventory ] ) + MAP_CONTROL(IDC_BBrew, m_aLabelControls[ eHowToPlay_LabelBBrew ] ) + MAP_CONTROL(IDC_BInventory, m_aLabelControls[ eHowToPlay_LabelBInventory ] ) + MAP_CONTROL(IDC_AInventory, m_aLabelControls[ eHowToPlay_LabelAnvil_Inventory ] ) + MAP_CONTROL(IDC_ACost, m_aLabelControls[ eHowToPlay_LabelAnvil_Cost ] ) + MAP_CONTROL(IDC_ARepairAndName, m_aLabelControls[ eHowToPlay_LabelAnvil_ARepairAndName ] ) + MAP_CONTROL(IDC_TInventory, m_aLabelControls[ eHowToPlay_LabelTrading_Inventory ] ) + //MAP_CONTROL(IDC_TOffer2Label, m_aLabelControls[ eHowToPlay_LabelTrading_Offer2 ] ) + MAP_CONTROL(IDC_TOffer1Label, m_aLabelControls[ eHowToPlay_LabelTrading_Offer1 ] ) + MAP_CONTROL(IDC_TNeededForTrade, m_aLabelControls[ eHowToPlay_LabelTrading_NeededForTrade ] ) + MAP_CONTROL(IDC_TVillagerOffers, m_aLabelControls[ eHowToPlay_LabelTrading_VillagerOffers ] ) + + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + void StartPage( EHowToPlayPage ePage ); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_HowToPlay, L"CScene_HowToPlay", XUI_CLASS_SCENE ) + + + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Helper.h b/Minecraft.Client/Common/XUI/XUI_Helper.h new file mode 100644 index 00000000..cb476185 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Helper.h @@ -0,0 +1,38 @@ +#pragma once + +#define BEGIN_CONTROL_MAP() \ + HRESULT MapChildControls() \ + { \ + HRESULT hr = S_OK; \ + CXuiElement e = m_hObj; \ + + + +#define MAP_CONTROL(name, member) \ + hr = e.GetChildById(name, &member); \ + assert(hr==0); \ + +#define BEGIN_MAP_CHILD_CONTROLS( member ) \ + { \ + CXuiElement tempE = e; \ + e = member; \ + +#define END_MAP_CHILD_CONTROLS() \ + e = tempE; \ + } \ + + +#define MAP_OVERRIDE(name, member) \ + { \ + HXUIOBJ h; \ + hr = e.GetChildById(name, &h); \ + assert(hr==0); \ + hr = XuiObjectFromHandle(h, reinterpret_cast<PVOID*>(&member)); \ + assert(hr==0); \ + } \ + + +#define END_CONTROL_MAP() \ + return hr; \ + } \ + diff --git a/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.cpp b/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.cpp new file mode 100644 index 00000000..14046f20 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.cpp @@ -0,0 +1,232 @@ +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_HowToPlayMenu.h" +#include "..\XUI\XUI_HelpHowToPlay.h" + +// strings for buttons in the list +unsigned int CScene_HowToPlayMenu::m_uiHTPButtonNameA[]= +{ + IDS_HOW_TO_PLAY_MENU_WHATSNEW, // eHTPButton_WhatsNew + IDS_HOW_TO_PLAY_MENU_BASICS, // eHTPButton_Basics, + IDS_HOW_TO_PLAY_MENU_MULTIPLAYER, // eHTPButton_Multiplayer + IDS_HOW_TO_PLAY_MENU_HUD, // eHTPButton_Hud, + IDS_HOW_TO_PLAY_MENU_CREATIVE, // eHTPButton_Creative, + IDS_HOW_TO_PLAY_MENU_INVENTORY, // eHTPButton_Inventory, + IDS_HOW_TO_PLAY_MENU_CHESTS, // eHTPButton_Chest, + IDS_HOW_TO_PLAY_MENU_CRAFTING, // eHTPButton_Crafting, + IDS_HOW_TO_PLAY_MENU_FURNACE, // eHTPButton_Furnace, + IDS_HOW_TO_PLAY_MENU_DISPENSER, // eHTPButton_Dispenser, + + IDS_HOW_TO_PLAY_MENU_BREWING, // eHTPButton_Brewing, + IDS_HOW_TO_PLAY_MENU_ENCHANTMENT, // eHTPButton_Enchantment, + IDS_HOW_TO_PLAY_MENU_ANVIL, + IDS_HOW_TO_PLAY_MENU_FARMANIMALS, // eHTPButton_Breeding, + IDS_HOW_TO_PLAY_MENU_BREEDANIMALS, // eHTPButton_Breeding, + IDS_HOW_TO_PLAY_MENU_TRADING, + + IDS_HOW_TO_PLAY_MENU_NETHERPORTAL, // eHTPButton_NetherPortal, + IDS_HOW_TO_PLAY_MENU_THEEND, // eHTPButton_TheEnd, + IDS_HOW_TO_PLAY_MENU_SOCIALMEDIA, // eHTPButton_SocialMedia, + IDS_HOW_TO_PLAY_MENU_BANLIST, // eHTPButton_BanningLevels, + IDS_HOW_TO_PLAY_MENU_HOSTOPTIONS, // eHTPButton_HostOptions, +}; + +// mapping the buttons to a scene value +unsigned int CScene_HowToPlayMenu::m_uiHTPSceneA[]= +{ + eHowToPlay_WhatsNew, + eHowToPlay_Basics, + eHowToPlay_Multiplayer, + eHowToPlay_HUD, + eHowToPlay_Creative, + eHowToPlay_Inventory, + eHowToPlay_Chest, + eHowToPlay_InventoryCrafting, + eHowToPlay_Furnace, + eHowToPlay_Dispenser, + + eHowToPlay_Brewing, + eHowToPlay_Enchantment, + eHowToPlay_Anvil, + eHowToPlay_FarmingAnimals, + eHowToPlay_Breeding, + eHowToPlay_Trading, + + eHowToPlay_NetherPortal, + eHowToPlay_TheEnd, + eHowToPlay_SocialMedia, + eHowToPlay_BanList, + eHowToPlay_HostOptions, +}; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_HowToPlayMenu::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + bool bSplitscreen= app.GetLocalPlayerCount()>1; + m_ButtonList=NULL; + + //MapChildControls(); + + //m_iButtons=0; + if(bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad, false); + } + + // 4J-PB - changing all versions to use a list of buttons, since we're adding some + // We're going to use a list of buttons here + CXuiElement e = m_hObj; + HRESULT hr = e.GetChildById(L"HowToListButtons", &m_ButtonList); + m_iButtons=eHTPButton_Max; + for(int i=0;i<eHTPButton_Max;i++) + { + //m_Buttons[i].SetShow(FALSE); + //m_Buttons[i].SetEnable(FALSE); + m_ButtonList.InsertItems( m_ButtonList.GetItemCount(), 1 ); + } + + // set the focus to the list + m_ButtonList.SetFocus(m_iPad); + + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || bSplitscreen) + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + } + else if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + // Display the tooltips + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + return S_OK; +} + +HRESULT CScene_HowToPlayMenu::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + if( pGetSourceTextData->bItemData ) + { + if( pGetSourceTextData->iItem < (int)eHTPButton_Max ) + { + pGetSourceTextData->szText = app.GetString(m_uiHTPButtonNameA[pGetSourceTextData->iItem]);//m_Buttons[pGetSourceTextData->iItem].GetText(); + pGetSourceTextData->bDisplay = TRUE; + + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_HowToPlayMenu::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +{ + pGetItemCountData->cItems = m_iButtons; + bHandled = TRUE; + return S_OK; +} + + +HRESULT CScene_HowToPlayMenu::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + // In a list, we need to play the 'focus' sound ourselves + if((pNotifySelChangedData->iOldItem!=-1) && m_ButtonList && (hObjSource==m_ButtonList.m_hObj)) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + + return S_OK; +} +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_HowToPlayMenu::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + unsigned int uiInitData; + unsigned int uiButtonCounter=0; + + // 4J-PB - now using a list for all resolutions + //if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + if(hObjPressed==m_ButtonList && m_ButtonList.TreeHasFocus() && (m_ButtonList.GetItemCount() > 0) && (m_ButtonList.GetCurSel() < (int)eHTPButton_Max) ) + { + uiButtonCounter=m_ButtonList.GetCurSel(); + } + } + /*else + { + while((uiButtonCounter<BUTTONS_HTP_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + }*/ + + // Determine which button was pressed, + // and call the appropriate function. + + uiInitData = ( ( 1 << 31 ) | ( m_uiHTPSceneA[uiButtonCounter] << 16 ) | ( short )( m_iPad ) ); + if(app.GetLocalPlayerCount()>1) + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_HowToPlay, ( void* )( uiInitData ) ); + } + else + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_HowToPlay, ( void* )( uiInitData ) ); + } + + rfHandled=TRUE; + return S_OK; +} + +HRESULT CScene_HowToPlayMenu::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + + break; + } + + return S_OK; +} + +HRESULT CScene_HowToPlayMenu::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + return S_OK; +} + +HRESULT CScene_HowToPlayMenu::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,false); +} diff --git a/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.h b/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.h new file mode 100644 index 00000000..ba334c80 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.h @@ -0,0 +1,76 @@ +#pragma once + +#include "../media/xuiscene_howtoplay_menu.h" +#include "XUI_CustomMessages.h" + +class CScene_HowToPlayMenu : public CXuiSceneImpl +{ +protected: + + enum eHTPButton + { + eHTPButton_WhatsNew = 0, + eHTPButton_Basics, + eHTPButton_Multiplayer, + eHTPButton_Hud, + eHTPButton_Creative, + eHTPButton_Inventory, + eHTPButton_Chest, + eHTPButton_Crafting, + eHTPButton_Furnace, + eHTPButton_Dispenser, + eHTPButton_Brewing, + eHTPButton_Enchantment, + eHTPButton_Anvil, + eHTPButton_FarmingAnimals, + eHTPButton_Breeding, + eHTPButton_Trading, + eHTPButton_NetherPortal, + eHTPButton_TheEnd, + eHTPButton_SocialMedia, + eHTPButton_BanningLevels, + eHTPButton_HostOptions, + eHTPButton_Max, + }; + + // Control and Element wrapper objects. + CXuiScene m_Scene; + CXuiElement m_Background; + CXuiList m_ButtonList; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_NOTIFY_SELCHANGED(OnNotifySelChanged) + + XUI_END_MSG_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_HowToPlayMenu, L"CScene_HowToPlayMenu", XUI_CLASS_SCENE ) + +private: + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + static unsigned int m_uiHTPButtonNameA[eHTPButton_Max]; + static unsigned int m_uiHTPSceneA[eHTPButton_Max]; + int m_iButtons; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.cpp b/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.cpp new file mode 100644 index 00000000..f0561745 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.cpp @@ -0,0 +1,150 @@ +#include "stdafx.h" +#include "XUI_MultiGameCreate.h" +#include "XUI_InGameHostOptions.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\ClientConnection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGameHostOptions::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + m_focusElement = m_CheckboxFireSpreads.m_hObj; + + XuiControlSetText(m_CheckboxFireSpreads,app.GetString(IDS_FIRE_SPREADS)); + XuiControlSetText(m_CheckboxTNTExplodes,app.GetString(IDS_TNT_EXPLODES)); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + m_CheckboxFireSpreads.SetEnable(TRUE); + m_CheckboxTNTExplodes.SetEnable(TRUE); + m_CheckboxFireSpreads.SetCheck((app.GetGameHostOption(eGameHostOption_FireSpreads)!=0)?TRUE:FALSE); + m_CheckboxTNTExplodes.SetCheck((app.GetGameHostOption(eGameHostOption_TNT)!=0)?TRUE:FALSE); + + INetworkPlayer *localPlayer = g_NetworkManager.GetLocalPlayerByUserIndex( m_iPad ); + unsigned int privs = app.GetPlayerPrivileges(localPlayer->GetSmallId()); + if ( app.GetGameHostOption(eGameHostOption_CheatsEnabled) + && Player::getPlayerGamePrivilege(privs,Player::ePlayerGamePrivilege_CanTeleport) + && (g_NetworkManager.GetPlayerCount() > 1) ) + { + m_buttonTeleportToPlayer.SetText(app.GetString(IDS_TELEPORT_TO_PLAYER)); + m_buttonTeleportToMe.SetText(app.GetString(IDS_TELEPORT_TO_ME)); + } + else + { + removeControl(m_buttonTeleportToPlayer, true); + removeControl(m_buttonTeleportToMe, true); + } + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + + + //SentientManager.RecordMenuShown(m_iPad, eUIScene_CreateWorldMenu, 0); + + return S_OK; +} + + +HRESULT CScene_InGameHostOptions::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + { + unsigned int hostOptions = app.GetGameHostOption(eGameHostOption_All); + app.SetGameHostOption(hostOptions,eGameHostOption_FireSpreads,m_CheckboxFireSpreads.IsChecked()); + app.SetGameHostOption(hostOptions,eGameHostOption_TNT,m_CheckboxTNTExplodes.IsChecked()); + + // Send update settings packet to server + if(hostOptions != app.GetGameHostOption(eGameHostOption_All) ) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> player = pMinecraft->localplayers[m_iPad]; + if(player != NULL && player->connection) + { + player->connection->send( shared_ptr<ServerSettingsChangedPacket>( new ServerSettingsChangedPacket( ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, hostOptions) ) ); + } + } + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + } + break; + } + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGameHostOptions::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed == m_buttonTeleportToPlayer || hObjPressed == m_buttonTeleportToMe) + { + TeleportMenuInitData *initData = new TeleportMenuInitData(); + initData->iPad = m_iPad; + initData->teleportToPlayer = false; + if( hObjPressed == m_buttonTeleportToPlayer ) + { + initData->teleportToPlayer = true; + } + ui.NavigateToScene(m_iPad,eUIScene_TeleportMenu,(void*)initData); + } + return S_OK; +} + +void CScene_InGameHostOptions::removeControl(HXUIOBJ hObjToRemove, bool center) +{ + D3DXVECTOR3 pos; + float fControlHeight, fTempHeight, fWidth; + + bool changeFocus = m_focusElement == hObjToRemove; + + XuiElementGetBounds(hObjToRemove,&fWidth,&fControlHeight); + + // Hide this control + XuiControlSetEnable(hObjToRemove, FALSE); + XuiElementSetShow(hObjToRemove, FALSE); + + // Move future downwards nav up + HXUIOBJ controlToMove = hObjToRemove; + while(controlToMove = XuiControlGetNavigation(controlToMove, XUI_CONTROL_NAVIGATE_DOWN, FALSE, TRUE) ) + { + if(changeFocus && XuiElementIsShown(controlToMove)) + { + m_focusElement = controlToMove; + XuiElementSetUserFocus( controlToMove, m_iPad ); + changeFocus = FALSE; + } + XuiElementGetPosition(controlToMove, &pos); + pos.y -= fControlHeight; + XuiElementSetPosition(controlToMove, &pos); + } + + // Resize and move scene + GetBounds(&fWidth, &fTempHeight); + SetBounds(fWidth, fTempHeight - fControlHeight); + + GetPosition(&pos); + pos.y += fControlHeight/2; + SetPosition(&pos); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.h b/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.h new file mode 100644 index 00000000..cdc99f7c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGameHostOptions.h @@ -0,0 +1,45 @@ +#pragma once +#include "..\Media\xuiscene_ingame_host_options.h" + +class CScene_InGameHostOptions : public CXuiSceneImpl +{ +protected: + CXuiScene m_GameOptionsGroup; + CXuiCheckbox m_CheckboxFireSpreads; + CXuiCheckbox m_CheckboxTNTExplodes; + CXuiControl m_buttonTeleportToPlayer, m_buttonTeleportToMe; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_GameOptions, m_GameOptionsGroup) + BEGIN_MAP_CHILD_CONTROLS(m_GameOptionsGroup) + MAP_CONTROL(IDC_CheckboxFireSpreads, m_CheckboxFireSpreads) + MAP_CONTROL(IDC_CheckboxTNT, m_CheckboxTNTExplodes) + MAP_CONTROL(IDC_ButtonTeleportToPlayer, m_buttonTeleportToPlayer) + MAP_CONTROL(IDC_ButtonTeleportPlayerToMe, m_buttonTeleportToMe) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_InGameHostOptions, L"CScene_InGameHostOptions", XUI_CLASS_SCENE ) + +private: + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + HXUIOBJ m_focusElement; // Only used for the remove control process + + void removeControl(HXUIOBJ hObjToRemove, bool center); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_InGameInfo.cpp b/Minecraft.Client/Common/XUI/XUI_InGameInfo.cpp new file mode 100644 index 00000000..4839013c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGameInfo.cpp @@ -0,0 +1,537 @@ +#include "stdafx.h" + +#include <assert.h> +#include "XUI_InGameInfo.h" +#include "..\..\ServerPlayer.h" +#include "..\..\PlayerConnection.h" +#include "..\..\PlayerList.h" +#include "..\..\MinecraftServer.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\PlayerRenderer.h" +#include "XUI_InGamePlayerOptions.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\ClientConnection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" +#include "..\..\Xbox\Network\NetworkPlayerXbox.h" + +#define IGNORE_KEYPRESS_TIMERID 0 +#define TOOLTIP_TIMERID 1 +#define IGNORE_KEYPRESS_TIME 100 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGameInfo::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_bIgnoreKeyPresses=true; + m_iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + XuiControlSetText(m_gameOptionsButton,app.GetString(IDS_HOST_OPTIONS)); + XuiControlSetText(m_title,app.GetString(IDS_PLAYERS_INVITE)); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + DWORD playerCount = g_NetworkManager.GetPlayerCount(); + + m_playersCount = 0; + for(DWORD i = 0; i < playerCount; ++i) + { + INetworkPlayer *player = g_NetworkManager.GetPlayerByIndex( i ); + + if( player != NULL ) + { + m_players[i] = player->GetSmallId(); + ++m_playersCount; + } + } + + g_NetworkManager.RegisterPlayerChangedCallback(m_iPad, &CScene_InGameInfo::OnPlayerChanged, this); + + INetworkPlayer *thisPlayer = g_NetworkManager.GetLocalPlayerByUserIndex( m_iPad ); + m_isHostPlayer = false; + if(thisPlayer != NULL) m_isHostPlayer = thisPlayer->IsHost() == TRUE; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> localPlayer = pMinecraft->localplayers[m_iPad]; + if(!m_isHostPlayer && !localPlayer->isModerator() ) + { + m_gameOptionsButton.SetEnable(FALSE); + m_gameOptionsButton.SetShow(FALSE); + playersList.SetFocus(m_iPad); + } + + int keyX = IDS_TOOLTIPS_INVITE_FRIENDS; + XPARTY_USER_LIST partyList; + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + keyX = IDS_TOOLTIPS_INVITE_PARTY; + } + if(g_NetworkManager.IsLocalGame()) keyX = -1; + + int keyA = -1; + ui.SetTooltips( m_iPad, keyA,IDS_TOOLTIPS_BACK,keyX,-1); + + + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + + SetTimer( TOOLTIP_TIMERID , INGAME_INFO_TOOLTIP_TIMER ); + + // get rid of the quadrant display if it's on + CXuiSceneBase::HidePressStart(); + + SetTimer(IGNORE_KEYPRESS_TIMERID,IGNORE_KEYPRESS_TIME); + + return S_OK; +} + +HRESULT CScene_InGameInfo::OnDestroy() +{ + XuiKillTimer(m_hObj,TOOLTIP_TIMERID); + g_NetworkManager.UnRegisterPlayerChangedCallback(m_iPad, &CScene_InGameInfo::OnPlayerChanged, this); + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGameInfo::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if( hObjSource == playersList) + { + updateTooltips(); + + bHandled = TRUE; + } + + return S_OK; +} + +HRESULT CScene_InGameInfo::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreKeyPresses) return S_OK; + + // 4J-PB - ignore repeats to stop the scene displaying and quitting right away if you hold the back button down + if((pInputData->dwKeyCode==VK_PAD_BACK) &&(pInputData->dwFlags&XUI_INPUT_FLAG_REPEAT )) + { + rfHandled = TRUE; + return S_OK; + } + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr = S_OK; + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_BACK: + case VK_ESCAPE: + CXuiSceneBase::PlayUISFX(eSFX_Back); + app.CloseXuiScenes(pInputData->UserIndex); + rfHandled = TRUE; + + break; + case VK_PAD_Y: + if(playersList.TreeHasFocus() && (playersList.GetItemCount() > 0) && (playersList.GetCurSel() < m_playersCount) ) + { + INetworkPlayer *player = g_NetworkManager.GetPlayerBySmallId(m_players[playersList.GetCurSel()]); + if( player != NULL ) + { + PlayerUID xuid = ((NetworkPlayerXbox *)player)->GetUID(); + if( xuid != INVALID_XUID ) + hr = XShowGamerCardUI(pInputData->UserIndex, xuid); + } + } + break; + case VK_PAD_X: + { + if(!g_NetworkManager.IsLocalGame()) + { + XPARTY_USER_LIST partyList; + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY) && (partyList.dwUserCount>1)) + { + hr = XShowPartyUI( pInputData->UserIndex ); + } + else + { + hr = XShowFriendsUI( pInputData->UserIndex ); + } + } + } + break; + } + + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGameInfo::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if( hObjPressed == playersList ) + { + INetworkPlayer *selectedPlayer = g_NetworkManager.GetPlayerBySmallId( m_players[ playersList.GetCurSel() ] ); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> localPlayer = pMinecraft->localplayers[m_iPad]; + + bool isOp = m_isHostPlayer || localPlayer->isModerator(); + bool cheats = app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0; + bool trust = app.GetGameHostOption(eGameHostOption_TrustPlayers) != 0; + + if( isOp && selectedPlayer != NULL && playersList.TreeHasFocus() && (playersList.GetItemCount() > 0) && (playersList.GetCurSel() < m_playersCount) ) + { + bool editingHost = selectedPlayer->IsHost(); + if( (cheats && (m_isHostPlayer || !editingHost ) ) + || (!trust && (m_isHostPlayer || !editingHost)) + || (m_isHostPlayer && !editingHost) +#if (!defined(_CONTENT_PACKAGE) && !defined(_FINAL_BUILD) && defined(_DEBUG_MENUS_ENABLED)) + || (m_isHostPlayer && editingHost) +#endif + ) + { + InGamePlayerOptionsInitData *pInitData = new InGamePlayerOptionsInitData(); + pInitData->iPad = m_iPad; + pInitData->networkSmallId = m_players[ playersList.GetCurSel() ]; + pInitData->playerPrivileges = app.GetPlayerPrivileges(m_players[ playersList.GetCurSel() ] ); + app.NavigateToScene(m_iPad,eUIScene_InGamePlayerOptionsMenu,pInitData); + } + else if(selectedPlayer->IsLocal() != TRUE && selectedPlayer->IsSameSystem(g_NetworkManager.GetHostPlayer()) != TRUE) + { + // Only ops will hit this, can kick anyone not local and not local to the host + BYTE *smallId = new BYTE(); + *smallId = m_players[playersList.GetCurSel()]; + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + StorageManager.RequestMessageBox(IDS_UNLOCK_KICK_PLAYER_TITLE, IDS_UNLOCK_KICK_PLAYER, uiIDA, 2, m_iPad,&CScene_InGameInfo::KickPlayerReturned,smallId,app.GetStringTable()); + } + } + } + else if( hObjPressed == m_gameOptionsButton ) + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_InGameHostOptionsMenu); + } + return S_OK; +} + +HRESULT CScene_InGameInfo::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==IGNORE_KEYPRESS_TIMERID) + { + XuiKillTimer(m_hObj,IGNORE_KEYPRESS_TIMERID); + m_bIgnoreKeyPresses=false; + } + else + { + updateTooltips(); + } + + return S_OK; +} + +HRESULT CScene_InGameInfo::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransType == XUI_TRANSITION_FROM) + { + KillTimer( TOOLTIP_TIMERID ); + } + return S_OK; +} + +HRESULT CScene_InGameInfo::OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + SetTimer( TOOLTIP_TIMERID , INGAME_INFO_TOOLTIP_TIMER ); + g_NetworkManager.RegisterPlayerChangedCallback(m_iPad, &CScene_InGameInfo::OnPlayerChanged, this); + } + return S_OK; +} + +HRESULT CScene_InGameInfo::OnNotifySetFocus( HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled ) +{ + updateTooltips(); + return S_OK; +} + +void CScene_InGameInfo::OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving) +{ + CScene_InGameInfo *scene = (CScene_InGameInfo *)callbackParam; + bool playerFound = false; + + for(int i = 0; i < scene->m_playersCount; ++i) + { + if(playerFound) + { + scene->m_players[i-1] = scene->m_players[i]; + } + else if( scene->m_players[i] == pPlayer->GetSmallId() ) + { + if( scene->playersList.GetCurSel() == scene->playersList.GetItemCount() - 1 ) + { + scene->playersList.SetCurSel( scene->playersList.GetItemCount() - 2 ); + } + // Player removed + playerFound = true; + } + } + + if( playerFound ) + { + --scene->m_playersCount; + scene->playersList.DeleteItems( scene->playersList.GetItemCount() - 1, 1 ); + } + + if( !playerFound ) + { + // Player added + scene->m_players[scene->m_playersCount] = pPlayer->GetSmallId(); + ++scene->m_playersCount; + scene->playersList.InsertItems( scene->playersList.GetItemCount(), 1 ); + } +} + + +HRESULT CScene_InGameInfo::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + if( pGetSourceTextData->bItemData ) + { + if( pGetSourceTextData->iItem < m_playersCount ) + { + INetworkPlayer *player = g_NetworkManager.GetPlayerBySmallId( m_players[pGetSourceTextData->iItem] ); + if( player != NULL ) + { +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + pGetSourceTextData->szText = L"WWWWWWWWWWWWWWWW"; + } + else +#endif + { + pGetSourceTextData->szText = player->GetOnlineName(); + } + } + else + { + pGetSourceTextData->szText = L""; + } + + HRESULT hr; + HXUIOBJ hButton, hVisual, hPlayerIcon, hVoiceIcon; + hButton = playersList.GetItemControl(pGetSourceTextData->iItem); + hr=XuiControlGetVisual(hButton,&hVisual); + + // Set the players icon + hr=XuiElementGetChildById(hVisual,L"IconGroup",&hPlayerIcon); + short colourIndex = app.GetPlayerColour( m_players[pGetSourceTextData->iItem] ); + int playFrame = 0; + switch(colourIndex) + { + case 1: + XuiElementFindNamedFrame(hPlayerIcon, L"P1", &playFrame); + break; + case 2: + XuiElementFindNamedFrame(hPlayerIcon, L"P2", &playFrame); + break; + case 3: + XuiElementFindNamedFrame(hPlayerIcon, L"P3", &playFrame); + break; + case 4: + XuiElementFindNamedFrame(hPlayerIcon, L"P4", &playFrame); + break; + case 5: + XuiElementFindNamedFrame(hPlayerIcon, L"P5", &playFrame); + break; + case 6: + XuiElementFindNamedFrame(hPlayerIcon, L"P6", &playFrame); + break; + case 7: + XuiElementFindNamedFrame(hPlayerIcon, L"P7", &playFrame); + break; + case 8: + XuiElementFindNamedFrame(hPlayerIcon, L"P8", &playFrame); + break; + case 9: + XuiElementFindNamedFrame(hPlayerIcon, L"P9", &playFrame); + break; + case 10: + XuiElementFindNamedFrame(hPlayerIcon, L"P10", &playFrame); + break; + case 11: + XuiElementFindNamedFrame(hPlayerIcon, L"P11", &playFrame); + break; + case 12: + XuiElementFindNamedFrame(hPlayerIcon, L"P12", &playFrame); + break; + case 13: + XuiElementFindNamedFrame(hPlayerIcon, L"P13", &playFrame); + break; + case 14: + XuiElementFindNamedFrame(hPlayerIcon, L"P14", &playFrame); + break; + case 15: + XuiElementFindNamedFrame(hPlayerIcon, L"P15", &playFrame); + break; + case 0: + default: + XuiElementFindNamedFrame(hPlayerIcon, L"P0", &playFrame); + break; + }; + if(playFrame < 0) playFrame = 0; + XuiElementPlayTimeline(hPlayerIcon,playFrame,playFrame,playFrame,FALSE,FALSE); + + // Set the voice icon + hr=XuiElementGetChildById(hVisual,L"VoiceGroup",&hVoiceIcon); + + playFrame = -1; + if(player != NULL && player->HasVoice() ) + { + if( player->IsMutedByLocalUser(m_iPad) ) + { + // Muted image + XuiElementFindNamedFrame(hVoiceIcon, L"Muted", &playFrame); + } + else if( player->IsTalking() ) + { + // Talking image + XuiElementFindNamedFrame(hVoiceIcon, L"Speaking", &playFrame); + } + else + { + // Not talking image + XuiElementFindNamedFrame(hVoiceIcon, L"NotSpeaking", &playFrame); + } + } + + if(playFrame < 0) + { + XuiElementFindNamedFrame(hVoiceIcon, L"Normal", &playFrame); + } + XuiElementPlayTimeline(hVoiceIcon,playFrame,playFrame,playFrame,FALSE,FALSE); + + pGetSourceTextData->bDisplay = TRUE; + + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_InGameInfo::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + if( pGetSourceImageData->bItemData ) + { + if( pGetSourceImageData->iItem < m_playersCount ) + { + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_InGameInfo::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +{ + pGetItemCountData->cItems = m_playersCount; + bHandled = TRUE; + return S_OK; +} + +void CScene_InGameInfo::updateTooltips() +{ + int keyX = IDS_TOOLTIPS_INVITE_FRIENDS; + int ikeyY = -1; + + XPARTY_USER_LIST partyList; + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + keyX = IDS_TOOLTIPS_INVITE_PARTY; + } + if(g_NetworkManager.IsLocalGame()) keyX = -1; + + INetworkPlayer *selectedPlayer = g_NetworkManager.GetPlayerBySmallId( m_players[ playersList.GetCurSel() ] ); + + int keyA = -1; + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> localPlayer = pMinecraft->localplayers[m_iPad]; + + bool isOp = m_isHostPlayer || localPlayer->isModerator(); + bool cheats = app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0; + bool trust = app.GetGameHostOption(eGameHostOption_TrustPlayers) != 0; + + if( isOp ) + { + if(m_gameOptionsButton.HasFocus()) + { + keyA = IDS_TOOLTIPS_SELECT; + } + else if( selectedPlayer != NULL) + { + bool editingHost = selectedPlayer->IsHost(); + if( (cheats && (m_isHostPlayer || !editingHost ) ) || (!trust && (m_isHostPlayer || !editingHost)) +#if (!defined(_CONTENT_PACKAGE) && !defined(_FINAL_BUILD) && defined(_DEBUG_MENUS_ENABLED)) + || (m_isHostPlayer && editingHost) +#endif + ) + { + keyA = IDS_TOOLTIPS_PRIVILEGES; + } + else if(selectedPlayer->IsLocal() != TRUE && selectedPlayer->IsSameSystem(g_NetworkManager.GetHostPlayer()) != TRUE) + { + // Only ops will hit this, can kick anyone not local and not local to the host + keyA = IDS_TOOLTIPS_KICK; + } + } + } + + if(!m_gameOptionsButton.HasFocus()) + { + // if the player is me, then view gamer profile + if(selectedPlayer != NULL && selectedPlayer->IsLocal() && selectedPlayer->GetUserIndex()==m_iPad) + { + ikeyY = IDS_TOOLTIPS_VIEW_GAMERPROFILE; + } + else + { + ikeyY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + } + ui.SetTooltips( m_iPad, keyA,IDS_TOOLTIPS_BACK,keyX,ikeyY); +} + + +HRESULT CScene_InGameInfo::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +int CScene_InGameInfo::KickPlayerReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + BYTE smallId = *(BYTE *)pParam; + delete pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> localPlayer = pMinecraft->localplayers[iPad]; + if(localPlayer != NULL && localPlayer->connection) + { + localPlayer->connection->send( shared_ptr<KickPlayerPacket>( new KickPlayerPacket(smallId) ) ); + } + } + + return 0; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_InGameInfo.h b/Minecraft.Client/Common/XUI/XUI_InGameInfo.h new file mode 100644 index 00000000..8b685aaf --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGameInfo.h @@ -0,0 +1,84 @@ +#pragma once +using namespace std; +#include "../media/xuiscene_ingameinfo.h" +#include "XUI_CustomMessages.h" + +class INetworkPlayer; + +#define INGAME_INFO_TOOLTIP_TIMER 1000 + +#define VOICE_ICON_DATA_ID 0 +#define MAP_ICON_DATA_ID 1 +#define OPS_ICON_DATA_ID 2 + +class CScene_InGameInfo : public CXuiSceneImpl +{ +protected: + // Control and Element wrapper objects. + CXuiList playersList; + CXuiControl m_gameOptionsButton; + CXuiControl m_title; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_TRANSITION_START( OnTransitionStart ) + XUI_ON_XM_TRANSITION_END( OnTransitionEnd ) + XUI_ON_XM_NOTIFY_SET_FOCUS( OnNotifySetFocus ) + + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_GamePlayers, playersList) + MAP_CONTROL(IDC_GameOptionsButton, m_gameOptionsButton) + MAP_CONTROL(IDC_Title, m_title) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnNotifySetFocus( HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled ); + + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_InGameInfo, L"CScene_InGameInfo", XUI_CLASS_SCENE ) + + static void OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving); + +private: + bool m_isHostPlayer; + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + + int m_playersCount; + BYTE m_players[MINECRAFT_NET_MAX_PLAYERS]; // An array of QNet small-id's + bool m_bIgnoreKeyPresses; + + void updateTooltips(); + +public: + static int KickPlayerReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); +}; diff --git a/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.cpp b/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.cpp new file mode 100644 index 00000000..156cd092 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.cpp @@ -0,0 +1,499 @@ +#include "stdafx.h" +#include "XUI_MultiGameCreate.h" +#include "XUI_InGamePlayerOptions.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\ClientConnection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "XUI_InGameInfo.h" + + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_InGamePlayerOptions::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + InGamePlayerOptionsInitData *initData = (InGamePlayerOptionsInitData *)pInitData->pvInitData; + m_iPad = initData->iPad; + m_networkSmallId = initData->networkSmallId; + m_playerPrivileges = initData->playerPrivileges; + + MapChildControls(); + + m_focusElement = m_checkboxes[eControl_BuildAndMine].m_hObj; + + m_TeleportGroup.SetShow(false); + + INetworkPlayer *localPlayer = g_NetworkManager.GetLocalPlayerByUserIndex( m_iPad ); + INetworkPlayer *editingPlayer = g_NetworkManager.GetPlayerBySmallId(m_networkSmallId); + + if(editingPlayer != NULL) + { + m_Gamertag.SetText(editingPlayer->GetOnlineName()); + } + + bool trustPlayers = app.GetGameHostOption(eGameHostOption_TrustPlayers) != 0; + bool cheats = app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0; + m_editingSelf = (localPlayer != NULL && localPlayer == editingPlayer); + + if( m_editingSelf || trustPlayers || editingPlayer->IsHost()) + { + removeControl( m_checkboxes[eControl_BuildAndMine], true ); + removeControl( m_checkboxes[eControl_UseDoorsAndSwitches], true ); + removeControl( m_checkboxes[eControl_UseContainers], true ); + removeControl( m_checkboxes[eControl_AttackPlayers], true ); + removeControl( m_checkboxes[eControl_AttackAnimals], true ); + } + else + { + bool checked = (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CannotMine)==0 && Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CannotBuild)==0); + m_checkboxes[eControl_BuildAndMine].SetText( app.GetString(IDS_CAN_BUILD_AND_MINE) ); + m_checkboxes[eControl_BuildAndMine].SetCheck(checked); + + checked = (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches)!=0); + m_checkboxes[eControl_UseDoorsAndSwitches].SetText( app.GetString(IDS_CAN_USE_DOORS_AND_SWITCHES) ); + m_checkboxes[eControl_UseDoorsAndSwitches].SetCheck(checked); + + checked = (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanUseContainers)!=0); + m_checkboxes[eControl_UseContainers].SetText( app.GetString(IDS_CAN_OPEN_CONTAINERS) ); + m_checkboxes[eControl_UseContainers].SetCheck(checked); + + checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CannotAttackPlayers)==0; + m_checkboxes[eControl_AttackPlayers].SetText( app.GetString(IDS_CAN_ATTACK_PLAYERS) ); + m_checkboxes[eControl_AttackPlayers].SetCheck(checked); + + checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CannotAttackAnimals)==0; + m_checkboxes[eControl_AttackAnimals].SetText( app.GetString(IDS_CAN_ATTACK_ANIMALS) ); + m_checkboxes[eControl_AttackAnimals].SetCheck(checked); + } + + if(m_editingSelf) + { +#if (defined(_CONTENT_PACKAGE) || defined(_FINAL_BUILD) && !defined(_DEBUG_MENUS_ENABLED)) + removeControl( m_checkboxes[eControl_Op], true ); +#else + m_checkboxes[eControl_Op].SetText(L"DEBUG: Creative"); + m_checkboxes[eControl_Op].SetCheck(Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CreativeMode)); +#endif + + removeControl( m_buttonKick, true ); + removeControl( m_checkboxes[eControl_CheatTeleport], true ); + + if(cheats) + { + bool canBeInvisible = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleInvisible) != 0; + m_checkboxes[eControl_HostInvisible].SetEnable(canBeInvisible); + bool checked = canBeInvisible && (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_Invisible)!=0 && Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_Invulnerable)!=0); + m_checkboxes[eControl_HostInvisible].SetText( app.GetString(IDS_INVISIBLE) ); + m_checkboxes[eControl_HostInvisible].SetCheck(checked); + + bool inCreativeMode = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CreativeMode) != 0; + if(inCreativeMode) + { + removeControl( m_checkboxes[eControl_HostFly], true ); + removeControl( m_checkboxes[eControl_HostHunger], true ); + } + else + { + bool canFly = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleFly); + bool canChangeHunger = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleClassicHunger); + + m_checkboxes[eControl_HostFly].SetEnable(canFly); + checked = canFly && Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanFly)!=0; + m_checkboxes[eControl_HostFly].SetText( app.GetString(IDS_CAN_FLY) ); + m_checkboxes[eControl_HostFly].SetCheck(checked); + + m_checkboxes[eControl_HostHunger].SetEnable(canChangeHunger); + checked = canChangeHunger && Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_ClassicHunger)!=0; + m_checkboxes[eControl_HostHunger].SetText( app.GetString(IDS_DISABLE_EXHAUSTION) ); + m_checkboxes[eControl_HostHunger].SetCheck(checked); + } + } + else + { + removeControl( m_checkboxes[eControl_HostInvisible], true ); + removeControl( m_checkboxes[eControl_HostFly], true ); + removeControl( m_checkboxes[eControl_HostHunger], true ); + } + } + else + { + if(localPlayer->IsHost()) + { + // Only host can make people moderators, or enable teleporting for them + m_checkboxes[eControl_Op].SetText( app.GetString(IDS_MODERATOR) ); + m_checkboxes[eControl_Op].SetCheck(Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_Op)!=0); + } + else + { + removeControl( m_checkboxes[eControl_Op], true ); + } + + if(localPlayer->IsHost() && cheats) + { + m_checkboxes[eControl_HostInvisible].SetEnable(true); + bool checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleInvisible)!=0; + m_checkboxes[eControl_HostInvisible].SetText( app.GetString(IDS_CAN_INVISIBLE) ); + m_checkboxes[eControl_HostInvisible].SetCheck(checked); + + + bool inCreativeMode = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CreativeMode) != 0; + if(inCreativeMode) + { + removeControl( m_checkboxes[eControl_HostFly], true ); + removeControl( m_checkboxes[eControl_HostHunger], true ); + } + else + { + m_checkboxes[eControl_HostFly].SetEnable(true); + checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleFly)!=0; + m_checkboxes[eControl_HostFly].SetText( app.GetString(IDS_CAN_FLY) ); + m_checkboxes[eControl_HostFly].SetCheck(checked); + + m_checkboxes[eControl_HostHunger].SetEnable(true); + checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleClassicHunger)!=0; + m_checkboxes[eControl_HostHunger].SetText( app.GetString(IDS_CAN_DISABLE_EXHAUSTION) ); + m_checkboxes[eControl_HostHunger].SetCheck(checked); + } + + checked = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanTeleport)!=0; + m_checkboxes[eControl_CheatTeleport].SetText(app.GetString(IDS_ENABLE_TELEPORT)); + m_checkboxes[eControl_CheatTeleport].SetCheck(checked); + } + else + { + removeControl( m_checkboxes[eControl_HostInvisible], true ); + removeControl( m_checkboxes[eControl_HostFly], true ); + removeControl( m_checkboxes[eControl_HostHunger], true ); + removeControl( m_checkboxes[eControl_CheatTeleport], true ); + } + + // Can only kick people if they are not local, and not local to the host + if(editingPlayer->IsLocal() != TRUE && editingPlayer->IsSameSystem(g_NetworkManager.GetHostPlayer()) != TRUE) + { + m_buttonKick.SetText( app.GetString(IDS_KICK_PLAYER)); + } + else + { + removeControl( m_buttonKick, true ); + } + } + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + + g_NetworkManager.RegisterPlayerChangedCallback(m_iPad, &CScene_InGamePlayerOptions::OnPlayerChanged, this); + + //SentientManager.RecordMenuShown(m_iPad, eUIScene_CreateWorldMenu, 0); + + resetCheatCheckboxes(); + + return S_OK; +} + +HRESULT CScene_InGamePlayerOptions::OnDestroy() +{ + g_NetworkManager.UnRegisterPlayerChangedCallback(m_iPad, &CScene_InGameInfo::OnPlayerChanged, this); + return S_OK; +} + + +HRESULT CScene_InGamePlayerOptions::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + { + bool trustPlayers = app.GetGameHostOption(eGameHostOption_TrustPlayers) != 0; + bool cheats = app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0; + if(m_editingSelf) + { +#if (defined(_CONTENT_PACKAGE) || defined(_FINAL_BUILD) && !defined(_DEBUG_MENUS_ENABLED)) +#else + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CreativeMode,m_checkboxes[eControl_Op].IsChecked()); +#endif + if(cheats) + { + bool canBeInvisible = Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleInvisible) != 0; + if(canBeInvisible) Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_Invisible,m_checkboxes[eControl_HostInvisible].IsChecked()); + if(canBeInvisible) Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_Invulnerable,m_checkboxes[eControl_HostInvisible].IsChecked()); + + bool inCreativeMode = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CreativeMode) != 0; + if(!inCreativeMode) + { + bool canFly = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleFly); + bool canChangeHunger = Player::getPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleClassicHunger); + + if(canFly) Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanFly,m_checkboxes[eControl_HostFly].IsChecked()); + if(canChangeHunger) Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_ClassicHunger,m_checkboxes[eControl_HostHunger].IsChecked()); + } + } + } + else + { + INetworkPlayer *editingPlayer = g_NetworkManager.GetPlayerBySmallId(m_networkSmallId); + if(!trustPlayers && (editingPlayer != NULL && !editingPlayer->IsHost() ) ) + { + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CannotMine,!m_checkboxes[eControl_BuildAndMine].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CannotBuild,!m_checkboxes[eControl_BuildAndMine].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CannotAttackPlayers,!m_checkboxes[eControl_AttackPlayers].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CannotAttackAnimals, !m_checkboxes[eControl_AttackAnimals].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches, m_checkboxes[eControl_UseDoorsAndSwitches].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanUseContainers, m_checkboxes[eControl_UseContainers].IsChecked()); + } + + INetworkPlayer *localPlayer = g_NetworkManager.GetLocalPlayerByUserIndex( m_iPad ); + + if(localPlayer->IsHost()) + { + if(cheats) + { + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleInvisible,m_checkboxes[eControl_HostInvisible].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleFly,m_checkboxes[eControl_HostFly].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanToggleClassicHunger,m_checkboxes[eControl_HostHunger].IsChecked()); + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_CanTeleport,m_checkboxes[eControl_CheatTeleport].IsChecked()); + } + + Player::setPlayerGamePrivilege(m_playerPrivileges,Player::ePlayerGamePrivilege_Op,m_checkboxes[eControl_Op].IsChecked()); + } + } + unsigned int originalPrivileges = app.GetPlayerPrivileges(m_networkSmallId); + if(originalPrivileges != m_playerPrivileges) + { + // Send update settings packet to server + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> player = pMinecraft->localplayers[m_iPad]; + if(player != NULL && player->connection) + { + player->connection->send( shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket( m_networkSmallId, -1, m_playerPrivileges) ) ); + } + } + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + } + break; + } + return S_OK; +} + +HRESULT CScene_InGamePlayerOptions::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + //HRESULT hr = S_OK; + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if( hObjPressed == m_buttonKick ) + { + BYTE *smallId = new BYTE(); + *smallId = m_networkSmallId; + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + StorageManager.RequestMessageBox(IDS_UNLOCK_KICK_PLAYER_TITLE, IDS_UNLOCK_KICK_PLAYER, uiIDA, 2, m_iPad,&CScene_InGamePlayerOptions::KickPlayerReturned,smallId,app.GetStringTable()); + } + else if (hObjPressed == m_checkboxes[eControl_Op] ) + { + resetCheatCheckboxes(); + } + + return S_OK; +} + +HRESULT CScene_InGamePlayerOptions::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +int CScene_InGamePlayerOptions::KickPlayerReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + BYTE smallId = *(BYTE *)pParam; + delete pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<MultiplayerLocalPlayer> localPlayer = pMinecraft->localplayers[iPad]; + if(localPlayer != NULL && localPlayer->connection) + { + localPlayer->connection->send( shared_ptr<KickPlayerPacket>( new KickPlayerPacket(smallId) ) ); + } + + // Fix for #61494 - [CRASH]: TU7: Code: Multiplayer: Title may crash while kicking a player from an online game. + // We cannot do a navigate back here is this actually occurs on a thread other than the main thread. On rare occasions this can clash + // with the XUI render and causes a crash. The OnPlayerChanged event should perform the navigate back on the main thread + //app.NavigateBack(iPad); + } + + return 0; +} + +void CScene_InGamePlayerOptions::OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving) +{ + CScene_InGamePlayerOptions *scene = (CScene_InGamePlayerOptions *)callbackParam; + + HXUIOBJ hBackScene = scene->GetBackScene(); + CScene_InGameInfo* infoScene; + VOID *pObj; + XuiObjectFromHandle( hBackScene, &pObj ); + infoScene = (CScene_InGameInfo *)pObj; + if(infoScene != NULL) CScene_InGameInfo::OnPlayerChanged(infoScene,pPlayer,leaving); + + if(leaving && pPlayer != NULL && pPlayer->GetSmallId() == scene->m_networkSmallId) + { + app.NavigateBack(scene->m_iPad); + } +} + +HRESULT CScene_InGamePlayerOptions::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + INetworkPlayer *editingPlayer = g_NetworkManager.GetPlayerBySmallId(m_networkSmallId); + if(editingPlayer != NULL) + { + short colourIndex = app.GetPlayerColour( m_networkSmallId ); + switch(colourIndex) + { + case 1: + m_Icon.PlayVisualRange(L"P1",NULL,L"P1"); + break; + case 2: + m_Icon.PlayVisualRange(L"P2",NULL,L"P2"); + break; + case 3: + m_Icon.PlayVisualRange(L"P3",NULL,L"P3"); + break; + case 4: + m_Icon.PlayVisualRange(L"P4",NULL,L"P4"); + break; + case 5: + m_Icon.PlayVisualRange(L"P5",NULL,L"P5"); + break; + case 6: + m_Icon.PlayVisualRange(L"P6",NULL,L"P6"); + break; + case 7: + m_Icon.PlayVisualRange(L"P7",NULL,L"P7"); + break; + case 8: + m_Icon.PlayVisualRange(L"P8",NULL,L"P8"); + break; + case 9: + m_Icon.PlayVisualRange(L"P9",NULL,L"P9"); + break; + case 10: + m_Icon.PlayVisualRange(L"P10",NULL,L"P10"); + break; + case 11: + m_Icon.PlayVisualRange(L"P11",NULL,L"P11"); + break; + case 12: + m_Icon.PlayVisualRange(L"P12",NULL,L"P12"); + break; + case 13: + m_Icon.PlayVisualRange(L"P13",NULL,L"P13"); + break; + case 14: + m_Icon.PlayVisualRange(L"P14",NULL,L"P14"); + break; + case 15: + m_Icon.PlayVisualRange(L"P15",NULL,L"P15"); + break; + case 0: + default: + m_Icon.PlayVisualRange(L"P0",NULL,L"P0"); + break; + }; + } + } + return S_OK; +} + +void CScene_InGamePlayerOptions::removeControl(HXUIOBJ hObjToRemove, bool center) +{ + D3DXVECTOR3 pos; + float fControlHeight, fTempHeight, fWidth; + + bool changeFocus = m_focusElement == hObjToRemove; + + XuiElementGetBounds(hObjToRemove,&fWidth,&fControlHeight); + + // Hide this control + XuiControlSetEnable(hObjToRemove, FALSE); + XuiElementSetShow(hObjToRemove, FALSE); + + // Move future downwards nav up + HXUIOBJ controlToMove = hObjToRemove; + while(controlToMove = XuiControlGetNavigation(controlToMove, XUI_CONTROL_NAVIGATE_DOWN, FALSE, TRUE) ) + { + if(changeFocus && XuiElementIsShown(controlToMove)) + { + m_focusElement = controlToMove; + XuiElementSetUserFocus( controlToMove, m_iPad ); + changeFocus = FALSE; + } + XuiElementGetPosition(controlToMove, &pos); + pos.y -= fControlHeight; + XuiElementSetPosition(controlToMove, &pos); + } + + // Resize and move scene + GetBounds(&fWidth, &fTempHeight); + SetBounds(fWidth, fTempHeight - fControlHeight); + + GetPosition(&pos); + pos.y += fControlHeight/2; + SetPosition(&pos); +} + +void CScene_InGamePlayerOptions::resetCheatCheckboxes() +{ + bool isModerator = m_checkboxes[eControl_Op].IsChecked(); + //bool cheatsEnabled = app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0; + + if (!m_editingSelf) + { + m_checkboxes[eControl_HostInvisible].SetEnable(isModerator); + m_checkboxes[eControl_HostInvisible].SetCheck( isModerator + && (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleInvisible) != 0) ); + + // NOT CREATIVE MODE. + { + m_checkboxes[eControl_HostFly].SetEnable(isModerator); + m_checkboxes[eControl_HostFly].SetCheck( isModerator + && (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleFly) != 0) ); + + m_checkboxes[eControl_HostHunger].SetEnable(isModerator); + m_checkboxes[eControl_HostHunger].SetCheck( isModerator + && (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanToggleClassicHunger) != 0) ); + } + + m_checkboxes[eControl_CheatTeleport].SetEnable(isModerator); + m_checkboxes[eControl_CheatTeleport].SetCheck( isModerator + && (Player::getPlayerGamePrivilege(m_playerPrivileges, Player::ePlayerGamePrivilege_CanTeleport) != 0) ); + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.h b/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.h new file mode 100644 index 00000000..87b9de13 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.h @@ -0,0 +1,96 @@ +#pragma once +#include "..\Media\xuiscene_ingame_player_options.h" + +class CScene_InGamePlayerOptions : public CXuiSceneImpl +{ +private: + enum EControls + { + // Checkboxes + eControl_BuildAndMine, + eControl_UseDoorsAndSwitches, + eControl_UseContainers, + eControl_AttackPlayers, + eControl_AttackAnimals, + eControl_Op, + eControl_CheatTeleport, + eControl_HostFly, + eControl_HostHunger, + eControl_HostInvisible, + + eControl_CHECKBOXES_COUNT, + + // Others + eControl_Kick = eControl_CHECKBOXES_COUNT, + }; + +protected: + HXUIOBJ m_focusElement; // Only used for the remove control process + + CXuiControl m_Icon; + CXuiControl m_Gamertag; + CXuiScene m_TeleportGroup; + CXuiControl m_buttonKick; + CXuiCheckbox m_checkboxes[eControl_CHECKBOXES_COUNT]; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START( OnTransitionStart ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Icon, m_Icon) + MAP_CONTROL(IDC_Gamertag, m_Gamertag) + + MAP_CONTROL(IDC_CheckboxBuildAndMine, m_checkboxes[eControl_BuildAndMine]) + MAP_CONTROL(IDC_CheckboxAttackPlayers, m_checkboxes[eControl_AttackPlayers]) + MAP_CONTROL(IDC_CheckboxAttackAnimals, m_checkboxes[eControl_AttackAnimals]) + MAP_CONTROL(IDC_CheckboxUseContainers, m_checkboxes[eControl_UseContainers]) + MAP_CONTROL(IDC_CheckboxUseDoorsAndSwitches, m_checkboxes[eControl_UseDoorsAndSwitches]) + MAP_CONTROL(IDC_CheckboxOp, m_checkboxes[eControl_Op]) + MAP_CONTROL(IDC_CheckboxTeleport, m_checkboxes[eControl_CheatTeleport]) + MAP_CONTROL(IDC_CheckboxHostInvisible, m_checkboxes[eControl_HostInvisible]) + MAP_CONTROL(IDC_CheckboxHostFly, m_checkboxes[eControl_HostFly]) + MAP_CONTROL(IDC_CheckboxHostHunger, m_checkboxes[eControl_HostHunger]) + + MAP_CONTROL(IDC_ButtonKick, m_buttonKick) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_InGamePlayerOptions, L"CScene_InGamePlayerOptions", XUI_CLASS_SCENE ) + + static void OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving); + +private: + bool m_editingSelf; + int m_iPad; + BYTE m_networkSmallId; + unsigned int m_playerPrivileges; + D3DXVECTOR3 m_OriginalPosition; + + void removeControl(HXUIOBJ hObjToRemove, bool center); + + /** 4J-JEV: + For enabling/disabling 'Can Fly', 'Can Teleport', 'Can Disable Hunger' etc + used after changing the moderator checkbox. + */ + void resetCheatCheckboxes(); + +public: + static int KickPlayerReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Intro.cpp b/Minecraft.Client/Common/XUI/XUI_Intro.cpp new file mode 100644 index 00000000..997abe5d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Intro.cpp @@ -0,0 +1,153 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_Intro.h" + +#define TIMELINE_NORMAL 0 +#define TIMELINE_ESRBFADE 1 +#define TIMELINE_LOGOSFADE 2 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Intro::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + // We may need to display a ratings image for a while at the start... + m_bWantsToSkip=false; + m_iTimeline=TIMELINE_NORMAL; + + // 4J-PB - We can't check to see if the version is a trial or full game until after 5 seconds... + // The reason that this is a requirement is that there is a problem that occasionally happens *only* in the production + // environment (not partnernet or cert), where if you don’t wait 5 seconds, you can run into an issue where the timing + // of the call fails and the game is always identified as being the trial version even if you have upgraded to the full version. + // -Joe Dunavant + + // start a timer for the required 5 seconds, plus an extra bit to allow the lib timer to enable the xcontent license check call +#ifdef _CONTENT_PACKAGE + m_bSkippable=false; + XuiSetTimer( m_hObj,0,5200); +#else + m_bSkippable=true; +#endif + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Intro::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + + return S_OK; +} + +HRESULT CScene_Intro::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + static bool bPressed=false; + + if(bPressed==false) + { + if(m_bSkippable) + { + // stop the animation + XuiElementStopTimeline(m_hObj,TRUE); + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_SaveMessage); + app.SetIntroRunning(false); + } + else + { + m_bWantsToSkip=true; + } + + bPressed=true; + } + + return S_OK; +} + +HRESULT CScene_Intro::OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled) +{ + int nStart, nEnd; + + if(m_bSkippable && m_bWantsToSkip) + { + // straight to the game + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_SaveMessage); + app.SetIntroRunning(false); + } + else + { + switch(m_iTimeline) + { + case TIMELINE_NORMAL: + { + // 4J-PB - lots of discussions over this because Brazil is in the NA region. This is what I have been advised to do... + //if(ProfileManager.RegionIsNorthAmerica()) + if(ProfileManager.LocaleIsUSorCanada()) + { + m_iTimeline=TIMELINE_ESRBFADE; + XuiElementFindNamedFrame( m_hObj, L"ESRBFade", &nStart ); + XuiElementFindNamedFrame( m_hObj, L"ESRBFadeEnd", &nEnd ); + XuiElementPlayTimeline( m_hObj, nStart, nStart, nEnd, FALSE, TRUE ); + } + else + { + m_iTimeline=TIMELINE_LOGOSFADE; + XuiElementFindNamedFrame( m_hObj, L"StartFade", &nStart ); + XuiElementFindNamedFrame( m_hObj, L"EndFade", &nEnd ); + XuiElementPlayTimeline( m_hObj, nStart, nStart, nEnd, FALSE, TRUE ); + } + } + break; + + case TIMELINE_ESRBFADE: + if(m_bWantsToSkip && m_bSkippable) + { + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_SaveMessage); + app.SetIntroRunning(false); + } + else + { + m_iTimeline=TIMELINE_LOGOSFADE; + XuiElementFindNamedFrame( m_hObj, L"StartFade", &nStart ); + XuiElementFindNamedFrame( m_hObj, L"EndFade", &nEnd ); + XuiElementPlayTimeline( m_hObj, nStart, nStart, nEnd, FALSE, TRUE ); + } + break; + case TIMELINE_LOGOSFADE: + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_SaveMessage); + app.SetIntroRunning(false); + break; + } + } + + return S_OK; +} + + +HRESULT CScene_Intro::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + HRESULT hr=XuiKillTimer(m_hObj,0); + m_bSkippable=true; + + if(m_bWantsToSkip) + { + // stop the animation + XuiElementStopTimeline(m_hObj,TRUE); + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_SaveMessage); + app.SetIntroRunning(false); + } + + return hr; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Intro.h b/Minecraft.Client/Common/XUI/XUI_Intro.h new file mode 100644 index 00000000..f896faed --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Intro.h @@ -0,0 +1,44 @@ +#pragma once + +#include "../media/xuiscene_intro.h" + +class CScene_Intro : public CXuiSceneImpl +{ + protected: + CXuiScene m_Scene; + CXuiControl m_4jlogo; + CXuiElement m_grpXbox; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_TIMELINE_END(OnTimelineEnd) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + //MAP_CONTROL(IDC_LogoGroup, m_grpXbox) + //BEGIN_MAP_CHILD_CONTROLS(m_grpXbox) + MAP_CONTROL(IDC_Logo4J, m_4jlogo) + //END_MAP_CHILD_CONTROLS() + + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + + bool m_bSkippable; + bool m_bWantsToSkip; + int m_iTimeline; +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Intro, L"CScene_Intro", XUI_CLASS_SCENE ) + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Leaderboards.cpp b/Minecraft.Client/Common/XUI/XUI_Leaderboards.cpp new file mode 100644 index 00000000..428b3e88 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Leaderboards.cpp @@ -0,0 +1,1202 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include "XUI_Leaderboards.h" +#include "..\..\..\Minecraft.World\Tile.h" +#include "..\..\..\Minecraft.World\Item.h" +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "XUI_XZP_Icons.h" + +LPCWSTR CScene_Leaderboards::m_TitleIconNameA[7]= +{ + L"XuiHSlot1", + L"XuiHSlot2", + L"XuiHSlot3", + L"XuiHSlot4", + L"XuiHSlot5", + L"XuiHSlot6", + L"XuiHSlot7", +}; + +LPCWSTR CScene_Leaderboards::m_TextColumnNameA[7]= +{ + L"text_Column1", + L"text_Column2", + L"text_Column3", + L"text_Column4", + L"text_Column5", + L"text_Column6", + L"text_Column7", +}; + + +// if the value is greater than 511, it's an xzp icon that needs displayed, rather than the game icon +const int CScene_Leaderboards::TitleIcons[CScene_Leaderboards::NUM_LEADERBOARDS][7] = +{ + { XZP_ICON_WALKED, XZP_ICON_FALLEN, Item::minecart_Id, Item::boat_Id, NULL }, + { Tile::dirt_Id, Tile::stoneBrick_Id, Tile::sand_Id, Tile::rock_Id, Tile::gravel_Id, Tile::clay_Id, Tile::obsidian_Id }, + { Item::egg_Id, Item::wheat_Id, Tile::mushroom1_Id, Tile::reeds_Id, Item::milk_Id, Tile::pumpkin_Id, NULL }, + { XZP_ICON_ZOMBIE, XZP_ICON_SKELETON, XZP_ICON_CREEPER, XZP_ICON_SPIDER, XZP_ICON_SPIDERJOCKEY, XZP_ICON_ZOMBIEPIGMAN, XZP_ICON_SLIME }, +}; + +const int CScene_Leaderboards::LEADERBOARD_HEADERS[CScene_Leaderboards::NUM_LEADERBOARDS][4] = { + { SPASTRING_LB_TRAVELLING_PEACEFUL_NAME, SPASTRING_LB_TRAVELLING_EASY_NAME, SPASTRING_LB_TRAVELLING_NORMAL_NAME, SPASTRING_LB_TRAVELLING_HARD_NAME }, + { SPASTRING_LB_MINING_BLOCKS_PEACEFUL_NAME, SPASTRING_LB_MINING_BLOCKS_EASY_NAME, SPASTRING_LB_MINING_BLOCKS_NORMAL_NAME, SPASTRING_LB_MINING_BLOCKS_HARD_NAME }, + { SPASTRING_LB_FARMING_PEACEFUL_NAME, SPASTRING_LB_FARMING_EASY_NAME, SPASTRING_LB_FARMING_NORMAL_NAME, SPASTRING_LB_FARMING_HARD_NAME }, + { NULL, SPASTRING_LB_KILLS_EASY_NAME, SPASTRING_LB_KILLS_NORMAL_NAME, SPASTRING_LB_KILLS_HARD_NAME }, +}; + +const CScene_Leaderboards::LeaderboardDescriptor CScene_Leaderboards::LEADERBOARD_DESCRIPTORS[CScene_Leaderboards::NUM_LEADERBOARDS][4] = { + { + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_PEACEFUL, 4, STATS_COLUMN_TRAVELLING_PEACEFUL_WALKED, STATS_COLUMN_TRAVELLING_PEACEFUL_FALLEN, STATS_COLUMN_TRAVELLING_PEACEFUL_MINECART, STATS_COLUMN_TRAVELLING_PEACEFUL_BOAT, NULL, NULL, NULL,NULL), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_EASY, 4, STATS_COLUMN_TRAVELLING_EASY_WALKED, STATS_COLUMN_TRAVELLING_EASY_FALLEN, STATS_COLUMN_TRAVELLING_EASY_MINECART, STATS_COLUMN_TRAVELLING_EASY_BOAT, NULL, NULL, NULL,NULL), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_NORMAL, 4, STATS_COLUMN_TRAVELLING_NORMAL_WALKED, STATS_COLUMN_TRAVELLING_NORMAL_FALLEN, STATS_COLUMN_TRAVELLING_NORMAL_MINECART, STATS_COLUMN_TRAVELLING_NORMAL_BOAT, NULL, NULL, NULL,NULL), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_HARD, 4, STATS_COLUMN_TRAVELLING_HARD_WALKED, STATS_COLUMN_TRAVELLING_HARD_FALLEN, STATS_COLUMN_TRAVELLING_HARD_MINECART, STATS_COLUMN_TRAVELLING_HARD_BOAT, NULL, NULL, NULL,NULL), + }, + { + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_PEACEFUL, 7, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_DIRT, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_STONE, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_SAND, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_GRAVEL, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_CLAY, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_OBSIDIAN,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_EASY, 7, STATS_COLUMN_MINING_BLOCKS_EASY_DIRT, STATS_COLUMN_MINING_BLOCKS_EASY_STONE, STATS_COLUMN_MINING_BLOCKS_EASY_SAND, STATS_COLUMN_MINING_BLOCKS_EASY_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_EASY_GRAVEL, STATS_COLUMN_MINING_BLOCKS_EASY_CLAY, STATS_COLUMN_MINING_BLOCKS_EASY_OBSIDIAN,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_NORMAL, 7, STATS_COLUMN_MINING_BLOCKS_NORMAL_DIRT, STATS_COLUMN_MINING_BLOCKS_NORMAL_STONE, STATS_COLUMN_MINING_BLOCKS_NORMAL_SAND, STATS_COLUMN_MINING_BLOCKS_NORMAL_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_NORMAL_GRAVEL, STATS_COLUMN_MINING_BLOCKS_NORMAL_CLAY, STATS_COLUMN_MINING_BLOCKS_NORMAL_OBSIDIAN,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_HARD, 7, STATS_COLUMN_MINING_BLOCKS_HARD_DIRT, STATS_COLUMN_MINING_BLOCKS_HARD_STONE, STATS_COLUMN_MINING_BLOCKS_HARD_SAND, STATS_COLUMN_MINING_BLOCKS_HARD_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_HARD_GRAVEL, STATS_COLUMN_MINING_BLOCKS_HARD_CLAY, STATS_COLUMN_MINING_BLOCKS_HARD_OBSIDIAN,NULL ), + }, + { + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_FARMING_PEACEFUL, 6, STATS_COLUMN_FARMING_PEACEFUL_EGGS, STATS_COLUMN_FARMING_PEACEFUL_WHEAT, STATS_COLUMN_FARMING_PEACEFUL_MUSHROOMS, STATS_COLUMN_FARMING_PEACEFUL_SUGARCANE, STATS_COLUMN_FARMING_PEACEFUL_MILK, STATS_COLUMN_FARMING_PEACEFUL_PUMPKINS, NULL,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_FARMING_EASY, 6, STATS_COLUMN_FARMING_EASY_EGGS, STATS_COLUMN_FARMING_PEACEFUL_WHEAT, STATS_COLUMN_FARMING_EASY_MUSHROOMS, STATS_COLUMN_FARMING_EASY_SUGARCANE, STATS_COLUMN_FARMING_EASY_MILK, STATS_COLUMN_FARMING_EASY_PUMPKINS, NULL,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_FARMING_NORMAL, 6, STATS_COLUMN_FARMING_NORMAL_EGGS, STATS_COLUMN_FARMING_NORMAL_WHEAT, STATS_COLUMN_FARMING_NORMAL_MUSHROOMS, STATS_COLUMN_FARMING_NORMAL_SUGARCANE, STATS_COLUMN_FARMING_NORMAL_MILK, STATS_COLUMN_FARMING_NORMAL_PUMPKINS, NULL,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_FARMING_HARD, 6, STATS_COLUMN_FARMING_HARD_EGGS, STATS_COLUMN_FARMING_HARD_WHEAT, STATS_COLUMN_FARMING_HARD_MUSHROOMS, STATS_COLUMN_FARMING_HARD_SUGARCANE, STATS_COLUMN_FARMING_HARD_MILK, STATS_COLUMN_FARMING_HARD_PUMPKINS, NULL,NULL ), + }, + { + CScene_Leaderboards::LeaderboardDescriptor( NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_KILLS_EASY, 7, STATS_COLUMN_KILLS_EASY_ZOMBIES, STATS_COLUMN_KILLS_EASY_SKELETONS, STATS_COLUMN_KILLS_EASY_CREEPERS, STATS_COLUMN_KILLS_EASY_SPIDERS, STATS_COLUMN_KILLS_EASY_SPIDERJOCKEYS, STATS_COLUMN_KILLS_EASY_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_EASY_SLIME,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_KILLS_NORMAL, 7, STATS_COLUMN_KILLS_NORMAL_ZOMBIES, STATS_COLUMN_KILLS_NORMAL_SKELETONS, STATS_COLUMN_KILLS_NORMAL_CREEPERS, STATS_COLUMN_KILLS_NORMAL_SPIDERS, STATS_COLUMN_KILLS_NORMAL_SPIDERJOCKEYS, STATS_COLUMN_KILLS_NORMAL_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_NORMAL_SLIME,NULL ), + CScene_Leaderboards::LeaderboardDescriptor( STATS_VIEW_KILLS_HARD, 7, STATS_COLUMN_KILLS_HARD_ZOMBIES, STATS_COLUMN_KILLS_HARD_SKELETONS, STATS_COLUMN_KILLS_HARD_CREEPERS, STATS_COLUMN_KILLS_HARD_SPIDERS, STATS_COLUMN_KILLS_HARD_SPIDERJOCKEYS, STATS_COLUMN_KILLS_HARD_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_HARD_SLIME,NULL ), + }, +}; + +HRESULT CScene_Leaderboards::OnInit(XUIMessageInit *pInitData, BOOL &bHandled) +{ + m_iPad = *(int *)pInitData->pvInitData; + MapChildControls(); + m_bReady=false; + + // if we're not in the game, we need to use basescene 0 + if(Minecraft::GetInstance()->level==NULL) + { + m_iPad=DEFAULT_XUI_MENU_USER; + } + + m_bPopulatedOnce = false; + + ui.SetTooltips(m_iPad,-1, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGE_FILTER, -1); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + + m_friends = NULL; + m_numFriends = 0; + m_filteredFriends = NULL; + m_numFilteredFriends = 0; + + m_newTop = m_newSel = -1; + + m_isProcessingStatsRead = false; + + // Alert the app the we want to be informed of ethernet connections + app.SetLiveLinkRequired( true ); + + LeaderboardManager::Instance()->OpenSession(); + + //GetFriends(); + + m_currentLeaderboard = 0; + m_currentDifficulty = 2; + SetLeaderboardHeader(); + + m_currentFilter = LeaderboardManager::eFM_Friends; + wchar_t filterBuffer[40]; + swprintf(filterBuffer, 40, L"%ls%ls", app.GetString(IDS_LEADERBOARD_FILTER), app.GetString(IDS_LEADERBOARD_FILTER_FRIENDS)); + m_textFilter.SetText(filterBuffer); + + wchar_t entriesBuffer[40]; + swprintf(entriesBuffer, 40, L"%ls%i", app.GetString(IDS_LEADERBOARD_ENTRIES), 0); + m_textEntries.SetText(entriesBuffer); + + ReadStats(-1); + + // title icons + for(int i=0;i<7;i++) + { + m_pHTitleIconSlots[i]=NULL; + m_fTitleIconXPositions[i]=0.0f; + m_fTextXPositions[i]=0.0f; + m_hTextEntryA[i]=NULL; + } + + + bHandled = TRUE; + return S_OK; +} + + +void CScene_Leaderboards::Reposition(int iNumber) +{ + float fIconSize; // including gap + float fNewIconIncrement; + D3DXVECTOR3 vPos; + + fIconSize=(m_fTitleIconXPositions[6]-m_fTitleIconXPositions[0])/6.0f; + fNewIconIncrement=(fIconSize*7.0f)/(float)iNumber; + + // reposition the title icons based on the number there are + for(int i=0;i<iNumber;i++) + { + m_pHTitleIconSlots[i]->GetPosition(&vPos); + vPos.x=m_fTitleIconXPositions[0]+(((float)i)*fNewIconIncrement)+(fNewIconIncrement-fIconSize)/2.0f; + m_pHTitleIconSlots[i]->SetPosition(&vPos); + } +} + +void CScene_Leaderboards::RepositionText(int iNumber) +{ + float fTextSize; // including gap + float fNewTextIncrement; + D3DXVECTOR3 vPos; + + fTextSize=(m_fTextXPositions[6]-m_fTextXPositions[0])/6.0f; + fNewTextIncrement=(fTextSize*7.0f)/(float)iNumber; + + // reposition the title icons based on the number there are + for(int i=0;i<iNumber;i++) + { + // and reposition the text + XuiElementGetPosition(m_hTextEntryA[i],&vPos); + vPos.x=m_fTextXPositions[0]+(((float)i)*fNewTextIncrement); + XuiElementSetPosition(m_hTextEntryA[i],&vPos); + // and change the size + float fWidth,fHeight; + XuiElementGetBounds(m_hTextEntryA[i],&fWidth,&fHeight); + XuiElementSetBounds(m_hTextEntryA[i],fNewTextIncrement,fHeight); + } +} + +HRESULT CScene_Leaderboards::OnDestroy() +{ + LeaderboardManager::Instance()->CancelOperation(); + LeaderboardManager::Instance()->CloseSession(); + + // Alert the app the we no longer want to be informed of ethernet connections + app.SetLiveLinkRequired( false ); + + while( m_isProcessingStatsRead ) + { + Sleep( 10 ); + } + + if( m_friends != NULL ) + delete [] m_friends; + + if( m_filteredFriends != NULL ) + delete [] m_filteredFriends; + + return S_OK; +} + +HRESULT CScene_Leaderboards::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + UpdateTooltips(); + return S_OK; +} + +HRESULT CScene_Leaderboards::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + + if(m_bReady && pNotifySelChangedData->iOldItem!=-1) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + + return S_OK; +} + +void CScene_Leaderboards::UpdateTooltips() +{ + int iTooltipFriendRequest=-1; + int iTooltipGamerCardOrProfile=-1; + if( m_leaderboard.m_currentEntryCount > 0 ) + { + unsigned int selection = (unsigned int)m_listGamers.GetCurSel(); + + // if the selected user is me, don't show Send Friend Request, and show the gamer profile, not the gamer card + + // Check that the index is actually within range of the data we've got before accessing the m_leaderboard.m_entries array + int idx = selection - (m_leaderboard.m_entryStartIndex-1); + if( ( idx < 0 ) || ( idx >= NUM_ENTRIES ) ) + { + return; + } + if(m_leaderboard.m_entries[idx].m_bPlayer) + { + iTooltipGamerCardOrProfile=IDS_TOOLTIPS_VIEW_GAMERPROFILE; + } + else + { + iTooltipGamerCardOrProfile=IDS_TOOLTIPS_VIEW_GAMERCARD; + // if we're on the friends filter, then don't show the Send Friend Request + bool bIsFriend = m_currentFilter == LeaderboardManager::eFM_Friends; + + if(!bIsFriend) + { + // check the entry we're on + if( m_leaderboard.m_currentEntryCount > 0 ) + { + if( selection >= m_leaderboard.m_entryStartIndex-1 && + selection < (m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount-1) ) + { + if( (m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1)].m_bFriend==false) && (m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1)].m_bRequestedFriend==false)) + { + iTooltipFriendRequest=IDS_TOOLTIPS_SEND_FRIEND_REQUEST; + } + } + } + } + } + } + + // 4J-PB - no room on the screen for the LT/RT prompt + /* + if(m_leaderboard.m_currentEntryCount>11) + { + ui.SetTooltips(m_iPad, iTooltipFriendRequest, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGE_FILTER, iTooltipGamerCardOrProfile, IDS_TOOLTIPS_PAGEUP, IDS_TOOLTIPS_PAGEDOWN); + } + else*/ + { + ui.SetTooltips(m_iPad, iTooltipFriendRequest, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGE_FILTER, iTooltipGamerCardOrProfile); + } +} + +HRESULT CScene_Leaderboards::OnKeyDown(XUIMessageInput* pInputData, BOOL& bHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + case VK_PAD_RSHOULDER: + case VK_PAD_LSHOULDER: + { + //Do nothing if a stats read is currently in progress, otherwise the system complains about to many read requests + if(m_bPopulatedOnce && LeaderboardManager::Instance()->isIdle() ) + { + if( pInputData->dwKeyCode == VK_PAD_RSHOULDER ) + { + ++m_currentDifficulty; + if( m_currentDifficulty == 4 ) + m_currentDifficulty = 0; + + if( m_currentLeaderboard == LEADERBOARD_KILLS_POSITION && m_currentDifficulty == 0 ) + m_currentDifficulty = 1; + } + else + { + if( m_currentDifficulty == 0 ) + m_currentDifficulty = 4; + --m_currentDifficulty; + + if( m_currentLeaderboard == LEADERBOARD_KILLS_POSITION && m_currentDifficulty == 0 ) + m_currentDifficulty = 3; + } + + SetLeaderboardHeader(); + ClearLeaderboardTitlebar(); + + ReadStats(-1); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + + bHandled = TRUE; + } + break; + case VK_PAD_LTHUMB_RIGHT: + case VK_PAD_LTHUMB_LEFT: + case VK_PAD_DPAD_LEFT: + case VK_PAD_DPAD_RIGHT: + { + //Do nothing if a stats read is currently in progress, otherwise the system complains about to many read requests + if ( m_bPopulatedOnce && LeaderboardManager::Instance()->isIdle() ) + { + m_bReady=false; + if(( pInputData->dwKeyCode == VK_PAD_LTHUMB_RIGHT ) ||(pInputData->dwKeyCode == VK_PAD_DPAD_RIGHT)) + { + ++m_currentLeaderboard; + if( m_currentLeaderboard == NUM_LEADERBOARDS ) + m_currentLeaderboard = 0; + } + else + { + if( m_currentLeaderboard == 0 ) + m_currentLeaderboard = NUM_LEADERBOARDS; + --m_currentLeaderboard; + } + + if( m_currentLeaderboard == LEADERBOARD_KILLS_POSITION && m_currentDifficulty == 0 ) + m_currentDifficulty = 1; + + SetLeaderboardHeader(); + ClearLeaderboardTitlebar(); + + + ReadStats(-1); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + bHandled = TRUE; + } + break; + case VK_PAD_LTRIGGER: + case VK_PAD_RTRIGGER: + { + //Do nothing if a stats read is currently in progress, otherwise the system complains about to many read requests + if( m_bPopulatedOnce && LeaderboardManager::Instance()->isIdle() ) + { + if( m_leaderboard.m_totalEntryCount <= 10 ) + break; + + if( pInputData->dwKeyCode == VK_PAD_LTRIGGER ) + { + m_newTop = m_listGamers.GetTopItem() - 10; + if( m_newTop < 0 ) + m_newTop = 0; + + m_newSel = m_newTop; + } + else + { + m_newTop = m_listGamers.GetTopItem() + 10; + if( m_newTop+10 > (int)m_leaderboard.m_totalEntryCount ) + { + m_newTop = m_leaderboard.m_totalEntryCount - 10; + if( m_newTop < 0 ) + m_newTop = 0; + } + + m_newSel = m_newTop; + } + //CXuiSceneBase::PlayUISFX(eSFX_Press); + } + bHandled = TRUE; + } + break; + case VK_PAD_X: + { + //Do nothing if a stats read is currently in progress, otherwise the system complains about to many read requests + if( m_bPopulatedOnce && LeaderboardManager::Instance()->isIdle() ) + { + switch( m_currentFilter ) + { + case LeaderboardManager::eFM_Friends: + { + m_currentFilter = LeaderboardManager::eFM_MyScore; + wchar_t filterBuffer[40]; + swprintf_s(filterBuffer, 40, L"%ls%ls", app.GetString(IDS_LEADERBOARD_FILTER), app.GetString(IDS_LEADERBOARD_FILTER_MYSCORE)); + m_textFilter.SetText(filterBuffer); + } + break; + case LeaderboardManager::eFM_MyScore: + { + m_currentFilter = LeaderboardManager::eFM_TopRank; + wchar_t filterBuffer[40]; + swprintf_s(filterBuffer, 40, L"%ls%ls", app.GetString(IDS_LEADERBOARD_FILTER), app.GetString(IDS_LEADERBOARD_FILTER_OVERALL)); + m_textFilter.SetText(filterBuffer); + } + break; + case LeaderboardManager::eFM_TopRank: + { + m_currentFilter = LeaderboardManager::eFM_Friends; + wchar_t filterBuffer[40]; + swprintf_s(filterBuffer, 40, L"%ls%ls", app.GetString(IDS_LEADERBOARD_FILTER), app.GetString(IDS_LEADERBOARD_FILTER_FRIENDS)); + m_textFilter.SetText(filterBuffer); + } + break; + } + + ReadStats(-1); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + bHandled = TRUE; + } + break; + case VK_PAD_Y: + { + //Show gamercard + if( m_leaderboard.m_currentEntryCount > 0 ) + { + unsigned int selection = (unsigned int)m_listGamers.GetCurSel(); + if( selection >= m_leaderboard.m_entryStartIndex-1 && + selection < (m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount-1) ) + { + PlayerUID xuid = m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1)].m_xuid; + if( xuid != INVALID_XUID ) + { + XShowGamerCardUI(ProfileManager.GetLockedProfile(), xuid); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + } + } + bHandled = TRUE; + } + break; + case VK_PAD_A: + { + //Send friend request if the filter mode is not friend, and they're not a friend or a pending friend + if( m_currentFilter != LeaderboardManager::eFM_Friends ) + { + if( m_leaderboard.m_currentEntryCount > 0 ) + { + unsigned int selection = (unsigned int)m_listGamers.GetCurSel(); + if( selection >= m_leaderboard.m_entryStartIndex-1 && + selection < (m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount-1) ) + { + //If not the player and neither currently a friend or requested to be a friend + if( !m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1) ].m_bPlayer && + !m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1) ].m_bFriend && + !m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1) ].m_bRequestedFriend ) + { + PlayerUID xuid = m_leaderboard.m_entries[selection - (m_leaderboard.m_entryStartIndex-1) ].m_xuid; + if( xuid != INVALID_XUID ) + { + XShowFriendRequestUI(ProfileManager.GetLockedProfile(), xuid); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + } + } + } + } + bHandled = TRUE; + } + break; + case VK_PAD_B: + case VK_ESCAPE: + { + BYTE userIndex = pInputData->UserIndex; + if( !app.IsPauseMenuDisplayed(userIndex) ) + { + // If we are not from a pause menu, then we are from the main menu + userIndex = XUSER_INDEX_ANY; + } + + app.NavigateBack(userIndex); + bHandled = TRUE; + } + break; + } + return S_OK; +} + +// DELETING // +#if 0 +void CScene_Leaderboards::GetFriends() +{ + DWORD resultsSize; + HANDLE hEnumerator; + DWORD ret; + + m_numFriends = 0; + + //First, get a list of (up to 100) friends (this is the maximum that the enumerator currently supports) + ret = XFriendsCreateEnumerator( ProfileManager.GetLockedProfile(), 0, 100, &resultsSize, &hEnumerator); + if( ret != ERROR_SUCCESS ) + return; + + m_friends = (XONLINE_FRIEND*) new BYTE[ resultsSize ]; + DWORD numFriends; + + ret = XEnumerate( + hEnumerator, + m_friends, + resultsSize, + &numFriends, + NULL ); + + if( ret != ERROR_SUCCESS ) + numFriends = 0; + + m_numFriends = numFriends; + + m_filteredFriends = new PlayerUID[m_numFriends+1]; + + m_numFilteredFriends = 0; + for( unsigned int friendIndex=0 ; friendIndex<numFriends ; ++friendIndex ) + { + if( ( m_friends[friendIndex].dwFriendState & ( XONLINE_FRIENDSTATE_FLAG_SENTREQUEST | XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST ) ) == 0 ) + { + m_filteredFriends[m_numFilteredFriends++] = m_friends[friendIndex].xuid; + } + } + m_filteredFriends[m_numFilteredFriends++] = LeaderboardManager::Instance()->GetMyXUID(); +} +#endif + +void CScene_Leaderboards::ReadStats(int startIndex) +{ + //If startIndex == -1, then use default values + if( startIndex == -1 ) + { + m_newEntryIndex = 1; + m_newReadSize = READ_SIZE; + + m_leaderboard.m_totalEntryCount = 0; + m_leaderboard.m_currentEntryCount = 0; + + m_listGamers.DeleteItems(0, m_listGamers.GetItemCount()); + } + else + { + m_newEntryIndex = (unsigned int)startIndex; + m_newReadSize = min((int)READ_SIZE, (int)m_leaderboard.m_totalEntryCount-(startIndex-1)); + } + + //Setup the spec structure for the read request + /* XUSER_STATS_SPEC* spec = new XUSER_STATS_SPEC[1]; // 4j-jev, moved into xboxLeaderboardManager + spec[0].dwViewId = LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_viewId; + spec[0].dwNumColumnIds = LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_columnCount; + for( unsigned int i=0 ; i<spec[0].dwNumColumnIds ; ++i ) + spec[0].rgwColumnIds[i] = LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_columnIds[i]; */ + + /*//This call takes ownership of spec and will free it when done + LeaderboardManager::Instance()->ReadStats( + m_newEntryIndex, + m_newReadSize, + 1, + spec, + (startIndex == -1) ? m_currentFilter : LeaderboardManager::eFM_TopRank, + CScene_Leaderboards::OnStatsReadComplete, + reinterpret_cast<void*>(this), + m_numFilteredFriends, + m_filteredFriends);*/ + + switch (startIndex == -1 ? m_currentFilter : LeaderboardManager::eFM_TopRank) + { + case LeaderboardManager::eFM_TopRank: + LeaderboardManager::Instance()->ReadStats_TopRank( this, + m_currentDifficulty, (LeaderboardManager::EStatsType) m_currentLeaderboard, + m_newEntryIndex, m_newReadSize + ); + break; + case LeaderboardManager::eFM_MyScore: + LeaderboardManager::Instance()->ReadStats_MyScore( this, + m_currentDifficulty, (LeaderboardManager::EStatsType) m_currentLeaderboard, + INVALID_XUID/*ignored*/, + m_newReadSize + ); + break; + case LeaderboardManager::eFM_Friends: + LeaderboardManager::Instance()->ReadStats_Friends( this, + m_currentDifficulty, (LeaderboardManager::EStatsType) m_currentLeaderboard, + INVALID_XUID /*ignored*/, + 0 /*ignored*/, 0 /*ignored*/ + ); + break; + } + + //Show the loading message + m_textInfo.SetText(app.GetString(IDS_LEADERBOARD_LOADING)); + m_textInfo.SetShow(true); +} + +bool CScene_Leaderboards::OnStatsReadComplete(bool success, int numResults, LeaderboardManager::ViewOut results) +{ + //CScene_Leaderboards* scene = reinterpret_cast<CScene_Leaderboards*>(userdata); + + m_isProcessingStatsRead = true; + + //bool noResults = LeaderboardManager::Instance()->GetStatsState() != XboxLeaderboardManager::eStatsState_Ready; + bool ret; + + if (success) + { + m_numStats = numResults; + m_stats = results; + ret = RetrieveStats(); + } + else ret = true; + + //else LeaderboardManager::Instance()->SetStatsRetrieved(false); + + PopulateLeaderboard(!success); + + m_isProcessingStatsRead = false; + + return ret; +} + + +bool CScene_Leaderboards::RetrieveStats() +{ + + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + m_leaderboard.m_totalEntryCount = NUM_ENTRIES; + m_leaderboard.m_currentEntryCount = NUM_ENTRIES; + m_leaderboard.m_entryStartIndex = 1; + m_leaderboard.m_numColumns = LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_columnCount; + + //For each entry in the leaderboard + for( unsigned int entryIndex=0 ; entryIndex<m_leaderboard.m_currentEntryCount ; entryIndex++ ) + { + m_leaderboard.m_entries[entryIndex].m_xuid = INVALID_XUID; + + m_leaderboard.m_entries[entryIndex].m_rank = entryIndex+1; + swprintf(m_leaderboard.m_entries[entryIndex].m_wcRank, 12, L"12345678");//(int)m_leaderboard.m_entries[entryIndex].m_rank); + + swprintf(m_leaderboard.m_entries[entryIndex].m_gamerTag, 17, L"WWWWWWWWWWWWWWWW"); + + //m_leaderboard.m_entries[entryIndex].m_locale = (entryIndex % 37) + 1; + + bool isDistanceLeaderboard = LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_viewId == STATS_VIEW_TRAVELLING_PEACEFUL || LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_viewId == STATS_VIEW_TRAVELLING_EASY || LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_viewId == STATS_VIEW_TRAVELLING_NORMAL || LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_viewId == STATS_VIEW_TRAVELLING_HARD; + + for( unsigned int i=0 ; i<m_leaderboard.m_numColumns ; i++ ) + { + if( !isDistanceLeaderboard ) + { + m_leaderboard.m_entries[entryIndex].m_columns[i] = USHRT_MAX; + swprintf(m_leaderboard.m_entries[entryIndex].m_wcColumns[i], 12, L"%u", m_leaderboard.m_entries[entryIndex].m_columns[i]); + } + else + { + m_leaderboard.m_entries[entryIndex].m_columns[i] = UINT_MAX; + swprintf(m_leaderboard.m_entries[entryIndex].m_wcColumns[i], 12, L"%.1fkm", ((float)m_leaderboard.m_entries[entryIndex].m_columns[i])/100.f/1000.f); + } + } + + m_leaderboard.m_entries[entryIndex].m_bPlayer = (entryIndex == 0); + m_leaderboard.m_entries[entryIndex].m_bOnline = (entryIndex != 0); + m_leaderboard.m_entries[entryIndex].m_bFriend = (entryIndex != 0); + m_leaderboard.m_entries[entryIndex].m_bRequestedFriend = false; + } + + //LeaderboardManager::Instance()->SetStatsRetrieved(true); + + return true; + } + + //assert( LeaderboardManager::Instance()->GetStats() != NULL ); + //PXUSER_STATS_READ_RESULTS stats = LeaderboardManager::Instance()->GetStats(); + //if( m_currentFilter == LeaderboardManager::eFM_Friends ) LeaderboardManager::Instance()->SortFriendStats(); + + bool isDistanceLeaderboard = m_stats->pViews[0].dwViewId == STATS_VIEW_TRAVELLING_PEACEFUL || m_stats->pViews[0].dwViewId == STATS_VIEW_TRAVELLING_EASY || m_stats->pViews[0].dwViewId == STATS_VIEW_TRAVELLING_NORMAL || m_stats->pViews[0].dwViewId == STATS_VIEW_TRAVELLING_HARD; + + //First read + if( m_leaderboard.m_totalEntryCount == 0 ) + { + m_leaderboard.m_totalEntryCount = (m_currentFilter == LeaderboardManager::eFM_Friends) ? m_stats->pViews[0].dwNumRows : m_stats->pViews[0].dwTotalViewRows; + m_leaderboard.m_currentEntryCount = m_stats->pViews[0].dwNumRows; + + if( m_leaderboard.m_totalEntryCount == 0 || m_leaderboard.m_currentEntryCount == 0 ) + { + //LeaderboardManager::Instance()->SetStatsRetrieved(false); + return false; + } + + m_leaderboard.m_numColumns = m_stats->pViews[0].pRows[0].dwNumColumns; + + m_leaderboard.m_entryStartIndex = (m_currentFilter == LeaderboardManager::eFM_Friends) ? 1 : m_stats->pViews[0].pRows[0].dwRank; + + for( unsigned int entryIndex=0 ; entryIndex<m_leaderboard.m_currentEntryCount ; ++entryIndex ) + CopyLeaderboardEntry(&(m_stats->pViews[0].pRows[entryIndex]), &(m_leaderboard.m_entries[entryIndex]), isDistanceLeaderboard); + + //If the filter mode is "My Score" then centre the list around the entries and select the player's score + if( m_currentFilter == LeaderboardManager::eFM_MyScore ) + { + //Centre the leaderboard list on the entries + m_newTop = m_leaderboard.m_entryStartIndex-1; + + //Select the player entry + for( unsigned int i=m_leaderboard.m_entryStartIndex ; i<m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount ; ++i ) + if( m_leaderboard.m_entries[i-m_leaderboard.m_entryStartIndex].m_bPlayer ) + { + m_newSel = i-1; // this might be off the screen! + // and reposition the top one + if(m_newSel-m_newTop>9) + { + m_newTop=m_newSel-9; + } + break; + } + } + } + //Additional read + else + { + unsigned int insertPosition = 0; + + //If the first new entry is at a smaller index than the current first entry + if( m_newEntryIndex < m_leaderboard.m_entryStartIndex ) + { + if( (m_leaderboard.m_entryStartIndex-1) < m_newReadSize ) + m_newReadSize = m_leaderboard.m_entryStartIndex-1; + + //Move current entries forward + memmove((void*)(m_leaderboard.m_entries+m_newReadSize), (void*)m_leaderboard.m_entries, sizeof(LeaderboardEntry)*(NUM_ENTRIES-m_newReadSize)); + + //Set the (now smaller) entry start index + m_leaderboard.m_entryStartIndex = m_newEntryIndex; + + //We will be inserting the new entries at the start of the array + insertPosition = 0; + + //Entry count is either max possible entries or current entry count + read size, whichever is smaller + m_leaderboard.m_currentEntryCount = min((int)NUM_ENTRIES, (int)(m_leaderboard.m_currentEntryCount+m_newReadSize)); + } + //If the last new entry is at a greater position than the last possible entry + else if( m_newEntryIndex+m_newReadSize-1 >= m_leaderboard.m_entryStartIndex+NUM_ENTRIES ) + { + //Calculate the overlap (this is by how much new entries would overhang the end of the array) + int overlap = (((m_newEntryIndex-1)+m_newReadSize-1) - (m_leaderboard.m_entryStartIndex-1)) - NUM_ENTRIES + 1; + + //Move current entries backwards + memmove((void*)m_leaderboard.m_entries, (void*)(m_leaderboard.m_entries+overlap), sizeof(LeaderboardEntry)*(NUM_ENTRIES-overlap)); + + //Set the (now larger) start index + m_leaderboard.m_entryStartIndex += overlap; + + //We will be inserting the new entries at the end of the array + insertPosition = NUM_ENTRIES - m_newReadSize; + + //Entry count is max possible entries + m_leaderboard.m_currentEntryCount = NUM_ENTRIES; + } + //Otherwise we're inserting at the end of the array and there is plenty of room + else + { + insertPosition = m_leaderboard.m_currentEntryCount; + m_leaderboard.m_currentEntryCount += m_newReadSize; + } + + //For each entry in the leaderboard + for( unsigned int entryIndex=0 ; entryIndex<m_newReadSize ; ++entryIndex ) + { + CopyLeaderboardEntry(&(m_stats->pViews[0].pRows[entryIndex]), &(m_leaderboard.m_entries[insertPosition]), isDistanceLeaderboard); + insertPosition++; + } + } + + //LeaderboardManager::Instance()->SetStatsRetrieved(true); + return true; +} + +HRESULT CScene_Leaderboards::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +{ + pGetItemCountData->cItems = m_leaderboard.m_totalEntryCount; + + //if(LeaderboardManager::Instance()->GetStatsRead()) + //{ + // m_bReady=true; + //} + bHandled = TRUE; + + return S_OK; +} + +HRESULT CScene_Leaderboards::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData,BOOL& bHandled) +{ + if( pGetSourceTextData->bItemData ) + { + if( m_newTop != -1 && m_newSel != -1 ) + { + HRESULT ret = m_listGamers.SetTopItem(m_newTop); + assert( ret == S_OK ); + + ret = m_listGamers.SetCurSel(m_newSel); + assert( ret == S_OK ); + + // update the tooltips + + m_newTop = m_newSel = -1; + + bHandled = true; + return S_OK; + } + + unsigned int item = pGetSourceTextData->iItem; + + if( m_leaderboard.m_totalEntryCount > 0 && (item+1) < m_leaderboard.m_entryStartIndex ) + { + if( LeaderboardManager::Instance()->isIdle() ) + { + int readIndex = m_leaderboard.m_entryStartIndex - READ_SIZE; + if( readIndex <= 0 ) + readIndex = 1; + assert( readIndex >= 1 && readIndex <= (int)m_leaderboard.m_totalEntryCount ); + ReadStats(readIndex); + } + } + else if( m_leaderboard.m_totalEntryCount > 0 && (item+1) >= (m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount) ) + { + if( LeaderboardManager::Instance()->isIdle() ) + { + int readIndex = m_leaderboard.m_entryStartIndex + m_leaderboard.m_currentEntryCount; + assert( readIndex >= 1 && readIndex <= (int)m_leaderboard.m_totalEntryCount ); + ReadStats(readIndex); + } + } + else + { + unsigned int index = item - (m_leaderboard.m_entryStartIndex-1); + if( 0 == pGetSourceTextData->iData ) + { + pGetSourceTextData->szText = m_leaderboard.m_entries[index].m_wcRank; + bHandled = TRUE; + } + else if( 1 == pGetSourceTextData->iData ) + { + pGetSourceTextData->szText = m_leaderboard.m_entries[index].m_gamerTag; + bHandled = TRUE; + } + else if( pGetSourceTextData->iData >= 3 && pGetSourceTextData->iData <= 9 ) + { + if( m_leaderboard.m_numColumns <= (unsigned int)(pGetSourceTextData->iData-3) ) + pGetSourceTextData->szText = L""; + else + pGetSourceTextData->szText = m_leaderboard.m_entries[index].m_wcColumns[pGetSourceTextData->iData-3]; + bHandled = TRUE; + } + } + } + return S_OK; +} + +HRESULT CScene_Leaderboards::OnGetSourceDataImage(XUIMessageGetSourceImage* pGetImage, BOOL& bHandled) +{ + if( (pGetImage->iData == 2) && (pGetImage->bItemData) ) + { + if( m_newTop != -1 && m_newSel != -1 ) + { + //Do nothing, alignment handled in OnGetSourceDataText + + bHandled = true; + return S_OK; + } + + unsigned int item = pGetImage->iItem; + if( m_leaderboard.m_totalEntryCount > 0 && (item+1) < m_leaderboard.m_entryStartIndex ) + { + //Do nothing, reading handled in OnGetSourceDataText + } + else if( m_leaderboard.m_totalEntryCount > 0 && (item+1) >= (m_leaderboard.m_entryStartIndex+m_leaderboard.m_currentEntryCount) ) + { + //Do nothing, reading handled in OnGetSourceDataText + } + // 4J-PB - we're not allowed to show flags any more +// else +// { +// unsigned int index = item - (m_leaderboard.m_entryStartIndex-1); +// if( m_leaderboard.m_entries[index].m_locale > 0 && m_leaderboard.m_entries[index].m_locale <= XC_LOCALE_RUSSIAN_FEDERATION ) +// pGetImage->szPath = FLAG_ICON_PATHS[ m_leaderboard.m_entries[index].m_locale-1 ]; +// bHandled = TRUE; +// } + } + + return S_OK; +} + +void CScene_Leaderboards::PopulateLeaderboard(bool noResults) +{ + HRESULT hr; + HXUIOBJ visual=NULL; + HXUIOBJ hTemp=NULL; + hr=XuiControlGetVisual(m_listGamers.m_hObj,&visual); + + if(m_pHTitleIconSlots[0]==NULL) + { + VOID *pObj; + HXUIOBJ button; + D3DXVECTOR3 vPos; + + for(int i=0;i<7;i++) + { + // retrieve the visual for the title icon + hr=XuiElementGetChildById(visual,m_TitleIconNameA[i],&button); + + XuiObjectFromHandle( button, &pObj ); + m_pHTitleIconSlots[i] = (CXuiCtrlCraftIngredientSlot *)pObj; + + // store the default position, since we'll be repositioning these depending on how many are valid for each board + m_pHTitleIconSlots[i]->GetPosition(&vPos); + m_fTitleIconXPositions[i]= vPos.x; + } + } + + int iValidSlots=SetLeaderboardTitleIcons(); + + if( !noResults && m_leaderboard.m_totalEntryCount > 0 ) + { + hr=XuiElementGetChildById(visual,L"XuiLabel_Gamertag",&hTemp); + if(hTemp) + { + XuiControlSetText(hTemp,app.GetString( IDS_LEADERBOARD_GAMERTAG )); + XuiElementSetShow(hTemp, TRUE); + } + hr=XuiElementGetChildById(visual,L"XuiLabel_Rank",&hTemp); + if(hTemp) + { + XuiControlSetText(hTemp,app.GetString( IDS_LEADERBOARD_RANK )); + XuiElementSetShow(hTemp, TRUE); + } + + //Update entries display + wchar_t entriesBuffer[40]; + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + swprintf(entriesBuffer, 40, L"%ls12345678", app.GetString(IDS_LEADERBOARD_ENTRIES)); + } + else + { + swprintf(entriesBuffer, 40, L"%ls%i", app.GetString(IDS_LEADERBOARD_ENTRIES), m_leaderboard.m_totalEntryCount); + } + + m_textEntries.SetText(entriesBuffer); + + //Hide the loading message + m_textInfo.SetShow(false); + + //Add space for new entries + m_listGamers.InsertItems(0, m_leaderboard.m_totalEntryCount); + + // 4J Stu - Fix for leaderboards taking forever to update. Was looping over m_totalEntryCount which is ~2mil in + // some leaderboards in production atm. + // Changed to loop over the range of cached values, although even that is probably overkill. + // Really only the newly updated rows need changed, but this shouldn't cause any performance issues + for(DWORD i = m_leaderboard.m_entryStartIndex - 1; i < (m_leaderboard.m_entryStartIndex - 1) + m_leaderboard.m_currentEntryCount; ++i) + { + HXUIOBJ visual=NULL; + HXUIOBJ button; + D3DXVECTOR3 vPos; + // 4J-PB - fix for #13768 - Leaderboards: Player scores appear misaligned when viewed under the "My Score" leaderboard filter + HXUIOBJ hTop=m_listGamers.GetItemControl(i-(m_leaderboard.m_entryStartIndex - 1)); + HRESULT hr=XuiControlGetVisual(hTop,&visual); + + for(int j=0;j<7;j++) + { + hr=XuiElementGetChildById(visual,m_TextColumnNameA[j],&button); + m_hTextEntryA[j]=button; + + XuiElementGetPosition(button,&vPos); + m_fTextXPositions[j]=vPos.x; + } + RepositionText(iValidSlots); + } + + // hide empty icon boxes + for(int i = (LEADERBOARD_DESCRIPTORS[m_currentLeaderboard][m_currentDifficulty].m_columnCount);i<7;i++) + { + m_pHTitleIconSlots[i]->SetShow(FALSE); + } + } + else + { + hr=XuiElementGetChildById(visual,L"XuiLabel_Gamertag",&hTemp); + if(hTemp) + { + XuiElementSetShow(hTemp, FALSE); + } + hr=XuiElementGetChildById(visual,L"XuiLabel_Rank",&hTemp); + if(hTemp) + { + XuiElementSetShow(hTemp, FALSE); + } + + //Update entries display (to zero) + wchar_t entriesBuffer[40]; + swprintf(entriesBuffer, 40, L"%ls0", app.GetString(IDS_LEADERBOARD_ENTRIES)); + m_textEntries.SetText(entriesBuffer); + + //Show the no results message + m_textInfo.SetText(app.GetString(IDS_LEADERBOARD_NORESULTS)); + m_textInfo.SetShow(true); + + // hide the icons + for(int i=0;i<7;i++) + { + m_pHTitleIconSlots[i]->SetShow(FALSE); + } + + } + + m_bPopulatedOnce = true; +} + +void CScene_Leaderboards::CopyLeaderboardEntry(PXUSER_STATS_ROW statsRow, LeaderboardEntry* leaderboardEntry, bool isDistanceLeaderboard) +{ + leaderboardEntry->m_xuid = statsRow->xuid; + + //Copy the rank + leaderboardEntry->m_rank = statsRow->dwRank; + DWORD displayRank = leaderboardEntry->m_rank; + if(displayRank > 9999999) displayRank = 9999999; + swprintf_s(leaderboardEntry->m_wcRank, 12, L"%u", displayRank); + + //strcpy(statsRow->szGamertag,"WWWWWWWWWWWWWWWW"); + + //Convert the gamertag from char to wchar_t + MultiByteToWideChar( + CP_UTF8, + 0, + statsRow->szGamertag, + strlen(statsRow->szGamertag), + leaderboardEntry->m_gamerTag, + XUSER_NAME_SIZE ); + //Null terminate the gamertag + leaderboardEntry->m_gamerTag[strlen(statsRow->szGamertag)] = L'\0'; + + //Copy the locale + //leaderboardEntry->m_locale = statsRow->pColumns[0].Value.nData; + + //Copy the other columns + for( unsigned int i=0 ; i<statsRow->dwNumColumns ; i++ ) + { + leaderboardEntry->m_columns[i] = statsRow->pColumns[i].Value.nData; + if( !isDistanceLeaderboard ) + { + DWORD displayValue = leaderboardEntry->m_columns[i]; + if(displayValue > 99999) displayValue = 99999; + swprintf_s(leaderboardEntry->m_wcColumns[i], 12, L"%u",displayValue); +#ifdef _DEBUG + app.DebugPrintf("Value - %d\n",leaderboardEntry->m_columns[i]); +#endif + } + else + { + // check how many digits we have + int iDigitC=0; + unsigned int uiVal=leaderboardEntry->m_columns[i]; +// uiVal=0xFFFFFFFF; +// leaderboardEntry->m_columns[i-1]=uiVal; + + while(uiVal!=0) + { + uiVal/=10; + iDigitC++; + } + +#ifdef _DEBUG + app.DebugPrintf("Value - %d\n",leaderboardEntry->m_columns[i]); +#endif + if(iDigitC<4) + { + // m + swprintf_s(leaderboardEntry->m_wcColumns[i], 12, L"%um", leaderboardEntry->m_columns[i]); +#ifdef _DEBUG + app.DebugPrintf("Display - %um\n", leaderboardEntry->m_columns[i]); +#endif + } + else if(iDigitC<8) + { + // km with a .X + swprintf_s(leaderboardEntry->m_wcColumns[i], 12, L"%.1fkm", ((float)leaderboardEntry->m_columns[i])/1000.f); +#ifdef _DEBUG + app.DebugPrintf("Display - %.1fkm\n", ((float)leaderboardEntry->m_columns[i])/1000.f); +#endif + } + else + { + // bigger than that, so no decimal point + swprintf_s(leaderboardEntry->m_wcColumns[i], 12, L"%.0fkm", ((float)leaderboardEntry->m_columns[i])/1000.f); +#ifdef _DEBUG + app.DebugPrintf("Display - %.0fkm\n", ((float)leaderboardEntry->m_columns[i])/1000.f); +#endif + } + } + } + + //Is the player + if( statsRow->xuid == ((XboxLeaderboardManager*)LeaderboardManager::Instance())->GetMyXUID() ) + { + leaderboardEntry->m_bPlayer = true; + leaderboardEntry->m_bOnline = false; + leaderboardEntry->m_bFriend = false; + leaderboardEntry->m_bRequestedFriend = false; + } + else + { + leaderboardEntry->m_bPlayer = false; + leaderboardEntry->m_bOnline = false; + leaderboardEntry->m_bFriend = false; + leaderboardEntry->m_bRequestedFriend = false; + + //Check for friend status + for( unsigned int friendIndex=0 ; friendIndex<m_numFriends ; ++friendIndex ) + { + if( m_friends[friendIndex].xuid == statsRow->xuid ) + { + if( ( m_friends[friendIndex].dwFriendState & ( XONLINE_FRIENDSTATE_FLAG_SENTREQUEST | XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST ) ) == 0 ) + { + //Is friend, might be online + leaderboardEntry->m_bFriend = true; + leaderboardEntry->m_bOnline = ( m_friends[friendIndex].dwFriendState & XONLINE_FRIENDSTATE_FLAG_ONLINE ); + leaderboardEntry->m_bRequestedFriend = false; + } + else + { + //Friend request sent but not accepted yet + leaderboardEntry->m_bOnline = false; + leaderboardEntry->m_bFriend = false; + leaderboardEntry->m_bRequestedFriend = true; + } + + break; + } + } + } +} + +void CScene_Leaderboards::SetLeaderboardHeader() +{ + WCHAR buffer[40]; + DWORD bufferLength = 40; + + DWORD ret = XResourceGetString(LEADERBOARD_HEADERS[m_currentLeaderboard][m_currentDifficulty], buffer, &bufferLength, NULL); + + if( ret == ERROR_SUCCESS ) + m_textLeaderboard.SetText(buffer); +} + +int CScene_Leaderboards::SetLeaderboardTitleIcons() +{ + int iValidIcons=0; + + for(int i=0;i<7;i++) + { + if(TitleIcons[m_currentLeaderboard][i]==0) + { + m_pHTitleIconSlots[i]->SetShow(FALSE); + } + else + { + iValidIcons++; + m_pHTitleIconSlots[i]->SetIcon(DEFAULT_XUI_MENU_USER,TitleIcons[m_currentLeaderboard][i],0,1,10,31,false,FALSE); + } + } + + Reposition(iValidIcons); + + return iValidIcons; +} +void CScene_Leaderboards::ClearLeaderboardTitlebar() +{ + for(int i=0;i<7;i++) + { + m_pHTitleIconSlots[i]->SetShow(FALSE); + } + + HXUIOBJ visual=NULL; + HXUIOBJ hTemp=NULL; + HRESULT hr; + hr=XuiControlGetVisual(m_listGamers.m_hObj,&visual); + + hr=XuiElementGetChildById(visual,L"XuiLabel_Gamertag",&hTemp); + if(hTemp) + { + XuiElementSetShow(hTemp, FALSE); + } + hr=XuiElementGetChildById(visual,L"XuiLabel_Rank",&hTemp); + if(hTemp) + { + XuiElementSetShow(hTemp, FALSE); + } +} diff --git a/Minecraft.Client/Common/XUI/XUI_Leaderboards.h b/Minecraft.Client/Common/XUI/XUI_Leaderboards.h new file mode 100644 index 00000000..e06f13e1 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Leaderboards.h @@ -0,0 +1,169 @@ +#pragma once +#include "XUI_Helper.h" +#include "../media/xuiscene_leaderboards.h" + +#include "..\Leaderboards\LeaderboardManager.h" + +class CXuiCtrlCraftIngredientSlot; + +class CScene_Leaderboards : public CXuiSceneImpl, public LeaderboardReadListener +{ +private: + // 4J Stu - Because the kills leaderboard doesn't a peaceful entry there are some special + // handling to make it skip that. We have re-arranged the order of the leaderboards so + // I am making this in case we do it again. + // 4J Stu - Made it a member of the class, rather than a #define + static const int LEADERBOARD_KILLS_POSITION = 3; + + static const int NUM_LEADERBOARDS = 4;//6; //Number of leaderboards + static const int NUM_ENTRIES = 101; //Cache up to this many entries + static const int READ_SIZE = 15; //Read this many entries at a time + +// static LPCWSTR FLAG_ICON_PATHS[37]; + int m_iPad; + + bool m_bPopulatedOnce; + + static const int LEADERBOARD_HEADERS[NUM_LEADERBOARDS][4]; + + static const int TitleIcons[NUM_LEADERBOARDS][7]; + static LPCWSTR m_TitleIconNameA[7]; + static LPCWSTR m_TextColumnNameA[7]; + HXUIOBJ m_hTextEntryA[7]; + + struct LeaderboardDescriptor { + DWORD m_viewId; + DWORD m_columnCount; + WORD m_columnIds[8]; + + LeaderboardDescriptor(DWORD viewId, DWORD columnCount, WORD columnId_0, WORD columnId_1, WORD columnId_2, WORD columnId_3, WORD columnId_4, WORD columnId_5, WORD columnId_6, WORD columnId_7) + { + m_viewId = viewId; + m_columnCount = columnCount; + m_columnIds[0] = columnId_0; + m_columnIds[1] = columnId_1; + m_columnIds[2] = columnId_2; + m_columnIds[3] = columnId_3; + m_columnIds[4] = columnId_4; + m_columnIds[5] = columnId_5; + m_columnIds[6] = columnId_6; + m_columnIds[7] = columnId_7; + } + }; + + static const LeaderboardDescriptor LEADERBOARD_DESCRIPTORS[NUM_LEADERBOARDS][4]; + + struct LeaderboardEntry { + PlayerUID m_xuid; + DWORD m_rank; + WCHAR m_wcRank[12]; + WCHAR m_gamerTag[XUSER_NAME_SIZE+1]; + //int m_locale; + unsigned int m_columns[7]; + WCHAR m_wcColumns[7][12]; + bool m_bPlayer; //Is the player + bool m_bOnline; //Is online + bool m_bFriend; //Is friend + bool m_bRequestedFriend; //Friend request sent but not answered + }; + + struct Leaderboard { + DWORD m_totalEntryCount; //Either total number of entries in leaderboard, or total number of results for a friends query + DWORD m_entryStartIndex; //Index of first entry + DWORD m_currentEntryCount; //Current number of entries + LeaderboardEntry m_entries[NUM_ENTRIES]; + DWORD m_numColumns; + }; + + Leaderboard m_leaderboard; //All leaderboard data for the currently selected filter + + unsigned int m_currentLeaderboard; //The current leaderboard selected for view + +#ifdef _XBOX + LeaderboardManager::EFilterMode m_currentFilter; //The current filter selected +#endif + unsigned int m_currentDifficulty; //The current difficulty selected + + unsigned int m_newEntryIndex; //Index of the first entry being read + unsigned int m_newReadSize; //Number of entries in the current read operation + + int m_newTop; //Index of the element that should be at the top of the list + int m_newSel; //Index of the element that should be selected in the list + + XONLINE_FRIEND* m_friends; //Current player's friends + unsigned int m_numFriends; //Count of friends + PlayerUID* m_filteredFriends; //List of all friend XUIDs (and player's), only counting actual friends, not pending + unsigned int m_numFilteredFriends; //Count of filtered friends + + CXuiList m_listGamers; //The XUI list showing the leaderboard info + CXuiControl m_textLeaderboard; //The XUI text box showing the current leaderboard name + CXuiControl m_textInfo; //The XUI text box showing info messages (loading, no results, etc.) + CXuiControl m_textFilter; //The XUI text box showing the current filter + CXuiControl m_textEntries; //The XUI text box showing the total number of entries in this leaderboard + CXuiCtrlCraftIngredientSlot *m_pHTitleIconSlots[7]; + float m_fTitleIconXPositions[7]; + float m_fTextXPositions[7]; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_NOTIFY_SELCHANGED(OnNotifySelChanged) + XUI_ON_XM_NOTIFY_SET_FOCUS(OnNotifySetFocus) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiListGamers, m_listGamers) + MAP_CONTROL(IDC_XuiTextLeaderboard, m_textLeaderboard) + MAP_CONTROL(IDC_XuiTextInfo, m_textInfo) + MAP_CONTROL(IDC_XuiTextFilter, m_textFilter) + MAP_CONTROL(IDC_XuiTextEntries, m_textEntries) + END_CONTROL_MAP() + + HRESULT OnInit(XUIMessageInit* pInitData, BOOL& bHandled); + HRESULT OnDestroy(); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage* pGetImage, BOOL& bHandled); + HRESULT OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled); + + //Start a read request with the current parameters + void ReadStats(int startIndex); + + //Callback function called when stats read completes, userdata contains pointer to instance of CScene_Leaderboards + virtual bool OnStatsReadComplete(bool success, int numResults, LeaderboardManager::ViewOut results); + + //Copy the stats from the raw m_stats structure into the m_leaderboards structure + int m_numStats; + PXUSER_STATS_READ_RESULTS m_stats; + bool RetrieveStats(); + + //Populate the XUI leaderboard with the contents of m_leaderboards + void PopulateLeaderboard(bool noResults); + + //Copy a leaderboard entry from the stats row + void CopyLeaderboardEntry(PXUSER_STATS_ROW statsRow, LeaderboardEntry* leaderboardEntry, bool isDistanceLeaderboard); + + //Set the header text of the leaderboard + void SetLeaderboardHeader(); + + // Set the title icons + int SetLeaderboardTitleIcons(); + void ClearLeaderboardTitlebar(); + void Reposition(int iNumber); + void RepositionText(int iNumber); + void UpdateTooltips(); + +protected: + bool m_isProcessingStatsRead; + bool m_bReady; +public: + + XUI_IMPLEMENT_CLASS( CScene_Leaderboards, L"CScene_Leaderboards", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_LoadSettings.cpp b/Minecraft.Client/Common/XUI/XUI_LoadSettings.cpp new file mode 100644 index 00000000..7f32ff89 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_LoadSettings.cpp @@ -0,0 +1,1686 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include <assert.h> +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" +#include "..\..\LocalPlayer.h" +#include "..\..\Minecraft.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\ArrayWithLength.h" +#include "..\..\..\Minecraft.World\File.h" +#include "..\..\..\Minecraft.World\InputOutputStream.h" +#include "..\..\MinecraftServer.h" +#include "..\..\Options.h" +#include "XUI_Ctrl_4JList.h" +#include "XUI_MultiGameInfo.h" +#include "XUI_MultiGameJoinLoad.h" +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_LoadSettings.h" +#include "..\..\..\Minecraft.World\LevelSettings.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" +#include "..\GameRules\ConsoleGameRules.h" +#include "..\..\StringTable.h" +#include "..\..\DLCTexturePack.h" + +#define GAME_CREATE_ONLINE_TIMER_ID 0 +#define GAME_CREATE_ONLINE_TIMER_TIME 100 +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID 1 +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 100 + +int CScene_LoadGameSettings::m_iDifficultyTitleSettingA[4]= +{ + IDS_DIFFICULTY_TITLE_PEACEFUL, + IDS_DIFFICULTY_TITLE_EASY, + IDS_DIFFICULTY_TITLE_NORMAL, + IDS_DIFFICULTY_TITLE_HARD +}; + + +HRESULT CScene_LoadGameSettings::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_hXuiBrush = NULL; + m_bSetup = false; + m_texturePackDescDisplayed = false; + m_iConfigA=NULL; + + WCHAR TempString[256]; + + m_params = (LoadMenuInitData *)pInitData->pvInitData; + + m_MoreOptionsParams.bGenerateOptions=FALSE; + m_MoreOptionsParams.bPVP = TRUE; + m_MoreOptionsParams.bTrust = TRUE; + m_MoreOptionsParams.bFireSpreads = TRUE; + m_MoreOptionsParams.bTNT = TRUE; + m_MoreOptionsParams.bHostPrivileges = FALSE; + m_MoreOptionsParams.bResetNether = FALSE; + m_MoreOptionsParams.iPad = m_params->iPad; + + // 4J-JEV: Fix for: + // TU12: Content: Gameplay: New "Mass Effect World" remembers and uses the settings of another - lately created - World. + m_MoreOptionsParams.bBonusChest = FALSE; + m_MoreOptionsParams.bFlatWorld = FALSE; + m_MoreOptionsParams.bStructures = TRUE; + + m_iPad=m_params->iPad; + m_iSaveGameInfoIndex=m_params->iSaveGameInfoIndex; + m_levelGen = m_params->levelGen; + + MapChildControls(); + + XuiControlSetText(m_MoreOptions,app.GetString(IDS_MORE_OPTIONS)); + XuiControlSetText(m_ButtonLoad,app.GetString(IDS_LOAD)); + XuiControlSetText(m_pTexturePacksList->m_hObj,app.GetString(IDS_DLC_MENU_TEXTUREPACKS)); + + m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + // 4J-PB - read the settings for the online flag. We'll only save this setting if the user changed it. + bool bGameSetting_Online=(app.GetGameSettings(m_iPad,eGameSetting_Online)!=0); + m_MoreOptionsParams.bOnlineSettingChangedBySystem=false; + + // Set the text for friends of friends, and default to on + if( m_bMultiplayerAllowed) + { + m_MoreOptionsParams.bOnlineGame = bGameSetting_Online?TRUE:FALSE; + if(bGameSetting_Online) + { + m_MoreOptionsParams.bInviteOnly = (app.GetGameSettings(m_iPad,eGameSetting_InviteOnly)!=0)?TRUE:FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = (app.GetGameSettings(m_iPad,eGameSetting_FriendsOfFriends)!=0)?TRUE:FALSE; + } + else + { + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + } + else + { + m_MoreOptionsParams.bOnlineGame = FALSE; + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + if(bGameSetting_Online) + { + // The profile settings say Online, but either the player is offline, or they are not allowed to play online + m_MoreOptionsParams.bOnlineSettingChangedBySystem=true; + } + } + + XuiSetTimer(m_hObj,GAME_CREATE_ONLINE_TIMER_ID,GAME_CREATE_ONLINE_TIMER_TIME); + XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); + + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); + m_bGameModeSurvival=true; + m_CurrentDifficulty=app.GetGameSettings(m_iPad,eGameSetting_Difficulty); + m_SliderDifficulty.SetValue(m_CurrentDifficulty); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[m_CurrentDifficulty])); + m_SliderDifficulty.SetText(TempString); + + m_bHasBeenInCreative = false; + + if(m_levelGen) + { + m_GameName.SetText(m_levelGen->getDisplayName()); + if(m_levelGen->requiresTexturePack()) + { + m_MoreOptionsParams.dwTexturePack = m_levelGen->getRequiredTexturePackId(); + m_pTexturePacksList->SetEnable(FALSE); + + // retrieve the save icon from the texture pack, if there is one + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(m_MoreOptionsParams.dwTexturePack); + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hXuiBrush); + } + + // Set this level as created in creative mode, so that people can't use the themed worlds as an easy way to get achievements + m_bHasBeenInCreative = true; + m_GameCreatedMode.SetText( app.GetString(IDS_CREATED_IN_CREATIVE) ); + } + } + else + { + // set the save icon + PBYTE pbImageData=NULL; + DWORD dwImageBytes=0; + + StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,m_XContentData); + StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,&pbImageData,&dwImageBytes); + + // if there is no thumbnail, retrieve the default one from the file. + // Don't delete the image data after creating the xuibrush, since we'll use it in the rename of the save + bool bHostOptionsRead = false; + unsigned int uiHostOptions = 0; + if(pbImageData==NULL) + { + DWORD dwResult=XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&m_XContentData,NULL,&dwImageBytes,NULL); + if(dwResult==ERROR_SUCCESS) + { + pbImageData = new BYTE[dwImageBytes]; + XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&m_XContentData,pbImageData,&dwImageBytes,NULL); + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hXuiBrush); + } + } + else + { + // retrieve the seed value from the image metadata + ZeroMemory(m_szSeed,50); + app.GetImageTextData(pbImageData,dwImageBytes,(unsigned char *)&m_szSeed,uiHostOptions,bHostOptionsRead,m_MoreOptionsParams.dwTexturePack); + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hXuiBrush); + +// #ifdef _DEBUG +// // dump out the thumbnail +// HANDLE hThumbnail = CreateFile("GAME:\\thumbnail.png", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL); +// DWORD dwBytes; +// WriteFile(hThumbnail,pbImageData,dwImageBytes,&dwBytes,NULL); +// XCloseHandle(hThumbnail); +// #endif + + if(m_szSeed[0]!=0) + { + swprintf( (WCHAR *)TempString, 256, L"%ls: %hs", app.GetString( IDS_SEED ),m_szSeed); + m_GameSeed.SetText(TempString); + } + else + { + m_GameSeed.SetText(L""); + } + } + + // Setup all the text and checkboxes to match what the game was saved with on + if(bHostOptionsRead) + { + m_MoreOptionsParams.bPVP = app.GetGameHostOption(uiHostOptions,eGameHostOption_PvP)>0?TRUE:FALSE; + m_MoreOptionsParams.bTrust = app.GetGameHostOption(uiHostOptions,eGameHostOption_TrustPlayers)>0?TRUE:FALSE; + m_MoreOptionsParams.bFireSpreads = app.GetGameHostOption(uiHostOptions,eGameHostOption_FireSpreads)>0?TRUE:FALSE; + m_MoreOptionsParams.bTNT = app.GetGameHostOption(uiHostOptions,eGameHostOption_TNT)>0?TRUE:FALSE; + m_MoreOptionsParams.bHostPrivileges = app.GetGameHostOption(uiHostOptions,eGameHostOption_CheatsEnabled)>0?TRUE:FALSE; + + m_bHasBeenInCreative = app.GetGameHostOption(uiHostOptions,eGameHostOption_HasBeenInCreative)>0; + if(app.GetGameHostOption(uiHostOptions,eGameHostOption_HasBeenInCreative)>0) + { + m_GameCreatedMode.SetText( app.GetString(IDS_CREATED_IN_CREATIVE) ); + } + else + { + m_GameCreatedMode.SetText( app.GetString(IDS_CREATED_IN_SURVIVAL) ); + } + + if(app.GetGameHostOption(uiHostOptions,eGameHostOption_GameType)>0) + { + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_CREATIVE)); + m_bGameModeSurvival=false; + } + + if(app.GetGameHostOption(uiHostOptions,eGameHostOption_FriendsOfFriends) && !(m_bMultiplayerAllowed && bGameSetting_Online)) + { + m_MoreOptionsParams.bAllowFriendsOfFriends = TRUE; + } + } + + m_GameName.SetText(m_XContentData.szDisplayName); + } + + // 4J-PB - Load up any texture pack data we have locally in the XZP + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.LoadLocalTMSFile(app.TMSFileA[i].wchFilename,app.TMSFileA[i].eEXT); + app.AddMemoryTPDFile(app.TMSFileA[i].iConfig, app.TMSFileA[i].pbData,app.TMSFileA[i].uiSize); + } + } + + int iRB=-1; + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1); + + //if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + } + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_LoadMenu, 0); + m_iTexturePacksNotInstalled=0; + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==true) + { + // not doing a mount, so enable input + m_bIgnoreInput=true; + } + else + { + m_bIgnoreInput = false; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); + + int texturePacksCount = pMinecraft->skins->getTexturePackCount(); + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + HRESULT hr; + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + ListInfo.fEnabled = TRUE; + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tp; + if(pDLCTexPack) + { + int id=pDLCTexPack->getDLCParentPackId(); + + if(id==0) + { + // default texture pack - should come first + ListInfo.iSortIndex=0x0FFFFFFF; + } + else + { + ListInfo.iSortIndex=id; + ListInfo.iData=id; + } + } +#ifdef _DEBUG + app.DebugPrintf("TP - "); + OutputDebugStringW(tp->getName().c_str()); + app.DebugPrintf(", sort index - %d\n",ListInfo.iSortIndex); +#endif + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + } + } + + m_currentTexturePackIndex = m_pTexturePacksList->GetIndexByUserData(m_MoreOptionsParams.dwTexturePack); + m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); + m_pTexturePacksList->SetTopItem(m_currentTexturePackIndex); // scroll the item into view if it's not visible + UpdateTexturePackDescription(m_currentTexturePackIndex); + + + // 4J-PB - there may be texture packs we don't have, so use the info from TMS for this + DLC_INFO *pDLCInfo=NULL; + + // first pass - look to see if there are any that are not in the list + bool bTexturePackAlreadyListed; + bool bNeedToGetTPD=false; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + // some missing + bNeedToGetTPD=true; + + m_iTexturePacksNotInstalled++; + } + } + + if(bNeedToGetTPD==true) + { + // add a TMS request for them + app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); + m_iConfigA= new int [m_iTexturePacksNotInstalled]; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; + } + } + } + } + + m_bSetup = true; + + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_LoadGameSettings::LaunchGame(void) +{ + // stop the timer running that causes a check for new texture packs in TMS but not installed, since this will run all through the load game, and will crash if it tries to create an hbrush + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + + if( (m_bGameModeSurvival != true || m_bHasBeenInCreative) || m_MoreOptionsParams.bHostPrivileges == TRUE) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + if(m_bGameModeSurvival != true || m_bHasBeenInCreative) + { + // 4J-PB - Need different text for Survival mode with a level that has been saved in Creative + if(m_bGameModeSurvival) + { + StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_SAVEDINCREATIVE, uiIDA, 2, m_iPad,&CScene_LoadGameSettings::ConfirmLoadReturned,this,app.GetStringTable()); + } + else // it's creative mode + { + // has it previously been saved in creative? + if(m_bHasBeenInCreative) + { + // 4J-PB - We don't really need to tell the user this will have achievements disabled, since they already saved it in creative + // and they got the warning then + // inform them that leaderboard writes and achievements will be disabled + //StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_SAVEDINCREATIVE_CONTINUE, uiIDA, 1, m_iPad,&CScene_LoadGameSettings::ConfirmLoadReturned,this,app.GetStringTable()); + + if(m_levelGen != NULL) + { + LoadLevelGen(m_levelGen); + } + else + { + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&m_XContentData,CScene_LoadGameSettings::LoadSaveDataReturned,this); + + if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved) + { + // disable saving + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(m_iPad,false); + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 1, m_iPad,&CScene_LoadGameSettings::DeviceRemovedDialogReturned,this); + + } + } + } + else + { + // ask if they're sure they want to turn this into a creative map + StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_CREATIVE, uiIDA, 2, m_iPad,&CScene_LoadGameSettings::ConfirmLoadReturned,this,app.GetStringTable()); + } + } + } + else + { + StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_HOST_PRIVILEGES, uiIDA, 2, m_iPad,&CScene_LoadGameSettings::ConfirmLoadReturned,this,app.GetStringTable()); + } + } + else + { + if(m_levelGen != NULL) + { + LoadLevelGen(m_levelGen); + } + else + { + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&m_XContentData,CScene_LoadGameSettings::LoadSaveDataReturned,this); + + if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved) + { + // disable saving + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(m_iPad,false); + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 1, m_iPad,&CScene_LoadGameSettings::DeviceRemovedDialogReturned,this); + } + } + } + return 0; +} + +int CScene_LoadGameSettings::CheckResetNetherReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + // continue and reset the nether + pClass->LaunchGame(); + } + else + { + // turn off the reset nether and continue + pClass->m_MoreOptionsParams.bResetNether=FALSE; + pClass->LaunchGame(); + } + return 0; +} + +HRESULT CScene_LoadGameSettings::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // 4J-PB - stop people double pressing this + if(m_bIgnoreInput) return S_OK; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_ButtonLoad) + { + // Check if we need to upsell the texture pack + if(m_MoreOptionsParams.dwTexturePack!=0) + { + // texture pack hasn't been set yet, so check what it will be + TexturePack *pTexturePack = pMinecraft->skins->getTexturePackById(m_MoreOptionsParams.dwTexturePack); + + if(pTexturePack==NULL) + { + // They've selected a texture pack they don't have yet + // upsell + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(m_currentTexturePackIndex); + + + // upsell the texture pack + + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + // 4J-PB - if the full offer id is 0, then the texture pack dlc load failed + if(ullOfferID_Full!=0LL) + { + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[3]; + + // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + uiIDA[2]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_LoadGameSettings::TexturePackDialogReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_LoadGameSettings::TexturePackDialogReturned,this,app.GetStringTable()); + } + + return S_OK; + } + } + } + + // if the profile data has been changed, then force a profile write (we save the online/invite/friends of friends settings) + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + // check the checkboxes + + // Only save the online setting if the user changed it - we may change it because we're offline, but don't want that saved + if(!m_MoreOptionsParams.bOnlineSettingChangedBySystem) + { + app.SetGameSettings(m_iPad,eGameSetting_Online,m_MoreOptionsParams.bOnlineGame?1:0); + } + app.SetGameSettings(m_iPad,eGameSetting_InviteOnly,m_MoreOptionsParams.bInviteOnly?1:0); + app.SetGameSettings(m_iPad,eGameSetting_FriendsOfFriends,m_MoreOptionsParams.bAllowFriendsOfFriends?1:0); + + app.CheckGameSettingsChanged(true,pNotifyPressData->UserIndex); + + SetShow( FALSE ); + m_bIgnoreInput = true; + + // Check that we have the rights to use a texture pack we have selected. + if(m_MoreOptionsParams.dwTexturePack!=0) + { + // texture pack hasn't been set yet, so check what it will be + TexturePack *pTexturePack = pMinecraft->skins->getTexturePackById(m_MoreOptionsParams.dwTexturePack); + + if(pTexturePack==NULL) + { + // DLC corrupt, so use the default textures + m_MoreOptionsParams.dwTexturePack=0; + } + else + { + m_pDLCPack=pTexturePack->getDLCPack(); + // do we have a license? + if(m_pDLCPack && !m_pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // no + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + if(!ProfileManager.IsSignedInLive(pNotifyPressData->UserIndex)) + { + // need to be signed in to live + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + return S_OK; + } + else + { + // upsell + + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(m_pDLCPack->getPurchaseOfferId()); + ULONGLONG ullOfferID_Full; + + if(pDLCInfo!=NULL) + { + ullOfferID_Full=pDLCInfo->ullOfferID_Full; + } + else + { + ullOfferID_Full=pTexturePack->getDLCPack()->getPurchaseOfferId(); + } + + // tell sentient about the upsell of the full version of the texture pack + TelemetryManager->RecordUpsellPresented(pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + //StorageManager.RequestMessageBox(IDS_UNLOCK_DLC_TITLE, IDS_UNLOCK_DLC_SKIN, uiIDA, 2, pInputData->UserIndex,&CScene_SkinSelect::UnlockSkinReturned,this,app.GetStringTable()); + StorageManager.RequestMessageBox(IDS_UNLOCK_DLC_TEXTUREPACK_TITLE, IDS_UNLOCK_DLC_TEXTUREPACK_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_LoadGameSettings::UnlockTexturePackReturned,this,app.GetStringTable()); + return S_OK; + } + } + } + } + + // Reset the background downloading, in case we changed it by attempting to download a texture pack + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + + // Check if they have the Reset Nether flag set, and confirm they want to do this + if(m_MoreOptionsParams.bResetNether==TRUE) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_DONT_RESET_NETHER; + uiIDA[1]=IDS_RESET_NETHER; + + StorageManager.RequestMessageBox(IDS_RESETNETHER_TITLE, IDS_RESETNETHER_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_LoadGameSettings::CheckResetNetherReturned,this,app.GetStringTable()); + } + else + { + LaunchGame(); + } + } + else if(hObjPressed==m_MoreOptions) + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_LaunchMoreOptionsMenu,&m_MoreOptionsParams); + } + else if(hObjPressed == m_ButtonGameMode) + { + if(m_bGameModeSurvival) + { + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_CREATIVE)); + m_bGameModeSurvival=false; + } + else + { + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); + m_bGameModeSurvival=true; + } + } + else if(hObjPressed == m_pTexturePacksList->m_hObj) + { + UpdateCurrentTexturePack(); + } + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + app.SetCorruptSaveDeleted(false); + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + case VK_PAD_RSHOULDER: +/* if(app.m_bTransferSavesToXboxOne && ProfileManager.IsFullVersion()) + { + app.NavigateToScene(m_iPad,eUIScene_TransferToXboxOne,m_params); + } + */ + break; + } + + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnFontRendererChange() +{ + int iRB=-1; + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1,-1,-1,-1,-1,-1,true); + + return S_OK; +} + +int CScene_LoadGameSettings::ConfirmLoadReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(pClass->m_levelGen != NULL) + { + pClass->LoadLevelGen(pClass->m_levelGen); + } + else + { + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&pClass->m_XContentData,CScene_LoadGameSettings::LoadSaveDataReturned,pClass); + + if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved) + { + // disable saving + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(pClass->m_iPad,false); + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 1, pClass->m_iPad,&CScene_LoadGameSettings::DeviceRemovedDialogReturned,pClass); + } + } + } + else + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + } + return 0; +} + +HRESULT CScene_LoadGameSettings::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly + switch(pTimer->nId) + { + case GAME_CREATE_ONLINE_TIMER_ID: + { + bool bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + + if(bMultiplayerAllowed != m_bMultiplayerAllowed) + { + if( bMultiplayerAllowed ) + { + bool bGameSetting_Online=(app.GetGameSettings(m_iPad,eGameSetting_Online)!=0); + m_MoreOptionsParams.bOnlineGame = bGameSetting_Online?TRUE:FALSE; + if(bGameSetting_Online) + { + m_MoreOptionsParams.bInviteOnly = (app.GetGameSettings(m_iPad,eGameSetting_InviteOnly)!=0)?TRUE:FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = (app.GetGameSettings(m_iPad,eGameSetting_FriendsOfFriends)!=0)?TRUE:FALSE; + } + else + { + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + } + else + { + m_MoreOptionsParams.bOnlineGame = FALSE; + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + + m_bMultiplayerAllowed = bMultiplayerAllowed; + } + } + break; + + case CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID: + { + // also check for any new texture packs info being available + // for each item in the mem list, check it's in the data list + + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + // for each iConfig, check if the data is available, and add it to the List, then remove it from the viConfig + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + DWORD dwBytes=0; + PBYTE pbData=NULL; + app.GetTPD(m_iConfigA[i],&pbData,&dwBytes); + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + if(dwBytes > 0 && pbData) + { + DWORD dwImageBytes=0; + PBYTE pbImageData=NULL; + + app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbImageData,&dwImageBytes ); + ListInfo.fEnabled = TRUE; + ListInfo.iData = m_iConfigA[i]; + HRESULT hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + + ListInfo.iSortIndex=m_iConfigA[i]; + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + + m_iConfigA[i]=-1; + + m_currentTexturePackIndex = m_pTexturePacksList->GetIndexByUserData(m_MoreOptionsParams.dwTexturePack); + m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); + m_pTexturePacksList->SetTopItem(m_currentTexturePackIndex); // scroll the item into view if it's not visible + } + } + } + bool bAllDone=true; + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + bAllDone = false; + } + } + + if(bAllDone ) + { + // kill this timer + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + } + } + break; + } + + return S_OK; +} + PBYTE pbData; + +int CScene_LoadGameSettings::Progress(void *pParam,float fProgress) +{ + app.DebugPrintf("Progress - %f\n",fProgress); + + return 0; +} + +int CScene_LoadGameSettings::LoadSaveDataReturned(void *pParam,bool bContinue) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + if(bContinue==true) + { + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(!isClientSide || connectedControllers == 1 || !RenderManager.IsHiDef()) + { + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && noUGC ) + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + DWORD dwLocalUsersMask = CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); + + // No guest problems so we don't need to force a sign-in of players here + StartGameFromSave(pClass, dwLocalUsersMask); + } + } + else + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_LoadGameSettings::StartGame_SignInReturned, pParam,ProfileManager.GetPrimaryPad()); + } + } + else + { + // the save is corrupt! + + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + + // give the option to delete the save + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE, IDS_CORRUPT_OR_DAMAGED_SAVE_TEXT, uiIDA, 2, + pClass->m_iPad,&CScene_LoadGameSettings::DeleteSaveDialogReturned,pClass, app.GetStringTable()); + + } + return 0; +} + +int CScene_LoadGameSettings::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { +#ifdef _XBOX + StorageManager.DeleteSaveData(&pClass->m_XContentData,CScene_LoadGameSettings::DeleteSaveDataReturned,pClass); +#endif + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} + +int CScene_LoadGameSettings::DeleteSaveDataReturned(void *pParam,bool bSuccess) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + app.SetCorruptSaveDeleted(true); + app.NavigateBack(pClass->m_iPad); + + return 0; +} + +int CScene_LoadGameSettings::DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // need to back out of this scene + app.NavigateBack(iPad); + + return 0; +} + +// 4J Stu - Shared functionality that is the same whether we needed a quadrant sign-in or not +void CScene_LoadGameSettings::StartGameFromSave(CScene_LoadGameSettings* pClass, DWORD dwLocalUsersMask) +{ + INT saveOrCheckpointId = 0; + bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); + TelemetryManager->RecordLevelResume(pClass->m_iPad, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, app.GetGameSettings(pClass->m_iPad,eGameSetting_Difficulty), app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount(), saveOrCheckpointId); + + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + bool isPrivate = (app.GetGameSettings(pClass->m_iPad,eGameSetting_InviteOnly)>0)?true:false; + + g_NetworkManager.HostGame(dwLocalUsersMask,isClientSide,isPrivate,MINECRAFT_NET_MAX_PLAYERS,0); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = 0; + param->saveData = NULL; + param->texturePackId = pClass->m_MoreOptionsParams.dwTexturePack; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->skins->selectTexturePackById(pClass->m_MoreOptionsParams.dwTexturePack); + //pMinecraft->skins->updateUI(); + + app.SetGameHostOption(eGameHostOption_Difficulty,Minecraft::GetInstance()->options->difficulty); + app.SetGameHostOption(eGameHostOption_FriendsOfFriends,app.GetGameSettings(pClass->m_iPad,eGameSetting_FriendsOfFriends)); + app.SetGameHostOption(eGameHostOption_Gamertags,app.GetGameSettings(pClass->m_iPad,eGameSetting_GamertagsVisible)); + + app.SetGameHostOption(eGameHostOption_BedrockFog,app.GetGameSettings(pClass->m_iPad,eGameSetting_BedrockFog)?1:0); + + app.SetGameHostOption(eGameHostOption_PvP,pClass->m_MoreOptionsParams.bPVP); + app.SetGameHostOption(eGameHostOption_TrustPlayers,pClass->m_MoreOptionsParams.bTrust ); + app.SetGameHostOption(eGameHostOption_FireSpreads,pClass->m_MoreOptionsParams.bFireSpreads ); + app.SetGameHostOption(eGameHostOption_TNT,pClass->m_MoreOptionsParams.bTNT ); + app.SetGameHostOption(eGameHostOption_HostCanFly,pClass->m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanChangeHunger,pClass->m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanBeInvisible,pClass->m_MoreOptionsParams.bHostPrivileges ); + + // flag if the user wants to reset the Nether to force a Fortress with netherwart etc. + app.SetResetNether((pClass->m_MoreOptionsParams.bResetNether==TRUE)?true:false); + // clear out the app's terrain features list + app.ClearTerrainFeaturePosition(); + + app.SetGameHostOption(eGameHostOption_GameType,pClass->m_bGameModeSurvival?GameType::SURVIVAL->getId():GameType::CREATIVE->getId()); + + param->settings = app.GetGameHostOption( eGameHostOption_All ); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + // Reset the autosave timer + app.SetAutosaveTimerTime(); + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + +int CScene_LoadGameSettings::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_LoadGameSettings* pClass = (CScene_LoadGameSettings*)pParam; + + if(bContinue==true) + { + // It's possible that the player has not signed in - they can back out + if(ProfileManager.IsSignedIn(iPad)) + { + DWORD dwLocalUsersMask = 0; + + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + bool noPrivileges = false; + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); + } + } + + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(), false, &pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && (noPrivileges || noUGC) ) + { + if( noUGC ) + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + //pClass->m_bAbortSearch=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + //pClass->m_bAbortSearch=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_HOST_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + } + else + { + StartGameFromSave(pClass, dwLocalUsersMask); + } + } + } + else + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + //pClass->m_bAbortSearch=false; + } + return 0; +} + + +HRESULT CScene_LoadGameSettings::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + if( pGetSourceImageData->bItemData ) + { + pGetSourceImageData->hBrush = m_hXuiBrush; + bHandled = TRUE; + } + return S_OK; +} + + +HRESULT CScene_LoadGameSettings::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderDifficulty.GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Difficulty,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[pNotifyValueChanged->nValue])); + m_SliderDifficulty.SetText(TempString); + } + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || + pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) + { + // 4J Stu - We may have had to unload our font renderer in this scene if one of the save files + // uses characters not in our font (eg asian chars) so restore our font renderer + // This will not do anything if our font renderer is already loaded + app.OverrideFontRenderer(true,true); + } + else if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + m_SliderDifficulty.SetValueDisplay(FALSE); + // 4J-PB - Need to check for installed DLC, which might have happened while you were on the More Options scene + if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + m_pTexturePacksList->RemoveAllData(); + } + } + } + + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || + pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) + { + } + else if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + if(m_bSetup && m_texturePackDescDisplayed) + { + XUITimeline *timeline; + XUINamedFrame *startFrame, *endFrame; + GetTimeline( &timeline ); + startFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + endFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + m_texturePackDescDisplayed = true; + } + } + + return S_OK; +} + +int CScene_LoadGameSettings::UnlockTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_LoadGameSettings* pScene = (CScene_LoadGameSettings*)pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedIn(iPad)) + { + ULONGLONG ullIndexA[1]; + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(pScene->m_pDLCPack->getPurchaseOfferId()); + + if(pDLCInfo!=NULL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Full; + } + else + { + ullIndexA[0]=pScene->m_pDLCPack->getPurchaseOfferId(); + } + + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + // the license change coming in when the offer has been installed will cause this scene to refresh + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Texture_DLC, ( pScene->m_pDLCPack->getPurchaseOfferId() & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined); + } + + pScene->m_bIgnoreInput = false; + pScene->SetShow( TRUE ); + + return 0; +} + +HRESULT CScene_LoadGameSettings::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if(hObjSource == m_pTexturePacksList->m_hObj) + { + UpdateTexturePackDescription(pNotifySelChangedData->iItem); + + if(m_bSetup && !m_texturePackDescDisplayed) + { + XUITimeline *timeline; + XUINamedFrame *startFrame, *endFrame; + GetTimeline( &timeline ); + startFrame = timeline->FindNamedFrame( L"SlideOut" ); + endFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + m_texturePackDescDisplayed = true; + } + } + + return S_OK; +} + +HRESULT CScene_LoadGameSettings::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + HXUIOBJ hSourceParent, hDestParent; + XuiElementGetParent(hObjSource,&hSourceParent); + XuiElementGetParent(pNotifyFocusData->hObjOther,&hDestParent); + if(hSourceParent != hDestParent && pNotifyFocusData->hObjOther != m_pTexturePacksList->m_hObj && hSourceParent == m_pTexturePacksList->m_hObj) + { + m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); + m_pTexturePacksList->SetTopItem(m_currentTexturePackIndex); // scroll the item into view if it's not visible + } + else if(!m_texturePackDescDisplayed && pNotifyFocusData->hObjOther == m_pTexturePacksList->m_hObj) + { + int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount(); + if(texturePacksCount == 1) + { + XUITimeline *timeline; + XUINamedFrame *startFrame, *endFrame; + GetTimeline( &timeline ); + startFrame = timeline->FindNamedFrame( L"SlideOut" ); + endFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + m_texturePackDescDisplayed = true; + } + } + + return S_OK; +} + +void CScene_LoadGameSettings::UpdateTexturePackDescription(int index) +{ + int iTexPackId=m_pTexturePacksList->GetData(index).iData; + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); + + if(tp==NULL) + { + // this is probably a texture pack icon added from TMS + DWORD dwBytes=0,dwFileBytes=0; + PBYTE pbData=NULL,pbFileData=NULL; + + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(index); + + app.GetTPD(ListItem.iData,&pbData,&dwBytes); + + app.GetFileFromTPD(eTPDFileType_Loc,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes > 0 && pbFileData) + { + StringTable *pStringTable = new StringTable(pbFileData, dwFileBytes); + m_texturePackTitle.SetText(pStringTable->getString(L"IDS_DISPLAY_NAME")); + m_texturePackDescription.SetText(pStringTable->getString(L"IDS_TP_DESCRIPTION")); + } + + app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes >= 0 && pbFileData) + { + XuiCreateTextureBrushFromMemory(pbFileData,dwFileBytes,&m_hTexturePackIconBrush); + m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); + } + app.GetFileFromTPD(eTPDFileType_Comparison,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes >= 0 && pbFileData) + { + XuiCreateTextureBrushFromMemory(pbFileData,dwFileBytes,&m_hTexturePackComparisonBrush); + m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); + } + else + { + m_texturePackComparison->UseBrush(NULL); + } + } + else + { + m_texturePackTitle.SetText(tp->getName().c_str()); + m_texturePackDescription.SetText(tp->getDesc1().c_str()); + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hTexturePackIconBrush); + m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); + } + else + { + m_texturePackIcon->UseBrush(NULL); + } + + pbImageData = tp->getPackComparison(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hTexturePackComparisonBrush); + m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); + } + else + { + m_texturePackComparison->UseBrush(NULL); + } + } +} + +void CScene_LoadGameSettings::ClearTexturePackDescription() +{ + m_texturePackTitle.SetText(L" "); + m_texturePackDescription.SetText(L" "); + m_texturePackComparison->UseBrush(NULL); + m_texturePackIcon->UseBrush(NULL); +} + +void CScene_LoadGameSettings::UpdateCurrentTexturePack() +{ + m_currentTexturePackIndex = m_pTexturePacksList->GetCurSel(); + int iTexPackId=m_pTexturePacksList->GetData(m_currentTexturePackIndex).iData; + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); + + // if the texture pack is null, you don't have it yet + if(tp==NULL) + { + // Upsell + + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(m_currentTexturePackIndex); + + + // upsell the texture pack + // tell sentient about the upsell of the full version of the skin pack + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[3]; + + // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + uiIDA[2]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_LoadGameSettings::TexturePackDialogReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_LoadGameSettings::TexturePackDialogReturned,this,app.GetStringTable()); + } + + // do set the texture pack id, and on the user pressing create world, check they have it + m_MoreOptionsParams.dwTexturePack = ListItem.iData; + + return ; + } + else + { + m_MoreOptionsParams.dwTexturePack = tp->getId(); + } +} + +HRESULT CScene_LoadGameSettings::OnDestroy() +{ + if( m_hXuiBrush ) + { + XuiDestroyBrush( m_hXuiBrush ); + } + + // clear out the texture pack data + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.RemoveMemoryTPDFile(app.TMSFileA[i].iConfig); + } + } + app.FreeLocalTMSFiles(eTMSFileType_TexturePack); + + return S_OK; +} + +void CScene_LoadGameSettings::LoadLevelGen(LevelGenerationOptions *levelGen) +{ + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && m_MoreOptionsParams.bOnlineGame; + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(!isClientSide || connectedControllers == 1 || !RenderManager.IsHiDef()) + { + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && noUGC ) + { + SetShow( TRUE ); + m_bIgnoreInput=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + return; + } + } + + DWORD dwLocalUsersMask = 0; + + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); + // Load data from disc + //File saveFile( L"Tutorial\\Tutorial" ); + //LoadSaveFromDisk(&saveFile); + + StorageManager.ResetSaveData(); + // Make our next save default to the name of the level + StorageManager.SetSaveTitle(levelGen->getDefaultSaveName().c_str()); + + bool isPrivate = (app.GetGameSettings(m_iPad,eGameSetting_InviteOnly)>0)?true:false; + + g_NetworkManager.HostGame(dwLocalUsersMask,isClientSide,isPrivate,MINECRAFT_NET_MAX_PLAYERS,0); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = 0; + param->saveData = NULL; + param->levelGen = levelGen; + + if(levelGen->requiresTexturePack()) + { + param->texturePackId = levelGen->getRequiredTexturePackId(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->skins->selectTexturePackById(param->texturePackId); + //pMinecraft->skins->updateUI(); + } + + + app.SetGameHostOption(eGameHostOption_Difficulty,Minecraft::GetInstance()->options->difficulty); + app.SetGameHostOption(eGameHostOption_FriendsOfFriends,app.GetGameSettings(m_iPad,eGameSetting_FriendsOfFriends)); + app.SetGameHostOption(eGameHostOption_Gamertags,app.GetGameSettings(m_iPad,eGameSetting_GamertagsVisible)); + + app.SetGameHostOption(eGameHostOption_BedrockFog,app.GetGameSettings(m_iPad,eGameSetting_BedrockFog)?1:0); + + // 4J-JEV: Fix for: + // TU12: Content: Gameplay: New "Mass Effect World" remembers and uses the settings of another - lately created - World. + app.SetGameHostOption(eGameHostOption_LevelType,m_MoreOptionsParams.bFlatWorld); + app.SetGameHostOption(eGameHostOption_Structures,m_MoreOptionsParams.bStructures); + app.SetGameHostOption(eGameHostOption_BonusChest,m_MoreOptionsParams.bBonusChest); + + app.SetGameHostOption(eGameHostOption_PvP,m_MoreOptionsParams.bPVP); + app.SetGameHostOption(eGameHostOption_TrustPlayers,m_MoreOptionsParams.bTrust ); + app.SetGameHostOption(eGameHostOption_FireSpreads,m_MoreOptionsParams.bFireSpreads ); + app.SetGameHostOption(eGameHostOption_TNT,m_MoreOptionsParams.bTNT ); + app.SetGameHostOption(eGameHostOption_HostCanFly,m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanChangeHunger,m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanBeInvisible,m_MoreOptionsParams.bHostPrivileges ); + + // flag if the user wants to reset the Nether to force a Fortress with netherwart etc. + app.SetResetNether((m_MoreOptionsParams.bResetNether==TRUE)?true:false); + // clear out the app's terrain features list + app.ClearTerrainFeaturePosition(); + + app.SetGameHostOption(eGameHostOption_GameType,m_bGameModeSurvival?GameType::SURVIVAL->getId():GameType::CREATIVE->getId()); + + param->settings = app.GetGameHostOption( eGameHostOption_All ); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + // Reset the autosave timer + app.SetAutosaveTimerTime(); + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + + +HRESULT CScene_LoadGameSettings::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + // clear out the texture pack list and do again + m_pTexturePacksList->RemoveAllData(); + m_iTexturePacksNotInstalled=0; + + } + + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + + +HRESULT CScene_LoadGameSettings::OnCustomMessage_DLCMountingComplete() +{ + m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); + Minecraft *pMinecraft = Minecraft::GetInstance(); + int texturePacksCount = pMinecraft->skins->getTexturePackCount(); + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + HRESULT hr; + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + ListInfo.fEnabled = TRUE; + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tp; + if(pDLCTexPack) + { + int id=pDLCTexPack->getDLCParentPackId(); + + if(id==0) + { + // default texture pack - should come first + ListInfo.iSortIndex=0x0FFFFFFF; + } + else + { + ListInfo.iSortIndex=id; + ListInfo.iData=id; + } + } + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + } + } + m_currentTexturePackIndex = m_pTexturePacksList->GetIndexByUserData(m_MoreOptionsParams.dwTexturePack); + m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); + m_pTexturePacksList->SetTopItem(m_currentTexturePackIndex); // scroll the item into view if it's not visible + + m_iTexturePacksNotInstalled=0; + + // 4J-PB - there may be texture packs we don't have, so use the info from TMS for this + DLC_INFO *pDLCInfo=NULL; + + // first pass - look to see if there are any that are not in the list + bool bTexturePackAlreadyListed; + bool bNeedToGetTPD=false; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + // some missing + bNeedToGetTPD=true; + + m_iTexturePacksNotInstalled++; + } + } + + if(bNeedToGetTPD==true) + { + // add a TMS request for them + app.DebugPrintf("+++ Adding TMSPP request for texture pack data\n"); + app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); + if(m_iConfigA!=NULL) + { + delete m_iConfigA; + } + m_iConfigA= new int [m_iTexturePacksNotInstalled]; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; + } + } + } + + UpdateTexturePackDescription(m_currentTexturePackIndex); + + m_bIgnoreInput=false; + app.m_dlcManager.checkForCorruptDLCAndAlert(); + return S_OK; +} + +int CScene_LoadGameSettings::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_LoadGameSettings *pClass = (CScene_LoadGameSettings *)pParam; +#ifdef _XBOX + pClass->m_currentTexturePackIndex = pClass->m_pTexturePacksList->GetCurSel(); + // Exit with or without saving + // Decline means install full version of the texture pack in this dialog + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultAccept) + { + // we need to enable background downloading for the DLC + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + ULONGLONG ullOfferID_Full; + ULONGLONG ullIndexA[1]; + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=pClass->m_pTexturePacksList->GetData(pClass->m_currentTexturePackIndex); + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + if( result==C4JStorage::EMessage_ResultAccept ) // Full version + { + ullIndexA[0]=ullOfferID_Full; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + } + else // trial version + { + // if there is no trial version, this is a Cancel + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Trial; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + } +#endif + pClass->m_bIgnoreInput=false; + return 0; +} + +HRESULT CScene_LoadGameSettings::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + // update the tooltips + int iRB=-1; +#ifdef _XBOX + +#endif + CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1,-1,-1,-1,iRB); + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_LoadSettings.h b/Minecraft.Client/Common/XUI/XUI_LoadSettings.h new file mode 100644 index 00000000..61e934b7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_LoadSettings.h @@ -0,0 +1,154 @@ +#pragma once +#include "../media/xuiscene_load_settings.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_CustomMessages.h" +#include "XUI_MultiGameLaunchMoreOptions.h" + +class CScene_LoadGameSettings : public CXuiSceneImpl +{ +public: + typedef struct + { + unsigned int uiLen; + unsigned int uiCode; + } + PNG_CHUNK; +protected: + // Control and Element wrapper objects. + CXuiScene m_MainScene; + CXuiScene m_TexturePackDetails; + CXuiControl m_GameName; + CXuiControl m_GameSeed; + CXuiControl m_GameCreatedMode; + CXuiControl m_ButtonLoad; + CXuiControl m_ButtonGameMode; + CXuiControl m_MoreOptions; + CXuiCtrl4JIcon m_GameIcon; + CXuiCtrlSliderWrapper m_SliderDifficulty; + CXuiCtrl4JList *m_pTexturePacksList; + CXuiControl m_texturePackTitle, m_texturePackDescription; + CXuiCtrl4JIcon *m_texturePackIcon, *m_texturePackComparison; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_TRANSITION_END(OnTransitionEnd) + XUI_ON_XM_FONTRENDERERCHANGE_MESSAGE(OnFontRendererChange) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_NOTIFY_KILL_FOCUS( OnNotifyKillFocus ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_MainScene, m_MainScene) + BEGIN_MAP_CHILD_CONTROLS(m_MainScene) + MAP_CONTROL(IDC_XuiLoadSettings, m_ButtonLoad) + MAP_CONTROL(IDC_XuiGameModeToggle, m_ButtonGameMode) + MAP_CONTROL(IDC_XuiMoreOptions, m_MoreOptions) + MAP_CONTROL(IDC_XuiGameIcon, m_GameIcon); + MAP_CONTROL(IDC_XuiGameName, m_GameName) + MAP_CONTROL(IDC_XuiGameSeed, m_GameSeed) + MAP_CONTROL(IDC_XuiCreatedMode, m_GameCreatedMode) + MAP_CONTROL(IDC_XuiSliderDifficulty, m_SliderDifficulty) + MAP_OVERRIDE(IDC_TexturePacksList, m_pTexturePacksList) + //MAP_CONTROL(IDC_XuiGameMode, m_GameMode) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TexturePackDetails, m_TexturePackDetails) + BEGIN_MAP_CHILD_CONTROLS(m_TexturePackDetails) + MAP_CONTROL(IDC_TexturePackName, m_texturePackTitle) + MAP_CONTROL(IDC_TexturePackDescription, m_texturePackDescription) + MAP_OVERRIDE(IDC_Icon, m_texturePackIcon) + MAP_OVERRIDE(IDC_ComparisonPic, m_texturePackComparison) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnFontRendererChange(); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnDestroy(); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + + + static int LoadSaveDataReturned(void *pParam,bool bContinue); + static int LoadSaveDataForNameChangeReturned(void *pParam,bool bContinue); + static int DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static void StartGameFromSave(CScene_LoadGameSettings* pClass, DWORD dwLocalUsersMask); + static int StartGame_SignInReturned(void *pParam,bool bContinue, int iPad); + static int DeviceSelectReturned(void *pParam,bool bContinue); + static int ConfirmLoadReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int DeleteSaveDataReturned(void *pParam,bool bSuccess); + static int CheckResetNetherReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + static int Progress(void *pParam,float fProgress); + + void LoadLevelGen(LevelGenerationOptions *levelGen); + + HRESULT LaunchGame(void); +public: + static unsigned char szPNG[8]; + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_LoadGameSettings, L"CScene_LoadGameSettings", XUI_CLASS_SCENE ) + +private: + static int UnlockTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + void UpdateTexturePackDescription(int index); + void ClearTexturePackDescription(); + void UpdateCurrentTexturePack(); + + bool m_bIgnoreInput; + HXUIBRUSH m_hXuiBrush; + HXUIBRUSH m_hTexturePackIconBrush; + HXUIBRUSH m_hTexturePackComparisonBrush; + + int m_iPad; + int m_iSaveGameInfoIndex; + bool m_bMultiplayerAllowed; + static int m_iDifficultyTitleSettingA[4]; + int m_CurrentDifficulty; + bool m_bHasBeenInCreative; + bool m_bSetup; + bool m_texturePackDescDisplayed; + + DWORD m_dwSaveFileC; +#ifdef _XBOX + C4JStorage::CACHEINFOSTRUCT *m_InfoA; +#endif + unsigned char m_szSeed[50]; + XCONTENT_DATA m_XContentData; + LaunchMoreOptionsMenuInitData m_MoreOptionsParams; + bool m_bGameModeSurvival; + unsigned int m_currentTexturePackIndex; + DLCPack * m_pDLCPack; + LevelGenerationOptions *m_levelGen; + + int m_iTexturePacksNotInstalled; + int *m_iConfigA; // track the texture packs that we don't have installed + LoadMenuInitData *m_params; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MainMenu.cpp b/Minecraft.Client/Common/XUI/XUI_MainMenu.cpp new file mode 100644 index 00000000..7b9c1a56 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MainMenu.cpp @@ -0,0 +1,1288 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_MainMenu.h" +#include "..\..\..\Minecraft.Client\SurvivalMode.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" +#include "..\..\LocalPlayer.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\User.h" +//#include "XUI_CreateLoad.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Random.h" +#include "..\..\MinecraftServer.h" +#include "..\..\Minecraft.h" +#include "..\..\Options.h" +#include "..\..\Font.h" +#include "..\..\Common\GameRules\ConsoleGameRules.h" + +#define DLC_INSTALLED_TIMER_ID 1 +#define DLC_INSTALLED_TIMER_TIME 100 +#define TMS_TIMER_ID 2 +#define TMS_TIMER_TIME 100 +Random *CScene_Main::random = new Random(); + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Main::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_Buttons[BUTTON_PLAYGAME],app.GetString(IDS_PLAY_GAME)); + XuiControlSetText(m_Buttons[BUTTON_LEADERBOARDS],app.GetString(IDS_LEADERBOARDS)); + XuiControlSetText(m_Buttons[BUTTON_ACHIEVEMENTS],app.GetString(IDS_ACHIEVEMENTS)); + XuiControlSetText(m_Buttons[BUTTON_HELPANDOPTIONS],app.GetString(IDS_HELP_AND_OPTIONS)); + XuiControlSetText(m_Buttons[BUTTON_UNLOCKFULLGAME],app.GetString(IDS_UNLOCK_FULL_GAME)); + XuiControlSetText(m_Buttons[BUTTON_EXITGAME],app.GetString(IDS_EXIT_GAME)); + + m_Timer.SetShow(FALSE); + m_eAction=eAction_None; + + // Display the tooltips + HRESULT hr = S_OK; + ui.SetTooltips(DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT); + + // can't set presence until someone is signed in and playing + + // Need to check which menu items to display + + // Are we the trial version? + // store the exitgame position + m_Buttons[BUTTON_EXITGAME].GetPosition(&m_vPosExitGame); + + if(ProfileManager.IsFullVersion()) + { + // Replace the Unlock Full Game with Downloadable Content + m_Buttons[BUTTON_UNLOCKFULLGAME].SetText(app.GetString(IDS_DOWNLOADABLECONTENT)); + XuiElementSetShow(m_Buttons[BUTTON_UNLOCKFULLGAME],TRUE); + } + + // Do we have downloadable content? - We need to have this in for a Pre-Cert test, whether or not we have DLC at the time. + + + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + // load from the .xzp file + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + swprintf(szResourceLocator, LOCATOR_SIZE ,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/splashes.txt"); + + BYTE *splashesData; + UINT splashesSize; + hr = XuiResourceLoadAllNoLoc(szResourceLocator, &splashesData, &splashesSize); + + if( HRESULT_SUCCEEDED( hr ) ) + { + //BufferedReader *br = new BufferedReader(new InputStreamReader(InputStream::getResourceAsStream(L"res\\title\\splashes.txt"))); //, Charset.forName("UTF-8") + byteArray splashesArray(splashesSize); + memcpy(splashesArray.data, splashesData, splashesSize); + ByteArrayInputStream *bais= new ByteArrayInputStream(splashesArray); + InputStreamReader *isr = new InputStreamReader( bais ); + BufferedReader *br = new BufferedReader( isr ); + + wstring line = L""; + while ( !(line = br->readLine()).empty() ) + { + line = trimString( line ); + if (line.length() > 0) + { + m_splashes.push_back(line); + } + } + + XuiFree(splashesData); // Frees copy returned from XuiResourceLoadAllNoLoc + + br->close(); + delete br; + delete isr; + delete bais; // Frees copy made in splashesArray + } + + XuiElementGetBounds(m_Subtitle,&m_fSubtitleWidth, &m_fSubtitleHeight); + +#if 1 + XuiElementSetShow(m_Subtitle, FALSE); + XuiElementSetShow(m_SubtitleMCFont, TRUE); +#else + XuiElementSetShow(m_Subtitle, TRUE); + XuiElementSetShow(m_SubtitleMCFont, FALSE); +#endif + + m_bIgnorePress=false; + + // 4J Stu - Clear out any loaded game rules + app.setLevelGenerationOptions(NULL); + + // Fix for #45154 - Frontend: DLC: Content can only be downloaded from the frontend if you have not joined/exited multiplayer + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + return S_OK; +} + +HRESULT CScene_Main::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + // If we sign out when in the saves list, we get a notifysetfocus in the saves list after the init of the main menu + ui.SetTooltips(DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT); + + return S_OK; +} + + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Main::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // should we ignore the button press? This will be set if we're waiting for a callback from a function launched from a button press + if(m_bIgnorePress) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + //Minecraft *pMinecraft=Minecraft::GetInstance(); + + while((uiButtonCounter<BUTTONS_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + ProfileManager.SetPrimaryPad(pNotifyPressData->UserIndex); + ProfileManager.SetLockedProfile(-1); + + // Determine which button was pressed, + // and call the appropriate function. + switch(uiButtonCounter) + { + case BUTTON_PLAYGAME: + // Move to the new/load game screen + // need a signed in user here + + ProfileManager.SetCurrentGameActivity(pNotifyPressData->UserIndex,CONTEXT_PRESENCE_MENUS,true); + + m_eAction=eAction_RunGame; + if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex)) + { + RunPlayGame(pNotifyPressData->UserIndex); + } + else + { + // get them to sign in + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable()); + } + + break; + + case BUTTON_LEADERBOARDS: + m_eAction=eAction_RunLeaderboards; + if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex)) + { + RunLeaderboards(pNotifyPressData->UserIndex); + } + else + { + // get them to sign in + //ProfileManager.RequestSignInUI(false, false, true,false,true, &CScene_Main::Leaderboards_SignInReturned, this); + // get them to sign in + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable()); + + } + break; + case BUTTON_ACHIEVEMENTS: + m_eAction=eAction_RunAchievements; + if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex)) + { + RunAchievements(pNotifyPressData->UserIndex); + } + else + { + // get them to sign in + //ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::Achievements_SignInReturned,this ); + // get them to sign in + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable()); + + } + + break; + case BUTTON_HELPANDOPTIONS: + // need a signed in user here, so we have a profile to write to + ProfileManager.SetLockedProfile(pNotifyPressData->UserIndex); + + m_eAction=eAction_RunHelpAndOptions; + if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex)) + { + RunHelpAndOptions(pNotifyPressData->UserIndex); + } + else + { + // get them to sign in + //ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::HelpAndOptions_SignInReturned,this ); + // get them to sign in + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable()); + + } + break; + // case BUTTON_RETURNTOARCADE: + // break; + case BUTTON_UNLOCKFULLGAME: + { + // need a signed in user here + ProfileManager.SetLockedProfile(pNotifyPressData->UserIndex); + + m_eAction=eAction_RunUnlockOrDLC; + if(ProfileManager.IsSignedIn(pNotifyPressData->UserIndex)) + { + RunUnlockOrDLC(pNotifyPressData->UserIndex); + } + else + { + // get them to sign in + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + StorageManager.RequestMessageBox(IDS_MUST_SIGN_IN_TITLE, IDS_MUST_SIGN_IN_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_Main::MustSignInReturned,this, app.GetStringTable()); + } + } + break; + case BUTTON_EXITGAME: + if( ProfileManager.IsFullVersion() ) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CANCEL; + uiIDA[1]=IDS_OK; + StorageManager.RequestMessageBox(IDS_WARNING_ARCADE_TITLE, IDS_WARNING_ARCADE_TEXT, uiIDA, 2, XUSER_INDEX_ANY,&CScene_Main::ExitGameReturned,this); + } + else + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_TrialExitUpsell); + } + break; + + default: + break; + } + + + + return S_OK; +} + +HRESULT CScene_Main::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT); + CXuiSceneBase::ShowLogo(DEFAULT_XUI_MENU_USER,TRUE); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + // unlock the locked profile - anyone can navigate the main menu + ProfileManager.SetLockedProfile(-1); + + // incase the debug trial version has been set + // Are we the trial version? + + m_Buttons[BUTTON_EXITGAME].GetPosition(&m_vPosExitGame); + + for(int i=0;i<BUTTONS_MAX;i++) + { + m_Buttons[i].SetShow(TRUE); + } + + + if(ProfileManager.IsFullVersion()) + { + // Replace the Unlock Full Game with Downloadable Content + m_Buttons[BUTTON_UNLOCKFULLGAME].SetText(app.GetString(IDS_DOWNLOADABLECONTENT)); + XuiElementSetShow(m_Buttons[BUTTON_UNLOCKFULLGAME],TRUE); + } + + // Fix for #45154 - Frontend: DLC: Content can only be downloaded from the frontend if you have not joined/exited multiplayer + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + m_bIgnorePress=false; + m_Timer.SetShow(FALSE); + + return S_OK; +} + +HRESULT CScene_Main::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - remove the "hobo humping" message legal (Sony) say we can't have - pretty sure Microsoft would say the same if they noticed it. + int splashIndex = eSplashRandomStart + 1 + random->nextInt( (int)m_splashes.size() - (eSplashRandomStart + 1) ); + + // Override splash text on certain dates + SYSTEMTIME LocalSysTime; + GetLocalTime( &LocalSysTime ); + if (LocalSysTime.wMonth == 11 && LocalSysTime.wDay == 9) + { + splashIndex = eSplashHappyBirthdayEx; + } + else if (LocalSysTime.wMonth == 6 && LocalSysTime.wDay == 1) + { + splashIndex = eSplashHappyBirthdayNotch; + } + else if (LocalSysTime.wMonth == 12 && LocalSysTime.wDay == 24) // the Java game shows this on Christmas Eve, so we will too + { + splashIndex = eSplashMerryXmas; + } + else if (LocalSysTime.wMonth == 1 && LocalSysTime.wDay == 1) + { + splashIndex = eSplashHappyNewYear; + } + //splashIndex = 47; // Very short string + //splashIndex = 197; // Very long string + //splashIndex = 296; // Coloured + //splashIndex = 297; // Noise + wstring splash = m_splashes.at( splashIndex ); + m_Subtitle.SetText(splash.c_str()); + m_SubtitleMCFont.SetText(splash.c_str()); + +#ifndef OVERRIDE_XUI_FONT_RENDERER + XUIRect xuiRect; + HRESULT hr=S_OK; + float fWidth,fHeight; + + HXUIOBJ visual=NULL; + HXUIOBJ pulser, subtitle, text; + hr=XuiControlGetVisual(m_Subtitle.m_hObj,&visual); + hr=XuiElementGetChildById(visual,L"Pulser",&pulser); + hr=XuiElementGetChildById(pulser,L"SubTitle",&subtitle); + hr=XuiElementGetChildById(subtitle,L"Text_String",&text); + + memset(&xuiRect, 0, sizeof(xuiRect)); + // Start with a base size + XuiElementSetBounds(m_Subtitle,m_fSubtitleWidth, m_fSubtitleHeight); + hr=XuiTextPresenterMeasureText(text, splash.c_str(), &xuiRect); + XuiElementGetBounds(text,&fWidth, &fHeight); + + float diff = fWidth / (xuiRect.right+5); + + diff = min(diff,MAIN_MENU_MAX_TEXT_SCALE); + + // Resize + XuiElementGetBounds(m_Subtitle,&fWidth, &fHeight); + XuiElementSetBounds(m_Subtitle,fWidth/diff, fHeight); + + // Scale + D3DXVECTOR3 vScale(diff,diff,0); + XuiElementSetScale(m_Subtitle,&vScale); + + //Adjust pivot for animation + D3DXVECTOR3 vPivot; + XuiElementGetPivot(subtitle,&vPivot); + vPivot.x = vPivot.x + ( ( (fWidth/diff) - fWidth) / 2 ); + XuiElementSetPivot(subtitle,&vPivot); + + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fTextVisualLen; + float fMaxButton; + + hr=XuiControlGetVisual(m_Buttons[0].m_hObj,&visual); + hr=XuiElementGetChildById(visual,L"text_Label",&text); + hr=XuiElementGetBounds(text,&fTextVisualLen,&fHeight); + m_Buttons[0].GetBounds(&fMaxButton,&fHeight); + + + for(int i=0;i<BUTTONS_MAX;i++) + { + hr=XuiTextPresenterMeasureText(text, m_Buttons[i].GetText(), &xuiRect); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + } + + if(fTextVisualLen<fMaxTextLen) + { + D3DXVECTOR3 vec; + + // centre is vec.x+(fWidth/2) + for(int i=0;i<BUTTONS_MAX;i++) + { + // need to resize and reposition the buttons + m_Buttons[i].GetPosition(&vec); + m_Buttons[i].GetBounds(&fWidth,&fHeight); + vec.x= vec.x+(fWidth/2.0f)-(fMaxTextLen/2.0f); + + m_Buttons[i].SetPosition(&vec); + m_Buttons[i].SetBounds(fMaxButton+fMaxTextLen-fTextVisualLen,fHeight); + } + } +#endif + } + + return S_OK; +} + +HRESULT CScene_Main::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ +#ifdef _MINECON + // added so we can skip greyed out items for Minecon + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } +#endif + return S_OK; +} + +HRESULT CScene_Main::OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Don't set handled to true. + + return S_OK; +} + +///////////////////////////////////////////////////////////// + +int CScene_Main::SignInReturned(void *pParam,bool bContinue) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,pClass); + } + + + return 0; +} + +int CScene_Main::DeviceSelectReturned(void *pParam,bool bContinue) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + //HRESULT hr; + + if(bContinue==true) + { + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + // ensure we've applied this player's settings + app.ApplyGameSettingsChanged(ProfileManager.GetPrimaryPad()); + // check for DLC + // start timer to track DLC check finished + pClass->m_Timer.SetShow(TRUE); + XuiSetTimer(pClass->m_hObj,DLC_INSTALLED_TIMER_ID,DLC_INSTALLED_TIMER_TIME); + + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MultiGameJoinLoad); + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + ProfileManager.SetPrimaryPad(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + } + + return 0; +} + +int CScene_Main::CreateLoad_OfflineProfileReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + // accepted offline profiles, so go on to select a device + ProfileManager.SetLockedProfile(ProfileManager.GetPrimaryPad()); + + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + if(ProfileManager.IsFullVersion()) + { + if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,pClass)) + { + // save device already selected + // ensure we've applied this player's settings + app.ApplyGameSettingsChanged(ProfileManager.GetPrimaryPad()); + + // check for DLC + // start timer to track DLC check finished + pClass->m_Timer.SetShow(TRUE); + XuiSetTimer(pClass->m_hObj,DLC_INSTALLED_TIMER_ID,DLC_INSTALLED_TIMER_TIME); + + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MultiGameJoinLoad); + } + } + else + { + // 4J-PB - if this is the trial game, we can't have any networking + // Can't apply the player's settings here - they haven't come back from the QuerySignInStatud call above yet. + // Need to let them action in the main loop when they come in + // ensure we've applied this player's settings + //app.ApplyGameSettingsChanged(iPad); + // go straight in to the trial level + LoadTrial(); + } + } + else + { + // force a sign-in - they were offline, and they want to be online, so don't let it display offline players + // set the bAddUser to false to allow offline to go online by selecting the already signed in player again + ProfileManager.RequestSignInUI(false, false, true,false,false,&CScene_Main::CreateLoad_SignInReturned,pClass, ProfileManager.GetPrimaryPad() ); + } + + return 0; +} + +int CScene_Main::CreateLoad_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + if(ProfileManager.IsGuest(ProfileManager.GetPrimaryPad())) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + ProfileManager.SetLockedProfile(ProfileManager.GetPrimaryPad()); + + + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + if(ProfileManager.IsFullVersion()) + { + // Check if we're signed in to LIVE + if(ProfileManager.IsSignedInLive(iPad)) + { + // 4J-PB - Need to check for installed DLC + if(!app.DLCInstallProcessCompleted()) app.StartInstallDLCProcess(iPad); + + if(ProfileManager.IsGuest(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + // check if all the TMS files are loaded + if(app.GetTMSDLCInfoRead() && app.GetTMSXUIDsFileRead() && app.GetBanListRead(iPad)) + { + if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,pClass)==true) + { + // save device already selected + + // ensure we've applied this player's settings + app.ApplyGameSettingsChanged(ProfileManager.GetPrimaryPad()); + // check for DLC + // start timer to track DLC check finished + pClass->m_Timer.SetShow(TRUE); + XuiSetTimer(pClass->m_hObj,DLC_INSTALLED_TIMER_ID,DLC_INSTALLED_TIMER_TIME); + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MultiGameJoinLoad); + } + } + else + { + // Changing to async TMS calls + app.SetTMSAction(iPad,eTMSAction_TMSPP_RetrieveFiles_RunPlayGame); + + // block all input + pClass->m_bIgnorePress=true; + // We want to hide everything in this scene and display a timer until we get a completion for the TMS files + for(int i=0;i<BUTTONS_MAX;i++) + { + pClass->m_Buttons[i].SetShow(FALSE); + } + + // turn off tooltips + ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1); + + pClass->m_Timer.SetShow(TRUE); + } + } + } + else + { + // offline + ProfileManager.DisplayOfflineProfile(&CScene_Main::CreateLoad_OfflineProfileReturned,pClass, ProfileManager.GetPrimaryPad() ); + } + } + else + { + // 4J-PB - if this is the trial game, we can't have any networking + // Can't apply the player's settings here - they haven't come back from the QuerySignInStatud call above yet. + // Need to let them action in the main loop when they come in + // ensure we've applied this player's settings + //app.ApplyGameSettingsChanged(iPad); + + // go straight in to the trial level + LoadTrial(); + } + } + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + + } + return 0; +} + +int CScene_Main::MustSignInReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + // we need to specify local game here to display local and LIVE profiles in the list + switch(pClass->m_eAction) + { + case eAction_RunGame: + ProfileManager.RequestSignInUI(false, true, false,false,true,&CScene_Main::CreateLoad_SignInReturned,pClass ,iPad); + break; + case eAction_RunLeaderboards: + ProfileManager.RequestSignInUI(false, false, true,false,true, &CScene_Main::Leaderboards_SignInReturned, pClass,iPad); + break; + case eAction_RunAchievements: + ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::Achievements_SignInReturned,pClass,iPad ); + break; + case eAction_RunHelpAndOptions: + ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::HelpAndOptions_SignInReturned,pClass,iPad ); + break; + case eAction_RunUnlockOrDLC: + ProfileManager.RequestSignInUI(false, false, true,false,true,&CScene_Main::UnlockFullGame_SignInReturned,pClass,iPad ); + break; + + } + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + } + + return 0; +} + + + + +int CScene_Main::AchievementsDeviceSelectReturned(void *pParam,bool bContinue) +{ + //CScene_Main* pClass = (CScene_Main*)pParam; + //HRESULT hr; + + if(bContinue==true) + { + XShowAchievementsUI( ProfileManager.GetLockedProfile() ); + } + + return 0; +} + + +int CScene_Main::Leaderboards_SignInReturned(void *pParam,bool bContinue,int iPad) +{ + //CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + // guests can't look at leaderboards + if(ProfileManager.IsGuest(ProfileManager.GetPrimaryPad())) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else if(!ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) + { + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + else + { + ProfileManager.SetLockedProfile(ProfileManager.GetPrimaryPad()); + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LeaderboardsMenu); + } + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + + } + return 0; +} + +int CScene_Main::Achievements_SignInReturned(void *pParam,bool bContinue,int iPad) +{ + //CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + XShowAchievementsUI( ProfileManager.GetPrimaryPad() ); + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + + } + return 0; +} +int CScene_Main::HelpAndOptions_SignInReturned(void *pParam,bool bContinue,int iPad) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + // 4J-PB - You can be offline and still can go into help and options + if(app.GetTMSDLCInfoRead() || !ProfileManager.IsSignedInLive(iPad)) + { + app.NavigateToScene(iPad,eUIScene_HelpAndOptionsMenu); + } + else + { + // Changing to async TMS calls + app.SetTMSAction(iPad,eTMSAction_TMSPP_RetrieveFiles_HelpAndOptions); + + // block all input + pClass->m_bIgnorePress=true; + // We want to hide everything in this scene and display a timer until we get a completion for the TMS files + for(int i=0;i<BUTTONS_MAX;i++) + { + pClass->m_Buttons[i].SetShow(FALSE); + } + + // turn off tooltips + ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1); + + pClass->m_Timer.SetShow(TRUE); + } + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + } + + return 0; +} + +int CScene_Main::UnlockFullGame_SignInReturned(void *pParam,bool bContinue,int iPad) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + if(bContinue==true) + { + pClass->RunUnlockOrDLC(iPad); + } + else + { + // unlock the profile + ProfileManager.SetLockedProfile(-1); + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + // if the user is valid, we should set the presence + if(ProfileManager.IsSignedIn(i)) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MENUS,false); + } + } + + } + + + + return 0; +} +int CScene_Main::SaveGameReturned(void *pParam,bool bContinue) +{ + //CScene_Main* pClass = (CScene_Main*)pParam; + + // display a saving complete message + ProfileManager.SetLockedProfile(-1); + return 0; +} + +int CScene_Main::ExitGameReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CScene_Main* pClass = (CScene_Main*)pParam; + + // buttons reversed on this + if(result==C4JStorage::EMessage_ResultDecline) + { + //XLaunchNewImage(XLAUNCH_KEYWORD_DASH_ARCADE, 0); + app.ExitGame(); + } + + return 0; +} + +void CScene_Main::LoadTrial(void) +{ + app.SetTutorialMode( true ); + + // clear out the app's terrain features list + app.ClearTerrainFeaturePosition(); + + StorageManager.ResetSaveData(); + + // Need to set the mode as trial + ProfileManager.StartTrialGame(); + + // No saving in the trial + StorageManager.SetSaveDisabled(true); + + StorageManager.SetSaveTitle(L"Tutorial"); + + // Reset the autosave time + app.SetAutosaveTimerTime(); + + // not online for the trial game + g_NetworkManager.HostGame(0,false,true,MINECRAFT_NET_MAX_PLAYERS,0); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = 0; + param->saveData = NULL; + param->settings = app.GetGameHostOption( eGameHostOption_Tutorial ); + + vector<LevelGenerationOptions *> *generators = app.getLevelGenerators(); + param->levelGen = generators->at(0); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = ProfileManager.GetPrimaryPad(); + loadingParams->completionData = completionData; + + CXuiSceneBase::ShowTrialTimer(TRUE); + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + + + +void CScene_Main::RunPlayGame(int iPad) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + app.ReleaseSaveThumbnail(); + + if(ProfileManager.IsGuest(iPad)) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + ProfileManager.SetLockedProfile(iPad); + + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + // 4J-PB - Need to check for installed DLC + if(!app.DLCInstallProcessCompleted()) app.StartInstallDLCProcess(iPad); + + if(ProfileManager.IsFullVersion()) + { + // are we offline? + if(!ProfileManager.IsSignedInLive(iPad)) + { + + ProfileManager.DisplayOfflineProfile(&CScene_Main::CreateLoad_OfflineProfileReturned,this,iPad ); + } + else + { + // Check if there is any new DLC + app.ClearNewDLCAvailable(); + StorageManager.GetAvailableDLCCount(iPad); + + // check if all the TMS files are loaded + if(app.GetTMSDLCInfoRead() && app.GetTMSXUIDsFileRead() && app.GetBanListRead(iPad)) + { + if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,this)==true) + { + // change the minecraft player name + pMinecraft->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + // save device already selected + + // ensure we've applied this player's settings + app.ApplyGameSettingsChanged(iPad); + // check for DLC + // start timer to track DLC check finished + m_Timer.SetShow(TRUE); + XuiSetTimer(m_hObj,DLC_INSTALLED_TIMER_ID,DLC_INSTALLED_TIMER_TIME); + //app.NavigateToScene(iPad,eUIScene_MultiGameJoinLoad); + } + } + else + { + // Changing to async TMS calls + + // flag the timer to start the TMS calls when there is nothing happening with TMS. + // fix for X360 - 162325 - TCR 001: BAS Game Stability: TU17: The game goes into an infinite loading upon entering the Play Game menu shortly after visiting the Minecraft Store + if(app.GetTMSAction(iPad)!=eTMSAction_Idle) + { + XuiSetTimer(m_hObj,TMS_TIMER_ID,TMS_TIMER_TIME); + } + else + { + app.SetTMSAction(iPad,eTMSAction_TMSPP_RetrieveFiles_RunPlayGame); + } + + // block all input + m_bIgnorePress=true; + // We want to hide everything in this scene and display a timer until we get a completion for the TMS files + for(int i=0;i<BUTTONS_MAX;i++) + { + m_Buttons[i].SetShow(FALSE); + } + + // turn off tooltips + ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1); + + m_Timer.SetShow(TRUE); + } + } + } + else + { + // 4J-PB - if this is the trial game, we can't have any networking + // go straight in to the trial level + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + // Can't apply the player's settings here - they haven't come back from the QuerySignInStatud call above yet. + // Need to let them action in the main loop when they come in + // ensure we've applied this player's settings + //app.ApplyGameSettingsChanged(iPad); + LoadTrial(); + } + } +} + +HRESULT CScene_Main::OnTMSBanFileRetrieved() +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + int iPad=ProfileManager.GetLockedProfile(); + + if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,this)==true) + { + // change the minecraft player name + pMinecraft->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + // save device already selected + + // ensure we've applied this player's settings + app.ApplyGameSettingsChanged(iPad); + // check for DLC + // start timer to track DLC check finished + m_Timer.SetShow(TRUE); + XuiSetTimer(m_hObj,DLC_INSTALLED_TIMER_ID,DLC_INSTALLED_TIMER_TIME); + //app.NavigateToScene(iPad,eUIScene_MultiGameJoinLoad); + } + return S_OK; +} + +void CScene_Main::RunLeaderboards(int iPad) +{ + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + // guests can't look at leaderboards + if(ProfileManager.IsGuest(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else if(!ProfileManager.IsSignedInLive(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + else + { + ProfileManager.SetLockedProfile(iPad); + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + app.NavigateToScene(iPad, eUIScene_LeaderboardsMenu); + } +} +void CScene_Main::RunAchievements(int iPad) +{ + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + // guests can't look at achievements + if(ProfileManager.IsGuest(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + XShowAchievementsUI( iPad ); + } +} +void CScene_Main::RunHelpAndOptions(int iPad) +{ + if(ProfileManager.IsGuest(iPad)) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + // 4J-PB - You can be offline and still can go into help and options + if(app.GetTMSDLCInfoRead() || !ProfileManager.IsSignedInLive(iPad)) + { + app.NavigateToScene(iPad,eUIScene_HelpAndOptionsMenu); + } + else + { + // Changing to async TMS calls + app.SetTMSAction(iPad,eTMSAction_TMSPP_RetrieveFiles_HelpAndOptions); + + // block all input + m_bIgnorePress=true; + // We want to hide everything in this scene and display a timer until we get a completion for the TMS files + for(int i=0;i<BUTTONS_MAX;i++) + { + m_Buttons[i].SetShow(FALSE); + } + + // turn off tooltips + ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1); + + m_Timer.SetShow(TRUE); + } + } +} + +HRESULT CScene_Main::OnTMSDLCFileRetrieved( ) +{ + m_Timer.SetShow(FALSE); + switch(m_eAction) + { + case eAction_RunHelpAndOptions: + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_HelpAndOptionsMenu); + break; + case eAction_RunUnlockOrDLC: + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DLCMainMenu); + break; + } + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DLCMainMenu); + + return S_OK; +} + +void CScene_Main::RunUnlockOrDLC(int iPad) +{ + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + // Check if this means downloadable content + if(ProfileManager.IsFullVersion()) + { + // downloadable content + if(ProfileManager.IsSignedInLive(iPad)) + { + if(ProfileManager.IsGuest(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + if(app.GetTMSDLCInfoRead()) + { + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DLCMainMenu); + } + else + { + // Changing to async TMS calls + app.SetTMSAction(iPad,eTMSAction_TMSPP_RetrieveFiles_DLCMain); + + // block all input + m_bIgnorePress=true; + // We want to hide everything in this scene and display a timer until we get a completion for the TMS files + for(int i=0;i<BUTTONS_MAX;i++) + { + m_Buttons[i].SetShow(FALSE); + } + + // turn off tooltips + ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1); + + m_Timer.SetShow(TRUE); + } + + // read the DLC info from TMS + /*app.ReadDLCFileFromTMS(iPad);*/ + + // We want to navigate to the DLC scene, but block input until we get the DLC file in from TMS + // Don't navigate - we might have an uplink disconnect + //app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_DLCMainMenu); + + } + } + else + { + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + } + else + { + // guests can't buy the game + if(ProfileManager.IsGuest(iPad)) + { + StorageManager.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_GUEST_TEXT, uiIDA, 1,iPad); + } + else if(!ProfileManager.IsSignedInLive(iPad)) + { + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + else + { + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + TelemetryManager->RecordUpsellPresented(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID); + ProfileManager.DisplayFullVersionPurchase(false,iPad,eSen_UpsellID_Full_Version_Of_Game); + } + } +} + +int CScene_Main::TMSReadFileListReturned(void *pParam,int iPad,C4JStorage::PTMSPP_FILE_LIST pTmsFileList) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + // push the file details in to a unordered map if they are not already in there +// for(int i=0;i<pTmsFileList->iCount;i++) +// { +// app.PutTMSPP_FileSize(filenametowstring(pTmsFileList->FileDetailsA[i].szFilename),pTmsFileList->FileDetailsA[i].iFileSize); +// } + return 0; +} + +int CScene_Main::TMSFileWriteReturned(void *pParam,int iPad,int iResult) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + // push the file details in to a unordered map if they are not already in there + // for(int i=0;i<pTmsFileList->iCount;i++) + // { + // app.PutTMSPP_FileSize(filenametowstring(pTmsFileList->FileDetailsA[i].szFilename),pTmsFileList->FileDetailsA[i].iFileSize); + // } + return 0; +} + +int CScene_Main::TMSFileReadReturned(void *pParam,int iPad,C4JStorage::PTMSPP_FILEDATA pData) +{ + CScene_Main* pClass = (CScene_Main*)pParam; + + // push the file details in to a unordered map if they are not already in there + // for(int i=0;i<pTmsFileList->iCount;i++) + // { + // app.PutTMSPP_FileSize(filenametowstring(pTmsFileList->FileDetailsA[i].szFilename),pTmsFileList->FileDetailsA[i].iFileSize); + // } + return 0; +} + +HRESULT CScene_Main::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly + if( pTimer->nId == DLC_INSTALLED_TIMER_ID) + { + if(!app.DLCInstallPending()) + { + XuiKillTimer(m_hObj,DLC_INSTALLED_TIMER_ID); + m_Timer.SetShow(FALSE); + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadOrJoinMenu); + } + } + + else if( pTimer->nId == TMS_TIMER_ID) + { + if(app.GetTMSAction(ProfileManager.GetPrimaryPad())==eTMSAction_Idle) + { + app.SetTMSAction(ProfileManager.GetPrimaryPad(),eTMSAction_TMSPP_RetrieveFiles_RunPlayGame); + XuiKillTimer(m_hObj,TMS_TIMER_ID); + } + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MainMenu.h b/Minecraft.Client/Common/XUI/XUI_MainMenu.h new file mode 100644 index 00000000..2e4279e4 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MainMenu.h @@ -0,0 +1,128 @@ +#pragma once + +#include "../media/xuiscene_main.h" +#include "XUI_CustomMessages.h" + +#define BUTTON_PLAYGAME 0 +#define BUTTON_LEADERBOARDS 1 +#define BUTTON_ACHIEVEMENTS 2 +#define BUTTON_HELPANDOPTIONS 3 +#define BUTTON_UNLOCKFULLGAME 4 +#define BUTTON_EXITGAME 5 +#define BUTTONS_MAX BUTTON_EXITGAME + 1 + +#define MAIN_MENU_MAX_TEXT_SCALE 1.5f + +class Random; + +class CScene_Main : public CXuiSceneImpl +{ +private: + static Random *random; + vector<wstring> m_splashes; + D3DXVECTOR3 m_vPosExitGame; + bool m_bIgnorePress; + float m_fSubtitleHeight, m_fSubtitleWidth; + CXuiControl m_Timer; + + // 4J Added + enum eSplashIndexes + { + eSplashHappyBirthdayEx = 0, + eSplashHappyBirthdayNotch, + eSplashMerryXmas, + eSplashHappyNewYear, + + // The start index in the splashes vector from which we can select a random splash + eSplashRandomStart, + }; + + enum eActions + { + eAction_None=0, + eAction_RunGame, + eAction_RunLeaderboards, + eAction_RunAchievements, + eAction_RunHelpAndOptions, + eAction_RunUnlockOrDLC, + }; + +protected: + // Control and Element wrapper objects. + CXuiScene m_Scene; + CXuiControl m_Buttons[BUTTONS_MAX]; + CXuiControl m_Subtitle, m_SubtitleMCFont; + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_SET_FOCUS(OnNotifySetFocus) + XUI_ON_XM_TMS_BANFILE_RETRIEVED_MESSAGE(OnTMSBanFileRetrieved) + XUI_ON_XM_TMS_DLCFILE_RETRIEVED_MESSAGE(OnTMSDLCFileRetrieved) + XUI_ON_XM_TIMER( OnTimer ) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiButton1, m_Buttons[BUTTON_PLAYGAME]) + MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_LEADERBOARDS ]) + MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_ACHIEVEMENTS ]) + MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_HELPANDOPTIONS]) + MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_UNLOCKFULLGAME]) + MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_EXITGAME]) + MAP_CONTROL(IDC_XuiSplash, m_Subtitle) + MAP_CONTROL(IDC_XuiSplashMCFont, m_SubtitleMCFont) + MAP_CONTROL(IDC_Timer, m_Timer) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnTMSBanFileRetrieved(); + HRESULT OnTMSDLCFileRetrieved( ); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + + int SetSaveDevice(); + static void LoadTrial(); + + void RunPlayGame(int iPad); + void RunLeaderboards(int iPad); + void RunAchievements(int iPad); + void RunHelpAndOptions(int iPad); + void RunUnlockOrDLC(int iPad); + + eActions m_eAction; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Main, L"CScene_Main", XUI_CLASS_SCENE ) + + static int SignInReturned(void *pParam,bool bContinue); + static int CreateLoad_SignInReturned(void *pParam,bool bContinue, int iPad); + static int CreateLoad_OfflineProfileReturned(void *pParam,bool bContinue, int iPad); + static int DeviceSelectReturned(void *pParam,bool bContinue); + static int SaveGameReturned(void *pParam,bool bContinue); + static int HelpAndOptions_SignInReturned(void *pParam,bool bContinue,int iPad); + static int ExitGameReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int AchievementsDeviceSelectReturned(void *pParam,bool bContinue); + static int Achievements_SignInReturned(void *pParam,bool bContinue,int iPad); + static int Leaderboards_SignInReturned(void* pParam, bool bContinue, int iPad); + static int UnlockFullGame_SignInReturned(void *pParam,bool bContinue,int iPad); + static int MustSignInReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); +#ifdef _XBOX + static int TMSReadFileListReturned(void *pParam,int iPad,C4JStorage::PTMSPP_FILE_LIST pTmsFileList); + static int TMSFileWriteReturned(void *pParam,int iPad,int iResult); + static int TMSFileReadReturned(void *pParam,int iPad,C4JStorage::PTMSPP_FILEDATA pData); +#endif +}; diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.cpp b/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.cpp new file mode 100644 index 00000000..b3608b06 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.cpp @@ -0,0 +1,1397 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\Random.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XUI_MultiGameCreate.h" +#include "XUI_Controls.h" +#include "..\..\MinecraftServer.h" +#include "..\..\Minecraft.h" +#include "..\..\Options.h" +#include "..\..\..\Minecraft.World\LevelSettings.h" +#include "XUI_MultiGameLaunchMoreOptions.h" +#include "..\..\..\Minecraft.World\BiomeSource.h" +#include "..\..\..\Minecraft.World\IntCache.h" +#include "..\..\..\Minecraft.World\LevelType.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" +#include "..\DLC\DLCLocalisationFile.h" +#include "..\..\StringTable.h" +#include "..\..\DLCTexturePack.h" + +#define GAME_CREATE_ONLINE_TIMER_ID 0 +#define GAME_CREATE_ONLINE_TIMER_TIME 100 +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID 1 +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 100 + +int CScene_MultiGameCreate::m_iDifficultyTitleSettingA[4]= +{ + IDS_DIFFICULTY_TITLE_PEACEFUL, + IDS_DIFFICULTY_TITLE_EASY, + IDS_DIFFICULTY_TITLE_NORMAL, + IDS_DIFFICULTY_TITLE_HARD +}; + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameCreate::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_bSetup = false; + m_texturePackDescDisplayed = false; + m_iConfigA=NULL; + + WCHAR TempString[256]; + MapChildControls(); + + XuiControlSetText(m_EditWorldName,app.GetString(IDS_DEFAULT_WORLD_NAME)); + XuiControlSetText(m_MoreOptions,app.GetString(IDS_MORE_OPTIONS)); + XuiControlSetText(m_NewWorld,app.GetString(IDS_CREATE_NEW_WORLD)); + + XuiControlSetText(m_labelWorldName,app.GetString(IDS_WORLD_NAME)); + XuiControlSetText(m_labelSeed,app.GetString(IDS_CREATE_NEW_WORLD_SEED)); + XuiControlSetText(m_labelRandomSeed,app.GetString(IDS_CREATE_NEW_WORLD_RANDOM_SEED)); + XuiControlSetText(m_pTexturePacksList->m_hObj,app.GetString(IDS_DLC_MENU_TEXTUREPACKS)); + + CreateWorldMenuInitData *params = (CreateWorldMenuInitData *)pInitData->pvInitData; + + m_MoreOptionsParams.bGenerateOptions=TRUE; + m_MoreOptionsParams.bStructures=TRUE; + m_MoreOptionsParams.bFlatWorld=FALSE; + m_MoreOptionsParams.bBonusChest=FALSE; + m_MoreOptionsParams.bPVP = TRUE; + m_MoreOptionsParams.bTrust = TRUE; + m_MoreOptionsParams.bFireSpreads = TRUE; + m_MoreOptionsParams.bHostPrivileges = FALSE; + m_MoreOptionsParams.bTNT = TRUE; + m_MoreOptionsParams.iPad = params->iPad; + m_iPad=params->iPad; + delete params; + + m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + // 4J-PB - read the settings for the online flag. We'll only save this setting if the user changed it. + bool bGameSetting_Online=(app.GetGameSettings(m_iPad,eGameSetting_Online)!=0); + m_MoreOptionsParams.bOnlineSettingChangedBySystem=false; + + // Set the text for friends of friends, and default to on + if( m_bMultiplayerAllowed) + { + m_MoreOptionsParams.bOnlineGame = bGameSetting_Online?TRUE:FALSE; + if(bGameSetting_Online) + { + m_MoreOptionsParams.bInviteOnly = (app.GetGameSettings(m_iPad,eGameSetting_InviteOnly)!=0)?TRUE:FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = (app.GetGameSettings(m_iPad,eGameSetting_FriendsOfFriends)!=0)?TRUE:FALSE; + } + else + { + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + } + else + { + m_MoreOptionsParams.bOnlineGame = FALSE; + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + if(bGameSetting_Online) + { + // The profile settings say Online, but either the player is offline, or they are not allowed to play online + m_MoreOptionsParams.bOnlineSettingChangedBySystem=true; + } + } + + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); + m_bGameModeSurvival=true; + + m_CurrentDifficulty=app.GetGameSettings(m_iPad,eGameSetting_Difficulty); + m_SliderDifficulty.SetValue(m_CurrentDifficulty); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[m_CurrentDifficulty])); + m_SliderDifficulty.SetText(TempString); + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + + // restrict the keyboard - don't want languages that are not supported, like cyrillic, etc. + switch(XGetLanguage()) + { + case XC_LANGUAGE_ENGLISH: + case XC_LANGUAGE_GERMAN: + case XC_LANGUAGE_FRENCH: + case XC_LANGUAGE_SPANISH: + case XC_LANGUAGE_ITALIAN: + case XC_LANGUAGE_PORTUGUESE: + case XC_LANGUAGE_JAPANESE: + case XC_LANGUAGE_TCHINESE: + case XC_LANGUAGE_KOREAN: + m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Default); + m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Default); + break; + default: + m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Full); + break; + } + + m_NewWorld.SetEnable(true); + + m_EditWorldName.SetTextLimit(XCONTENT_MAX_DISPLAYNAME_LENGTH); + + wstring wWorldName = m_EditWorldName.GetText(); + + // set the caret to the end of the default text + m_EditWorldName.SetCaretPosition((int)wWorldName.length()); + // In the dashboard, there's room for about 30 W characters on two lines before they go over the top of things + m_EditWorldName.SetTextLimit(25); + + m_EditWorldName.SetTitleAndText(IDS_NAME_WORLD,IDS_NAME_WORLD_TEXT); + m_EditSeed.SetTitleAndText(IDS_CREATE_NEW_WORLD,IDS_CREATE_NEW_WORLD_SEEDTEXT); + + XuiSetTimer(m_hObj,GAME_CREATE_ONLINE_TIMER_ID,GAME_CREATE_ONLINE_TIMER_TIME); + XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_CreateWorldMenu, 0); + + // 4J-PB - Load up any texture pack data we have locally in the XZP + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.LoadLocalTMSFile(app.TMSFileA[i].wchFilename,app.TMSFileA[i].eEXT); + app.AddMemoryTPDFile(app.TMSFileA[i].iConfig, app.TMSFileA[i].pbData,app.TMSFileA[i].uiSize); + } + } + + m_iTexturePacksNotInstalled=0; + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==true) + { + // not doing a mount, so enable input + m_bIgnoreInput=true; + } + else + { + m_bIgnoreInput = false; + + m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + int texturePacksCount = pMinecraft->skins->getTexturePackCount(); + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + HRESULT hr; + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + ListInfo.fEnabled = TRUE; + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tp; + if(pDLCTexPack) + { + int id=pDLCTexPack->getDLCParentPackId(); + + if(id==0) + { + // default texture pack - should come first + ListInfo.iSortIndex=0x0FFFFFFF; + } + else + { + ListInfo.iSortIndex=id; + ListInfo.iData=id; + } + } + +#ifdef _DEBUG + app.DebugPrintf("TP - "); + OutputDebugStringW(tp->getName().c_str()); + app.DebugPrintf(", sort index - %d\n",ListInfo.iSortIndex); +#endif + + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + } + } + + + // 4J-PB - there may be texture packs we don't have, so use the info from TMS for this + + DLC_INFO *pDLCInfo=NULL; + + // first pass - look to see if there are any that are not in the list + bool bTexturePackAlreadyListed; + bool bNeedToGetTPD=false; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + // some missing + bNeedToGetTPD=true; + + m_iTexturePacksNotInstalled++; + } + } + + if(bNeedToGetTPD==true) + { + // add a TMS request for them + app.DebugPrintf("+++ Adding TMSPP request for texture pack data\n"); + app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); + m_iConfigA= new int [m_iTexturePacksNotInstalled]; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; + } + } + } + + m_currentTexturePackIndex = pMinecraft->skins->getTexturePackIndex(0); + UpdateTexturePackDescription(m_currentTexturePackIndex); + + m_bSetup = true; + } + return S_OK; +} + + +HRESULT CScene_MultiGameCreate::OnDestroy() +{ + // clear out the texture pack data + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.RemoveMemoryTPDFile(app.TMSFileA[i].iConfig); + } + } + + app.FreeLocalTMSFiles(eTMSFileType_TexturePack); + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameCreate::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_NewWorld) + { + // Check if we need to upsell the texture pack + if(m_MoreOptionsParams.dwTexturePack!=0) + { + // texture pack hasn't been set yet, so check what it will be + TexturePack *pTexturePack = pMinecraft->skins->getTexturePackById(m_MoreOptionsParams.dwTexturePack); + + if(pTexturePack==NULL) + { + // They've selected a texture pack they don't have yet + // upsell + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(m_currentTexturePackIndex); + + + // upsell the texture pack + // tell sentient about the upsell of the full version of the skin pack + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + // DLC might have been corrupt + if(ullOfferID_Full!=0LL) + { + TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[3]; + + // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + uiIDA[2]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_MultiGameCreate::TexturePackDialogReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_MultiGameCreate::TexturePackDialogReturned,this,app.GetStringTable()); + } + + return S_OK; + } + } + } + + m_bIgnoreInput = true; + SetShow( FALSE ); + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && m_MoreOptionsParams.bOnlineGame; + + // if the profile data has been changed, then force a profile write (we save the online/invite/friends of friends settings) + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + // check the checkboxes + + // Only save the online setting if the user changed it - we may change it because we're offline, but don't want that saved + if(!m_MoreOptionsParams.bOnlineSettingChangedBySystem) + { + app.SetGameSettings(m_iPad,eGameSetting_Online,m_MoreOptionsParams.bOnlineGame?1:0); + } + app.SetGameSettings(m_iPad,eGameSetting_InviteOnly,m_MoreOptionsParams.bInviteOnly?1:0); + app.SetGameSettings(m_iPad,eGameSetting_FriendsOfFriends,m_MoreOptionsParams.bAllowFriendsOfFriends?1:0); + + app.CheckGameSettingsChanged(true,pNotifyPressData->UserIndex); + + // Check that we have the rights to use a texture pack we have selected. + if(m_MoreOptionsParams.dwTexturePack!=0) + { + // texture pack hasn't been set yet, so check what it will be + TexturePack *pTexturePack = pMinecraft->skins->getTexturePackById(m_MoreOptionsParams.dwTexturePack); + + if(pTexturePack==NULL) + { + // corrupt DLC so set it to the default textures + m_MoreOptionsParams.dwTexturePack=0; + } + else + { + m_pDLCPack=pTexturePack->getDLCPack(); + // do we have a license? + if(m_pDLCPack && !m_pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // no + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + if(!ProfileManager.IsSignedInLive(pNotifyPressData->UserIndex)) + { + // need to be signed in to live + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + return S_OK; + } + else + { + // upsell + + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(m_pDLCPack->getPurchaseOfferId()); + ULONGLONG ullOfferID_Full; + + if(pDLCInfo!=NULL) + { + ullOfferID_Full=pDLCInfo->ullOfferID_Full; + } + else + { + ullOfferID_Full=pTexturePack->getDLCPack()->getPurchaseOfferId(); + } + + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + // Give the player a warning about the trial version of the texture pack + StorageManager.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 1, pNotifyPressData->UserIndex,&CScene_MultiGameCreate::WarningTrialTexturePackReturned,this,app.GetStringTable()); + return S_OK; + } + } + } + } + + if(m_bGameModeSurvival != true || m_MoreOptionsParams.bHostPrivileges == TRUE) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + if(m_bGameModeSurvival != true) + { + StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_CREATIVE, uiIDA, 2, m_iPad,&CScene_MultiGameCreate::ConfirmCreateReturned,this,app.GetStringTable()); + } + else + { + StorageManager.RequestMessageBox(IDS_TITLE_START_GAME, IDS_CONFIRM_START_HOST_PRIVILEGES, uiIDA, 2, m_iPad,&CScene_MultiGameCreate::ConfirmCreateReturned,this,app.GetStringTable()); + } + } + else + { + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_MultiGameCreate::StartGame_SignInReturned, this,ProfileManager.GetPrimaryPad()); + } + else + { + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + //bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && m_MoreOptionsParams.bOnlineGame; + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && noUGC ) + { + m_bIgnoreInput = false; + SetShow( TRUE ); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + CreateGame(this, 0); + } + } + } + } + else if(hObjPressed==m_MoreOptions) + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_LaunchMoreOptionsMenu,&m_MoreOptionsParams); + } + else if(hObjPressed == m_ButtonGameMode) + { + if(m_bGameModeSurvival) + { + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_CREATIVE)); + m_bGameModeSurvival=false; + } + else + { + m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); + m_bGameModeSurvival=true; + } + } + else if(hObjPressed == m_pTexturePacksList->m_hObj) + { + UpdateCurrentTexturePack(); + } + + return S_OK; +} + + +int CScene_MultiGameCreate::UnlockTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameCreate* pScene = (CScene_MultiGameCreate*)pParam; +#ifdef _XBOX + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedIn(iPad)) + { + ULONGLONG ullIndexA[1]; + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(pScene->m_pDLCPack->getPurchaseOfferId()); + + if(pDLCInfo!=NULL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Full; + } + else + { + ullIndexA[0]=pScene->m_pDLCPack->getPurchaseOfferId(); + } + + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + // the license change coming in when the offer has been installed will cause this scene to refresh + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Texture_DLC, ( pScene->m_pDLCPack->getPurchaseOfferId() & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined); + } +#endif + pScene->m_bIgnoreInput = false; + pScene->SetShow( TRUE ); + + return 0; +} + +int CScene_MultiGameCreate::WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameCreate* pScene = (CScene_MultiGameCreate*)pParam; + pScene->m_bIgnoreInput = false; + pScene->SetShow( TRUE ); + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pScene->m_MoreOptionsParams.bOnlineGame; + + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_MultiGameCreate::StartGame_SignInReturned, pScene,ProfileManager.GetPrimaryPad()); + } + else + { + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && noUGC ) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + // This is called from a storage manager thread... need to set up thread storage for IntCache as CreateGame requires this to search for a suitable seed if we haven't set a seed. + IntCache::CreateNewThreadStorage(); + CreateGame(pScene, 0); + IntCache::ReleaseThreadStorage(); + } + } + + return 0; +} + +HRESULT CScene_MultiGameCreate::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) +{ + WCHAR TempString[256]; + + if(hObjSource == m_EditWorldName) + { + // Enable the done button when we have all of the necessary information + wstring wWorldName = m_EditWorldName.GetText(); + BOOL bHasWorldName = ( wWorldName.length()!=0); + m_NewWorld.SetEnable(bHasWorldName); + } + else if(hObjSource==m_SliderDifficulty.GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Difficulty,pValueChangedData->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[pValueChangedData->nValue])); + m_SliderDifficulty.SetText(TempString); + } + + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest==NULL) + { + pControlNavigateData->hObjDest=pControlNavigateData->hObjSource; + } + + bHandled=TRUE; + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly + switch(pTimer->nId) + { + + + case GAME_CREATE_ONLINE_TIMER_ID: + { + bool bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + + if(bMultiplayerAllowed != m_bMultiplayerAllowed) + { + if( bMultiplayerAllowed ) + { + bool bGameSetting_Online=(app.GetGameSettings(m_iPad,eGameSetting_Online)!=0); + m_MoreOptionsParams.bOnlineGame = bGameSetting_Online?TRUE:FALSE; + if(bGameSetting_Online) + { + m_MoreOptionsParams.bInviteOnly = (app.GetGameSettings(m_iPad,eGameSetting_InviteOnly)!=0)?TRUE:FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = (app.GetGameSettings(m_iPad,eGameSetting_FriendsOfFriends)!=0)?TRUE:FALSE; + } + else + { + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + } + else + { + m_MoreOptionsParams.bOnlineGame = FALSE; + m_MoreOptionsParams.bInviteOnly = FALSE; + m_MoreOptionsParams.bAllowFriendsOfFriends = FALSE; + } + + m_bMultiplayerAllowed = bMultiplayerAllowed; + } + } + break; + + case CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID: + { + // also check for any new texture packs info being available + // for each item in the mem list, check it's in the data list + + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + // for each iConfig, check if the data is available, and add it to the List, then remove it from the viConfig + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + DWORD dwBytes=0; + PBYTE pbData=NULL; + //app.DebugPrintf("Retrieving iConfig %d from TPD\n",m_iConfigA[i]); + + app.GetTPD(m_iConfigA[i],&pbData,&dwBytes); + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + if(dwBytes > 0 && pbData) + { + DWORD dwImageBytes=0; + PBYTE pbImageData=NULL; + + app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbImageData,&dwImageBytes ); + ListInfo.fEnabled = TRUE; + ListInfo.iData = m_iConfigA[i]; + HRESULT hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + app.DebugPrintf("Adding texturepack %d from TPD\n",m_iConfigA[i]); + + ListInfo.iSortIndex=m_iConfigA[i]; + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + + m_iConfigA[i]=-1; + } + } + } + + bool bAllDone=true; + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + bAllDone = false; + } + } + + if(bAllDone ) + { + // kill this timer + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + } + } + break; + } + + return S_OK; +} + +int CScene_MultiGameCreate::ConfirmCreateReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameCreate* pClass = (CScene_MultiGameCreate*)pParam; + + if(result==C4JStorage::EMessage_ResultAccept) + { + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_MultiGameCreate::StartGame_SignInReturned, pClass,ProfileManager.GetPrimaryPad()); + } + else + { + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && noUGC ) + { + pClass->m_bIgnoreInput = false; + pClass->SetShow( TRUE ); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + // This is called from a storage manager thread... need to set up thread storage for IntCache as CreateGame requires this to search for a suitable seed if we haven't set a seed. + IntCache::CreateNewThreadStorage(); + CreateGame(pClass, 0); + IntCache::ReleaseThreadStorage(); + } + } + } + else + { + pClass->m_bIgnoreInput = false; + pClass->SetShow( TRUE ); + } + return 0; +} + +int CScene_MultiGameCreate::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_MultiGameCreate* pClass = (CScene_MultiGameCreate*)pParam; + + if(bContinue==true) + { + // It's possible that the player has not signed in - they can back out + if(ProfileManager.IsSignedIn(iPad)) + { + DWORD dwLocalUsersMask = 0; + + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + bool noPrivileges = false; + + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); + } + } + + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(isClientSide && (noPrivileges || noUGC) ) + { + if( noUGC ) + { + pClass->m_bIgnoreInput = false; + pClass->SetShow( TRUE ); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + pClass->m_bIgnoreInput = false; + pClass->SetShow( TRUE ); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_HOST_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + } + else + { + // This is NOT called from a storage manager thread, and is in fact called from the main thread in the Profile library tick. Therefore we use the main threads IntCache. + CreateGame(pClass, dwLocalUsersMask); + } + } + } + else + { + pClass->m_bIgnoreInput = false; + pClass->SetShow( TRUE ); + } + return 0; +} + +// 4J Stu - Shared functionality that is the same whether we needed a quadrant sign-in or not +void CScene_MultiGameCreate::CreateGame(CScene_MultiGameCreate* pClass, DWORD dwLocalUsersMask) +{ + // stop the timer running that causes a check for new texture packs in TMS but not installed, since this will run all through the create game, and will crash if it tries to create an hbrush + XuiKillTimer(pClass->m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; + bool isPrivate = pClass->m_MoreOptionsParams.bInviteOnly?true:false; + + // clear out the app's terrain features list + app.ClearTerrainFeaturePosition(); + + // create the world and launch + wstring wWorldName = pClass->m_EditWorldName.GetText(); + + StorageManager.ResetSaveData(); + // Make our next save default to the name of the level + StorageManager.SetSaveTitle((wchar_t *)wWorldName.c_str()); + + BOOL bHasSeed = (pClass->m_EditSeed.GetText() != NULL); + + wstring wSeed; + if(bHasSeed) + { + wSeed=pClass->m_EditSeed.GetText(); + } + else + { + // random + wSeed=L""; + } + + // start the game + bool isFlat = (pClass->m_MoreOptionsParams.bFlatWorld==TRUE); + __int64 seedValue = 0; //BiomeSource::findSeed(isFlat?LevelType::lvl_flat:LevelType::lvl_normal); // 4J - was (new Random())->nextLong() - now trying to actually find a seed to suit our requirements + + if (wSeed.length() != 0) + { + __int64 value = 0; + unsigned int len = (unsigned int)wSeed.length(); + + //Check if the input string contains a numerical value + bool isNumber = true; + for( unsigned int i = 0 ; i < len ; ++i ) + if( wSeed.at(i) < L'0' || wSeed.at(i) > L'9' ) + if( !(i==0 && wSeed.at(i) == L'-' ) ) + { + isNumber = false; + break; + } + + //If the input string is a numerical value, convert it to a number + if( isNumber ) + value = _fromString<__int64>(wSeed); + + //If the value is not 0 use it, otherwise use the algorithm from the java String.hashCode() function to hash it + if( value != 0 ) + seedValue = value; + else + { + int hashValue = 0; + for( unsigned int i = 0 ; i < len ; ++i ) + hashValue = 31 * hashValue + wSeed.at(i); + seedValue = hashValue; + } + + } + else + { + seedValue = BiomeSource::findSeed(isFlat?LevelType::lvl_flat:LevelType::lvl_normal); // 4J - was (new Random())->nextLong() - now trying to actually find a seed to suit our requirements + } + + g_NetworkManager.HostGame(dwLocalUsersMask,isClientSide,isPrivate,MINECRAFT_NET_MAX_PLAYERS,0); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = seedValue; + param->saveData = NULL; + param->texturePackId = pClass->m_MoreOptionsParams.dwTexturePack; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->skins->selectTexturePackById(pClass->m_MoreOptionsParams.dwTexturePack); + //pMinecraft->skins->updateUI(); + + app.SetGameHostOption(eGameHostOption_Difficulty,Minecraft::GetInstance()->options->difficulty); + app.SetGameHostOption(eGameHostOption_FriendsOfFriends,pClass->m_MoreOptionsParams.bAllowFriendsOfFriends); + app.SetGameHostOption(eGameHostOption_Gamertags,app.GetGameSettings(pClass->m_iPad,eGameSetting_GamertagsVisible)?1:0); + + app.SetGameHostOption(eGameHostOption_BedrockFog,app.GetGameSettings(pClass->m_iPad,eGameSetting_BedrockFog)?1:0); + +// CXuiList listObject; +// listObject.Attach( pClass->m_GameMode.GetListObject() ); + app.SetGameHostOption(eGameHostOption_GameType,pClass->m_bGameModeSurvival?GameType::SURVIVAL->getId():GameType::CREATIVE->getId()); + app.SetGameHostOption(eGameHostOption_LevelType,pClass->m_MoreOptionsParams.bFlatWorld ); + app.SetGameHostOption(eGameHostOption_Structures,pClass->m_MoreOptionsParams.bStructures ); + app.SetGameHostOption(eGameHostOption_BonusChest,pClass->m_MoreOptionsParams.bBonusChest ); + + app.SetGameHostOption(eGameHostOption_PvP,pClass->m_MoreOptionsParams.bPVP); + app.SetGameHostOption(eGameHostOption_TrustPlayers,pClass->m_MoreOptionsParams.bTrust ); + app.SetGameHostOption(eGameHostOption_FireSpreads,pClass->m_MoreOptionsParams.bFireSpreads ); + app.SetGameHostOption(eGameHostOption_TNT,pClass->m_MoreOptionsParams.bTNT ); + app.SetGameHostOption(eGameHostOption_HostCanFly,pClass->m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanChangeHunger,pClass->m_MoreOptionsParams.bHostPrivileges); + app.SetGameHostOption(eGameHostOption_HostCanBeInvisible,pClass->m_MoreOptionsParams.bHostPrivileges ); + + + param->settings = app.GetGameHostOption( eGameHostOption_All ); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + // Reset the autosave time + app.SetAutosaveTimerTime(); + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + +HRESULT CScene_MultiGameCreate::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + m_SliderDifficulty.SetValueDisplay(FALSE); + } + + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || + pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) + { + } + else if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + if(m_bSetup && m_texturePackDescDisplayed) + { + XUITimeline *timeline; + XUINamedFrame *startFrame, *endFrame; + GetTimeline( &timeline ); + startFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + endFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + m_texturePackDescDisplayed = true; + } + // 4J-PB - Need to check for installed DLC, which might have happened while you were on the info scene + if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // Can't call this here because if you back out of the load info screen and then go back in and load a game, it will attempt to use the dlc as it's running a mount of the dlc + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + m_pTexturePacksList->RemoveAllData(); + } + } + + } + + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + if(hObjSource == m_pTexturePacksList->m_hObj) + { + UpdateTexturePackDescription(pNotifySelChangedData->iItem); + + // 4J-JEV: Removed expand description check, taken care of elsewhere. + } + + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + HXUIOBJ hSourceParent, hDestParent; + XuiElementGetParent(hObjSource,&hSourceParent); + XuiElementGetParent(pNotifyFocusData->hObjOther,&hDestParent); + if(hSourceParent != hDestParent && pNotifyFocusData->hObjOther != m_pTexturePacksList->m_hObj && hSourceParent == m_pTexturePacksList->m_hObj) + { + m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); + m_pTexturePacksList->SetTopItem(m_currentTexturePackIndex); // scroll the item into view if it's not visible + } + else if(!m_texturePackDescDisplayed && pNotifyFocusData->hObjOther == m_pTexturePacksList->m_hObj) + { + // 4J-JEV: Shouldn't we always do this? + //int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount(); + //if(texturePacksCount == 1) + //{ + XUITimeline *timeline; + XUINamedFrame *startFrame, *endFrame; + GetTimeline( &timeline ); + startFrame = timeline->FindNamedFrame( L"SlideOut" ); + endFrame = timeline->FindNamedFrame( L"SlideOutEnd" ); + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + m_texturePackDescDisplayed = true; + //} + } + + return S_OK; +} + +void CScene_MultiGameCreate::UpdateTexturePackDescription(int index) +{ + int iTexPackId=m_pTexturePacksList->GetData(index).iData; + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); + + if(tp==NULL) + { + // this is probably a texture pack icon added from TMS + + DWORD dwBytes=0,dwFileBytes=0; + PBYTE pbData=NULL,pbFileData=NULL; + + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(index); + + app.GetTPD(ListItem.iData,&pbData,&dwBytes); + + app.GetFileFromTPD(eTPDFileType_Loc,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes > 0 && pbFileData) + { + StringTable *pStringTable = new StringTable(pbFileData, dwFileBytes); + m_texturePackTitle.SetText(pStringTable->getString(L"IDS_DISPLAY_NAME")); + m_texturePackDescription.SetText(pStringTable->getString(L"IDS_TP_DESCRIPTION")); + } + + app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes >= 0 && pbFileData) + { + XuiCreateTextureBrushFromMemory(pbFileData,dwFileBytes,&m_hTexturePackIconBrush); + m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); + } + app.GetFileFromTPD(eTPDFileType_Comparison,pbData,dwBytes,&pbFileData,&dwFileBytes ); + if(dwFileBytes >= 0 && pbFileData) + { + XuiCreateTextureBrushFromMemory(pbFileData,dwFileBytes,&m_hTexturePackComparisonBrush); + m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); + } + else + { + m_texturePackComparison->UseBrush(NULL); + } + } + else + { + m_texturePackTitle.SetText(tp->getName().c_str()); + m_texturePackDescription.SetText(tp->getDesc1().c_str()); + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hTexturePackIconBrush); + m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); + } + + pbImageData = tp->getPackComparison(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&m_hTexturePackComparisonBrush); + m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); + } + else + { + m_texturePackComparison->UseBrush(NULL); + } + } +} + +void CScene_MultiGameCreate::UpdateCurrentTexturePack() +{ + m_currentTexturePackIndex = m_pTexturePacksList->GetCurSel(); + int iTexPackId=m_pTexturePacksList->GetData(m_currentTexturePackIndex).iData; + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); + + // if the texture pack is null, you don't have it yet + if(tp==NULL) + { + // Upsell + + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=m_pTexturePacksList->GetData(m_currentTexturePackIndex); + + + // upsell the texture pack + // tell sentient about the upsell of the full version of the skin pack + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[3]; + + // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + uiIDA[2]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_MultiGameCreate::TexturePackDialogReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_MultiGameCreate::TexturePackDialogReturned,this,app.GetStringTable()); + } + + // do set the texture pack id, and on the user pressing create world, check they have it + m_MoreOptionsParams.dwTexturePack = ListItem.iData; + return ; + } + else + { + m_MoreOptionsParams.dwTexturePack = tp->getId(); + } +} + +int CScene_MultiGameCreate::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameCreate *pClass = (CScene_MultiGameCreate *)pParam; + pClass->m_currentTexturePackIndex = pClass->m_pTexturePacksList->GetCurSel(); + // Exit with or without saving + // Decline means install full version of the texture pack in this dialog + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultAccept) + { + // we need to enable background downloading for the DLC + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + ULONGLONG ullOfferID_Full; + ULONGLONG ullIndexA[1]; + CXuiCtrl4JList::LIST_ITEM_INFO ListItem; + // get the current index of the list, and then get the data + ListItem=pClass->m_pTexturePacksList->GetData(pClass->m_currentTexturePackIndex); + app.GetDLCFullOfferIDForPackID(ListItem.iData,&ullOfferID_Full); + + if( result==C4JStorage::EMessage_ResultAccept ) // Full version + { + ullIndexA[0]=ullOfferID_Full; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + } + else // trial version + { + // if there is no trial version, this is a Cancel + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Trial; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + } + pClass->m_bIgnoreInput=false; + return 0; +} + +HRESULT CScene_MultiGameCreate::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + // clear out the texture pack list + m_pTexturePacksList->RemoveAllData(); + ClearTexturePackDescription(); + } + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + +HRESULT CScene_MultiGameCreate::OnCustomMessage_DLCMountingComplete() +{ + // refill the texture pack list + m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + int texturePacksCount = pMinecraft->skins->getTexturePackCount(); + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + HRESULT hr; + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + + if(dwImageBytes > 0 && pbImageData) + { + ListInfo.fEnabled = TRUE; + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&ListInfo.hXuiBrush); + + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tp; + if(pDLCTexPack) + { + int id=pDLCTexPack->getDLCParentPackId(); + + if(id==0) + { + // default texture pack - should come first + ListInfo.iSortIndex=0x0FFFFFFF; + } + else + { + ListInfo.iSortIndex=id; + ListInfo.iData=id; + } + } + m_pTexturePacksList->AddData(ListInfo,0,CXuiCtrl4JList::eSortList_Index); + } + } + + m_iTexturePacksNotInstalled=0; + + // 4J-PB - there may be texture packs we don't have, so use the info from TMS for this + // REMOVE UNTIL WORKING + DLC_INFO *pDLCInfo=NULL; + + // first pass - look to see if there are any that are not in the list + bool bTexturePackAlreadyListed; + bool bNeedToGetTPD=false; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + // some missing + bNeedToGetTPD=true; + + m_iTexturePacksNotInstalled++; + } + } + + if(bNeedToGetTPD==true) + { + // add a TMS request for them + app.DebugPrintf("+++ Adding TMSPP request for texture pack data\n"); + app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); + if(m_iConfigA!=NULL) + { + delete m_iConfigA; + } + m_iConfigA= new int [m_iTexturePacksNotInstalled]; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; + } + } + } + + m_currentTexturePackIndex = pMinecraft->skins->getTexturePackIndex(0); + UpdateTexturePackDescription(m_currentTexturePackIndex); + + m_bSetup = true; + m_bIgnoreInput=false; + app.m_dlcManager.checkForCorruptDLCAndAlert(); + return S_OK; +} + +void CScene_MultiGameCreate::ClearTexturePackDescription() +{ + m_texturePackTitle.SetText(L" "); + m_texturePackDescription.SetText(L" "); + m_texturePackComparison->UseBrush(NULL); + m_texturePackIcon->UseBrush(NULL); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.h b/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.h new file mode 100644 index 00000000..5b4e6ef7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameCreate.h @@ -0,0 +1,118 @@ +#pragma once +#include "..\Media\xuiscene_multi_create.h" +#include "XUI_Ctrl_4JEdit.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_MultiGameLaunchMoreOptions.h" + +class CXuiCtrl4JList; +class CXuiCtrl4JIcon; + +class CScene_MultiGameCreate : public CXuiSceneImpl +{ +protected: + CXuiScene m_MainScene; + CXuiScene m_TexturePackDetails; + CXuiControl m_NewWorld; + CXuiControl m_labelWorldName; + CXuiControl m_labelSeed; + CXuiControl m_labelRandomSeed; + CXuiControl m_MoreOptions; + CXuiCtrl4JEdit m_EditSeed; + CXuiCtrl4JEdit m_EditWorldName; + CXuiControl m_ButtonGameMode; + CXuiCtrlSliderWrapper m_SliderDifficulty; + CXuiCtrl4JList *m_pTexturePacksList; + CXuiControl m_texturePackTitle, m_texturePackDescription; + CXuiCtrl4JIcon *m_texturePackIcon, *m_texturePackComparison; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_ON_XM_CONTROL_NAVIGATE(OnControlNavigate) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_TRANSITION_END(OnTransitionEnd) + XUI_ON_XM_NOTIFY_SELCHANGED( OnNotifySelChanged ) + XUI_ON_XM_NOTIFY_KILL_FOCUS( OnNotifyKillFocus ) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_MainScene, m_MainScene) + BEGIN_MAP_CHILD_CONTROLS(m_MainScene) + MAP_CONTROL(IDC_XuiLabelWorldName, m_labelWorldName) + MAP_CONTROL(IDC_XuiLabelSeed, m_labelSeed) + MAP_CONTROL(IDC_XuiLabelRandomSeed, m_labelRandomSeed) + MAP_CONTROL(IDC_XuiGameModeToggle, m_ButtonGameMode) + MAP_CONTROL(IDC_XuiNewWorld, m_NewWorld) + MAP_CONTROL(IDC_XuiMoreOptions, m_MoreOptions) + MAP_CONTROL(IDC_XuiEditSeed, m_EditSeed) + MAP_CONTROL(IDC_XuiEditWorldName, m_EditWorldName) + MAP_CONTROL(IDC_XuiSliderDifficulty, m_SliderDifficulty) + MAP_OVERRIDE(IDC_TexturePacksList, m_pTexturePacksList) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TexturePackDetails, m_TexturePackDetails) + BEGIN_MAP_CHILD_CONTROLS(m_TexturePackDetails) + MAP_CONTROL(IDC_TexturePackName, m_texturePackTitle) + MAP_CONTROL(IDC_TexturePackDescription, m_texturePackDescription) + MAP_OVERRIDE(IDC_Icon, m_texturePackIcon) + MAP_OVERRIDE(IDC_ComparisonPic, m_texturePackComparison) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled); + HRESULT OnControlNavigate( XUIMessageControlNavigate *pControlNavigateData, BOOL &bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ); + HRESULT OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); + HRESULT OnDestroy(); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_MultiGameCreate, L"CScene_MultiGameCreate", XUI_CLASS_SCENE ) + +private: + static int LoadSaveDataReturned(void *pParam,bool bContinue); + static int StartGame_SignInReturned(void *pParam,bool bContinue, int iPad); + static void CreateGame(CScene_MultiGameCreate* pClass, DWORD dwLocalUsersMask); + static int ConfirmCreateReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int UnlockTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + + void ToggleShowSaveList(); + void UpdateTexturePackDescription(int index); + void ClearTexturePackDescription(); + void UpdateCurrentTexturePack(); + + bool m_bMultiplayerAllowed; + int m_iPad; + int m_CurrentDifficulty; + static int m_iDifficultyTitleSettingA[4]; + LaunchMoreOptionsMenuInitData m_MoreOptionsParams; + bool m_bGameModeSurvival; + bool m_bIgnoreInput; + unsigned int m_currentTexturePackIndex; + DLCPack * m_pDLCPack; + bool m_bSetup; + bool m_texturePackDescDisplayed; + HXUIBRUSH m_hTexturePackIconBrush; + HXUIBRUSH m_hTexturePackComparisonBrush; + int *m_iConfigA; // track the texture packs that we don't have installed + int m_iTexturePacksNotInstalled; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.cpp b/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.cpp new file mode 100644 index 00000000..bbfa243b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.cpp @@ -0,0 +1,392 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include <assert.h> +#include "..\..\..\Minecraft.World\LevelSettings.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XUI_MultiGameInfo.h" +#include "XUI_MultiGameJoinLoad.h" +#include "..\..\..\Minecraft.World\LevelSettings.h" +#include "..\..\..\Minecraft.World\Difficulty.h" + +#define UPDATE_PLAYERS_TIMER_ID 0 +#define UPDATE_PLAYERS_TIMER_TIME 30000 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameInfo::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(playersList,app.GetString(IDS_PLAYERS)); + XuiControlSetText(m_JoinGame,app.GetString(IDS_JOIN_GAME)); + XuiControlSetText(m_labelDifficulty,app.GetString(IDS_LABEL_DIFFICULTY)); + XuiControlSetText(m_labelGameType,app.GetString(IDS_LABEL_GAME_TYPE)); + XuiControlSetText(m_labelGamertagsOn,app.GetString(IDS_LABEL_GAMERTAGS)); + XuiControlSetText(m_labelStructuresOn,app.GetString(IDS_LABEL_STRUCTURES)); + XuiControlSetText(m_labelLevelType,app.GetString(IDS_LABEL_LEVEL_TYPE)); + XuiControlSetText(m_labelPvP,app.GetString(IDS_LABEL_PvP)); + XuiControlSetText(m_labelTrust,app.GetString(IDS_LABEL_TRUST)); + XuiControlSetText(m_labelTNTOn,app.GetString(IDS_LABEL_TNT)); + XuiControlSetText(m_labelFireOn,app.GetString(IDS_LABEL_FIRE_SPREADS)); + + JoinMenuInitData *initData = (JoinMenuInitData *)pInitData->pvInitData; + m_selectedSession = initData->selectedSession; + m_iPad = initData->iPad; + // 4J-PB - don't delete this - it's part of the joinload structure + //delete initData; + + for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) + { + if( m_selectedSession->data.players[i] != NULL ) + { + playersList.InsertItems(i,1); +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + playersList.SetText(i, L"WWWWWWWWWWWWWWWW" ); + } + else +#endif + { + playersList.SetText(i, convStringToWstring( m_selectedSession->data.szPlayers[i] ).c_str() ); + } + } + else + { + // Leave the loop when we hit the first NULL player + break; + } + } + + unsigned int uiGameHostSettings = m_selectedSession->data.m_uiGameHostSettings; + switch(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_Difficulty)) + { + case Difficulty::EASY: + m_difficulty.SetText( app.GetString(IDS_DIFFICULTY_TITLE_EASY) ); + break; + case Difficulty::NORMAL: + m_difficulty.SetText( app.GetString(IDS_DIFFICULTY_TITLE_NORMAL) ); + break; + case Difficulty::HARD: + m_difficulty.SetText( app.GetString(IDS_DIFFICULTY_TITLE_HARD) ); + break; + case Difficulty::PEACEFUL: + default: + m_difficulty.SetText( app.GetString(IDS_DIFFICULTY_TITLE_PEACEFUL) ); + break; + } + + unsigned int hostOption = app.GetGameHostOption(uiGameHostSettings,eGameHostOption_GameType); + + if (hostOption == GameType::CREATIVE->getId()) + { + m_GameType.SetText( app.GetString(IDS_CREATIVE) ); + } + else if (hostOption == GameType::SURVIVAL->getId()) + { + m_GameType.SetText( app.GetString(IDS_SURVIVAL) ); + } + else + { + m_GameType.SetText( app.GetString(IDS_SURVIVAL) ); + } + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_Gamertags)) m_gamertagsOn.SetText( app.GetString(IDS_ON) ); + else m_gamertagsOn.SetText( app.GetString(IDS_OFF) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_Structures)) m_structuresOn.SetText( app.GetString(IDS_ON) ); + else m_structuresOn.SetText( app.GetString(IDS_OFF) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_LevelType)) m_levelType.SetText( app.GetString(IDS_LEVELTYPE_SUPERFLAT) ); + else m_levelType.SetText( app.GetString(IDS_LEVELTYPE_NORMAL) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_PvP)) m_pvpOn.SetText( app.GetString(IDS_ON) ); + else m_pvpOn.SetText( app.GetString(IDS_OFF) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_TrustPlayers)) m_trustPlayers.SetText( app.GetString(IDS_ON) ); + else m_trustPlayers.SetText( app.GetString(IDS_OFF) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_TNT)) m_tntOn.SetText( app.GetString(IDS_ON) ); + else m_tntOn.SetText( app.GetString(IDS_OFF) ); + + if(app.GetGameHostOption(uiGameHostSettings,eGameHostOption_FireSpreads)) m_fireOn.SetText( app.GetString(IDS_ON) ); + else m_fireOn.SetText( app.GetString(IDS_OFF) ); + + m_bIgnoreInput = false; + + // Alert the app the we want to be informed of ethernet connections + app.SetLiveLinkRequired( true ); + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_JoinMenu, 0); + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK ); + + XuiSetTimer(m_hObj,UPDATE_PLAYERS_TIMER_ID,UPDATE_PLAYERS_TIMER_TIME); + + return S_OK; +} + + + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameInfo::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if ( hObjPressed == m_JoinGame ) + { + // check we have the texture pack required for the game + + + SetShow( FALSE ); + m_bIgnoreInput=true; + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(connectedControllers == 1 || !RenderManager.IsHiDef()) + { + JoinGame( this ); + } + else + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_MultiGameInfo::StartGame_SignInReturned, this,ProfileManager.GetPrimaryPad()); + } + } + + return S_OK; +} + +HRESULT CScene_MultiGameInfo::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr = S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + case VK_PAD_Y: + if(m_selectedSession != NULL && playersList.TreeHasFocus() && playersList.GetItemCount() > 0) + { + PlayerUID xuid = m_selectedSession->data.players[playersList.GetCurSel()]; + if( xuid != INVALID_XUID ) + hr = XShowGamerCardUI(ProfileManager.GetLockedProfile(), xuid); + } + break; + } + + return hr; +} + +HRESULT CScene_MultiGameInfo::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK); + + return S_OK; +} + +HRESULT CScene_MultiGameInfo::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + if(pNotifySelChangedData->iOldItem!=-1) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + bHandled = TRUE; + + return S_OK; +} + +HRESULT CScene_MultiGameInfo::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + if( playersList.TreeHasFocus() && playersList.GetItemCount() > 0 ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1, IDS_TOOLTIPS_BACK, -1, IDS_TOOLTIPS_VIEW_GAMERCARD ); + bHandled = TRUE; + } + return S_OK; +} + +HRESULT CScene_MultiGameInfo::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + if( pNotifyFocusData->hObjOther == m_JoinGame ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK ); + bHandled = TRUE; + } + return S_OK; +} + +int CScene_MultiGameInfo::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_MultiGameInfo* pClass = (CScene_MultiGameInfo*)pParam; + + if(bContinue==true) + { + // It's possible that the player has not signed in - they can back out + if(ProfileManager.IsSignedIn(iPad)) + { + JoinGame(pClass); + } + } + else + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + } + return 0; +} + +// Shared function to join the game that is the same whether we used the sign-in UI or not +void CScene_MultiGameInfo::JoinGame(CScene_MultiGameInfo* pClass) +{ + DWORD dwLocalUsersMask = 0; + bool noPrivileges = false; + DWORD dwSignedInUsers = 0; + + // if we're in SD mode, then only the primary player gets to play + if(RenderManager.IsHiDef()) + { + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + ++dwSignedInUsers; + if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); + } + } + } + else + { + if(ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad()) ) + { + ++dwSignedInUsers; + if( !ProfileManager.AllowedToPlayMultiplayer(ProfileManager.GetPrimaryPad()) ) noPrivileges = true; + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); + } + } + + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; + + if(noUGC) + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + int messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + if(dwSignedInUsers > 1) messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + + StorageManager.RequestMessageBox( IDS_CONNECTION_FAILED, messageText, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + + } + else if(noPrivileges) + { + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + CGameNetworkManager::eJoinGameResult result = g_NetworkManager.JoinGame( pClass->m_selectedSession, dwLocalUsersMask ); + + // Alert the app the we no longer want to be informed of ethernet connections + app.SetLiveLinkRequired( false ); + + if( result != CGameNetworkManager::JOINGAME_SUCCESS ) + { + int exitReasonStringId = -1; + switch(result) + { + case CGameNetworkManager::JOINGAME_FAIL_SERVER_FULL: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + break; + } + + if( exitReasonStringId == -1 ) + { + app.NavigateBack(ProfileManager.GetPrimaryPad()); + } + else + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox( IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + exitReasonStringId = -1; + + app.NavigateToHomeMenu(); + } + } + } +} + +HRESULT CScene_MultiGameInfo::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + if ( pTimer->nId == UPDATE_PLAYERS_TIMER_ID) + { + PlayerUID selectedPlayerXUID = m_selectedSession->data.players[playersList.GetCurSel()]; + + bool success = g_NetworkManager.GetGameSessionInfo(m_iPad, m_selectedSession->sessionId,m_selectedSession); + + if( success ) + { + playersList.DeleteItems(0, playersList.GetItemCount()); + int selectedIndex = 0; + for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) + { + if( m_selectedSession->data.players[i] != NULL ) + { + if(m_selectedSession->data.players[i] == selectedPlayerXUID) selectedIndex = i; + playersList.InsertItems(i,1); +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + playersList.SetText(i, L"WWWWWWWWWWWWWWWW" ); + } + else +#endif + { + playersList.SetText(i, convStringToWstring( m_selectedSession->data.szPlayers[i] ).c_str() ); + } + } + else + { + // Leave the loop when we hit the first NULL player + break; + } + } + playersList.SetCurSel(selectedIndex); + } + } + + return S_OK; +} + + diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.h b/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.h new file mode 100644 index 00000000..9664640b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameInfo.h @@ -0,0 +1,85 @@ +#pragma once +using namespace std; +#include <vector> +#include <qnet.h> +#include "..\Media\xuiscene_multi_gameinfo.h" + +class FriendSessionInfo; + +class CScene_MultiGameInfo : public CXuiSceneImpl +{ +protected: + CXuiList playersList; + CXuiControl m_JoinGame; + CXuiControl m_GameSettingsGroup; + CXuiControl m_difficulty, m_GameType, m_gamertagsOn, m_structuresOn, m_levelType, m_pvpOn, m_trustPlayers, m_tntOn, m_fireOn; + CXuiControl m_labelDifficulty, m_labelGameType, m_labelGamertagsOn, m_labelStructuresOn, m_labelLevelType, m_labelPvP, m_labelTrust, m_labelTNTOn, m_labelFireOn; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_NOTIFY_SELCHANGED(OnNotifySelChanged) + XUI_ON_XM_NOTIFY_SET_FOCUS(OnNotifySetFocus) + XUI_ON_XM_NOTIFY_KILL_FOCUS(OnNotifyKillFocus) + XUI_ON_XM_TIMER(OnTimer) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_JoinGame, m_JoinGame) + MAP_CONTROL(IDC_GamePlayers, playersList) + + MAP_CONTROL(IDC_GameSettings, m_GameSettingsGroup) + BEGIN_MAP_CHILD_CONTROLS(m_GameSettingsGroup) + MAP_CONTROL(IDC_GamertagsOn, m_gamertagsOn) + MAP_CONTROL(IDC_StructuresOn, m_structuresOn) + MAP_CONTROL(IDC_Difficulty, m_difficulty) + MAP_CONTROL(IDC_GameType, m_GameType) + MAP_CONTROL(IDC_LevelType, m_levelType) + MAP_CONTROL(IDC_PvP, m_pvpOn) + MAP_CONTROL(IDC_Trust, m_trustPlayers) + MAP_CONTROL(IDC_TNTOn, m_tntOn) + MAP_CONTROL(IDC_FireOn, m_fireOn) + + MAP_CONTROL(IDC_LabelGamertagsOn, m_labelGamertagsOn) + MAP_CONTROL(IDC_LabelStructuresOn, m_labelStructuresOn) + MAP_CONTROL(IDC_LabelDifficulty, m_labelDifficulty) + MAP_CONTROL(IDC_LabelGameType, m_labelGameType) + MAP_CONTROL(IDC_LabelLevelType, m_labelLevelType) + MAP_CONTROL(IDC_LabelPvP, m_labelPvP) + MAP_CONTROL(IDC_LabelTrust, m_labelTrust) + MAP_CONTROL(IDC_LabelTNTOn, m_labelTNTOn) + MAP_CONTROL(IDC_LabelFireOn, m_labelFireOn) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled); + HRESULT OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_MultiGameInfo, L"CScene_MultiGameInfo", XUI_CLASS_SCENE ) + + + +protected: + FriendSessionInfo *m_selectedSession; + unsigned char m_localPlayers; + bool m_bIgnoreInput; + int m_iPad; + + static int StartGame_SignInReturned(void *pParam,bool bContinue, int iPad); + static void JoinGame(CScene_MultiGameInfo* pClass); + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.cpp b/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.cpp new file mode 100644 index 00000000..73f25da5 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.cpp @@ -0,0 +1,2767 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include <assert.h> +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" +#include "..\..\LocalPlayer.h" +#include "..\..\Minecraft.h" +#include "..\..\ProgressRenderer.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\ArrayWithLength.h" +#include "..\..\..\Minecraft.World\File.h" +#include "..\..\..\Minecraft.World\InputOutputStream.h" +#include "XUI_Ctrl_4JList.h" +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_LoadSettings.h" +#include "XUI_MultiGameInfo.h" +#include "XUI_MultiGameJoinLoad.h" +#include "XUI_MultiGameCreate.h" +#include "..\..\MinecraftServer.h" +#include "..\..\Options.h" + +#include "..\GameRules\LevelGenerationOptions.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" +#include "..\..\..\Minecraft.World\LevelSettings.h" + +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID 3 +#define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 100 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameJoinLoad::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + + m_iPad=*(int *)pInitData->pvInitData; + m_bReady=false; + MapChildControls(); + + m_iTexturePacksNotInstalled=0; + m_iConfigA=NULL; + + XuiControlSetText(m_LabelNoGames,app.GetString(IDS_NO_GAMES_FOUND)); + XuiControlSetText(m_GamesList,app.GetString(IDS_JOIN_GAME)); + XuiControlSetText(m_SavesList,app.GetString(IDS_START_GAME)); + + + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + swprintf(szResourceLocator, LOCATOR_SIZE ,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/TexturePackIcon.png"); + + m_DefaultMinecraftIconSize = 0; + HRESULT hr = XuiResourceLoadAllNoLoc(szResourceLocator, &m_DefaultMinecraftIconData, &m_DefaultMinecraftIconSize); + + m_localPlayers = 1; + m_bKillSaveInfoEnumerate=false; + + m_bShowingPartyGamesOnly = false; + + m_bRetrievingSaveInfo=false; + m_bSaveTransferInProgress=false; + + // check for a default custom cloak in the global storage + // 4J-PB - changed to a config file +// if(ProfileManager.IsSignedInLive( m_iPad )) +// { +// app.InstallDefaultCape(); +// } + + m_initData= new JoinMenuInitData(); + m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + + XPARTY_USER_LIST partyList; + + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + m_bInParty=true; + } + else + { + m_bInParty=false; + } + + int iLB = -1; + if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; + + XuiSetTimer(m_hObj,JOIN_LOAD_ONLINE_TIMER_ID,JOIN_LOAD_ONLINE_TIMER_TIME); + + m_iSaveInfoC=0; + + VOID *pObj; + XuiObjectFromHandle( m_SavesList, &pObj ); + m_pSavesList = (CXuiCtrl4JList *)pObj; + + XuiObjectFromHandle( m_GamesList, &pObj ); + m_pGamesList = (CXuiCtrl4JList *)pObj; + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==true) + { + // not doing a mount, so enable input + m_bIgnoreInput=true; + } + else + { + // if we're waiting for DLC to mount, don't fill the save list. The custom message on end of dlc mounting will do that + m_bIgnoreInput=false; + + + + m_iChangingSaveGameInfoIndex = 0; + + m_generators = app.getLevelGenerators(); + m_iDefaultButtonsC = 0; + m_iMashUpButtonsC=0; + + // check if we're in the trial version + if(ProfileManager.IsFullVersion()==false) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); + + AddDefaultButtons(); + + m_pSavesList->SetCurSelVisible(0); + } + else if(StorageManager.GetSaveDisabled()) + { + if(StorageManager.GetSaveDeviceSelected(m_iPad)) + { + // saving is disabled, but we should still be able to load from a selected save device + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,-1,-1,-1,iLB,IDS_TOOLTIPS_DELETESAVE); + + GetSaveInfo(); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,-1,-1,-1,iLB); + + AddDefaultButtons(); + m_SavesListTimer.SetShow( FALSE ); + + m_pSavesList->SetCurSelVisible(0); + } + } + else + { + // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) + bool bCanRename = StorageManager.EnoughSpaceForAMinSaveGame(); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,-1,-1,-1,-1,bCanRename?IDS_TOOLTIPS_SAVEOPTIONS:IDS_TOOLTIPS_DELETESAVE); + + GetSaveInfo(); + } + } + //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); + + UpdateGamesList(); + + g_NetworkManager.SetSessionsUpdatedCallback( &CScene_MultiGameJoinLoad::UpdateGamesListCallback, this ); + + // 4J Stu - Fix for #12530 -TCR 001 BAS Game Stability: Title will crash if the player disconnects while starting a new world and then opts to play the tutorial once they have been returned to the Main Menu. + MinecraftServer::resetFlags(); + + // If we're not ignoring input, then we aren't still waiting for the DLC to mount, and can now check for corrupt dlc. Otherwise this will happen when the dlc has finished mounting. + if( !m_bIgnoreInput) + { + app.m_dlcManager.checkForCorruptDLCAndAlert(); + } + + + // 4J-PB - Load up any texture pack data we have locally in the XZP + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.LoadLocalTMSFile(app.TMSFileA[i].wchFilename,app.TMSFileA[i].eEXT); + app.AddMemoryTPDFile(app.TMSFileA[i].iConfig, app.TMSFileA[i].pbData,app.TMSFileA[i].uiSize); + } + } + + // 4J-PB - there may be texture packs we don't have, so use the info from TMS for this + + DLC_INFO *pDLCInfo=NULL; + + // first pass - look to see if there are any that are not in the list + bool bTexturePackAlreadyListed; + bool bNeedToGetTPD=false; + Minecraft *pMinecraft = Minecraft::GetInstance(); + int texturePacksCount = pMinecraft->skins->getTexturePackCount(); + //CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + //HRESULT hr; + + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + // some missing + bNeedToGetTPD=true; + + m_iTexturePacksNotInstalled++; + } + } + + if(bNeedToGetTPD==true) + { + // add a TMS request for them + app.DebugPrintf("+++ Adding TMSPP request for texture pack data\n"); + app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); + m_iConfigA= new int [m_iTexturePacksNotInstalled]; + m_iTexturePacksNotInstalled=0; + + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + bTexturePackAlreadyListed=false; + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + for(unsigned int i = 0; i < texturePacksCount; ++i) + { + TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); + if(pDLCInfo->iConfig==tp->getDLCParentPackId()) + { + bTexturePackAlreadyListed=true; + } + } + if(bTexturePackAlreadyListed==false) + { + m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; + } + } + } + + XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); + + return S_OK; +} + +void CScene_MultiGameJoinLoad::AddDefaultButtons() +{ + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + + // Add two for New Game and Tutorial + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + ListInfo.pwszText = app.GetString(IDS_CREATE_NEW_WORLD); + ListInfo.fEnabled = TRUE; + ListInfo.iData = -1; + m_pSavesList->AddData(ListInfo); + + int iSavesListIndex = 0; + int iGeneratorIndex = 0; + m_iMashUpButtonsC=0; + + for(AUTO_VAR(it, m_generators->begin()); it != m_generators->end(); ++it) + { + LevelGenerationOptions *levelGen = *it; + ListInfo.pwszText = levelGen->getWorldName(); + ListInfo.fEnabled = TRUE; + ListInfo.iData = iGeneratorIndex++; // used to index into the list of generators + + // need to check if the user has disabled this pack in the save display list + unsigned int uiTexturePackID=levelGen->getRequiredTexturePackId(); + + if(uiTexturePackID!=0) + { + unsigned int uiMashUpWorldsBitmask=app.GetMashupPackWorlds(m_iPad); + + if((uiMashUpWorldsBitmask & (1<<(uiTexturePackID-1024)))==0) + { + // this world is hidden, so skip + continue; + } + } + m_pSavesList->AddData(ListInfo); + + // retrieve the save icon from the texture pack, if there is one + if(uiTexturePackID!=0) + { + // increment the count of the mash-up pack worlds in the save list + m_iMashUpButtonsC++; + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(levelGen->getRequiredTexturePackId()); + DWORD dwImageBytes; + PBYTE pbImageData = tp->getPackIcon(dwImageBytes); + HXUIBRUSH hXuiBrush; + + if(dwImageBytes > 0 && pbImageData) + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); + // the index inside the list item for this will be i+1 because they start at m_vListData.size(), so the first etry (tutorial) is 1 + m_pSavesList->UpdateGraphic(iSavesListIndex+1,hXuiBrush); + } + } + + ++iSavesListIndex; + } + + m_iDefaultButtonsC = iSavesListIndex + 1; +} + + +HRESULT CScene_MultiGameJoinLoad::GetSaveInfo( ) +{ + unsigned int uiSaveC=0; + + // This will return with the number retrieved in uiSaveC + + if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) + { + uiSaveC = 0; + File savesDir(L"GAME:\\Saves"); + if( savesDir.exists() ) + { + m_saves = savesDir.listFiles(); + uiSaveC = (unsigned int)m_saves->size(); + } + // add the New Game and Tutorial after the saves list is retrieved, if there are any saves + + // Add two for New Game and Tutorial + unsigned int listItems = uiSaveC; + + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + AddDefaultButtons(); + + for(unsigned int i=0;i<listItems;i++) + { + + wstring wName = m_saves->at(i)->getName(); + wchar_t *name = new wchar_t[wName.size()+1]; + for(unsigned int j = 0; j < wName.size(); ++j) + { + name[j] = wName[j]; + } + name[wName.size()] = 0; + ListInfo.pwszText = name; + ListInfo.fEnabled=TRUE; + ListInfo.iData = -1; + m_pSavesList->AddData(ListInfo); + } + m_pSavesList->SetCurSelVisible(0); + } + else + { + m_bRetrievingSaveInfo=true; // we're blocking the exit from this scene until complete + + // clear the saves list + m_pSavesList->RemoveAllData(); + + m_iSaveInfoC=0; +#ifdef _XBOX + C4JStorage::ESGIStatus eSGIStatus=StorageManager.GetSavesInfo(ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::GetSavesInfoCallback,this,"savegame.dat"); + + if(eSGIStatus==C4JStorage::ESGIStatus_NoSaves) + { + uiSaveC=0; + m_SavesListTimer.SetShow( FALSE ); + m_SavesList.SetEnable(TRUE); + } +#else + + //C4JStorage::ESaveGameState eStatus=StorageManager.GetSavesInfo(ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::GetSavesInfoCallback,this,"savegame.dat"); + +#endif + } + + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnDestroy() +{ + g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL ); + + for(AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) + { + delete (*it); + } + + if(m_bSaveTransferInProgress) + { + CancelSaveUploadCallback(this); + } + + // Reset the background downloading, in case we changed it by attempting to download a texture pack + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + + // clear out the texture pack data + for(int i=0;i<TMS_COUNT;i++) + { + if(app.TMSFileA[i].eTMSType==eTMSFileType_TexturePack) + { + app.RemoveMemoryTPDFile(app.TMSFileA[i].iConfig); + } + } + app.FreeLocalTMSFiles(eTMSFileType_TexturePack); + + return S_OK; +} + + +int CScene_MultiGameJoinLoad::DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(ProfileManager.GetPrimaryPad(),false); + // use the device select returned function to wipe the saves list and change the tooltip + CScene_MultiGameJoinLoad::DeviceSelectReturned(pClass,true); + } + else // continue without saving + { + // Change device + StorageManager.SetSaveDevice(&CScene_MultiGameJoinLoad::DeviceSelectReturned,pClass,true); + } + + pClass->m_bIgnoreInput=false; + return 0; +} +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameJoinLoad::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // if we're retrieving save info, ignore key presses + if(m_bRetrievingSaveInfo) + { + return S_OK; + } + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if ( hObjPressed == m_GamesList ) + { + m_bIgnoreInput=true; + + DWORD nIndex = m_pGamesList->GetCurSel(); + + if( m_pGamesList->GetItemCount() > 0 && nIndex < currentSessions.size() ) + { + //CScene_MultiGameInfo::JoinMenuInitData *initData = new CScene_MultiGameInfo::JoinMenuInitData(); + m_initData->iPad = m_iPad; + m_initData->selectedSession = currentSessions.at( nIndex ); + + // check that we have the texture pack available + // If it's not the default texture pack + if(m_initData->selectedSession->data.texturePackParentId!=0) + { + int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount(); + bool bHasTexturePackInstalled=false; + + for(int i=0;i<texturePacksCount;i++) + { + TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackByIndex(i); + if(tp->getDLCParentPackId()==m_initData->selectedSession->data.texturePackParentId) + { + bHasTexturePackInstalled=true; + break; + } + } + + if(bHasTexturePackInstalled==false) + { + // upsell the texture pack + // tell sentient about the upsell of the full version of the skin pack + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full); + + TelemetryManager->RecordUpsellPresented(pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[3]; + + // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + uiIDA[2]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::TexturePackDialogReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_CONFIRM_CANCEL; + // Give the player a warning about the texture pack missing + StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::TexturePackDialogReturned,this,app.GetStringTable()); + } + + return S_OK; + } + } + + m_NetGamesListTimer.SetShow( FALSE ); + + // Reset the background downloading, in case we changed it by attempting to download a texture pack + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + + // kill the texture pack check timer + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_JoinMenu,m_initData); + } + } + else if(hObjPressed==m_SavesList) + { + m_bIgnoreInput=true; + + CXuiControl pItem; + int iIndex; + // get the selected item + iIndex=m_SavesList.GetCurSel(&pItem); + + CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesList->GetData(iIndex); + + if(iIndex == JOIN_LOAD_CREATE_BUTTON_INDEX) + { + app.SetTutorialMode( false ); + m_NetGamesListTimer.SetShow( FALSE ); + + app.SetCorruptSaveDeleted(false); + + CreateWorldMenuInitData *params = new CreateWorldMenuInitData(); + params->iPad = m_iPad; + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_CreateWorldMenu,(void *)params); + } + else if(info.iData >= 0) + { + LevelGenerationOptions *levelGen = m_generators->at(info.iData); + app.SetTutorialMode( levelGen->isTutorial() ); + // Reset the autosave time + app.SetAutosaveTimerTime(); + + if(levelGen->isTutorial()) + { + LoadLevelGen(levelGen); + } + else + { + LoadMenuInitData *params = new LoadMenuInitData(); + params->iPad = m_iPad; + // need to get the iIndex from the list item, since the position in the list doesn't correspond to the GetSaveGameInfo list because of sorting + params->iSaveGameInfoIndex=-1; + //params->pbSaveRenamed=&m_bSaveRenamed; + params->levelGen = levelGen; + + // navigate to the settings scene + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadMenu, params); + } + } + else + { + // check if this is a damaged save + if(m_pSavesList->GetData(iIndex).bIsDamaged) + { + // give the option to delete the save + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE, IDS_CORRUPT_OR_DAMAGED_SAVE_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); + } + else + { + app.SetTutorialMode( false ); + if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) + { + LoadSaveFromDisk(m_saves->at(iIndex-m_iDefaultButtonsC)); + } + else + { + LoadMenuInitData *params = new LoadMenuInitData(); + params->iPad = m_iPad; + // need to get the iIndex from the list item, since the position in the list doesn't correspond to the GetSaveGameInfo list because of sorting + params->iSaveGameInfoIndex=m_pSavesList->GetData(iIndex).iIndex-m_iDefaultButtonsC; + //params->pbSaveRenamed=&m_bSaveRenamed; + params->levelGen = NULL; + + // kill the texture pack timer + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + // navigate to the settings scene + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadMenu, params); + } + } + } + } + + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // if we're retrieving save info, ignore key presses + if(m_bRetrievingSaveInfo) + { + return S_OK; + } + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr = S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + m_NetGamesListTimer.SetShow( FALSE ); + + app.NavigateBack(XUSER_INDEX_ANY); + rfHandled = TRUE; + break; + case VK_PAD_X: + + // Change device + // Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage + // device, and repeatedly backs out of the SD screen, disconnects from LIVE, and then selects a SD, the title crashes. + m_bIgnoreInput=true; + StorageManager.SetSaveDevice(&CScene_MultiGameJoinLoad::DeviceSelectReturned,this,true); + CXuiSceneBase::PlayUISFX(eSFX_Press); + break; + case VK_PAD_Y: + if(m_pGamesList->TreeHasFocus() && m_pGamesList->GetItemCount() > 0) + { + DWORD nIndex = m_pGamesList->GetCurSel(); + FriendSessionInfo *pSelectedSession = currentSessions.at( nIndex ); + + PlayerUID xuid = pSelectedSession->data.hostPlayerUID; + if( xuid != INVALID_XUID ) + hr = XShowGamerCardUI(ProfileManager.GetLockedProfile(), xuid); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + else if(DoesSavesListHaveFocus()) + { + // save transfer - make sure they want to overwrite a save that is up there + if(ProfileManager.IsSignedInLive( m_iPad )) + { + // 4J-PB - required for a delete of the save if it's found to be a corrupted save + DWORD nIndex = m_pSavesList->GetCurSel(); + m_iChangingSaveGameInfoIndex=m_pSavesList->GetData(nIndex).iIndex; + + UINT uiIDA[2]; + uiIDA[0]=IDS_UPLOAD_SAVE; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + ui.RequestMessageBox(IDS_SAVE_TRANSFER_TITLE, IDS_SAVE_TRANSFER_TEXT, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::SaveTransferDialogReturned,this, app.GetStringTable()); + } + } + break; + case VK_PAD_RSHOULDER: + if(DoesSavesListHaveFocus()) + { + m_bIgnoreInput = true; + + int iIndex=m_SavesList.GetCurSel(); + m_iChangingSaveGameInfoIndex=m_pSavesList->GetData(iIndex).iIndex; + + // Could be delete save or Save Options + if(StorageManager.GetSaveDisabled()) + { + // delete the save game + // Have to ask the player if they are sure they want to delete this game + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + UINT uiIDA[3]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_TITLE_RENAMESAVE; + uiIDA[2]=IDS_TOOLTIPS_DELETESAVE; + StorageManager.RequestMessageBox(IDS_TOOLTIPS_SAVEOPTIONS, IDS_TEXT_SAVEOPTIONS, uiIDA, 3, pInputData->UserIndex,&CScene_MultiGameJoinLoad::SaveOptionsDialogReturned,this, app.GetStringTable()); + } + else + { + // delete the save game + // Have to ask the player if they are sure they want to delete this game + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); + } + } + CXuiSceneBase::PlayUISFX(eSFX_Press); + + } + else if(DoesMashUpWorldHaveFocus()) + { + // hiding a mash-up world + // get the mash-up pack id + CXuiControl pItem; + int iIndex; + iIndex=m_SavesList.GetCurSel(&pItem); + + CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesList->GetData(iIndex); + if((iIndex != JOIN_LOAD_CREATE_BUTTON_INDEX) && (info.iData >= 0)) + { + LevelGenerationOptions *levelGen = m_generators->at(info.iData); + + if(!levelGen->isTutorial()) + { + if(levelGen->requiresTexturePack()) + { + unsigned int uiPackID=levelGen->getRequiredTexturePackId(); + + m_bIgnoreInput = true; + app.HideMashupPackWorld(m_iPad,uiPackID); + + // update the saves list + m_pSavesList->RemoveAllData(); + m_iSaveInfoC=0; + GetSaveInfo(); + m_bIgnoreInput = false; + } + } + } + + CXuiSceneBase::PlayUISFX(eSFX_Press); + + } + break; + case VK_PAD_LSHOULDER: + if( m_bInParty ) + { + m_bShowingPartyGamesOnly = !m_bShowingPartyGamesOnly; + UpdateGamesList(); + CXuiSceneBase::PlayUISFX(eSFX_Press); + } + break; + } + + return hr; +} + +HRESULT CScene_MultiGameJoinLoad::OnNavReturn(HXUIOBJ hSceneFrom,BOOL& rfHandled) +{ + + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + // start the texture pack timer again + XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); + + m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + + // re-enable button presses + m_bIgnoreInput=false; + + if( m_bMultiplayerAllowed ) + { + HXUICLASS hClassFullscreenProgress = XuiFindClass( L"CScene_FullscreenProgress" ); + HXUICLASS hClassConnectingProgress = XuiFindClass( L"CScene_ConnectingProgress" ); + + // If we are navigating back from a full screen progress scene, then that means a connection attempt failed + if( XuiIsInstanceOf( hSceneFrom, hClassFullscreenProgress ) || XuiIsInstanceOf( hSceneFrom, hClassConnectingProgress ) ) + { + UpdateGamesList(); + } + } + else + { + m_pGamesList->RemoveAllData(); + //m_GamesList.DeleteItems(0, m_GamesList.GetItemCount() ); + m_pGamesList->SetEnable(FALSE); + //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); + m_NetGamesListTimer.SetShow( TRUE ); + m_LabelNoGames.SetShow( FALSE ); + m_SavesList.InitFocus(m_iPad); + } + + // are we back here because of a delete of a corrupt save? + + if(app.GetCorruptSaveDeleted()) + { + // need to re-get the saves list and update the display + // clear the saves list + m_pSavesList->RemoveAllData(); + m_iSaveInfoC=0; + GetSaveInfo(); + app.SetCorruptSaveDeleted(false); + } + + int iY = -1; + int iRB=-1; + if( DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) + + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + + } + } + } + else if(DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1,-1,-1,iLB); + } + else if(StorageManager.GetSaveDisabled()) + { + // clear out the saves list, since the disable save may have happened in the load screen because of a device removal + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); + } + + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + + if(m_bReady) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + + return S_OK; +} + + +HRESULT CScene_MultiGameJoinLoad::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || + pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) + { + // 4J Stu - We may have had to unload our font renderer in this scene if one of the save files + // uses characters not in our font (eg asian chars) so restore our font renderer + // This will not do anything if our font renderer is already loaded + app.OverrideFontRenderer(true,true); + + KillTimer(JOIN_LOAD_ONLINE_TIMER_ID); + } + else if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + SetTimer(JOIN_LOAD_ONLINE_TIMER_ID,JOIN_LOAD_ONLINE_TIMER_TIME); + // 4J-PB - Need to check for installed DLC, which might have happened while you were on the info scene + if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // Can't call this here because if you back out of the load info screen and then go back in and load a game, it will attempt to use the dlc as it's running a mount of the dlc + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + m_pSavesList->RemoveAllData(); + m_SavesListTimer.SetShow( TRUE ); + } + } + } + + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnFontRendererChange() +{ + // update the tooltips + // if the saves list has focus, then we should show the Delete Save tooltip + // if the games list has focus, then we should the the View Gamercard tooltip + int iRB=-1; + int iY = -1; + if( DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + } + else if(DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1,-1,true); + } + else if(StorageManager.GetSaveDisabled()) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB,-1,true); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB,-1,true); + } + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + // update the tooltips + // if the saves list has focus, then we should show the Delete Save tooltip + // if the games list has focus, then we should the the View Gamercard tooltip + int iRB=-1; + int iY = -1; + if( DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + } + else if(DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1); + } + else if(StorageManager.GetSaveDisabled()) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); + } + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + return S_OK; +} + +bool CScene_MultiGameJoinLoad::DoesSavesListHaveFocus() +{ + HXUIOBJ hParentObj,hObj=TreeGetFocus(); + + if(hObj!=NULL) + { + // get the parent and see if it's the saves list + XuiElementGetParent(hObj,&hParentObj); + if(hParentObj==m_SavesList.m_hObj) + { + // check it's not the first or second element (new world or tutorial) + if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC-1)) + { + return true; + } + } + } + return false; +} + +bool CScene_MultiGameJoinLoad::DoesMashUpWorldHaveFocus() +{ + HXUIOBJ hParentObj,hObj=TreeGetFocus(); + + if(hObj!=NULL) + { + // get the parent and see if it's the saves list + XuiElementGetParent(hObj,&hParentObj); + if(hParentObj==m_SavesList.m_hObj) + { + // check it's not the first or second element (new world or tutorial) + if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC-1)) + { + return false; + } + + if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC - 1 - m_iMashUpButtonsC)) + { + return true; + } + else return false; + } + else return false; + } + return false; +} + +bool CScene_MultiGameJoinLoad::DoesGamesListHaveFocus() +{ + HXUIOBJ hParentObj,hObj=TreeGetFocus(); + + if(hObj!=NULL) + { + // get the parent and see if it's the saves list + XuiElementGetParent(hObj,&hParentObj); + if(hParentObj==m_pGamesList->m_hObj) + { + return true; + } + } + return false; +} + +void CScene_MultiGameJoinLoad::UpdateGamesListCallback(LPVOID lpParam) +{ + if(lpParam != NULL) + { + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; + // check this there's no save transfer in progress + if(!pClass->m_bSaveTransferInProgress) + { + pClass->UpdateGamesList(); + } + } +} + +void CScene_MultiGameJoinLoad::UpdateGamesList() +{ + if( m_bIgnoreInput ) return; + + // if we're retrieving save info, don't show the list yet as we will be ignoring press events + if(m_bRetrievingSaveInfo) + { + return; + } + + DWORD nIndex = -1; + FriendSessionInfo *pSelectedSession = NULL; + if(m_pGamesList->TreeHasFocus() && m_pGamesList->GetItemCount() > 0) + { + nIndex = m_pGamesList->GetCurSel(); + pSelectedSession = currentSessions.at( nIndex ); + } + + SessionID selectedSessionId; + if( pSelectedSession != NULL )selectedSessionId = pSelectedSession->sessionId; + pSelectedSession = NULL; + + for(AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) + { + delete (*it); + } + currentSessions.clear(); + + m_NetGamesListTimer.SetShow( FALSE ); + + // if the saves list has focus, then we should show the Delete Save tooltip + // if the games list has focus, then we should show the View Gamercard tooltip + int iRB=-1; + int iY = -1; + + if( DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + } + else if(DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1); + } + else if(StorageManager.GetSaveDisabled()) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); + } + + currentSessions = *g_NetworkManager.GetSessionList( m_iPad, m_localPlayers, m_bShowingPartyGamesOnly ); + + // Update the xui list displayed + unsigned int xuiListSize = m_pGamesList->GetItemCount(); + unsigned int filteredListSize = (unsigned int)currentSessions.size(); + + BOOL gamesListHasFocus = m_pGamesList->TreeHasFocus(); + + if(filteredListSize > 0) + { + if( !m_pGamesList->IsEnabled() ) + { + m_pGamesList->SetEnable(TRUE); + //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, FALSE); + m_pGamesList->SetCurSel( 0 ); + } + m_LabelNoGames.SetShow( FALSE ); + m_NetGamesListTimer.SetShow( FALSE ); + } + else + { + m_pGamesList->SetEnable(FALSE); + //XuiElementSetDisableFocusRecursion(m_pGamesList->m_hObj, TRUE); + m_NetGamesListTimer.SetShow( FALSE ); + m_LabelNoGames.SetShow( TRUE ); + + if( gamesListHasFocus ) m_pGamesList->InitFocus(m_iPad); + } + + // clear out the games list and re-fill + m_pGamesList->RemoveAllData(); + + if( filteredListSize > 0 ) + { + // Reset the focus to the selected session if it still exists + unsigned int sessionIndex = 0; + m_pGamesList->SetCurSel(0); + + for( AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) + { + FriendSessionInfo *sessionInfo = *it; + HXUIBRUSH hXuiBrush; + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + ListInfo.pwszText = sessionInfo->displayLabel; + ListInfo.fEnabled = TRUE; + ListInfo.iData = sessionIndex; + m_pGamesList->AddData(ListInfo); + // display an icon too + + // Is this a default game or a texture pack game? + if(sessionInfo->data.texturePackParentId!=0) + { + // Do we have the texture pack + Minecraft *pMinecraft = Minecraft::GetInstance(); + TexturePack *tp = pMinecraft->skins->getTexturePackById(sessionInfo->data.texturePackParentId); + HRESULT hr; + + DWORD dwImageBytes=0; + PBYTE pbImageData=NULL; + + if(tp==NULL) + { + DWORD dwBytes=0; + PBYTE pbData=NULL; + app.GetTPD(sessionInfo->data.texturePackParentId,&pbData,&dwBytes); + + // is it in the tpd data ? + app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbImageData,&dwImageBytes ); + if(dwImageBytes > 0 && pbImageData) + { + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); + m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); + } + } + else + { + pbImageData = tp->getPackIcon(dwImageBytes); + if(dwImageBytes > 0 && pbImageData) + { + hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); + m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); + } + } + } + else + { + // default texture pack + XuiCreateTextureBrushFromMemory(m_DefaultMinecraftIconData,m_DefaultMinecraftIconSize,&hXuiBrush); + m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); + } + + + if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) + { + m_pGamesList->SetCurSel(sessionIndex); + break; + } + ++sessionIndex; + } + } +} + +void CScene_MultiGameJoinLoad::UpdateGamesList(DWORD dwNumResults, IQNetGameSearch *pGameSearch) +{ + // We don't use the QNet callback, but could resurrect this if we ever do normal matchmaking, but updated to work as the function above +#if 0 + const XSESSION_SEARCHRESULT *pSearchResult; + const XNQOSINFO * pxnqi; + + if(m_searches>0) + --m_searches; + + if(m_searches==0) + { + m_NetGamesListTimer.SetShow( FALSE ); + + // if the saves list has focus, then we should show the Delete Save tooltip + // if the games list has focus, then we should show the View Gamercard tooltip + int iRB=-1; + int iY = -1; + + if( DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(DoesSavesListHaveFocus()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,iRB); + } + else if(StorageManager.GetSaveDisabled()) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); + } + } + + if( dwNumResults == 0 ) + { + if(m_searches==0 && m_GamesList.GetItemCount() == 0) + { + m_LabelNoGames.SetShow( TRUE ); + } + return; + } + + unsigned int startOffset = m_GamesList.GetItemCount(); + //m_GamesList.InsertItems(startOffset,dwNumResults); + //m_GamesList.SetEnable(TRUE); + //XuiElementSetDisableFocusRecursion( m_GamesList.m_hObj, FALSE); + + // Loop through all the results. + for( DWORD dwResult = 0; dwResult < pGameSearch->GetNumResults(); dwResult++ ) + { + + pSearchResult = pGameSearch->GetSearchResultAtIndex( dwResult ); + + // No room for us, so ignore it + if(pSearchResult->dwOpenPublicSlots < m_localPlayers) + continue; + + FriendSessionInfo *sessionInfo = NULL; + bool foundSession = false; + for(AUTO_VAR(it, friendsSessions.begin()); it < friendsSessions.end(); ++it) + { + sessionInfo = *it; + if(memcmp( &pSearchResult->info.sessionID, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) + { + sessionInfo->searchResult = *pSearchResult; + sessionInfo->displayLabel = new wchar_t[100]; + foundSession = true; + break; + } + } + + // We received a search result for a session no longer in our list of friends sessions + if(!foundSession) + continue; + + // Print some info about this result. + //printf( "Search result %u:\n", dwResult ); + //printf( " public slots open = %u, filled = %u\n", pSearchResult->dwOpenPublicSlots, pSearchResult->dwFilledPublicSlots ); + //printf( " private slots open = %u, filled = %u\n", pSearchResult->dwOpenPrivateSlots, pSearchResult->dwFilledPrivateSlots ); + + // See if this result was contacted successfully via QoS probes. + pxnqi = pGameSearch->GetQosInfoAtIndex( dwResult ); + if( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) + { + // Print the round trip time and the rough estimation of + // bandwidth. + app.DebugPrintf( " RTT min = %u, med = %u\n", pxnqi->wRttMinInMsecs, pxnqi->wRttMedInMsecs ); + app.DebugPrintf( " bps up = %u, down = %u\n", pxnqi->dwUpBitsPerSec, pxnqi->dwDnBitsPerSec ); + + if(pxnqi->cbData > 0) + { + sessionInfo->data = *(GameSessionData *)pxnqi->pbData; + + wstring gamerName = convStringToWstring(sessionInfo->data.hostName); + swprintf(sessionInfo->displayLabel,L"%ls's Game", gamerName.c_str() ); + } + else + { + swprintf(sessionInfo->displayLabel,L"Unknown host Game"); + } + + // If this host wasn't disabled use this one. + if( !( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) && sessionInfo->data.netVersion == MINECRAFT_NET_VERSION ) + { + //printf("This game is valid\n"); + filteredResults.push_back(sessionInfo); + m_GamesList.InsertItems(startOffset,1); + m_GamesList.SetText(startOffset,sessionInfo->displayLabel); + startOffset++; + } +#ifndef _CONTENT_PACKAGE + if( sessionInfo->data.netVersion != MINECRAFT_NET_VERSION ) + { + wprintf(L"%ls version of %d does not match our version of %d\n", sessionInfo->displayLabel, sessionInfo->data.netVersion, MINECRAFT_NET_VERSION); + } +#endif + } + } + + if( m_GamesList.GetItemCount() == 0) + { + m_LabelNoGames.SetShow( TRUE ); + } + else + { + m_GamesList.SetEnable(TRUE); + XuiElementSetDisableFocusRecursion( m_GamesList.m_hObj, FALSE); + if( DoesGamesListHaveFocus() ) + { + m_GamesList.SetCurSel(0); + } + } +#endif +} + +/*void CScene_MultiGameJoinLoad::UpdateGamesListLabels() +{ + for( unsigned int i = 0; i < currentSessions.size(); ++i ) + { + FriendSessionInfo *sessionInfo = currentSessions.at(i); + m_GamesList.SetText(i,sessionInfo->displayLabel); + HXUIBRUSH hBrush; + CXuiCtrl4JList::LIST_ITEM_INFO info = m_pGamesList->GetData(i); + + // display an icon too + XuiCreateTextureBrushFromMemory(m_DefaultMinecraftIconData,m_DefaultMinecraftIconSize,&hBrush); + m_pGamesList->UpdateGraphic(i,hBrush); + } +#if 0 + XUIRect xuiRect; + HXUIOBJ item = XuiListGetItemControl(m_GamesList,0); + + HXUIOBJ hObj=NULL; + HXUIOBJ hTextPres=NULL; + HRESULT hr=XuiControlGetVisual(item,&hObj); + hr=XuiElementGetChildById(hObj,L"text_Label",&hTextPres); + + unsigned char displayLabelViewableStartIndex = 0; + for( unsigned int i = 0; i < currentSessions.size(); ++i ) + { + FriendSessionInfo *sessionInfo = currentSessions.at(i); + + if(hTextPres != NULL ) + { + hr=XuiTextPresenterMeasureText(hTextPres, sessionInfo->displayLabel, &xuiRect); + + float fWidth, fHeight; + XuiElementGetBounds(hTextPres,&fWidth,&fHeight); + int characters = (fWidth/xuiRect.right) * sessionInfo->displayLabelLength; + + if( characters < sessionInfo->displayLabelLength ) + { + static wchar_t temp[100]; + ZeroMemory(temp, (100)*sizeof(wchar_t)); + wcsncpy_s( temp, sessionInfo->displayLabel+sessionInfo->displayLabelViewableStartIndex, characters ); + m_GamesList.SetText(i,temp); + sessionInfo->displayLabelViewableStartIndex++; + if( sessionInfo->displayLabelViewableStartIndex >= sessionInfo->displayLabelLength ) sessionInfo->displayLabelViewableStartIndex = 0; + } + } + } +#endif +}*/ + +void CScene_MultiGameJoinLoad::SearchForGameCallback(void *param, DWORD dwNumResults, IQNetGameSearch *pGameSearch) +{ +#if 0 + HXUIOBJ hObj = (HXUIOBJ)param; + + void *pObj; + XuiObjectFromHandle( hObj, &pObj); + CScene_MultiGameJoinLoad *MultiGameJoinLoad = (CScene_MultiGameJoinLoad *)pObj; + + MultiGameJoinLoad->UpdateGamesList(dwNumResults, pGameSearch); +#endif +} + +int CScene_MultiGameJoinLoad::DeviceSelectReturned(void *pParam,bool bContinue) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + //HRESULT hr; + + if(bContinue==true) + { + // if the saves list has focus, then we should show the Delete Save tooltip + // if the games list has focus, then we should show the View Gamercard tooltip + int iRB=-1; + int iY = -1; + if( pClass->DoesGamesListHaveFocus() ) + { + iY = IDS_TOOLTIPS_VIEW_GAMERCARD; + } + else if(pClass->DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( pClass->m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + } + else if(pClass->DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + int iLB = -1; + if(pClass->m_bInParty) + { + if( pClass->m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + + //BOOL bOnlineGame=pClass->m_CheckboxOnline.IsChecked(); + + // refresh the saves list (if there is a device selected) + + // clear out the list first + + if(StorageManager.GetSaveDisabled()) + { + if(StorageManager.GetSaveDeviceSelected(pClass->m_iPad)) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); + // saving is disabled, but we should still be able to load from a selected save device + pClass->GetSaveInfo(); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); + // clear the saves list + pClass->m_pSavesList->RemoveAllData(); + + pClass->m_iSaveInfoC=0; + //pClass->m_iThumbnailsLoadedC=0; + + pClass->AddDefaultButtons(); + + pClass->m_SavesListTimer.SetShow( FALSE ); + + pClass->m_pSavesList->SetCurSelVisible(0); + } + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); + pClass->GetSaveInfo(); + } + } + + // enable input again + pClass->m_bIgnoreInput=false; + + return 0; +} + +HRESULT CScene_MultiGameJoinLoad::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly + switch(pTimer->nId) + { + + + case JOIN_LOAD_ONLINE_TIMER_ID: + { + XPARTY_USER_LIST partyList; + + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + m_bInParty=true; + } + else + { + m_bInParty=false; + } + + bool bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); + if(bMultiplayerAllowed != m_bMultiplayerAllowed) + { + if( bMultiplayerAllowed ) + { +// m_CheckboxOnline.SetEnable(TRUE); +// m_CheckboxPrivate.SetEnable(TRUE); + } + else + { + m_bInParty = false; + m_pGamesList->RemoveAllData(); + //m_GamesList.DeleteItems(0, m_GamesList.GetItemCount() ); + m_pGamesList->SetEnable(FALSE); + //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); + m_NetGamesListTimer.SetShow( TRUE ); + m_LabelNoGames.SetShow( FALSE ); + } + + int iLB = -1; + if(m_bInParty) + { + if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; + else iLB = IDS_TOOLTIPS_PARTY_GAMES; + } + int iRB=-1; + int iY=-1; + + if( DoesGamesListHaveFocus() ) + { + } + else if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + + if(StorageManager.GetSaveDisabled()) + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + if(StorageManager.EnoughSpaceForAMinSaveGame()) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + } + else if(DoesMashUpWorldHaveFocus()) + { + // If it's a mash-up pack world, give the Hide option + iRB=IDS_TOOLTIPS_HIDE; + } + + if(ProfileManager.IsFullVersion()==false ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1,-1,-1,iLB); + } + else if(StorageManager.GetSaveDisabled()) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,-1,-1,-1,iLB,iRB); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); + } + m_bMultiplayerAllowed = bMultiplayerAllowed; + } + } + break; + case JOIN_LOAD_SEARCH_MINIMUM_TIMER_ID: + { + XuiKillTimer( m_hObj, JOIN_LOAD_SEARCH_MINIMUM_TIMER_ID ); + m_NetGamesListTimer.SetShow( FALSE ); + m_LabelNoGames.SetShow( TRUE ); + } + break; + case JOIN_LOAD_SCROLL_GAME_NAMES_TIMER_ID: + { + // This is called by the gameslist callback function, so isn't needed on a timer + //UpdateGamesListLabels(); + } + break; + case CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID: + { + // also check for any new texture packs info being available + // for each item in the mem list, check it's in the data list + + //CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + // for each iConfig, check if the data is available, and add it to the List, then remove it from the viConfig + + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + DWORD dwBytes=0; + PBYTE pbData=NULL; + //app.DebugPrintf("Retrieving iConfig %d from TPD\n",m_iConfigA[i]); + + app.GetTPD(m_iConfigA[i],&pbData,&dwBytes); + + if(dwBytes > 0 && pbData) + { + //update the games list + UpdateGamesList(); + + m_iConfigA[i]=-1; + } + } + } + bool bAllDone=true; + for(int i=0;i<m_iTexturePacksNotInstalled;i++) + { + if(m_iConfigA[i]!=-1) + { + bAllDone = false; + } + } + + if(bAllDone) + { + // kill this timer + XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); + } + } + break; + } + + return S_OK; +} + +/* +int CScene_MultiGameJoinLoad::LoadSaveDataReturned(void *pParam,bool bContinue) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + if(bContinue==true) + { + bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()); + + // 4J Stu - If we only have one controller connected, then don't show the sign-in UI again + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + if(!isClientSide || connectedControllers == 1 || !RenderManager.IsHiDef()) + { + DWORD dwLocalUsersMask = CGameNetworkManager::GetLocalPlayerMask(ProfileManager.GetPrimaryPad()); + + // No guest problems so we don't need to force a sign-in of players here + StartGameFromSave(pClass, dwLocalUsersMask); + } + else + { + ProfileManager.RequestSignInUI(false, false, false, true, false,&CScene_MultiGameJoinLoad::StartGame_SignInReturned, pParam,ProfileManager.GetPrimaryPad()); + } + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} +*/ + +int CScene_MultiGameJoinLoad::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + if(bContinue==true) + { + // It's possible that the player has not signed in - they can back out + if(ProfileManager.IsSignedIn(iPad)) + { + DWORD dwLocalUsersMask = 0; + + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); + } + } + StartGameFromSave(pClass, dwLocalUsersMask); + } + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} + +// 4J Stu - Shared functionality that is the same whether we needed a quadrant sign-in or not +void CScene_MultiGameJoinLoad::StartGameFromSave(CScene_MultiGameJoinLoad* pClass, DWORD dwLocalUsersMask) +{ + /*bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_CheckboxOnline.IsChecked() == TRUE; + //bool isPrivate = pClass->m_CheckboxPrivate.IsChecked() == TRUE; + + SenStatGameEvent(ProfileManager.GetPrimaryPad(),eTelemetryGameEvent_Load,Minecraft::GetInstance()->options->difficulty, isClientSide, ProfileManager.IsFullVersion(), 1,0 ); + + g_NetworkManager.HostGame(dwLocalUsersMask,isClientSide,isPrivate,MINECRAFT_NET_MAX_PLAYERS,0); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = NULL; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams);*/ +} + +int CScene_MultiGameJoinLoad::DeleteSaveDataReturned(void *pParam,bool bSuccess) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + if(bSuccess==true) + { + // need to re-get the saves list and update the display + // clear the saves list + pClass->m_pSavesList->RemoveAllData(); + pClass->m_iSaveInfoC=0; + pClass->GetSaveInfo(); + } + + pClass->m_bIgnoreInput=false; + + return 0; +} + +void CScene_MultiGameJoinLoad::LoadLevelGen(LevelGenerationOptions *levelGen) +{ + // Load data from disc + //File saveFile( L"Tutorial\\Tutorial" ); + //LoadSaveFromDisk(&saveFile); + + // clear out the app's terrain features list + app.ClearTerrainFeaturePosition(); + + StorageManager.ResetSaveData(); + // Make our next save default to the name of the level + StorageManager.SetSaveTitle(levelGen->getDefaultSaveName().c_str()); + + bool isClientSide = false; + bool isPrivate = false; + int maxPlayers = MINECRAFT_NET_MAX_PLAYERS; + + if( app.GetTutorialMode() ) + { + isClientSide = false; + maxPlayers = 4; + } + + g_NetworkManager.HostGame(0,isClientSide,isPrivate,maxPlayers,0); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = 0; + param->saveData = NULL; + param->settings = app.GetGameHostOption( eGameHostOption_Tutorial ); + param->levelGen = levelGen; + + if(levelGen->requiresTexturePack()) + { + param->texturePackId = levelGen->getRequiredTexturePackId(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->skins->selectTexturePackById(param->texturePackId); + //pMinecraft->skins->updateUI(); + } + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + +void CScene_MultiGameJoinLoad::LoadSaveFromDisk(File *saveFile) +{ + // we'll only be coming in here when the tutorial is loaded now + + StorageManager.ResetSaveData(); + + // Make our next save default to the name of the level + StorageManager.SetSaveTitle(saveFile->getName().c_str()); + + __int64 fileSize = saveFile->length(); + FileInputStream fis(*saveFile); + byteArray ba(fileSize); + fis.read(ba); + fis.close(); + + bool isClientSide = false; + bool isPrivate = false; + int maxPlayers = MINECRAFT_NET_MAX_PLAYERS; + + if( app.GetTutorialMode() ) + { + isClientSide = false; + maxPlayers = 4; + } + + app.SetGameHostOption(eGameHostOption_GameType,GameType::CREATIVE->getId()); + + g_NetworkManager.HostGame(0,isClientSide,isPrivate,maxPlayers,0); + + LoadSaveDataThreadParam *saveData = new LoadSaveDataThreadParam(ba.data, ba.length, saveFile->getName()); + + NetworkGameInitData *param = new NetworkGameInitData(); + param->seed = 0; + param->saveData = saveData; + param->settings = app.GetGameHostOption( eGameHostOption_All ); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = (LPVOID)param; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); +} + +int CScene_MultiGameJoinLoad::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) + { + pClass->m_bIgnoreInput=false; + } + else + { + XCONTENT_DATA XContentData; + StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); + StorageManager.DeleteSaveData(&XContentData,CScene_MultiGameJoinLoad::DeleteSaveDataReturned,pClass); + pClass->m_SavesListTimer.SetShow( TRUE ); + } + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} + +int CScene_MultiGameJoinLoad::SaveTransferDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultAccept) + { + // upload the save + + // first load the save + int iIndex=pClass->m_pSavesList->GetData(pClass->m_pSavesList->GetCurSel()).iIndex-pClass->m_iDefaultButtonsC; + XCONTENT_DATA ContentData; + + // 4J-PB - ensure we've switched to the right title group id for uploading to + app.TMSPP_SetTitleGroupID(SAVETRANSFER_GROUP_ID); + StorageManager.GetSaveCacheFileInfo(iIndex,ContentData); + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&ContentData,CScene_MultiGameJoinLoad::LoadSaveDataReturned,pClass); + + pClass->m_bIgnoreInput=false; + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} + +int CScene_MultiGameJoinLoad::UploadSaveForXboxOneThreadProc( LPVOID lpParameter ) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParameter; + Minecraft *pMinecraft = Minecraft::GetInstance(); + + pMinecraft->progressRenderer->progressStart(IDS_SAVE_TRANSFER_TITLE); + pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADING ); + + // Delete the marker file + DeleteFile(pClass, "completemarker"); + if(!WaitForTransferComplete(pClass)) return 0; + + // Upload the save data + { + unsigned int uiSaveBytes; + uiSaveBytes=StorageManager.GetSaveSize(); + pClass->m_pbSaveTransferData=new BYTE [uiSaveBytes]; + + StorageManager.GetSaveData(pClass->m_pbSaveTransferData,&uiSaveBytes); + + app.DebugPrintf("Uploading save data (%d bytes)\n", uiSaveBytes); + UploadFile(pClass, "savedata", pClass->m_pbSaveTransferData, uiSaveBytes); + } + + if(!WaitForTransferComplete(pClass)) return 0; + if(pClass->m_bTransferFail) + { + // something went wrong, user has been informed + pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); + return 0; + } + + // Upload the metadata and thumbnail + { + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + + LPCWSTR title = StorageManager.GetSaveTitle(); + dos.writeUTF(title); + + char szUniqueMapName[14]; + StorageManager.GetSaveUniqueFilename(szUniqueMapName); + dos.writeUTF(convStringToWstring(szUniqueMapName)); + + { + // set the save icon + PBYTE pbImageData=NULL; + DWORD dwImageBytes=0; + XCONTENT_DATA XContentData; + int iIndex=pClass->m_pSavesList->GetData(pClass->m_pSavesList->GetCurSel()).iIndex-pClass->m_iDefaultButtonsC; + StorageManager.GetSaveCacheFileInfo(iIndex,XContentData); + StorageManager.GetSaveCacheFileInfo(iIndex,&pbImageData,&dwImageBytes); + + // if there is no thumbnail, retrieve the default one from the file. + // Don't delete the image data after creating the xuibrush, since we'll use it in the rename of the save + if(pbImageData==NULL) + { + DWORD dwResult=XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,NULL,&dwImageBytes,NULL); + if(dwResult==ERROR_SUCCESS) + { + pClass->m_pbSaveTransferData = new BYTE[dwImageBytes]; + pbImageData = pClass->m_pbSaveTransferData; // Copy pointer so that we can use the same name as the library owned one, but m_pbSaveTransferData will get deleted when done + XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,pbImageData,&dwImageBytes,NULL); + } + } + + dos.writeInt(dwImageBytes); + + byteArray ba(pbImageData, dwImageBytes); + dos.write(ba); + } + + pClass->m_pbSaveTransferData=new BYTE [baos.size()]; + memcpy(pClass->m_pbSaveTransferData,baos.buf.data,baos.size()); + + app.DebugPrintf("Uploading meta data (%d bytes)\n", baos.size()); + UploadFile(pClass, "metadata", pClass->m_pbSaveTransferData, baos.size()); + } + + // Wait for metadata and thumbnail + if(!WaitForTransferComplete(pClass)) return 0; + if(pClass->m_bTransferFail) + { + // something went wrong, user has been informed + pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); + return 0; + } + + // Upload the marker file + { + char singleByteData[1] = {1}; + app.DebugPrintf("Uploading marker (%d bytes)\n", 1); + UploadFile(pClass, "completemarker", &singleByteData, 1); + } + + // Wait for marker + if(!WaitForTransferComplete(pClass)) return 0; + if(pClass->m_bTransferFail) + { + // something went wrong, user has been informed + pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); + + return 0; + } + // change text for completion confirmation + pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADCOMPLETE ); + + // done + return 0; +} + +void CScene_MultiGameJoinLoad::DeleteFile(CScene_MultiGameJoinLoad *pClass, char *filename) +{ + pClass->m_fProgress=0.0f; + pClass->m_bTransferComplete=false; + + C4JStorage::ETMSStatus result = StorageManager.TMSPP_DeleteFile( + ProfileManager.GetPrimaryPad(), + filename, + C4JStorage::TMS_FILETYPE_BINARY, + &CScene_MultiGameJoinLoad::DeleteComplete, + pClass, + NULL); + + if(result != C4JStorage::ETMSStatus_DeleteInProgress) + { + DeleteComplete(pClass,ProfileManager.GetPrimaryPad(), -1); + } +} + +void CScene_MultiGameJoinLoad::UploadFile(CScene_MultiGameJoinLoad *pClass, char *filename, LPVOID data, DWORD size) +{ + pClass->m_fProgress=0.0f; + pClass->m_bTransferComplete=false; + + C4JStorage::ETMSStatus result = StorageManager.TMSPP_WriteFileWithProgress( + ProfileManager.GetPrimaryPad(), + C4JStorage::eGlobalStorage_TitleUser, + C4JStorage::TMS_FILETYPE_BINARY, + C4JStorage::TMS_UGCTYPE_NONE, + filename, + (CHAR *)data, + size, + &CScene_MultiGameJoinLoad::TransferComplete,pClass, 0, + &CScene_MultiGameJoinLoad::Progress,pClass); + +#ifdef _DEBUG_MENUS_ENABLED + if(app.GetWriteSavesToFolderEnabled()) + { + File targetFileDir(L"GAME:\\FakeTMSPP"); + if(!targetFileDir.exists()) targetFileDir.mkdir(); + string path = string( wstringtofilename( targetFileDir.getPath() ) ).append("\\").append(filename); + HANDLE hSaveFile = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL); + + DWORD numberOfBytesWritten = 0; + WriteFile( hSaveFile,data,size,&numberOfBytesWritten,NULL); + assert(numberOfBytesWritten == size); + + CloseHandle(hSaveFile); + } +#endif + + if(result != C4JStorage::ETMSStatus_WriteInProgress) + { + TransferComplete(pClass,ProfileManager.GetPrimaryPad(), -1); + } +} + +bool CScene_MultiGameJoinLoad::WaitForTransferComplete( CScene_MultiGameJoinLoad *pClass ) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + // loop until complete + while(pClass->m_bTransferComplete==false) + { + // check for a cancel + if(pClass->m_bSaveTransferInProgress==false) + { + // cancelled + return false; + } + Sleep(50); + // update the progress + pMinecraft->progressRenderer->progressStagePercentage((unsigned int)(pClass->m_fProgress*100.0f)); + } + + // was there a transfer error? + + return true; +} + +int CScene_MultiGameJoinLoad::SaveOptionsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + // results switched for this dialog + // EMessage_ResultAccept means cancel + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultThirdOption) + { + if(result==C4JStorage::EMessage_ResultDecline) // rename + { + ZeroMemory(pClass->m_wchNewName,sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); + // bring up a keyboard + InputManager.RequestKeyboard(IDS_RENAME_WORLD_TITLE,L"",IDS_RENAME_WORLD_TEXT,iPad,pClass->m_wchNewName,XCONTENT_MAX_DISPLAYNAME_LENGTH,&CScene_MultiGameJoinLoad::KeyboardReturned,pClass,C_4JInput::EKeyboardMode_Default,app.GetStringTable()); + } + else // delete + { + // delete the save game + // Have to ask the player if they are sure they want to delete this game + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, iPad,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,pClass, app.GetStringTable()); + //pClass->m_bIgnoreInput=false; + } + } + else + { + pClass->m_bIgnoreInput=false; + } + return 0; +} + +int CScene_MultiGameJoinLoad::LoadSaveDataReturned(void *pParam,bool bContinue) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + if(bContinue==true) + { + pClass->m_bSaveTransferInProgress=true; + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CScene_MultiGameJoinLoad::UploadSaveForXboxOneThreadProc; + loadingParams->lpParam = (LPVOID)pParam; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_NavigateBack; + completionData->iPad = DEFAULT_XUI_MENU_USER; + completionData->bRequiresUserAction=TRUE; + loadingParams->completionData = completionData; + + loadingParams->cancelFunc=&CScene_MultiGameJoinLoad::CancelSaveUploadCallback; + loadingParams->completeFunc=&CScene_MultiGameJoinLoad::SaveUploadCompleteCallback; + loadingParams->m_cancelFuncParam=pClass; + loadingParams->m_completeFuncParam=pClass; + loadingParams->cancelText=IDS_TOOLTIPS_CANCEL; + + app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + else + { + // switch back to the normal title group id + app.TMSPP_SetTitleGroupID(GROUP_ID); + + // the save is corrupt! + + pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + + // give the option to delete the save + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE, IDS_CORRUPT_OR_DAMAGED_SAVE_TEXT, uiIDA, 2, + pClass->m_iPad,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,pClass, app.GetStringTable()); + + } + + return 0; +} + +int CScene_MultiGameJoinLoad::Progress(void *pParam,float fProgress) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + app.DebugPrintf("Progress - %f\n",fProgress); + pClass->m_fProgress=fProgress; + return 0; +} + +int CScene_MultiGameJoinLoad::TransferComplete(void *pParam,int iPad, int iResult) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + + delete [] pClass->m_pbSaveTransferData; + pClass->m_pbSaveTransferData = NULL; + if(iResult!=0) + { + // There was a transfer fail + // Display a dialog + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_SAVE_TRANSFER_TITLE, IDS_SAVE_TRANSFER_UPLOADFAILED, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,NULL,app.GetStringTable()); + pClass->m_bTransferFail=true; + } + else + { + pClass->m_bTransferFail=false; + } + pClass->m_bTransferComplete=true; + //pClass->m_bSaveTransferInProgress=false; + return 0; +} + +int CScene_MultiGameJoinLoad::DeleteComplete(void *pParam,int iPad, int iResult) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + pClass->m_bTransferComplete=true; + return 0; +} + +int CScene_MultiGameJoinLoad::KeyboardReturned(void *pParam,bool bSet) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; + HRESULT hr = S_OK; + + // if the user has left the name empty, treat this as backing out + if((pClass->m_wchNewName[0]!=0) && bSet) + { +#ifdef _XBOX + XCONTENT_DATA XContentData; + StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); + + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&XContentData,CScene_MultiGameJoinLoad::LoadSaveDataForRenameReturned,pClass); + + if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved) + { + // disable saving + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(ProfileManager.GetPrimaryPad(),false); + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::DeviceRemovedDialogReturned,pClass); + } +#else + // rename the save + +#endif + } + else + { + pClass->m_bIgnoreInput=false; + } + + return hr; +} + +int CScene_MultiGameJoinLoad::LoadSaveDataForRenameReturned(void *pParam,bool bContinue) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; +#ifdef _XBOX + if(bContinue==true) + { + // set the save icon + PBYTE pbImageData=NULL; + DWORD dwImageBytes=0; + HXUIBRUSH hXuiBrush; + XCONTENT_DATA XContentData; + StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); + StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,&pbImageData,&dwImageBytes); + + // if there is no thumbnail, retrieve the default one from the file. + // Don't delete the image data after creating the xuibrush, since we'll use it in the rename of the save + if(pbImageData==NULL) + { + DWORD dwResult=XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,NULL,&dwImageBytes,NULL); + if(dwResult==ERROR_SUCCESS) + { + pbImageData = new BYTE[dwImageBytes]; + XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,pbImageData,&dwImageBytes,NULL); + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); + } + } + else + { + XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); + } + // save the data with this icon + StorageManager.CopySaveDataToNewSave( pbImageData,dwImageBytes,pClass->m_wchNewName,&CScene_MultiGameJoinLoad::CopySaveReturned,pClass); + } + else +#endif + { + //pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + } + return 0; +} + +int CScene_MultiGameJoinLoad::CopySaveReturned(void *pParam,bool bResult) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; +#ifdef _XBOX + if(bResult) + { + // and delete the old save + XCONTENT_DATA XContentData; + StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); + StorageManager.DeleteSaveData(&XContentData,CScene_MultiGameJoinLoad::DeleteSaveDataReturned,pClass); + pClass->m_SavesListTimer.SetShow( TRUE ); + } + else +#endif + { + //pClass->SetShow( TRUE ); + pClass->m_bIgnoreInput=false; + } + + return 0; +} + +int CScene_MultiGameJoinLoad::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_MultiGameJoinLoad *pClass = (CScene_MultiGameJoinLoad *)pParam; + + // Exit with or without saving + // Decline means install full version of the texture pack in this dialog + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultAccept) + { + // we need to enable background downloading for the DLC + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + ULONGLONG ullOfferID_Full; + ULONGLONG ullIndexA[1]; + app.GetDLCFullOfferIDForPackID(pClass->m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full); + + if( result==C4JStorage::EMessage_ResultAccept ) // Full version + { + ullIndexA[0]=ullOfferID_Full; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + } + else // trial version + { + // if there is no trial version, this is a Cancel + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + if(pDLCInfo->ullOfferID_Trial!=0LL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Trial; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + } + pClass->m_bIgnoreInput=false; + return 0; +} + +HRESULT CScene_MultiGameJoinLoad::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + // clear out the saves list and re-fill + + m_pSavesList->RemoveAllData(); + m_SavesListTimer.SetShow( TRUE ); + } + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + +HRESULT CScene_MultiGameJoinLoad::OnCustomMessage_DLCMountingComplete() +{ + + VOID *pObj; + XuiObjectFromHandle( m_SavesList, &pObj ); + m_pSavesList = (CXuiCtrl4JList *)pObj; + + m_iChangingSaveGameInfoIndex = 0; + + m_generators = app.getLevelGenerators(); + m_iDefaultButtonsC = 0; + m_iMashUpButtonsC = 0; + XPARTY_USER_LIST partyList; + + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + m_bInParty=true; + } + else + { + m_bInParty=false; + } + + int iLB = -1; + + int iY=-1; + if(DoesSavesListHaveFocus()) + { + if(ProfileManager.IsSignedInLive( m_iPad )) + { + iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; + } + } + if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; + // check if we're in the trial version + if(ProfileManager.IsFullVersion()==false) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); + + AddDefaultButtons(); + + m_pSavesList->SetCurSelVisible(0); + } + else if(StorageManager.GetSaveDisabled()) + { + if(StorageManager.GetSaveDeviceSelected(m_iPad)) + { + // saving is disabled, but we should still be able to load from a selected save device + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,IDS_TOOLTIPS_DELETESAVE); + + GetSaveInfo(); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB); + + AddDefaultButtons(); + m_SavesListTimer.SetShow( FALSE ); + + m_pSavesList->SetCurSelVisible(0); + } + } + else + { + // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) + bool bCanRename = StorageManager.EnoughSpaceForAMinSaveGame(); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,-1,bCanRename?IDS_TOOLTIPS_SAVEOPTIONS:IDS_TOOLTIPS_DELETESAVE); + + GetSaveInfo(); + } + + m_bIgnoreInput=false; + app.m_dlcManager.checkForCorruptDLCAndAlert(); + return S_OK; +} + +/* +void CScene_MultiGameJoinLoad::UpdateTooltips() +{ + int iA=IDS_TOOLTIPS_SELECT; + int iB=IDS_TOOLTIPS_BACK; + int iX=-1; + int iY=-1 + int iLB = -1; + XPARTY_USER_LIST partyList; + + if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) + { + m_bInParty=true; + } + else + { + m_bInParty=false; + } + + if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; + + if(ProfileManager.IsFullVersion()==false) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); + } + else if(StorageManager.GetSaveDisabled()) + { + if(StorageManager.GetSaveDeviceSelected(m_iPad)) + { + // saving is disabled, but we should still be able to load from a selected save device + iX=IDS_TOOLTIPS_CHANGEDEVICE; + iRB=IDS_TOOLTIPS_DELETESAVE; + } + else + { + iX=IDS_TOOLTIPS_SELECTDEVICE; + } + } + else + { + // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) + bool bCanRename = StorageManager.EnoughSpaceForAMinSaveGame(); + + if(bCanRename) + { + iRB=IDS_TOOLTIPS_SAVEOPTIONS; + } + else + { + iRB=IDS_TOOLTIPS_DELETESAVE; + } + } + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA,iB, iX, iY, iLT, iRT,iLB, iRB); +} +*/ + + + +#ifdef _XBOX +bool CScene_MultiGameJoinLoad::GetSavesInfoCallback(LPVOID pParam,int iTotalSaveInfoC, C4JStorage::CACHEINFOSTRUCT *InfoA, int iPad, HRESULT hResult) +{ + CScene_MultiGameJoinLoad *pClass=(CScene_MultiGameJoinLoad *)pParam; + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + PBYTE pbImageData=(PBYTE)InfoA; + PBYTE pbCurrentImagePtr; + HXUIBRUSH hXuiBrush; + HRESULT hr; + + // move the image data pointer to the right place + if(iTotalSaveInfoC!=0) + { + pbImageData+=sizeof(C4JStorage::CACHEINFOSTRUCT)*iTotalSaveInfoC; + } + + pClass->m_SavesListTimer.SetShow( FALSE ); + pClass->m_SavesList.SetEnable(TRUE); + + pClass->AddDefaultButtons(); + + for(int i=0;i<iTotalSaveInfoC;i++) + { + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + // Add these to the save list + if(!(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled())) + { + // if the save is corrupt, display this instead of the title + if(InfoA[i].dwImageBytes==0) + { + ListInfo.pwszText=app.GetString(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE); + ListInfo.bIsDamaged=true; + } + else + { + ListInfo.pwszText=InfoA[i].wchDisplayName; + ListInfo.bIsDamaged=false; + } + ListInfo.fEnabled=TRUE; + ListInfo.iData = -1; + + pClass->m_pSavesList->AddData(ListInfo,-1); + + // update the graphic on the list item + + // if there is no thumbnail, this is a corrupt file + if(InfoA[i].dwImageBytes!=0) + { + pbCurrentImagePtr=pbImageData+InfoA[i].dwImageOffset; + hr=XuiCreateTextureBrushFromMemory(pbCurrentImagePtr,InfoA[i].dwImageBytes,&hXuiBrush); + pClass->m_pSavesList->UpdateGraphic(i+pClass->m_iDefaultButtonsC,hXuiBrush ); + } + else + { + // we could put in a damaged save icon here + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/MinecraftBrokenIcon.png"); + + XuiCreateTextureBrush(szResourceLocator,&hXuiBrush); + pClass->m_pSavesList->UpdateGraphic(i+pClass->m_iDefaultButtonsC,hXuiBrush ); + } + } + } + + pClass->m_iSaveInfoC=iTotalSaveInfoC; + + // If there are some saves, then set the focus to be on the most recent one, which will be the first one after the create and tutorial + if(iTotalSaveInfoC>0) + { + pClass->m_pSavesList->SetCurSelVisible(pClass->m_iDefaultButtonsC); + pClass->m_bReady=true; + } + + pClass->m_bRetrievingSaveInfo=false; + + // It's possible that the games list is updated but we haven't displayed it yet as we were still waiting on saves list to load + // This is to fix a bug where joining a game before the saves list has loaded causes a crash when this callback is called + // as the scene no longer exists + pClass->UpdateGamesList(); + + // Fix for #45154 - Frontend: DLC: Content can only be downloaded from the frontend if you have not joined/exited multiplayer + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + + return false; +} +#else +int CScene_MultiGameJoinLoad::GetSavesInfoCallback(LPVOID lpParam,const bool) +{ + return true; +} +#endif + +void CScene_MultiGameJoinLoad::CancelSaveUploadCallback(LPVOID lpParam) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; + + StorageManager.TMSPP_CancelWriteFileWithProgress(pClass->m_iPad); + + pClass->m_bSaveTransferInProgress=false; + + // change back to the normal title group id + app.TMSPP_SetTitleGroupID(GROUP_ID); +// app.getRemoteStorage()->abort(); +// pClass->m_eSaveUploadState = eSaveUpload_Idle; + + UINT uiIDA[1] = { IDS_CONFIRM_OK }; + ui.RequestMessageBox(IDS_XBONE_CANCEL_UPLOAD_TITLE, IDS_XBONE_CANCEL_UPLOAD_TEXT, uiIDA, 1, pClass->m_iPad, NULL, NULL, app.GetStringTable()); +} + +void CScene_MultiGameJoinLoad::SaveUploadCompleteCallback(LPVOID lpParam) +{ + CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; + + pClass->m_bSaveTransferInProgress=false; + // change back to the normal title group id + app.TMSPP_SetTitleGroupID(GROUP_ID); + // app.getRemoteStorage()->abort(); + // pClass->m_eSaveUploadState = eSaveUpload_Idle; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.h b/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.h new file mode 100644 index 00000000..e91fbac2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.h @@ -0,0 +1,168 @@ +#pragma once +using namespace std; +#include <vector> +#include "..\Media\xuiscene_multi_joinload.h" +#include "XUI_CustomMessages.h" + + +#define JOIN_LOAD_CREATE_BUTTON_INDEX 0 + +#define JOIN_LOAD_ONLINE_TIMER_ID 0 +#define JOIN_LOAD_ONLINE_TIMER_TIME 100 +#define JOIN_LOAD_SEARCH_MINIMUM_TIMER_ID 1 +#define JOIN_LOAD_SEARCH_MINIMUM_TIMER_TIME 2000 +#define JOIN_LOAD_SCROLL_GAME_NAMES_TIMER_ID 2 +#define JOIN_LOAD_SCROLL_GAME_NAMES_TIMER_TIME 1000 + +class CXuiCtrl4JList; +class LevelGenerationOptions; +class CScene_MultiGameInfo; + +class CScene_MultiGameJoinLoad : public CXuiSceneImpl +{ +protected: + CXuiCtrl4JList *m_pSavesList; + CXuiCtrl4JList *m_pGamesList; + CXuiList m_SavesList; + CXuiList m_GamesList; + CXuiControl m_SavesListTimer; + CXuiControl m_NetGamesListTimer; + CXuiControl m_LabelNoGames; + int m_iPad; + + bool m_bShowingPartyGamesOnly; + bool m_bInParty; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_NOTIFY_SELCHANGED(OnNotifySelChanged) + XUI_ON_XM_NOTIFY_SET_FOCUS(OnNotifySetFocus) + XUI_ON_XM_NOTIFY_KILL_FOCUS(OnNotifyKillFocus) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_FONTRENDERERCHANGE_MESSAGE(OnFontRendererChange) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_GamesList, m_GamesList) + MAP_CONTROL(IDC_SavesTimer, m_SavesListTimer) + MAP_CONTROL(IDC_Timer, m_NetGamesListTimer) + MAP_CONTROL(IDC_LabelNoGames, m_LabelNoGames) + MAP_CONTROL(IDC_SavesList, m_SavesList) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled); + HRESULT OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnFontRendererChange(); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); + + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_MultiGameJoinLoad, L"CScene_MultiGameJoinLoad", XUI_CLASS_SCENE ) + +private: + bool DoesSavesListHaveFocus(); + bool DoesGamesListHaveFocus(); + bool DoesMashUpWorldHaveFocus(); + +public: + static void UpdateGamesListCallback(LPVOID pParam); + +private: + void AddDefaultButtons(); + void UpdateGamesList(); + void UpdateGamesList(DWORD dwNumResults, IQNetGameSearch *pGameSearch); + //void UpdateGamesListLabels(); + static void SearchForGameCallback(void *hObj, DWORD dwNumResults, IQNetGameSearch *pGameSearch); + static int DeviceSelectReturned(void *pParam,bool bContinue); + + unsigned char m_localPlayers; + + HRESULT GetSaveInfo( ); + static int LoadSaveDataReturned(void *pParam,bool bContinue); + static int DeleteSaveDataReturned(void *pParam,bool bSuccess); + + unsigned int m_uiSaveC; + void LoadLevelGen(LevelGenerationOptions *levelGen); + void LoadSaveFromDisk(File *saveFile); + + // callback +#ifdef _XBOX + static bool GetSavesInfoCallback(LPVOID pParam,int iInstalledC, C4JStorage::CACHEINFOSTRUCT *InfoA, int iPad, HRESULT hRes); +#else + static int GetSavesInfoCallback(LPVOID lpParam,const bool); +#endif + static int DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int SaveOptionsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int StartGame_SignInReturned(void *pParam,bool bContinue, int iPad); + static int CopySaveReturned(void *pParam,bool bResult); + static int LoadSaveDataForRenameReturned(void *pParam,bool bContinue); + static int KeyboardReturned(void *pParam,bool bSet); + static void StartGameFromSave(CScene_MultiGameJoinLoad* pClass, DWORD dwLocalUsersMask); + static int TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int SaveTransferDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + static int Progress(void *pParam,float fProgress); + static int TransferComplete(void *pParam,int i1, int i2); + static int DeleteComplete(void *pParam,int i1, int i2); + static int UploadSaveForXboxOneThreadProc( LPVOID lpParameter ); + static void DeleteFile(CScene_MultiGameJoinLoad *pClass, char *filename); + static void UploadFile(CScene_MultiGameJoinLoad *pClass, char *filename, LPVOID data, DWORD size); + static bool WaitForTransferComplete( CScene_MultiGameJoinLoad *pClass ); + static void CancelSaveUploadCallback(LPVOID lpParam); + static void SaveUploadCompleteCallback(LPVOID lpParam); + + + bool m_bIgnoreInput; + vector<File *> *m_saves; + + int m_iSaveInfoC; + int m_iDefaultButtonsC; + int m_iMashUpButtonsC; + int m_iChangingSaveGameInfoIndex; + + bool m_bMultiplayerAllowed; + bool m_bKillSaveInfoEnumerate; + + vector<FriendSessionInfo *> currentSessions; + bool m_bReady; + bool m_bRetrievingSaveInfo; + //bool m_bSaveRenamed; + WCHAR m_wchNewName[XCONTENT_MAX_DISPLAYNAME_LENGTH]; + unsigned char m_szSeed[50]; + + vector<LevelGenerationOptions *> *m_generators; + JoinMenuInitData *m_initData; + + UINT m_DefaultMinecraftIconSize; + PBYTE m_DefaultMinecraftIconData; + int *m_iConfigA; // track the texture packs that we don't have installed + int m_iTexturePacksNotInstalled; + PBYTE m_pbSaveTransferData; + + float m_fProgress; + bool m_bTransferComplete; + bool m_bTransferFail; + bool m_bSaveTransferInProgress; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.cpp b/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.cpp new file mode 100644 index 00000000..08656111 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.cpp @@ -0,0 +1,306 @@ +#include "stdafx.h" +#include "XUI_MultiGameCreate.h" +#include "XUI_MultiGameLaunchMoreOptions.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\Minecraft.h" + +#define GAME_CREATE_ONLINE_TIMER_ID 0 +#define GAME_CREATE_ONLINE_TIMER_TIME 100 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameLaunchMoreOptions::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_CheckboxOnline,app.GetString(IDS_ONLINE_GAME)); + XuiControlSetText(m_CheckboxInviteOnly,app.GetString(IDS_INVITE_ONLY)); + XuiControlSetText(m_CheckboxAllowFoF,app.GetString(IDS_ALLOWFRIENDSOFFRIENDS)); + XuiControlSetText(m_CheckboxPVP,app.GetString(IDS_PLAYER_VS_PLAYER)); + XuiControlSetText(m_CheckboxTrustPlayers,app.GetString(IDS_TRUST_PLAYERS)); + XuiControlSetText(m_CheckboxFireSpreads,app.GetString(IDS_FIRE_SPREADS)); + XuiControlSetText(m_CheckboxTNTExplodes,app.GetString(IDS_TNT_EXPLODES)); + XuiControlSetText(m_CheckboxHostPrivileges,app.GetString(IDS_HOST_PRIVILEGES)); + XuiControlSetText(m_CheckboxResetNether,app.GetString(IDS_RESET_NETHER)); + XuiControlSetText(m_LabelWorldOptions,app.GetString(IDS_WORLD_OPTIONS)); + XuiControlSetText(m_CheckboxStructures,app.GetString(IDS_GENERATE_STRUCTURES)); + XuiControlSetText(m_CheckboxFlatWorld,app.GetString(IDS_SUPERFLAT_WORLD)); + XuiControlSetText(m_CheckboxBonusChest,app.GetString(IDS_BONUS_CHEST)); + + m_params = (LaunchMoreOptionsMenuInitData *)pInitData->pvInitData; + + if(m_params->bGenerateOptions) + { + m_CheckboxStructures.SetEnable(TRUE); + m_CheckboxFlatWorld.SetEnable(TRUE); + m_CheckboxBonusChest.SetEnable(TRUE); + m_CheckboxStructures.SetCheck(m_params->bStructures); + m_CheckboxFlatWorld.SetCheck (m_params->bFlatWorld); + m_CheckboxBonusChest.SetCheck(m_params->bBonusChest); + + // This is a create world, so don't need Reset Nether + float fHeight, fCheckboxHeight, fWidth; + m_CheckboxResetNether.GetBounds(&fWidth, &fCheckboxHeight); + + m_HostOptionGroup.GetBounds(&fWidth, &fHeight); + m_HostOptionGroup.SetBounds(fWidth, fHeight - fCheckboxHeight); + + GetBounds(&fWidth,&fHeight); + SetBounds(fWidth, fHeight - fCheckboxHeight); + + D3DXVECTOR3 pos; + GetPosition(&pos); + pos.y += (fCheckboxHeight/2); + SetPosition(&pos); + + m_GenerationGroup.GetPosition(&pos); + pos.y -= fCheckboxHeight; + m_GenerationGroup.SetPosition(&pos); + + m_CheckboxResetNether.SetShow(FALSE); + } + else + { + float fHeight, fGroupHeight, fWidth; + m_GenerationGroup.GetBounds(&fWidth, &fGroupHeight); + m_GenerationGroup.SetShow(FALSE); + m_GenerationGroup.SetEnable(FALSE); + m_CheckboxStructures.SetShow(FALSE); + m_CheckboxFlatWorld.SetShow(FALSE); + m_CheckboxBonusChest.SetShow(FALSE); + + GetBounds(&fWidth,&fHeight); + SetBounds(fWidth, fHeight +10 - fGroupHeight); + + D3DXVECTOR3 pos; + GetPosition(&pos); + pos.y += (fGroupHeight/2); + SetPosition(&pos); + + m_CheckboxResetNether.SetEnable(TRUE); + m_CheckboxResetNether.SetCheck(m_params->bResetNether); + } + + m_CheckboxPVP.SetEnable(TRUE); + m_CheckboxTrustPlayers.SetEnable(TRUE); + m_CheckboxFireSpreads.SetEnable(TRUE); + m_CheckboxTNTExplodes.SetEnable(TRUE); + m_CheckboxHostPrivileges.SetEnable(TRUE); + + m_CheckboxPVP.SetCheck(m_params->bPVP); + m_CheckboxTrustPlayers.SetCheck (m_params->bTrust); + m_CheckboxFireSpreads.SetCheck(m_params->bFireSpreads); + m_CheckboxTNTExplodes.SetCheck(m_params->bTNT); + m_CheckboxHostPrivileges.SetCheck(m_params->bHostPrivileges); + + + m_CheckboxOnline.SetCheck(m_params->bOnlineGame); + m_CheckboxInviteOnly.SetCheck(m_params->bInviteOnly); + m_CheckboxAllowFoF.SetCheck(m_params->bAllowFriendsOfFriends); + + m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_params->iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_params->iPad); + if(m_params->bOnlineSettingChangedBySystem) + { + m_CheckboxOnline.SetCheck(FALSE); + m_CheckboxOnline.SetEnable(FALSE); + m_CheckboxInviteOnly.SetCheck(FALSE); + m_CheckboxInviteOnly.SetEnable(FALSE); + m_CheckboxAllowFoF.SetCheck(FALSE); + m_CheckboxAllowFoF.SetEnable(FALSE); + } + else if(!m_params->bOnlineGame) + { + m_CheckboxInviteOnly.SetEnable(FALSE); + m_CheckboxAllowFoF.SetEnable(FALSE); + } + + XuiSetTimer(m_hObj,GAME_CREATE_ONLINE_TIMER_ID,GAME_CREATE_ONLINE_TIMER_TIME); + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + + + //SentientManager.RecordMenuShown(m_params->iPad, eUIScene_CreateWorldMenu, 0); + + return S_OK; +} + + +HRESULT CScene_MultiGameLaunchMoreOptions::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + m_params->bOnlineGame = m_CheckboxOnline.IsChecked(); + m_params->bInviteOnly = m_CheckboxInviteOnly.IsChecked(); + m_params->bAllowFriendsOfFriends = m_CheckboxAllowFoF.IsChecked(); + + m_params->bStructures = m_CheckboxStructures.IsChecked(); + m_params->bFlatWorld = m_CheckboxFlatWorld.IsChecked(); + m_params->bBonusChest = m_CheckboxBonusChest.IsChecked(); + m_params->bPVP = m_CheckboxPVP.IsChecked(); + m_params->bTrust = m_CheckboxTrustPlayers.IsChecked(); + m_params->bFireSpreads = m_CheckboxFireSpreads.IsChecked(); + m_params->bTNT = m_CheckboxTNTExplodes.IsChecked(); + + m_params->bHostPrivileges = m_CheckboxHostPrivileges.IsChecked(); + + m_params->bResetNether = m_CheckboxResetNether.IsChecked(); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + return S_OK; +} + + +HRESULT CScene_MultiGameLaunchMoreOptions::OnNotifySetFocus( HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled ) +{ + int stringId = 0; + if(hObjSource == m_CheckboxStructures) + { + stringId = IDS_GAMEOPTION_STRUCTURES; + } + else if(hObjSource == m_CheckboxOnline) + { + stringId = IDS_GAMEOPTION_ONLINE; + } + else if(hObjSource == m_CheckboxInviteOnly) + { + stringId = IDS_GAMEOPTION_INVITEONLY; + } + else if(hObjSource == m_CheckboxAllowFoF) + { + stringId = IDS_GAMEOPTION_ALLOWFOF; + } + else if(hObjSource == m_CheckboxFlatWorld) + { + stringId = IDS_GAMEOPTION_SUPERFLAT; + } + else if(hObjSource == m_CheckboxBonusChest) + { + stringId = IDS_GAMEOPTION_BONUS_CHEST; + } + else if(hObjSource == m_CheckboxPVP) + { + stringId = IDS_GAMEOPTION_PVP; + } + else if(hObjSource == m_CheckboxTrustPlayers) + { + stringId = IDS_GAMEOPTION_TRUST; + } + else if(hObjSource == m_CheckboxFireSpreads) + { + stringId = IDS_GAMEOPTION_FIRE_SPREADS; + } + else if(hObjSource == m_CheckboxTNTExplodes) + { + stringId = IDS_GAMEOPTION_TNT_EXPLODES; + } + else if(hObjSource == m_CheckboxHostPrivileges) + { + stringId = IDS_GAMEOPTION_HOST_PRIVILEGES; + } + else if(hObjSource == m_CheckboxResetNether) + { + stringId = IDS_GAMEOPTION_RESET_NETHER; + } + + wstring wsText=app.GetString(stringId); + int size = 14; + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + size = 12; + } + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=%d>",app.GetHTMLColour(eHTMLColor_White), size); + wsText= startTags + wsText; + + m_Description.SetText(wsText.c_str()); + return S_OK; +} + +HRESULT CScene_MultiGameLaunchMoreOptions::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_MultiGameLaunchMoreOptions::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_CheckboxOnline) + { + if(m_CheckboxOnline.IsChecked()) + { + m_CheckboxInviteOnly.SetEnable(TRUE); + m_CheckboxAllowFoF.SetEnable(TRUE); + } + else + { + m_CheckboxInviteOnly.SetCheck(FALSE); + m_CheckboxInviteOnly.SetEnable(FALSE); + m_CheckboxAllowFoF.SetCheck(FALSE); + m_CheckboxAllowFoF.SetEnable(FALSE); + } + } + return S_OK; +} + +HRESULT CScene_MultiGameLaunchMoreOptions::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly + if( pTimer->nId == GAME_CREATE_ONLINE_TIMER_ID) + { + bool bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_params->iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_params->iPad); + + if(bMultiplayerAllowed != m_bMultiplayerAllowed) + { + if( bMultiplayerAllowed ) + { + bool bGameSetting_Online=(app.GetGameSettings(m_params->iPad,eGameSetting_Online)!=0); + m_CheckboxOnline.SetCheck(bGameSetting_Online?TRUE:FALSE); + if(bGameSetting_Online) + { + m_CheckboxInviteOnly.SetCheck((app.GetGameSettings(m_params->iPad,eGameSetting_InviteOnly)!=0)?TRUE:FALSE); + m_CheckboxAllowFoF.SetCheck((app.GetGameSettings(m_params->iPad,eGameSetting_FriendsOfFriends)!=0)?TRUE:FALSE); + } + else + { + m_CheckboxInviteOnly.SetCheck(FALSE); + m_CheckboxAllowFoF.SetCheck(FALSE); + } + } + else + { + m_CheckboxOnline.SetCheck(FALSE); + m_CheckboxOnline.SetEnable(FALSE); + m_CheckboxInviteOnly.SetCheck(FALSE); + m_CheckboxInviteOnly.SetEnable(FALSE); + m_CheckboxAllowFoF.SetCheck(FALSE); + } + + m_bMultiplayerAllowed = bMultiplayerAllowed; + } + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.h b/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.h new file mode 100644 index 00000000..92876240 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.h @@ -0,0 +1,75 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_multi_launch_more_options.h" + +class CScene_MultiGameLaunchMoreOptions : public CXuiSceneImpl +{ +protected: + CXuiScene m_GenerationGroup, m_HostOptionGroup; + CXuiCheckbox m_CheckboxOnline; + CXuiCheckbox m_CheckboxInviteOnly; + CXuiCheckbox m_CheckboxAllowFoF; + CXuiCheckbox m_CheckboxStructures; + CXuiCheckbox m_CheckboxFlatWorld; + CXuiCheckbox m_CheckboxBonusChest; + CXuiCheckbox m_CheckboxPVP; + CXuiCheckbox m_CheckboxTrustPlayers; + CXuiCheckbox m_CheckboxFireSpreads; + CXuiCheckbox m_CheckboxTNTExplodes; + CXuiCheckbox m_CheckboxHostPrivileges; + CXuiCheckbox m_CheckboxResetNether; + CXuiControl m_Description; + CXuiControl m_LabelWorldOptions; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_SET_FOCUS( OnNotifySetFocus ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_GenerationOptions, m_GenerationGroup) + BEGIN_MAP_CHILD_CONTROLS(m_GenerationGroup) + MAP_CONTROL(IDC_WorldOptions, m_LabelWorldOptions) + MAP_CONTROL(IDC_CheckboxStructures, m_CheckboxStructures) + MAP_CONTROL(IDC_CheckboxFlatWorld, m_CheckboxFlatWorld) + MAP_CONTROL(IDC_CheckboxBonusChest, m_CheckboxBonusChest) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_HostOptions, m_HostOptionGroup) + BEGIN_MAP_CHILD_CONTROLS(m_HostOptionGroup) + MAP_CONTROL(IDC_CheckboxOnline, m_CheckboxOnline) + MAP_CONTROL(IDC_CheckboxInviteOnly, m_CheckboxInviteOnly) + MAP_CONTROL(IDC_CheckboxAllowFoF, m_CheckboxAllowFoF) + MAP_CONTROL(IDC_CheckboxPVP, m_CheckboxPVP) + MAP_CONTROL(IDC_CheckboxTrustSystem, m_CheckboxTrustPlayers) + MAP_CONTROL(IDC_CheckboxFireSpreads, m_CheckboxFireSpreads) + MAP_CONTROL(IDC_CheckboxTNT, m_CheckboxTNTExplodes) + MAP_CONTROL(IDC_CheckboxHostPrivileges, m_CheckboxHostPrivileges) + MAP_CONTROL(IDC_CheckboxResetNether, m_CheckboxResetNether) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_Description, m_Description) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifySetFocus( HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_MultiGameLaunchMoreOptions, L"CScene_MultiGameLaunchMoreOptions", XUI_CLASS_SCENE ) + +private: + LaunchMoreOptionsMenuInitData *m_params; + bool m_bMultiplayerAllowed; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.cpp b/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.cpp new file mode 100644 index 00000000..49b524ff --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.cpp @@ -0,0 +1,90 @@ + + +#include "stdafx.h" + // #include "XUI_Ctrl_4JIcon.h" +#include "XUI_NewUpdateMessage.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" + + +HRESULT CScene_NewUpdateMessage::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *) pInitData->pvInitData; + m_bIsSD=!RenderManager.IsHiDef() && !RenderManager.IsWidescreen(); + + MapChildControls(); + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1, IDS_TOOLTIPS_BACK ); + + // set the text in the XuiHTMLMessage + wchar_t formatting[40]; + wstring wstrTemp = app.GetString(IDS_TITLEUPDATE); + swprintf(formatting, 40, L"<font size=\"%d\">", m_bIsSD?12:14); + wstrTemp = formatting + wstrTemp; + + wstring wsText=app.FormatHTMLString(m_iPad,wstrTemp); + m_HTMLText.SetText(wsText.c_str()); + m_HTMLText.SetShow(TRUE); + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_NewUpdateMessage, 0); + + return S_OK; +} + + + +HRESULT CScene_NewUpdateMessage::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + { + int iVal=app.GetGameSettings(m_iPad,eGameSetting_DisplayUpdateMessage); + if(iVal>0) iVal--; + + // set the update text as seen, by clearing the flag + app.SetGameSettings(m_iPad,eGameSetting_DisplayUpdateMessage,iVal); + // force a profile write + app.CheckGameSettingsChanged(true,m_iPad); + app.NavigateBack(XUSER_INDEX_ANY); + rfHandled = TRUE; + } + + break; + case VK_PAD_RTHUMB_DOWN: + case VK_PAD_LTHUMB_DOWN: + { + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_HTMLText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_HTMLText.m_hObj,1); + } + } + break; + case VK_PAD_RTHUMB_UP: + case VK_PAD_LTHUMB_UP: + { + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_HTMLText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_HTMLText.m_hObj,-1); + } + } + break; } + + return S_OK; +} + +HRESULT CScene_NewUpdateMessage::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK ); + + return S_OK; +} + diff --git a/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.h b/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.h new file mode 100644 index 00000000..8c4fbb36 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../media\xuiscene_NewUpdateMessage.h" + +class CScene_NewUpdateMessage : public CXuiSceneImpl +{ + // Xui Elements + CXuiHtmlControl m_HTMLText; + // Misc + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiHTMLMessage, m_HTMLText) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + +public: + XUI_IMPLEMENT_CLASS( CScene_NewUpdateMessage, L"CScene_NewUpdateMessage", XUI_CLASS_SCENE ) + +private: + int m_iPad; + bool m_bIsSD; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.cpp b/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.cpp new file mode 100644 index 00000000..76b820d3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "XUI_PartnernetPassword.h" +#include "..\XUI\XUI_Ctrl_4JList.h" + +#ifdef _CONTENT_PACKAGE +#ifndef _FINAL_BUILD + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_PartnernetPassword::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT); + + m_PartnernetPassword.SetEnable(true); + + m_PartnernetPassword.SetTextLimit(XCONTENT_MAX_DISPLAYNAME_LENGTH); + + // set the caret to the end of the default text + m_PartnernetPassword.SetCaretPosition(0); + m_PartnernetPassword.SetKeyboardType(C_4JInput::EKeyboardMode_Phone); + + m_PartnernetPassword.SetTitleAndText(IDS_NAME_WORLD,IDS_NAME_WORLD_TEXT); + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_PartnernetPassword::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_OK) + { + // create the world and launch + wstring wPassword = m_PartnernetPassword.GetText(); + if(wPassword==L"5183") + { + app.NavigateBack(pNotifyPressData->UserIndex); + app.SetPartnernetPasswordRunning(false); + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1); + } + rfHandled = TRUE; + } + + return S_OK; +} + +HRESULT CScene_PartnernetPassword::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_A: + case VK_PAD_B: + case VK_ESCAPE: + rfHandled = TRUE; + break; + } + return S_OK; +} + +#endif +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.h b/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.h new file mode 100644 index 00000000..b05206c0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_PartnernetPassword.h @@ -0,0 +1,40 @@ +#pragma once +#include "..\Media\xuiscene_partnernetpassword.h" +#include "XUI_Ctrl_4JEdit.h" + +#ifdef _CONTENT_PACKAGE +#ifndef _FINAL_BUILD + +class CScene_PartnernetPassword : public CXuiSceneImpl +{ + +protected: + CXuiCtrl4JEdit m_PartnernetPassword; + CXuiControl m_OK; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiEditPartnernetPassword, m_PartnernetPassword) + MAP_CONTROL(IDC_XuiOK, m_OK) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_PartnernetPassword, L"CScene_PartnernetPassword", XUI_CLASS_SCENE ) + +}; + +#endif +#endif diff --git a/Minecraft.Client/Common/XUI/XUI_PauseMenu.cpp b/Minecraft.Client/Common/XUI/XUI_PauseMenu.cpp new file mode 100644 index 00000000..4de74d1f --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_PauseMenu.cpp @@ -0,0 +1,1219 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\..\Minecraft.Client\StatsCounter.h" +#include "..\..\..\Minecraft.World\Entity.h" +#include "..\..\..\Minecraft.World\Level.h" +#include "..\..\..\Minecraft.Client\MultiplayerLocalPlayer.h" +#include "..\..\MinecraftServer.h" +#include "..\..\MultiPlayerLevel.h" +#include "..\..\ProgressRenderer.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" +#include "..\..\Minecraft.h" +#include "..\..\Options.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" +#include "..\..\DLCTexturePack.h" + +#define IGNORE_KEYPRESS_TIMERID 0 +#define IGNORE_KEYPRESS_TIME 100 + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT UIScene_PauseMenu::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_bIgnoreInput=true; + m_iPad = *(int *)pInitData->pvInitData; + bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); + + app.DebugPrintf("PAUSE PRESS PROCESSING - ipad = %d, UIScene_PauseMenu::OnInit\n",m_iPad); + + bool bIsisPrimaryHost=g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad()==m_iPad); + bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); + + MapChildControls(); + + XuiControlSetText(m_Buttons[BUTTON_PAUSE_RESUMEGAME],app.GetString(IDS_RESUME_GAME)); + XuiControlSetText(m_Buttons[BUTTON_PAUSE_HELPANDOPTIONS],app.GetString(IDS_HELP_AND_OPTIONS)); + XuiControlSetText(m_Buttons[BUTTON_PAUSE_LEADERBOARDS],app.GetString(IDS_LEADERBOARDS)); + XuiControlSetText(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS],app.GetString(IDS_ACHIEVEMENTS)); + XuiControlSetText(m_Buttons[BUTTON_PAUSE_SAVEGAME],app.GetString(IDS_SAVE_GAME)); + XuiControlSetText(m_Buttons[BUTTON_PAUSE_EXITGAME],app.GetString(IDS_EXIT_GAME)); + + if(app.GetLocalPlayerCount()>1) + { + m_bSplitscreen = true; + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + m_bSplitscreen = false; + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + + // test award the theme + //ProfileManager.Award( ProfileManager.GetPrimaryPad(), eAward_socialPost ); + // Display the tooltips, we are only allowed to display "SHARE" if we have the capability (TCR). + + if(!ProfileManager.IsFullVersion()) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + // hide the trial timer + CXuiSceneBase::ShowTrialTimer(FALSE); + } + else if(StorageManager.GetSaveDisabled()) + { + if( CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide ) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_SELECTDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_SELECTDEVICE:-1,-1,-1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + } + else + { + if( CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,-1, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + } + + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + + // are we the primary player? + // 4J-PB - fix for 7844 & 7845 - + // TCR # 128: XLA Pause Menu: When in a multiplayer game as a client the Pause Menu does not have a Leaderboards option. + // TCR # 128: XLA Pause Menu: When in a multiplayer game as a client the Pause Menu does not have an Achievements option. + if(ProfileManager.GetPrimaryPad()==m_iPad) // && g_NetworkManager.IsHost()) + { + // are we in splitscreen? + // how many local players do we have? + + D3DXVECTOR3 vPos; + if( app.GetLocalPlayerCount()>1 ) + { + m_Buttons[BUTTON_PAUSE_LEADERBOARDS].GetPosition(&vPos); + m_Buttons[BUTTON_PAUSE_SAVEGAME].SetPosition(&vPos); + m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS].GetPosition(&vPos); + m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); + // Hide the BUTTON_PAUSE_LEADERBOARDS and BUTTON_PAUSE_ACHIEVEMENTS + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_LEADERBOARDS],FALSE); + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS],FALSE); + } + + if( !g_NetworkManager.IsHost() ) + { + m_Buttons[BUTTON_PAUSE_SAVEGAME].GetPosition(&vPos); + m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); + // Hide the BUTTON_PAUSE_SAVEGAME + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_SAVEGAME],FALSE); + } + } + else + { + D3DXVECTOR3 vPos; + m_Buttons[BUTTON_PAUSE_LEADERBOARDS].GetPosition(&vPos); + m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); + // Hide the BUTTON_PAUSE_LEADERBOARDS, BUTTON_PAUSE_ACHIEVEMENTS and BUTTON_PAUSE_SAVEGAME + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_LEADERBOARDS],FALSE); + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS],FALSE); + XuiElementSetShow(m_Buttons[BUTTON_PAUSE_SAVEGAME],FALSE); + } + + // is saving disabled? + if(StorageManager.GetSaveDisabled()) + { + // disable save button + m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(FALSE); + m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(FALSE); + } + + m_iLastButtonPressed=0; + + // get rid of the quadrant display if it's on + CXuiSceneBase::HidePressStart(); + + XuiSetTimer(m_hObj,IGNORE_KEYPRESS_TIMERID,IGNORE_KEYPRESS_TIME); + + if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)TRUE); + } + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_PauseMenu, 0); + TelemetryManager->RecordPauseOrInactive(m_iPad); + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT UIScene_PauseMenu::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + + while((uiButtonCounter<BUTTONS_PAUSE_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // ignore buttons not from this user + //if(pNotifyPressData->UserIndex!=pMinecraft->player->GetXboxPad()) return S_OK; + + // Determine which button was pressed, + // and call the appropriate function. + + // store the last button pressed, so on a nav back we can set the focus properly + m_iLastButtonPressed=uiButtonCounter; + switch(uiButtonCounter) + { + case BUTTON_PAUSE_RESUMEGAME: + if( m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame() ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + } + app.CloseXuiScenes(pNotifyPressData->UserIndex); + break; + + case BUTTON_PAUSE_LEADERBOARDS: + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + //4J Gordon: Being used for the leaderboards proper now + // guests can't look at leaderboards + if(ProfileManager.IsGuest(pNotifyPressData->UserIndex)) + { + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else if(!ProfileManager.IsSignedInLive(pNotifyPressData->UserIndex)) + { + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + else + { + app.NavigateToScene(pNotifyPressData->UserIndex, eUIScene_LeaderboardsMenu); + } + } + break; + case BUTTON_PAUSE_ACHIEVEMENTS: + // guests can't look at achievements + if(ProfileManager.IsGuest(pNotifyPressData->UserIndex)) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + else + { + XShowAchievementsUI( pNotifyPressData->UserIndex ); + } + + break; + case BUTTON_PAUSE_HELPANDOPTIONS: + if(app.GetLocalPlayerCount()>1) + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_HelpAndOptionsMenu); + } + else + { + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_HelpAndOptionsMenu); + } + break; + + case BUTTON_PAUSE_SAVEGAME: + { + // 4J-PB - Is the player trying to save but they are using a trial texturepack ? + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + m_pDLCPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack(); + + if(!m_pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // upsell + ULONGLONG ullOfferID_Full; + // get the dlc texture pack + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full); + + // tell sentient about the upsell of the full version of the texture pack + TelemetryManager->RecordUpsellPresented(pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + // Give the player a warning about the trial version of the texture pack + StorageManager.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::WarningTrialTexturePackReturned,this,app.GetStringTable()); + + return S_OK; + } + } + + // does the save exist? + bool bSaveExists; + C4JStorage::ELoadGameStatus result=StorageManager.DoesSaveExist(&bSaveExists); + + if(result == C4JStorage::ELoadGame_DeviceRemoved) + { + // this will be a tester trying to be clever + UINT uiIDA[2]; + uiIDA[0]=IDS_SELECTANEWDEVICE; + uiIDA[1]=IDS_NODEVICE_DECLINE; + + StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::DeviceRemovedDialogReturned,this); + } + else + { + // we need to ask if they are sure they want to overwrite the existing game + if(bSaveExists) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::SaveGameDialogReturned,this, app.GetStringTable()); + } + else + { + // flag a app action of save game + app.SetAction(pNotifyPressData->UserIndex,eAppAction_SaveGame); + } + } + } + + break; + case BUTTON_PAUSE_EXITGAME: + { + // Check if it's the trial version + if(ProfileManager.IsFullVersion()) + { + UINT uiIDA[3]; + + // is it the primary player exiting? + if(pNotifyPressData->UserIndex==ProfileManager.GetPrimaryPad()) + { + int playTime = -1; + if( pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL ) + { + playTime = (int)pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer(); + } + + if(StorageManager.GetSaveDisabled()) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + else + { + if( g_NetworkManager.IsHost() ) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + if(g_NetworkManager.GetPlayerCount()>1) + { + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameSaveDialogReturned,this, app.GetStringTable()); + } + else + { + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameSaveDialogReturned,this, app.GetStringTable()); + } + } + else + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + } + } + else + { + int playTime = -1; + if( pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL ) + { + playTime = (int)pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer(); + } + + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Exited); + + + // just exit the player + app.SetAction(pNotifyPressData->UserIndex,eAppAction_ExitPlayer); + } + } + else + { + // is it the primary player exiting? + if(pNotifyPressData->UserIndex==ProfileManager.GetPrimaryPad()) + { + int playTime = -1; + if( pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL ) + { + playTime = (int)pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer(); + } + + // adjust the trial time played + CXuiSceneBase::ReduceTrialTimerValue(); + + // exit the level + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex,&UIScene_PauseMenu::ExitGameDialogReturned,this, app.GetStringTable()); + } + else + { + int playTime = -1; + if( pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL ) + { + playTime = (int)pMinecraft->localplayers[pNotifyPressData->UserIndex]->getSessionTimer(); + } + + TelemetryManager->RecordLevelExit(pNotifyPressData->UserIndex, eSen_LevelExitStatus_Exited); + + // just exit the player + app.SetAction(pNotifyPressData->UserIndex,eAppAction_ExitPlayer); + } + } + } + break; + default: + break; + } + + return S_OK; +} + +HRESULT UIScene_PauseMenu::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + // ignore repeated start presses to avoid the scene closing before it's opened + if((pInputData->dwKeyCode==VK_PAD_START) &&(pInputData->dwFlags&XUI_INPUT_FLAG_REPEAT )) + { + rfHandled = TRUE; + return S_OK; + } + + bool bIsisPrimaryHost=g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad()==m_iPad); + bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); + bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + app.DebugPrintf("PAUSE- Keydown in the xui %d flags = %d\n",pInputData->dwKeyCode,pInputData->dwFlags); + + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_ESCAPE: + app.DebugPrintf("PAUSE PRESS PROCESSING - ipad = %d, UIScene_PauseMenu::OnKeyDown - LEAVING PAUSE MENU\n",m_iPad); + + if( m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame() ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + } + + CXuiSceneBase::PlayUISFX(eSFX_Back); + app.CloseXuiScenes(pInputData->UserIndex); + if(!ProfileManager.IsFullVersion()) + { + CXuiSceneBase::ShowTrialTimer(TRUE); + } + rfHandled = TRUE; + + break; + + case VK_PAD_X: + // Change device + if(bIsisPrimaryHost) + { + // we need a function to deal with the return from this - if it changes, we need to update the pause menu and tooltips + // Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage + // device, and repeatedly backs out of the SD screen, disconnects from LIVE, and then selects a SD, the title crashes. + m_bIgnoreInput=true; + + StorageManager.SetSaveDevice(&UIScene_PauseMenu::DeviceSelectReturned,this,true); + } + rfHandled = TRUE; + break; + + + case VK_PAD_Y: + { + if(bUserisClientSide) + { + // 4J Stu - Added check in 1.8.2 bug fix (TU6) to stop repeat key presses + bool bCanScreenshot = true; + for(int j=0; j < XUSER_MAX_COUNT;++j) + { + if(app.GetXuiAction(j) == eAppAction_SocialPostScreenshot) + { + bCanScreenshot = false; + break; + } + } + if(bCanScreenshot) app.SetAction(pInputData->UserIndex,eAppAction_SocialPost); + } + rfHandled = TRUE; + } + break; + + case VK_PAD_RSHOULDER: + if( bDisplayBanTip ) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + StorageManager.RequestMessageBox(IDS_ACTION_BAN_LEVEL_TITLE, IDS_ACTION_BAN_LEVEL_DESCRIPTION, uiIDA, 2, pInputData->UserIndex,&UIScene_PauseMenu::BanGameDialogReturned,this, app.GetStringTable()); + + rfHandled = TRUE; + } + break; + + // handle a keyboard Return specifically, because we've turned off the VK_A_OR_START for the pause menu, since this should exit the menu, rather than cause the button to be activated + case VK_RETURN: + // call OnNotifyPressEx directly to trigger the button press action + + HXUIOBJ hObjPressed=TreeGetFocus(); + XUINotifyPress NotifyPressData; + BOOL rfHandled=FALSE; + + NotifyPressData.UserIndex=pInputData->UserIndex; + OnNotifyPressEx(hObjPressed,&NotifyPressData,rfHandled); + + break; + } + + return S_OK; +} + +HRESULT UIScene_PauseMenu::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bIsisPrimaryHost=g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad()==m_iPad); + bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); + bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); + + // Display the tooltips, we are only allowed to display "SHARE" if we have the capability (TCR). + if(StorageManager.GetSaveDisabled()) + { + if( ProfileManager.IsFullVersion() && CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_SELECTDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,-1,-1, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + } + else + { + if( CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,-1, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + } + + // set the focus to the last button we were on + XuiElementSetUserFocus(m_Buttons[m_iLastButtonPressed],m_iPad); + + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + + bool isWrongSize = false; + if(app.GetLocalPlayerCount()==1) + { + // If we were created as a splitscreen scene, then it's now going to be in the wrong place. Get rid of this scene. + if(m_bSplitscreen) + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + isWrongSize = true; + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + if(!m_bSplitscreen) isWrongSize = true; + } + + if(isWrongSize) + { + if( m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame() ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + } + + app.CloseXuiScenes(m_iPad); + if(!ProfileManager.IsFullVersion()) + { + CXuiSceneBase::ShowTrialTimer(TRUE); + } + } + + return S_OK; +} + +HRESULT UIScene_PauseMenu::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +int UIScene_PauseMenu::BanGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + // 4J Stu - Only do this if we are currently idle, don't want the (relatively) low priority ban task overriding something else + if(app.GetXuiAction(iPad) == eAppAction_Idle) app.SetAction(iPad,eAppAction_BanLevel); + } + return 0; +} + +int UIScene_PauseMenu::DeviceSelectReturned(void *pParam,bool bContinue) +{ + // Has someone pulled the ethernet cable and caused the pause menu to be closed before this callback returns? + if(!app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) + { + return 0; + } + + UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; + bool bIsisPrimaryHost=g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad()==pClass->m_iPad); + bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(pClass->m_iPad); + bool bUserisClientSide = ProfileManager.IsSignedInLive(pClass->m_iPad); + + //Whatever happen, we need to update the pause menu and the tooltips + // Display the tooltips, we are only allowed to display "SHARE" if we have the capability (TCR). + if(StorageManager.GetSaveDisabled()) + { + if( ProfileManager.IsFullVersion() && CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) + { + ui.SetTooltips( pClass->m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_SELECTDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + else + { + ui.SetTooltips( pClass->m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,-1,-1, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + // disable save button + // set the focus on to another button + pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(FALSE); + pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(FALSE); + + pClass->m_Buttons[BUTTON_PAUSE_RESUMEGAME].InitFocus(pClass->m_iPad); + } + else + { + if( CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) + { + ui.SetTooltips(pClass->m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,IDS_TOOLTIPS_SHARE, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + else + { + ui.SetTooltips( pClass->m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,bIsisPrimaryHost?IDS_TOOLTIPS_CHANGEDEVICE:-1,-1, -1,-1,-1,bDisplayBanTip?IDS_TOOLTIPS_BANLEVEL:-1); + } + // enable save button + pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(TRUE); + pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(TRUE); + + } + + pClass->m_bIgnoreInput=false; + return 0; +} + +HRESULT UIScene_PauseMenu::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,false); +} + +HRESULT UIScene_PauseMenu::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==IGNORE_KEYPRESS_TIMERID) + { + XuiKillTimer(m_hObj,IGNORE_KEYPRESS_TIMERID); + + // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again + if(app.StartInstallDLCProcess(m_iPad)==true) + { + // not doing a mount, so enable input + m_bIgnoreInput=true; + } + else + { + m_bIgnoreInput=false; + } + } + + return S_OK; +} + + +HRESULT UIScene_PauseMenu::OnDestroy() +{ + //XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + TelemetryManager->RecordUnpauseOrActive(m_iPad); + + if( m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame() ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + } + + return S_OK; +} + +int UIScene_PauseMenu::DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + // continue without saving + StorageManager.SetSaveDisabled(true); + StorageManager.SetSaveDeviceSelected(ProfileManager.GetPrimaryPad(),false); + + // Has someone pulled the ethernet cable and caused the pause menu to be closed before this callback returns? + if(app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) + { + UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; + + // use the device select returned function to wipe the saves list and change the tooltip + pClass->DeviceSelectReturned(pClass,true); + } + } + else + { + // Change device + if(app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) + { + UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; + StorageManager.SetSaveDevice(&UIScene_PauseMenu::DeviceSelectReturned,pClass,true); + } + } + return 0; +} + +HRESULT UIScene_PauseMenu::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + } + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + +HRESULT UIScene_PauseMenu::OnCustomMessage_DLCMountingComplete() +{ + m_bIgnoreInput=false; + app.m_dlcManager.checkForCorruptDLCAndAlert(); + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + return S_OK; +} + +void UIScene_PauseMenu::ShowScene(bool show) +{ + SetShow(show?TRUE:FALSE); +} + +int UIScene_PauseMenu::WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + UIScene_PauseMenu* pScene = (UIScene_PauseMenu*)pParam; + + //pScene->m_bIgnoreInput = false; + pScene->ShowScene( true ); + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedIn(iPad)) + { + ULONGLONG ullIndexA[1]; + + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + // get the dlc texture pack + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + // Need to get the parent packs id, since this may be one of many child packs with their own ids + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullIndexA[0]); + + // need to allow downloads here, or the player would need to quit the game to let the download of a texture pack happen. This might affect the network traffic, since the download could take all the bandwidth... + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Texture_DLC, ( pScene->m_pDLCPack->getPurchaseOfferId() & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined); + } + + + return 0; +} + +int UIScene_PauseMenu::ExitGameSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + UIScene_PauseMenu *pClass = (UIScene_PauseMenu *)pParam; + // Exit with or without saving + // Decline means save in this dialog + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultThirdOption) + { + if( result==C4JStorage::EMessage_ResultDecline ) // Save + { + // 4J-PB - Is the player trying to save but they are using a trial texturepack ? + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + DLCPack *pDLCPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack(); + if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { +#ifdef _XBOX + // upsell + ULONGLONG ullOfferID_Full; + // get the dlc texture pack + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full); + + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); +#endif + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + // Give the player a warning about the trial version of the texture pack + ui.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad() ,&UIScene_PauseMenu::WarningTrialTexturePackReturned,pClass,app.GetStringTable()); + + return S_OK; + } + } + + // does the save exist? + bool bSaveExists; + StorageManager.DoesSaveExist(&bSaveExists); + // 4J-PB - we check if the save exists inside the libs + // we need to ask if they are sure they want to overwrite the existing game + if(bSaveExists) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameAndSaveReturned,pClass, app.GetStringTable()); + return 0; + } + else + { + MinecraftServer::getInstance()->setSaveOnExit( true ); + } + } + else + { + // been a few requests for a confirm on exit without saving + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_DECLINE_SAVE_GAME, IDS_CONFIRM_DECLINE_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameDeclineSaveReturned, dynamic_cast<IUIScene_PauseMenu*>(pClass), app.GetStringTable()); + return 0; + } + + app.SetAction(iPad,eAppAction_ExitWorld); + } + return 0; +} + +int UIScene_PauseMenu::ExitGameDeclineSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + MinecraftServer::getInstance()->setSaveOnExit( false ); + // flag a app action of exit game + app.SetAction(iPad,eAppAction_ExitWorld); + } + else + { + // has someone disconnected the ethernet here, causing the pause menu to shut? + if(ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) + { + IUIScene_PauseMenu* pClass = (IUIScene_PauseMenu*)pParam; + UINT uiIDA[3]; + // you cancelled the save on exit after choosing exit and save? You go back to the Exit choices then. + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + if(g_NetworkManager.GetPlayerCount()>1) + { + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameSaveDialogReturned,pClass, app.GetStringTable(), 0, 0, false); + } + else + { + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameSaveDialogReturned,pClass, app.GetStringTable(), 0, 0, false); + } + } + + } + return 0; +} + +int UIScene_PauseMenu::ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // 4J-PB - we won't come in here if we have a trial texture pack + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + MinecraftServer::getInstance()->setSaveOnExit( true ); + // flag a app action of exit game + app.SetAction(iPad,eAppAction_ExitWorld); + } + else + { + // has someone disconnected the ethernet here, causing the pause menu to shut? + if(ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) + { + UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; + UINT uiIDA[3]; + // you cancelled the save on exit after choosing exit and save? You go back to the Exit choices then. + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + if(g_NetworkManager.GetPlayerCount()>1) + { + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameSaveDialogReturned,pClass, app.GetStringTable(), 0, 0, false); + } + else + { + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, ProfileManager.GetPrimaryPad(),&UIScene_PauseMenu::ExitGameSaveDialogReturned,pClass, app.GetStringTable(), 0, 0, false); + } + } + + } + return 0; +} + +int UIScene_PauseMenu::SaveGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + // flag a app action of save game + app.SetAction(iPad,eAppAction_SaveGame); + } + return 0; +} + +int UIScene_PauseMenu::ExitGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + app.SetAction(iPad,eAppAction_ExitWorld); + } + return 0; +} + +int UIScene_PauseMenu::SaveWorldThreadProc( LPVOID lpParameter ) +{ + bool bAutosave=(bool)lpParameter; + if(bAutosave) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_AutoSaveGame); + } + else + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_SaveGame); + } + + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + //wprintf(L"Loading world on thread\n"); + + if(ProfileManager.IsFullVersion()) + { + app.SetGameStarted(false); + + while( app.GetXuiServerAction(ProfileManager.GetPrimaryPad() ) != eXuiServerAction_Idle && !MinecraftServer::serverHalted() ) + { + Sleep(10); + } + + if(!MinecraftServer::serverHalted() && !app.GetChangingSessionType() ) app.SetGameStarted(true); + } + + HRESULT hr = S_OK; + if(app.GetChangingSessionType()) + { + // 4J Stu - This causes the fullscreenprogress scene to ignore the action it was given + hr = ERROR_CANCELLED; + } + return hr; +} + +int UIScene_PauseMenu::ExitWorldThreadProc( void* lpParameter ) +{ + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + //app.SetGameStarted(false); + + _ExitWorld(lpParameter); + + return S_OK; +} + +// This function performs the meat of exiting from a level. It should be called from a thread other than the main thread. +void UIScene_PauseMenu::_ExitWorld(LPVOID lpParameter) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + + int exitReasonStringId = pMinecraft->progressRenderer->getCurrentTitle(); + int exitReasonTitleId = IDS_CONNECTION_LOST; + + bool saveStats = true; + if (pMinecraft->isClientSide() || g_NetworkManager.IsInSession()) + { + if(lpParameter != NULL ) + { + // 4J-PB - check if we have lost connection to Live + if(ProfileManager.GetLiveConnectionStatus()!=XONLINE_S_LOGON_CONNECTION_ESTABLISHED ) + { + exitReasonStringId = IDS_CONNECTION_LOST_LIVE; + } + else + { + switch( app.GetDisconnectReason() ) + { + case DisconnectPacket::eDisconnect_Kicked: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + case DisconnectPacket::eDisconnect_NoUGC_AllLocal: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; + case DisconnectPacket::eDisconnect_NoUGC_Single_Local: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; +#ifdef _XBOX + case DisconnectPacket::eDisconnect_NoUGC_Remote: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; +#endif + case DisconnectPacket::eDisconnect_NoFlying: + exitReasonStringId = IDS_DISCONNECTED_FLYING; + break; + case DisconnectPacket::eDisconnect_Quitting: + exitReasonStringId = IDS_DISCONNECTED_SERVER_QUIT; + break; + case DisconnectPacket::eDisconnect_NoFriendsInGame: + exitReasonStringId = IDS_DISCONNECTED_NO_FRIENDS_IN_GAME; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_Banned: + exitReasonStringId = IDS_DISCONNECTED_BANNED; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_NotFriendsWithHost: + exitReasonStringId = IDS_NOTALLOWED_FRIENDSOFFRIENDS; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_OutdatedServer: + exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_OutdatedClient: + exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_ServerFull: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + default: + exitReasonStringId = IDS_CONNECTION_LOST_SERVER; + } + } + //pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId ); + + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + // 4J Stu - Fix for #48669 - TU5: Code: Compliance: TCR #15: Incorrect/misleading messages after signing out a profile during online game session. + // If the primary player is signed out, then that is most likely the cause of the disconnection so don't display a message box. This will allow the message box requested by the libraries to be brought up + if( ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad())) ui.RequestMessageBox( exitReasonTitleId, exitReasonStringId, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + exitReasonStringId = -1; + + // 4J - Force a disconnection, this handles the situation that the server has already disconnected + if( pMinecraft->levels[0] != NULL ) pMinecraft->levels[0]->disconnect(false); + if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect(false); + if( pMinecraft->levels[2] != NULL ) pMinecraft->levels[2]->disconnect(false); + } + else + { + exitReasonStringId = IDS_EXITING_GAME; + pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME ); + if( pMinecraft->levels[0] != NULL ) pMinecraft->levels[0]->disconnect(); + if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect(); + if( pMinecraft->levels[2] != NULL ) pMinecraft->levels[2]->disconnect(); + } + + // 4J Stu - This only does something if we actually have a server, so don't need to do any other checks + MinecraftServer::HaltServer(); + + // We need to call the stats & leaderboards save before we exit the session + // 4J We need to do this in a QNet callback where it is safe + //pMinecraft->forceStatsSave(); + saveStats = false; + + // 4J Stu - Leave the session once the disconnect packet has been sent + g_NetworkManager.LeaveGame(FALSE); + } + else + { + if(lpParameter != NULL && ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad()) ) + { + switch( app.GetDisconnectReason() ) + { + case DisconnectPacket::eDisconnect_Kicked: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + case DisconnectPacket::eDisconnect_NoUGC_AllLocal: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; + case DisconnectPacket::eDisconnect_NoUGC_Single_Local: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; +#ifdef _XBOX + case DisconnectPacket::eDisconnect_NoUGC_Remote: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; + exitReasonTitleId = IDS_CONNECTION_FAILED; + break; +#endif + case DisconnectPacket::eDisconnect_Quitting: + exitReasonStringId = IDS_DISCONNECTED_SERVER_QUIT; + break; + case DisconnectPacket::eDisconnect_NoMultiplayerPrivilegesJoin: + exitReasonStringId = IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT; + break; + case DisconnectPacket::eDisconnect_OutdatedServer: + exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_OutdatedClient: + exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + case DisconnectPacket::eDisconnect_ServerFull: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + exitReasonTitleId = IDS_CANTJOIN_TITLE; + break; + default: + exitReasonStringId = IDS_DISCONNECTED; + } + //pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId ); + + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox( exitReasonTitleId, exitReasonStringId, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + exitReasonStringId = -1; + } + } + // Fix for #93148 - TCR 001: BAS Game Stability: Title will crash for the multiplayer client if host of the game will exit during the clients loading to created world. + while( g_NetworkManager.IsNetworkThreadRunning() ) + { + Sleep(1); + } + pMinecraft->setLevel(NULL,exitReasonStringId,nullptr,saveStats); + + TelemetryManager->Flush(); + + app.m_gameRules.unloadCurrentGameRules(); + //app.m_Audio.unloadCurrentAudioDetails(); + + MinecraftServer::resetFlags(); + + // Fix for #48385 - BLACK OPS :TU5: Functional: Client becomes pseudo soft-locked when returned to the main menu after a remote disconnect + // Make sure there is text explaining why the player is waiting + pMinecraft->progressRenderer->progressStart(IDS_EXITING_GAME); + + // Fix for #13259 - CRASH: Gameplay: loading process is halted when player loads saved data + // We can't start/join a new game until the session is destroyed, so wait for it to be idle again + while( g_NetworkManager.IsInSession() ) + { + Sleep(1); + } + + app.SetChangingSessionType(false); + app.SetReallyChangingSessionType(false); +} + +void UIScene_PauseMenu::SetIgnoreInput(bool ignoreInput) +{ + m_bIgnoreInput = ignoreInput; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_PauseMenu.h b/Minecraft.Client/Common/XUI/XUI_PauseMenu.h new file mode 100644 index 00000000..9c0e0015 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_PauseMenu.h @@ -0,0 +1,89 @@ +#pragma once +#include "../media/xuiscene_Pause.h" +#include "..\UI\IUIScene_PauseMenu.h" +#include "XUI_CustomMessages.h" + +#define BUTTON_PAUSE_RESUMEGAME 0 +#define BUTTON_PAUSE_HELPANDOPTIONS 1 +#define BUTTON_PAUSE_LEADERBOARDS 2 +#define BUTTON_PAUSE_ACHIEVEMENTS 3 +#define BUTTON_PAUSE_SAVEGAME 4 +#define BUTTON_PAUSE_EXITGAME 5 +#define BUTTONS_PAUSE_MAX BUTTON_PAUSE_EXITGAME + 1 + + + +class UIScene_PauseMenu : public CXuiSceneImpl, public IUIScene_PauseMenu +{ + protected: + // Control and Element wrapper objects. + CXuiScene m_Scene; + CXuiControl m_Buttons[BUTTONS_PAUSE_MAX]; + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiButton1, m_Buttons[BUTTON_PAUSE_RESUMEGAME]) + MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_PAUSE_HELPANDOPTIONS ]) + MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_PAUSE_LEADERBOARDS ]) + MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS]) + MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_PAUSE_SAVEGAME]) + MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_PAUSE_EXITGAME]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + HRESULT OnDestroy(); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( UIScene_PauseMenu, L"CScene_Pause", XUI_CLASS_SCENE ) + + static int BanGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int DeviceSelectReturned(void *pParam,bool bContinue); + static int DeviceRemovedDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitGameSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitGameDeclineSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int SaveGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitGameDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + static int SaveWorldThreadProc( void* lpParameter ); + static int ExitWorldThreadProc( void* lpParameter ); + static void _ExitWorld(LPVOID lpParameter); // Call only from a thread + + +protected: + virtual void ShowScene(bool show); + virtual void SetIgnoreInput(bool ignoreInput); + +private: + int m_iPad; + int m_iLastButtonPressed; + D3DXVECTOR3 m_OriginalPosition; + bool m_bIgnoreInput; + bool m_bSplitscreen; + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Reinstall.cpp b/Minecraft.Client/Common/XUI/XUI_Reinstall.cpp new file mode 100644 index 00000000..c1e06c0d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Reinstall.cpp @@ -0,0 +1,339 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_Reinstall.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\..\Minecraft.Client\StatsCounter.h" +#include "..\..\..\Minecraft.World\Entity.h" +#include "..\..\..\Minecraft.World\Level.h" +#include "..\..\..\Minecraft.Client\LocalPlayer.h" +#include "..\..\MinecraftServer.h" +#include "..\..\ProgressRenderer.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" +#include "..\..\Minecraft.h" +#include "..\..\Options.h" + + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Reinstall::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + // We'll only be in this menu from the main menu, not in game + m_iPad = *(int *)pInitData->pvInitData; + + m_bIgnoreInput=false; + MapChildControls(); + + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_THEME],app.GetString(IDS_REINSTALL_THEME)); + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_GAMERPIC1],app.GetString(IDS_REINSTALL_GAMERPIC_1)); + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_GAMERPIC2],app.GetString(IDS_REINSTALL_GAMERPIC_2)); + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_AVATAR1],app.GetString(IDS_REINSTALL_AVATAR_ITEM_1)); + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_AVATAR2],app.GetString(IDS_REINSTALL_AVATAR_ITEM_2)); + XuiControlSetText(m_Buttons[BUTTON_REINSTALL_AVATAR3],app.GetString(IDS_REINSTALL_AVATAR_ITEM_3)); + + int iFirstEnabled=-1; + + // we can only come in here if we are the primary player, it's the full version, and we have some content to re-install + + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_mine100Blocks) ) + { + m_Buttons[BUTTON_REINSTALL_GAMERPIC1].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_GAMERPIC1].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_GAMERPIC1; + } + else + { + m_Buttons[BUTTON_REINSTALL_GAMERPIC1].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_GAMERPIC1].EnableInput(FALSE); + } + + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_kill10Creepers) ) + { + m_Buttons[BUTTON_REINSTALL_GAMERPIC2].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_GAMERPIC2].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_GAMERPIC2; + } + else + { + m_Buttons[BUTTON_REINSTALL_GAMERPIC2].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_GAMERPIC2].EnableInput(FALSE); + } + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_eatPorkChop) ) + { + m_Buttons[BUTTON_REINSTALL_AVATAR1].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_AVATAR1].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_AVATAR1; + } + else + { + m_Buttons[BUTTON_REINSTALL_AVATAR1].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_AVATAR1].EnableInput(FALSE); + } + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_play100Days) ) + { + m_Buttons[BUTTON_REINSTALL_AVATAR2].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_AVATAR2].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_AVATAR2; + } + else + { + m_Buttons[BUTTON_REINSTALL_AVATAR2].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_AVATAR2].EnableInput(FALSE); + } + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_arrowKillCreeper) ) + { + m_Buttons[BUTTON_REINSTALL_AVATAR3].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_AVATAR3].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_AVATAR3; + } + else + { + m_Buttons[BUTTON_REINSTALL_AVATAR3].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_AVATAR3].EnableInput(FALSE); + } + if(ProfileManager.IsAwardsFlagSet(m_iPad,eAward_socialPost) ) + { + m_Buttons[BUTTON_REINSTALL_THEME].SetEnable(TRUE); + m_Buttons[BUTTON_REINSTALL_THEME].EnableInput(TRUE); + if(iFirstEnabled==-1) iFirstEnabled=BUTTON_REINSTALL_THEME; + } + else + { + m_Buttons[BUTTON_REINSTALL_THEME].SetEnable(FALSE); + m_Buttons[BUTTON_REINSTALL_THEME].EnableInput(FALSE); + } + + // if iFirstEnabled is still -1 then we shouldn't set focus to a button + if(iFirstEnabled!=-1) + { + m_Buttons[iFirstEnabled].InitFocus(m_iPad); + } + + // allow the user to change the storage device + if(!StorageManager.GetSaveDeviceSelected(m_iPad)) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE); + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Reinstall::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + + while((uiButtonCounter<BUTTONS_REINSTALL_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + // Determine which button was pressed, + // and call the appropriate function. + + // store the last button pressed, so on a nav back we can set the focus properly + m_iLastButtonPressed=uiButtonCounter; + // you do have a storage device don't you? + if(!StorageManager.GetSaveDeviceSelected(m_iPad) || StorageManager.GetSaveDisabled()) + { + // Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage + // device, and repeatedly backs out of the SD screen, disconnects from LIVE, and then selects a SD, the title crashes. + m_bIgnoreInput=true; + + StorageManager.SetSaveDevice(&CScene_Reinstall::DeviceSelectReturned_AndReinstall,this,true); + return S_OK; + } + + switch(uiButtonCounter) + { + case BUTTON_REINSTALL_THEME: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_socialPost, true ); + break; + case BUTTON_REINSTALL_GAMERPIC1: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_mine100Blocks, true); + break; + case BUTTON_REINSTALL_GAMERPIC2: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_kill10Creepers, true); + break; + case BUTTON_REINSTALL_AVATAR1: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_eatPorkChop, true ); + break; + case BUTTON_REINSTALL_AVATAR2: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_play100Days, true ); + break; + case BUTTON_REINSTALL_AVATAR3: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_arrowKillCreeper, true ); + break; + } + + return S_OK; +} + +HRESULT CScene_Reinstall::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_PAD_START: + case VK_ESCAPE: + app.NavigateBack(m_iPad); + rfHandled = TRUE; + + break; + case VK_PAD_X: + // Change device + // we need a function to deal with the return from this - if it changes, we need to update the tooltips + // Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage + // device, and repeatedly backs out of the SD screen, disconnects from LIVE, and then selects a SD, the title crashes. + m_bIgnoreInput=true; + StorageManager.SetSaveDevice(&CScene_Reinstall::DeviceSelectReturned,this,true); + + rfHandled = TRUE; + break; + } + + return S_OK; +} + +HRESULT CScene_Reinstall::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + + return S_OK; +} + +HRESULT CScene_Reinstall::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_Reinstall::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + XUIRect xuiRect; + HXUIOBJ visual=NULL; + HXUIOBJ text; + float fMaxTextLen=0.0f; + float fTextVisualLen; + float fMaxButton; + float fWidth,fHeight; + + HRESULT hr=XuiControlGetVisual(m_Buttons[0].m_hObj,&visual); + hr=XuiElementGetChildById(visual,L"text_Label",&text); + hr=XuiElementGetBounds(text,&fTextVisualLen,&fHeight); + m_Buttons[0].GetBounds(&fMaxButton,&fHeight); + + + for(int i=0;i<BUTTONS_REINSTALL_MAX;i++) + { + hr=XuiTextPresenterMeasureText(text, m_Buttons[i].GetText(), &xuiRect); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + } + + if(fTextVisualLen<fMaxTextLen) + { + D3DXVECTOR3 vec; + + // centre is vec.x+(fWidth/2) + for(int i=0;i<BUTTONS_REINSTALL_MAX;i++) + { + // need to resize and reposition the buttons + m_Buttons[i].GetPosition(&vec); + m_Buttons[i].GetBounds(&fWidth,&fHeight); + vec.x= vec.x+(fWidth/2.0f)-(fMaxTextLen/2.0f); + + m_Buttons[i].SetPosition(&vec); + m_Buttons[i].SetBounds(fMaxButton+fMaxTextLen-fTextVisualLen,fHeight); + } + } + } + + return S_OK; +} + +int CScene_Reinstall::DeviceSelectReturned(void *pParam,bool bContinue) +{ + CScene_Reinstall* pClass = (CScene_Reinstall*)pParam; + + if(!StorageManager.GetSaveDeviceSelected(pClass->m_iPad)) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE); + } + else + { + ui.SetTooltips(DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE); + } + + pClass->m_bIgnoreInput=false; + return 0; +} + +int CScene_Reinstall::DeviceSelectReturned_AndReinstall(void *pParam,bool bContinue) +{ + CScene_Reinstall* pClass = (CScene_Reinstall*)pParam; + + if(!StorageManager.GetSaveDeviceSelected(pClass->m_iPad)) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE); + // reinstall + switch(pClass->m_iLastButtonPressed) + { + case BUTTON_REINSTALL_THEME: + ProfileManager.Award( pClass->m_iPad, eAward_socialPost, true ); + break; + case BUTTON_REINSTALL_GAMERPIC1: + ProfileManager.Award( pClass->m_iPad, eAward_mine100Blocks, true); + break; + case BUTTON_REINSTALL_GAMERPIC2: + ProfileManager.Award( pClass->m_iPad, eAward_kill10Creepers, true); + break; + case BUTTON_REINSTALL_AVATAR1: + ProfileManager.Award( pClass->m_iPad, eAward_eatPorkChop, true ); + break; + case BUTTON_REINSTALL_AVATAR2: + ProfileManager.Award( pClass->m_iPad, eAward_play100Days, true ); + break; + case BUTTON_REINSTALL_AVATAR3: + ProfileManager.Award( pClass->m_iPad, eAward_arrowKillCreeper, true ); + break; + } + } + pClass->m_bIgnoreInput=false; + return 0; +} + + diff --git a/Minecraft.Client/Common/XUI/XUI_Reinstall.h b/Minecraft.Client/Common/XUI/XUI_Reinstall.h new file mode 100644 index 00000000..06b823cb --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Reinstall.h @@ -0,0 +1,63 @@ +#pragma once + +#include "../media/xuiscene_Reinstall.h" + +#define BUTTON_REINSTALL_THEME 0 +#define BUTTON_REINSTALL_GAMERPIC1 1 +#define BUTTON_REINSTALL_GAMERPIC2 2 +#define BUTTON_REINSTALL_AVATAR1 3 +#define BUTTON_REINSTALL_AVATAR2 4 +#define BUTTON_REINSTALL_AVATAR3 5 +#define BUTTONS_REINSTALL_MAX BUTTON_REINSTALL_AVATAR3 + 1 + + + +class CScene_Reinstall : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiControl m_Buttons[BUTTONS_REINSTALL_MAX]; + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiButton1, m_Buttons[BUTTON_REINSTALL_THEME ]) + MAP_CONTROL(IDC_XuiButton2, m_Buttons[BUTTON_REINSTALL_GAMERPIC1 ]) + MAP_CONTROL(IDC_XuiButton3, m_Buttons[BUTTON_REINSTALL_GAMERPIC2 ]) + MAP_CONTROL(IDC_XuiButton4, m_Buttons[BUTTON_REINSTALL_AVATAR1 ]) + MAP_CONTROL(IDC_XuiButton5, m_Buttons[BUTTON_REINSTALL_AVATAR2 ]) + MAP_CONTROL(IDC_XuiButton6, m_Buttons[BUTTON_REINSTALL_AVATAR3 ]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + + static int DeviceSelectReturned(void *pParam,bool bContinue); + static int DeviceSelectReturned_AndReinstall(void *pParam,bool bContinue); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Reinstall, L"CScene_Reinstall", XUI_CLASS_SCENE ) + + //static int InstallReturned(void *pParam,bool bContinue); + +private: + int m_iPad; + int m_iLastButtonPressed; + bool m_bIgnoreInput; + + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SaveMessage.cpp b/Minecraft.Client/Common/XUI/XUI_SaveMessage.cpp new file mode 100644 index 00000000..7c816033 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SaveMessage.cpp @@ -0,0 +1,76 @@ +#include "stdafx.h" +#include <assert.h> +#include "..\XUI\XUI_SaveMessage.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SaveMessage::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + + m_button.SetText(app.GetString(IDS_CONFIRM_OK)); + + m_SaveMessage.SetText(app.GetString(IDS_SAVE_ICON_MESSAGE)); + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT ); + + // 4J-PB - If we have a signed in user connected, let's get the DLC now + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ) + { + if(!app.DLCInstallProcessCompleted() && !app.DLCInstallPending()) + { + app.StartInstallDLCProcess(i); + break; + } + } + } + + // set a timer on the saving message screen, so we continue after 8 seconds + XuiSetTimer( m_hObj,0,8000); + m_bIgnoreInput=false; + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SaveMessage::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + XuiKillTimer(m_hObj,0); + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_MainMenu); + rfHandled = TRUE; + return S_OK; +} + +HRESULT CScene_SaveMessage::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + return S_OK; +} + +// 4J-PB - added for Compliance fail - +// Games must enter an interactive state that accepts player input within 20 seconds after the initial start-up sequence. +// If an animation or cinematic shown during the start-up sequence runs longer than 20 seconds, it must be skippable using the START button or natural input. +HRESULT CScene_SaveMessage::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + m_bIgnoreInput=true; + XuiKillTimer(m_hObj,0); + app.NavigateToScene(XUSER_INDEX_ANY,eUIScene_MainMenu); + + return S_OK; +} + + diff --git a/Minecraft.Client/Common/XUI/XUI_SaveMessage.h b/Minecraft.Client/Common/XUI/XUI_SaveMessage.h new file mode 100644 index 00000000..3e84541c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SaveMessage.h @@ -0,0 +1,36 @@ +#pragma once + +#include "../media/xuiscene_savemessage.h" + +class CScene_SaveMessage : public CXuiSceneImpl +{ + protected: + CXuiControl m_button; + CXuiControl m_SaveMessage; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_ConfirmButton, m_button) + MAP_CONTROL(IDC_Description, m_SaveMessage) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled); + + bool m_bIgnoreInput; +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SaveMessage, L"CScene_SaveMessage", XUI_CLASS_SCENE ) + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.cpp new file mode 100644 index 00000000..10369d5e --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.cpp @@ -0,0 +1,475 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include <assert.h> + +#include "..\..\..\Minecraft.World\Player.h" +#include "..\..\..\Minecraft.Client\LocalPlayer.h" +#include "..\..\..\Minecraft.Client\Minecraft.h" +#include "..\..\..\Minecraft.Client\GameMode.h" +#include "..\..\..\Minecraft.World\AbstractContainerMenu.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\Tile.h" +#include "..\..\..\Minecraft.World\FurnaceRecipes.h" +#include "..\..\..\Minecraft.World\Recipy.h" +#include "..\..\..\Minecraft.World\Recipes.h" +#include "..\..\..\Minecraft.World\ArmorRecipes.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" + +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" + +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Ctrl_SlotItem.h" +#include "XUI_Ctrl_SlotItemListItem.h" +#include "XUI_Scene_AbstractContainer.h" +#ifdef _DEBUG_MENUS_ENABLED +#include "XUI_DebugItemEditor.h" +#endif + +#define IGNORE_KEYPRESS_TIMERID 11 +#define IGNORE_KEYPRESS_TIME 100 + +void CXuiSceneAbstractContainer::PlatformInitialize(int iPad, int startIndex) +{ + m_bIgnoreKeyPresses=true; + m_iPad = iPad; + + XuiControlSetText(m_InventoryText,app.GetString(IDS_INVENTORY)); + + // Determine min and max extents for pointer, it needs to be able to move off the container to drop items. + float fPanelWidth, fPanelHeight; + float fPointerWidth, fPointerHeight; + + // We may have varying depths of controls here, so base off the pointers parent + HXUIOBJ parent; + XuiElementGetBounds( m_pointerControl->m_hObj, &fPointerWidth, &fPointerHeight ); + XuiElementGetParent( m_pointerControl->m_hObj, &parent ); + m_pointerControl->SetShow(TRUE); + XuiElementGetBounds( parent, &fPanelWidth, &fPanelHeight ); + // Get size of pointer + m_fPointerImageOffsetX = floor(fPointerWidth/2.0f); + m_fPointerImageOffsetY = floor(fPointerHeight/2.0f); + + m_fPanelMinX = 0.0f; + m_fPanelMaxX = fPanelWidth; + m_fPanelMinY = 0.0f; + m_fPanelMaxY = fPanelHeight; + + // 4J-PB - need to limit this in splitscreen + if(app.GetLocalPlayerCount()>1) + { + // don't let the pointer go into someone's screen + m_fPointerMinY = floor(fPointerHeight/2.0f); + } + else + { + m_fPointerMinY = -fPointerHeight; + } + m_fPointerMinX = -fPointerWidth; + m_fPointerMaxX = fPanelWidth + fPointerWidth; + m_fPointerMaxY = fPanelHeight + (fPointerHeight/2); + +// m_hPointerText=NULL; +// m_hPointerTextBkg=NULL; + + UIVec2D itemPos; + UIVec2D itemSize; + GetItemScreenData( m_eCurrSection, 0, &( itemPos ), &( itemSize ) ); + + UIVec2D sectionPos; + GetPositionOfSection( m_eCurrSection, &( sectionPos ) ); + + UIVec2D vPointerPos = sectionPos; + vPointerPos += itemPos; + vPointerPos.x += ( itemSize.x / 2.0f ); + vPointerPos.y += ( itemSize.y / 2.0f ); + + vPointerPos.x -= m_fPointerImageOffsetX; + vPointerPos.y -= m_fPointerImageOffsetY; + + D3DXVECTOR3 newPointerPos; + newPointerPos.x = vPointerPos.x; + newPointerPos.y = vPointerPos.y; + newPointerPos.z = 0.0f; + m_pointerControl->SetPosition( &newPointerPos ); + m_pointerPos.x = newPointerPos.x; + m_pointerPos.y = newPointerPos.y; + +#ifdef USE_POINTER_ACCEL + m_fPointerVelX = 0.0f; + m_fPointerVelY = 0.0f; + m_fPointerAccelX = 0.0f; + m_fPointerAccelY = 0.0f; +#endif + + // Add timer to poll controller stick input at 60Hz + HRESULT timerResult = SetTimer( POINTER_INPUT_TIMER_ID, ( 1000 / 60 ) ); + assert( timerResult == S_OK ); + + XuiSetTimer(m_hObj,IGNORE_KEYPRESS_TIMERID,IGNORE_KEYPRESS_TIME); + + // Disable the default navigation behaviour for all slot lsit items (prevent old style cursor navigation). + for ( int iSection = m_eFirstSection; iSection < m_eMaxSection; ++iSection ) + { + ESceneSection eSection = ( ESceneSection )( iSection ); + + if(!IsSectionSlotList(eSection)) continue; + + // Get dimensions of this section. + int iNumRows; + int iNumColumns; + int iNumItems = GetSectionDimensions( eSection, &( iNumColumns ), &( iNumRows ) ); + + for ( int iItem = 0; iItem < iNumItems; ++iItem ) + { + CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem; + GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iItem, &( pCXuiCtrlSlotItem ) ); + pCXuiCtrlSlotItem->SetSkipsDefaultNavigation( TRUE ); + } + } +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneAbstractContainer::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + // TODO Inventory dimensions need defined as constants + m_inventoryControl->SetData( iPad, menu, 3, 9, startIndex, startIndex + 3*9 ); + + // TODO Inventory dimensions need defined as constants + m_useRowControl->SetData( iPad, menu, 1, 9, startIndex + 3*9, startIndex + 4*9 ); + + m_pointerControl->SetUserIndex(m_pointerControl->m_hObj, iPad); +} + +int CXuiSceneAbstractContainer::getSectionColumns(ESceneSection eSection) +{ + return GetSectionSlotList( eSection )->GetColumns(); +} + +int CXuiSceneAbstractContainer::getSectionRows(ESceneSection eSection) +{ + return GetSectionSlotList( eSection )->GetRows(); +} + +// Adding this so we can turn off the pointer text background, since it flickers on then off at the start of a scene where a tutorial popup is +HRESULT CXuiSceneAbstractContainer::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J Stu - Added to support auto-save. Need to re-associate on a navigate back + if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // Add timer to poll controller stick input at 60Hz + HRESULT timerResult = SetTimer( POINTER_INPUT_TIMER_ID, ( 1000 / 60 ) ); + assert( timerResult == S_OK ); + + InitDataAssociations(m_iPad, m_menu); + } + + HXUIOBJ hObj=NULL; + HRESULT hr=XuiControlGetVisual(m_pointerControl->m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"text_measurer",&m_hPointerTextMeasurer); + hr=XuiElementGetChildById(hObj,L"text_name",&m_hPointerText); + hr=XuiElementGetChildById(hObj,L"text_panel",&m_hPointerTextBkg); + hr=XuiElementGetChildById(hObj,L"pointer_image",&m_hPointerImg); + XuiElementSetShow(m_hPointerText,FALSE); + XuiElementSetShow(m_hPointerTextBkg,FALSE); + } + + return S_OK; +} + + +D3DXVECTOR3 CXuiSceneAbstractContainer::GetCursorScreenPosition() +{ + return app.GetElementScreenPosition(m_pointerControl->m_hObj); +} + +HRESULT CXuiSceneAbstractContainer::OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) +{ + if(m_bIgnoreKeyPresses) return S_OK; + + bHandled = handleKeyDown(pInputData->UserIndex, mapVKToAction(pInputData->dwKeyCode), (pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT) != 0); + + return S_OK; +} + +int CXuiSceneAbstractContainer::mapVKToAction(int vk) +{ + int action = MINECRAFT_ACTION_MAX; + switch(vk) + { + case VK_PAD_A: + action = ACTION_MENU_A; + break; + case VK_PAD_B: + case VK_PAD_START: + action = ACTION_MENU_B; + break; + case VK_PAD_X: + action = ACTION_MENU_X; + break; + case VK_PAD_Y: + action = ACTION_MENU_Y; + break; + case VK_PAD_DPAD_LEFT: + action = ACTION_MENU_LEFT; + break; + case VK_PAD_DPAD_RIGHT: + action = ACTION_MENU_RIGHT; + break; + case VK_PAD_DPAD_UP: + action = ACTION_MENU_UP; + break; + case VK_PAD_DPAD_DOWN: + action = ACTION_MENU_DOWN; + break; + case VK_PAD_LTRIGGER: + action = ACTION_MENU_PAGEUP; + break; + case VK_PAD_RTRIGGER: + action = ACTION_MENU_PAGEDOWN; + break; + case VK_PAD_LSHOULDER: + action = ACTION_MENU_LEFT_SCROLL; + break; + case VK_PAD_RSHOULDER: + action = ACTION_MENU_RIGHT_SCROLL; + break; + case VK_PAD_RTHUMB_UP: + action = ACTION_MENU_OTHER_STICK_UP; + break; + case VK_PAD_RTHUMB_DOWN: + action = ACTION_MENU_OTHER_STICK_DOWN; + break; + case VK_PAD_RTHUMB_RIGHT: + action = ACTION_MENU_OTHER_STICK_RIGHT; + break; + case VK_PAD_RTHUMB_LEFT: + action = ACTION_MENU_OTHER_STICK_LEFT; + break; + }; + + return action; +} + +void CXuiSceneAbstractContainer::handleSectionClick(ESceneSection eSection) +{ + CXuiCtrlSlotList *slotList = GetSectionSlotList( eSection ); + slotList->Clicked(); +} + +HRESULT CXuiSceneAbstractContainer::handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + return S_OK; +} + +// Returns XUI position of given scene section. +void CXuiSceneAbstractContainer::GetPositionOfSection( ESceneSection eSection, UIVec2D* pPosition ) +{ + D3DXVECTOR3 xuiPos; + GetSectionControl( eSection )->GetPosition( &xuiPos ); + pPosition->x = xuiPos.x; + pPosition->y = xuiPos.y; +} + +void CXuiSceneAbstractContainer::GetItemScreenData( ESceneSection eSection, int iItemIndex, UIVec2D* pPosition, UIVec2D* pSize ) +{ + D3DXVECTOR3 xuiPos; + if(IsSectionSlotList(eSection)) + { + // Get slot item. + CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem; + GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iItemIndex, &( pCXuiCtrlSlotItem ) ); + + // Get size of slot. + pCXuiCtrlSlotItem->GetBounds( &( pSize->x ), &( pSize->y ) ); + + // Get position of slot. + pCXuiCtrlSlotItem->GetPosition( &xuiPos ); + pPosition->x = xuiPos.x; + pPosition->y = xuiPos.y; + } + else + { + // Get size of control + GetSectionControl( eSection )->GetBounds( &( pSize->x ), &( pSize->y ) ); + + // Get position of control + GetSectionControl( eSection )->GetPosition( &xuiPos ); + pPosition->x = xuiPos.x; + pPosition->y = xuiPos.y; + } +} + +shared_ptr<ItemInstance> CXuiSceneAbstractContainer::getSlotItem(ESceneSection eSection, int iSlot) +{ + CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem; + GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iSlot, &( pCXuiCtrlSlotItem ) ); + return pCXuiCtrlSlotItem->getItemInstance( pCXuiCtrlSlotItem->m_hObj ); +} + +bool CXuiSceneAbstractContainer::isSlotEmpty(ESceneSection eSection, int iSlot) +{ + CXuiCtrlSlotItemListItem* pCXuiCtrlSlotItem; + GetSectionSlotList( eSection )->GetCXuiCtrlSlotItem( iSlot, &( pCXuiCtrlSlotItem ) ); + return pCXuiCtrlSlotItem->isEmpty( pCXuiCtrlSlotItem->m_hObj ); +} + +HRESULT CXuiSceneAbstractContainer::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + HRESULT hr = S_OK; + + // Update pointer from stick input on timer. + if ( pTimer->nId == POINTER_INPUT_TIMER_ID ) + { + + onMouseTick(); + D3DXVECTOR3 pointerPos; + pointerPos.x = m_pointerPos.x; + pointerPos.y = m_pointerPos.y; + pointerPos.z = 0.0f; + m_pointerControl->SetPosition( &pointerPos ); + // This message has been dealt with, don't pass it on further. + bHandled = TRUE; + } + else if ( pTimer->nId == IGNORE_KEYPRESS_TIMERID) + { + KillTimer(IGNORE_KEYPRESS_TIMERID); + m_bIgnoreKeyPresses=false; + } + else + { + // Some scenes may have their own timers for other events, so handle them here + hr = handleCustomTimer( pTimer, bHandled ); + } + return hr; +} + +HRESULT CXuiSceneAbstractContainer::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +bool CXuiSceneAbstractContainer::doesSectionTreeHaveFocus(ESceneSection eSection) +{ + return GetSectionControl( eSection )->TreeHasFocus(); +} + +void CXuiSceneAbstractContainer::setSectionFocus(ESceneSection eSection, int iPad) +{ + HRESULT focusResult = GetSectionControl( eSection )->SetFocus( iPad ); + assert( focusResult == S_OK ); +} + +void CXuiSceneAbstractContainer::setSectionSelectedSlot(ESceneSection eSection, int x, int y) +{ + GetSectionSlotList( eSection )->SetCurrentSlot(y,x); +} + +void CXuiSceneAbstractContainer::setFocusToPointer(int iPad) +{ + m_pointerControl->SetFocus( iPad ); +} + +void CXuiSceneAbstractContainer::SetPointerText(const wstring &description, vector<wstring> &unformattedStrings, bool newSlot) +{ + if(description.empty()) + { + m_pointerControl->SetText(L""); + XuiElementSetShow(m_hPointerText,FALSE); + XuiElementSetShow(m_hPointerTextBkg,FALSE); + return; + } + + bool smallPointer = m_bSplitscreen || (!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()); + wstring desc = L"<font size=\"" + _toString<int>(smallPointer ? 12 :14) + L"\">" + description + L"</font>"; + + XUIRect tempXuiRect, xuiRect; + HRESULT hr; + xuiRect.right = 0; + + for(AUTO_VAR(it, unformattedStrings.begin()); it != unformattedStrings.end(); ++it) + { + XuiTextPresenterMeasureText(m_hPointerTextMeasurer, parseXMLSpecials((*it)).c_str(), &tempXuiRect); + if(tempXuiRect.right > xuiRect.right) xuiRect = tempXuiRect; + } + + // Set size with the new width so that the HTML height check is correct + XuiElementSetBounds(m_hPointerTextBkg,xuiRect.right+4.0f+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge + XuiElementSetBounds(m_hPointerText,xuiRect.right+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, text is centred + + XuiHtmlSetText(m_hPointerText, desc.c_str() ); + + // Check if we need to resize the box + XUIContentDims contentDims; + XuiHtmlGetContentDims(m_hPointerText,&contentDims); + xuiRect.bottom = contentDims.nContentHeight; + + // get the size of the button, and apply the change in size due to the text to the whole button + float fImgWidth,fImgHeight; + XuiElementGetBounds(m_hPointerImg,&fImgWidth, &fImgHeight); + // 4J-PB - changing to calculate values + D3DXVECTOR3 vPosText, vPosTextBkg,vPosImg; + + XuiElementGetPosition(m_hPointerImg,&vPosImg); + XuiElementGetPosition(m_hPointerText,&vPosText); + XuiElementGetPosition(m_hPointerTextBkg,&vPosTextBkg); + + // Set the new height + XuiElementSetBounds(m_hPointerTextBkg,xuiRect.right+4.0f+4.0f+4.0f,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge + XuiElementSetBounds(m_hPointerText,xuiRect.right+4.0f+4.0f,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, text is centred + + // position the text and panel relative to the pointer image + vPosTextBkg.x=vPosImg.x+fImgWidth*0.6f; + vPosText.x=vPosTextBkg.x + 4; + vPosTextBkg.y=vPosImg.y-(xuiRect.bottom+4.0f+4.0f)+fImgWidth*0.4f; + vPosText.y=vPosTextBkg.y + 4; + + XuiElementSetPosition(m_hPointerText,&vPosText); + XuiElementSetPosition(m_hPointerTextBkg,&vPosTextBkg); + + XuiElementSetShow(m_hPointerTextBkg,TRUE); + XuiElementSetShow(m_hPointerText,TRUE); +} + +void CXuiSceneAbstractContainer::adjustPointerForSafeZone() +{ + D3DXVECTOR2 baseSceneOrigin; + float baseWidth, baseHeight; + if(CXuiSceneBase::GetBaseSceneSafeZone( m_iPad, baseSceneOrigin, baseWidth, baseHeight)) + { + D3DXMATRIX pointerBackgroundMatrix; + XuiElementGetFullXForm( m_hPointerTextBkg, &pointerBackgroundMatrix); + + float width, height; + XuiElementGetBounds( m_hPointerTextBkg, &width, &height ); + + if( ( (pointerBackgroundMatrix._41 / pointerBackgroundMatrix._11) + width) > (baseSceneOrigin.x + baseWidth) ) + { + //app.DebugPrintf("Pointer is outside the safe zone for this base scene\n"); + + // get the size of the button, and apply the change in size due to the text to the whole button + float fImgWidth,fImgHeight; + XuiElementGetBounds(m_hPointerImg,&fImgWidth, &fImgHeight); + // 4J-PB - changing to calculate values + D3DXVECTOR3 vPosText, vPosTextBkg,vPosImg; + + XuiElementGetPosition(m_hPointerImg,&vPosImg); + XuiElementGetPosition(m_hPointerText,&vPosText); + XuiElementGetPosition(m_hPointerTextBkg,&vPosTextBkg); + + // position the text and panel relative to the pointer image + vPosTextBkg.x= (vPosImg.x+fImgWidth*0.4f) - width; + vPosText.x=vPosTextBkg.x + 4; + + XuiElementSetPosition(m_hPointerText,&vPosText); + XuiElementSetPosition(m_hPointerTextBkg,&vPosTextBkg); + } + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.h b/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.h new file mode 100644 index 00000000..ca191db5 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.h @@ -0,0 +1,83 @@ +#pragma once +#include "..\UI\IUIScene_AbstractContainerMenu.h" +#include "XUI_CustomMessages.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" + +class CXuiCtrlSlotList; +class CXuiCtrlSlotItem; +class AbstractContainerMenu; +class Slot; + +class CXuiSceneAbstractContainer : public CXuiSceneImpl, public virtual IUIScene_AbstractContainerMenu +{ +public: + BOOL isPauseScreen() { + return FALSE; + }; + + D3DXVECTOR3 GetCursorScreenPosition(); + +protected: + virtual void PlatformInitialize(int iPad, int startIndex); + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + + CXuiCtrlSlotList* m_inventoryControl; + CXuiCtrlSlotList* m_useRowControl; + CXuiCtrlSlotItem* m_pointerControl; + CXuiControl m_InventoryText; + + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + // Timer function to poll stick input and update pointer position. + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + +protected: + // 4J JEV - Wanted to override onClick method in XUI_Scene_Inventory_Creative, + // so am making this protected. + + +protected: + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + bool m_bIgnoreKeyPresses; + +private: + int mapVKToAction(int vk); + +protected: + virtual HRESULT handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + +public: + int getPad() { return m_iPad; } + +#ifdef USE_POINTER_ACCEL + float m_fPointerVelX; + float m_fPointerVelY; + + float m_fPointerAccelX; + float m_fPointerAccelY; +#endif + + + HXUIOBJ m_hPointerTextMeasurer; + HXUIOBJ m_hPointerText; + HXUIOBJ m_hPointerTextBkg; + HXUIOBJ m_hPointerImg; + + virtual int getSectionColumns(ESceneSection eSection); + virtual int getSectionRows(ESceneSection eSection); + virtual CXuiControl* GetSectionControl( ESceneSection eSection ) = 0; + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ) = 0; + virtual void GetPositionOfSection( ESceneSection eSection, UIVec2D* pPosition ); + virtual void GetItemScreenData( ESceneSection eSection, int iItemIndex, UIVec2D* pPosition, UIVec2D* pSize ); + void handleSectionClick(ESceneSection eSection); + virtual bool doesSectionTreeHaveFocus(ESceneSection eSection); + virtual void setSectionFocus(ESceneSection eSection, int iPad); + void setSectionSelectedSlot(ESceneSection eSection, int x, int y); + void setFocusToPointer(int iPad); + void SetPointerText(const wstring &description, vector<wstring> &unformattedStrings, bool newSlot); + virtual shared_ptr<ItemInstance> getSlotItem(ESceneSection eSection, int iSlot); + virtual bool isSlotEmpty(ESceneSection eSection, int iSlot); + virtual void adjustPointerForSafeZone(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.cpp new file mode 100644 index 00000000..4a8617b4 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.cpp @@ -0,0 +1,242 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_Anvil.h" + + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneAnvil::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneAnvil::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_anvilText,app.GetString(IDS_REPAIR_AND_NAME)); + + m_cross.SetShow(FALSE); + m_editName.SetText(L""); + m_editName.SetTextLimit(30); + m_editName.SetTitleAndText(IDS_TITLE_RENAME,IDS_TITLE_RENAME); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + AnvilScreenInput* initData = (AnvilScreenInput*)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + m_inventory = initData->inventory; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Anvil_Menu, this); + } + + m_repairMenu = new RepairMenu( initData->inventory, initData->level, initData->x, initData->y, initData->z, pMinecraft->localplayers[m_iPad] ); + m_repairMenu->addSlotListener(this); + + InitDataAssociations(m_iPad, m_repairMenu); + + delete initData; + + CXuiSceneAbstractContainer::Initialize( m_iPad, m_repairMenu, true, RepairMenu::INV_SLOT_START, eSectionAnvilUsing, eSectionAnvilMax ); + + //ProfileManager.SetRichPresenceContextValue(m_iPad,CONTEXT_GAME_STATE,CONTEXT_GAME_STATE_FORGING); + + XuiSetTimer(m_hObj,ANVIL_UPDATE_TIMER_ID,ANVIL_UPDATE_TIMER_TIME); + + return S_OK; +} + +HRESULT CXuiSceneAnvil::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +HRESULT CXuiSceneAnvil::OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) +{ + if(hObjSource == m_editName) + { + wstring newValue = m_editName.GetText(); + LPCWSTR szText=newValue.c_str(); + stripWhitespaceForHtml(newValue); + + // strip leading spaces + wstring b; + int start = (int)newValue.find_first_not_of(L" "); + int end = (int)newValue.find_last_not_of(L" "); + + if( start == wstring::npos ) + { + // the string is all space + newValue=L""; + } + else + { + if( end == wstring::npos ) end = (int)newValue.size()-1; + b = newValue.substr(start,(end-start)+1); + newValue=b; + } + + // 4J-PB - This was stopping the player deleting the last character in the name using the chatpad + //if(!newValue.empty() && !(newValue.size() == 1 && newValue.at(0) == L' ')) + { + newValue = escapeXML(newValue); + m_itemName = newValue; + updateItemName(); + } +// else +// { +// LPCWSTR szText=m_itemName.c_str(); +// m_editName.SetText(szText); +// m_editName.SetCaretPosition(m_itemName.length()); +// } + } + + return S_OK; +} + +HRESULT CXuiSceneAnvil::handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + if(pTimer->nId == ANVIL_UPDATE_TIMER_ID) + { + handleTick(); + bHandled = TRUE; + } + return S_OK; +} + +CXuiControl* CXuiSceneAnvil::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionAnvilItem1: + return (CXuiControl *)m_ingredient1Control; + break; + case eSectionAnvilItem2: + return (CXuiControl *)m_ingredient2Control; + break; + case eSectionAnvilResult: + return (CXuiControl *)m_resultControl; + break; + case eSectionAnvilName: + return (CXuiControl *)&m_editName; + break; + case eSectionAnvilInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionAnvilUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneAnvil::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionAnvilItem1: + return m_ingredient1Control; + break; + case eSectionAnvilItem2: + return m_ingredient2Control; + break; + case eSectionAnvilResult: + return m_resultControl; + break; + case eSectionAnvilInventory: + return m_inventoryControl; + break; + case eSectionAnvilUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneAnvil::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + // TODO Inventory dimensions need defined as constants + m_resultControl->SetData( iPad, menu, 1, 1, RepairMenu::RESULT_SLOT ); + + m_ingredient1Control->SetData( iPad, menu, 1, 1, RepairMenu::INPUT_SLOT ); + m_ingredient2Control->SetData( iPad, menu, 1, 1, RepairMenu::ADDITIONAL_SLOT); + + //m_litProgressControl->SetUserData( initData->furnace.get() ); + + //m_burnProgress->SetUserData( initData->furnace.get() ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, RepairMenu::INV_SLOT_START); +} + +void CXuiSceneAnvil::handleEditNamePressed() +{ + // 4J Stu - The edit control already handles A/Start presses, so ignore anything else + //m_editName.RequestKeyboard(m_iPad); +} + +void CXuiSceneAnvil::setEditNameValue(const wstring &name) +{ + wstring parsedName = parseXMLSpecials(name); + m_editName.SetText(parsedName.c_str()); + m_editName.SetCaretPosition(parsedName.length()); +} + +void CXuiSceneAnvil::setEditNameEditable(bool enabled) +{ +} + +void CXuiSceneAnvil::setCostLabel(const wstring &label, bool canAfford) +{ + if(canAfford) + { + m_affordableText.SetText(label.c_str()); + m_affordableText.SetShow(TRUE); + m_expensiveText.SetShow(FALSE); + } + else + { + m_expensiveText.SetText(label.c_str()); + m_affordableText.SetShow(FALSE); + m_expensiveText.SetShow(TRUE); + } +} + +void CXuiSceneAnvil::showCross(bool show) +{ + m_cross.SetShow(show?TRUE:FALSE); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.h b/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.h new file mode 100644 index 00000000..2b16c8ab --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Anvil.h @@ -0,0 +1,88 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_anvil.h" +#include "XUI_Scene_AbstractContainer.h" +#include "..\UI\IUIScene_AnvilMenu.h" +#include "Common\XUI\XUI_Ctrl_4JEdit.h" + +#define ANVIL_UPDATE_TIMER_ID (10) +#define ANVIL_UPDATE_TIMER_TIME (1000) // 1 second + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneAnvil : public CXuiSceneAbstractContainer, public IUIScene_AnvilMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneAnvil, L"CXuiSceneAnvil", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Ingredient, m_ingredient1Control) + MAP_OVERRIDE(IDC_Ingredient2, m_ingredient2Control) + MAP_OVERRIDE(IDC_Result, m_resultControl) + + MAP_CONTROL(IDC_AnvilTextInput, m_editName) + + MAP_CONTROL(IDC_AnvilText,m_anvilText) + MAP_CONTROL(IDC_LabelAffordable,m_affordableText) + MAP_CONTROL(IDC_LabelExpensive,m_expensiveText) + MAP_CONTROL(IDC_AnvilCross,m_cross) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled); +// HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + virtual HRESULT handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + +private: + CXuiCtrlSlotList *m_ingredient1Control; + CXuiCtrlSlotList *m_ingredient2Control; + CXuiCtrlSlotList *m_resultControl; + + CXuiCtrl4JEdit m_editName; + + CXuiControl m_anvilText; + CXuiControl m_affordableText; + CXuiControl m_expensiveText; + CXuiControl m_cross; + CXuiControl m_sceneGroup; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); + +protected: + virtual void handleEditNamePressed(); + virtual void setEditNameValue(const wstring &name); + virtual void setEditNameEditable(bool enabled); + virtual void setCostLabel(const wstring &label, bool canAfford); + virtual void showCross(bool show); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Base.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Base.cpp new file mode 100644 index 00000000..03782c79 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Base.cpp @@ -0,0 +1,2243 @@ +#include "stdafx.h" + +#include <assert.h> +#include "..\..\MultiplayerLevel.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\StatsCounter.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\Minecraft.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\LevelData.h" +#include "XUI_CustomMessages.h" +#include "..\..\..\Minecraft.World\Dimension.h" +#include "..\..\..\Minecraft.World\SharedConstants.h" +#include "..\..\GameMode.h" +#include "..\..\EnderDragonRenderer.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" +#include "..\..\DLCTexturePack.h" + +#define PRESS_START_TIMER 0 + +CXuiSceneBase *CXuiSceneBase::Instance = NULL; +DWORD CXuiSceneBase::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME; +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CXuiSceneBase::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + ASSERT( CXuiSceneBase::Instance == NULL ); + CXuiSceneBase::Instance = this; + + m_iWrongTexturePackTickC=20*5; // default 5 seconds before bringing up the upsell for not having the texture pack + MapChildControls(); + + // Display the tooltips + HRESULT hr = S_OK; + CXuiElement xuiElement = m_hObj; + HXUIOBJ hTemp; + + + m_hEmptyQuadrantLogo=NULL; + XuiElementGetChildById(m_hObj,L"EmptyQuadrantLogo",&m_hEmptyQuadrantLogo); + + D3DXVECTOR3 lastPos; + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + for( unsigned int i = 0; i < BUTTONS_TOOLTIP_MAX; ++i ) + { + m_visible[idx][ i ] = FALSE; + m_iCurrentTooltipTextID[idx][i]=-1; + hTooltipText[idx][i]=NULL; + hTooltipTextSmall[idx][i]=NULL; + // set all tooltips to shown FALSE by default + m_Buttons[idx][i].SetShow( FALSE ); + m_ButtonsSmall[idx][i].SetShow( FALSE ); + } + + XuiElementGetPosition( m_bottomLeftAnchorPoint[idx].m_hObj, &lastPos); + lastPos.y-=110; + + m_bCrouching[idx]=false; + m_uiSelectedItemOpacityCountDown[idx] =0; + m_bossHealthVisible[idx] = FALSE; + + switch(idx) + { + case 0: + XuiElementGetChildById(m_hObj,L"BasePlayer0",&hTemp); + XuiElementGetChildById(hTemp,L"XuiGamertag",&m_hGamerTagA[0]); + break; + case 1: + XuiElementGetChildById(m_hObj,L"BasePlayer1",&hTemp); + XuiElementGetChildById(hTemp,L"XuiGamertag",&m_hGamerTagA[1]); + break; + case 2: + XuiElementGetChildById(m_hObj,L"BasePlayer2",&hTemp); + XuiElementGetChildById(hTemp,L"XuiGamertag",&m_hGamerTagA[2]); + break; + case 3: + XuiElementGetChildById(m_hObj,L"BasePlayer3",&hTemp); + XuiElementGetChildById(hTemp,L"XuiGamertag",&m_hGamerTagA[3]); + break; + } + } + + m_ticksWithNoBoss = 0; + + UpdatePlayerBasePositions(); + + m_iQuadrantsMask=0; + + return S_OK; +} + +HRESULT CXuiSceneBase::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==PRESS_START_TIMER) + { + XuiKillTimer(m_hObj,PRESS_START_TIMER); + XuiElementStopTimeline(m_hObj,TRUE); + m_PressStart.SetShow(FALSE); + + // clear the quadrants + m_iQuadrantsMask=0; + + HXUIOBJ hObj=NULL,hQuadrant; + + HRESULT hr=XuiControlGetVisual(m_PressStart.m_hObj,&hObj); + + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + switch(i) + { + case 0: + hr=XuiElementGetChildById(hObj,L"Quadrant1",&hQuadrant); + XuiElementSetShow(hQuadrant,FALSE); + break; + case 1: + hr=XuiElementGetChildById(hObj,L"Quadrant2",&hQuadrant); + XuiElementSetShow(hQuadrant,FALSE); + break; + case 2: + hr=XuiElementGetChildById(hObj,L"Quadrant3",&hQuadrant); + XuiElementSetShow(hQuadrant,FALSE); + break; + case 3: + hr=XuiElementGetChildById(hObj,L"Quadrant4",&hQuadrant); + XuiElementSetShow(hQuadrant,FALSE); + break; + } + } + } + + return S_OK; +} + +HRESULT CXuiSceneBase::OnSkinChanged(BOOL& bHandled) +{ + // Clear visuals held for tooltips + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + for( unsigned int i = 0; i < BUTTONS_TOOLTIP_MAX; ++i ) + { + hTooltipText[idx][i]=NULL; + hTooltipTextSmall[idx][i]=NULL; + } + } + + // Don't set to handled + + return S_OK; +} + +void CXuiSceneBase::_TickAllBaseScenes() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + // 4J-PB - added to upsell the texture pack if you join from invite and don't have it + // what texture pack are we using? + bool bCheckTexturePack=false; + + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + bCheckTexturePack= app.GetGameStarted() && (ui.GetMenuDisplayed(0)==false) && (app.GetXuiAction(i)==eAppAction_Idle); + } + + // make sure there's not a mount going on before using the textures + if(bCheckTexturePack && app.DLCInstallProcessCompleted() ) + { + TexturePack *tPack = pMinecraft->skins->getSelected(); + + if(tPack->getId()!=app.GetRequiredTexturePackID()) + { + // we're not using the texture pack we need + + //Is it available? + TexturePack * pRequiredTPack=pMinecraft->skins->getTexturePackById(app.GetRequiredTexturePackID()); + if(pRequiredTPack!=NULL) + { + // we can switch to the required pack + // reset the timer + m_iWrongTexturePackTickC=20*60*5; // reset to 5 minutes + + pMinecraft->skins->selectTexturePackById(app.GetRequiredTexturePackID()); + + // probably had background downloads enabled, so turn them off + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + } + else + { + // decrement the counter + m_iWrongTexturePackTickC--; + + if(m_iWrongTexturePackTickC==0) + { + // action + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_TexturePackRequired); + + // reset the timer + m_iWrongTexturePackTickC=20*60*5; // reset to 5 minutes + } + } + } + } + + if (EnderDragonRenderer::bossInstance == NULL) + { + if(m_ticksWithNoBoss<=20) + { + ++m_ticksWithNoBoss; + } + } + else + { + shared_ptr<EnderDragon> boss = EnderDragonRenderer::bossInstance; + EnderDragonRenderer::bossInstance = nullptr; + m_ticksWithNoBoss = 0; + + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(pMinecraft->localplayers[i] != NULL && pMinecraft->localplayers[i]->dimension == 1 && !ui.GetMenuDisplayed(i) && app.GetGameSettings(i,eGameSetting_DisplayHUD)) + { + int iGuiScale; + + if(pMinecraft->localplayers[i]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + iGuiScale=app.GetGameSettings(i,eGameSetting_UISize); + } + else + { + iGuiScale=app.GetGameSettings(i,eGameSetting_UISizeSplitscreen); + } + m_BossHealthGroup[i].SetShow(TRUE); + m_BossHealthText[i].SetText( app.GetString( IDS_BOSS_ENDERDRAGON_HEALTH ) ); + + if(pMinecraft->localplayers[i]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + switch(iGuiScale) + { + case 0: + m_pBossHealthProgress = m_BossHealthProgress1; + m_BossHealthProgress1[i].SetShow(TRUE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(FALSE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + + + break; + case 1: + m_pBossHealthProgress = m_BossHealthProgress2; + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(TRUE); + m_BossHealthProgress3[i].SetShow(FALSE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + + break; + case 2: + m_pBossHealthProgress = m_BossHealthProgress3; + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(TRUE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + + break; + } + } + else + { + // if we have 2 player top & bottom, we can use the fullscreen bar + if((pMinecraft->localplayers[i]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP) || + (pMinecraft->localplayers[i]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM)) + { + switch(iGuiScale) + { + case 0: + m_pBossHealthProgress = m_BossHealthProgress1; + m_BossHealthProgress1[i].SetShow(TRUE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(FALSE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + + break; + case 1: + m_pBossHealthProgress = m_BossHealthProgress2; + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(TRUE); + m_BossHealthProgress3[i].SetShow(FALSE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + break; + case 2: + m_pBossHealthProgress = m_BossHealthProgress3; + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(TRUE); + if(m_BossHealthProgress1_small[i]!=NULL) + { + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + } + break; + } + } + else + { + // use the small versions + switch(iGuiScale) + { + case 0: + m_pBossHealthProgress = m_BossHealthProgress1_small; + m_BossHealthProgress1_small[i].SetShow(TRUE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(FALSE); + + break; + case 1: + m_pBossHealthProgress = m_BossHealthProgress2_small; + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(TRUE); + m_BossHealthProgress3_small[i].SetShow(FALSE); + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(FALSE); + break; + case 2: + m_pBossHealthProgress = m_BossHealthProgress3_small; + m_BossHealthProgress1_small[i].SetShow(FALSE); + m_BossHealthProgress2_small[i].SetShow(FALSE); + m_BossHealthProgress3_small[i].SetShow(TRUE); + m_BossHealthProgress1[i].SetShow(FALSE); + m_BossHealthProgress2[i].SetShow(FALSE); + m_BossHealthProgress3[i].SetShow(FALSE); + break; + } + } + } + + m_pBossHealthProgress[i].SetRange(0, boss->getMaxHealth() ); + m_pBossHealthProgress[i].SetValue( boss->getSynchedHealth() ); + m_bossHealthVisible[i] = TRUE; + + _UpdateSelectedItemPos(i); + } + else if( m_bossHealthVisible[i] == TRUE) + { + m_BossHealthGroup[i].SetShow(FALSE); + m_bossHealthVisible[i] = FALSE; + + _UpdateSelectedItemPos(i); + } + } + } + + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + if(m_uiSelectedItemOpacityCountDown[i] > 0) --m_uiSelectedItemOpacityCountDown[i]; + if( m_ticksWithNoBoss > 20 ) + { + m_BossHealthGroup[i].SetShow(FALSE); + m_bossHealthVisible[i] = FALSE; + + _UpdateSelectedItemPos(i); + } + + // check if we have the timer running for the opacity + unsigned int uiOpacityTimer=m_uiSelectedItemOpacityCountDown[i]; + + if(uiOpacityTimer>0 && !ui.GetMenuDisplayed(i) && app.GetGameStarted()) + { + if(uiOpacityTimer < (SharedConstants::TICKS_PER_SECOND * 1) ) + { + float fStep=(80.0f)/10.0f; + float fVal=0.01f*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep)); + + XuiElementSetOpacity(m_selectedItemA[i],fVal); + XuiElementSetOpacity(m_selectedItemSmallA[i],fVal); + } + + if( m_playerBaseScenePosition[i] == e_BaseScene_Fullscreen ) + { + m_selectedItemA[i].SetShow(TRUE); + m_selectedItemSmallA[i].SetShow(FALSE); + } + else + { + m_selectedItemA[i].SetShow(FALSE); + m_selectedItemSmallA[i].SetShow(TRUE); + } + } + else + { + m_selectedItemA[i].SetShow(FALSE); + m_selectedItemSmallA[i].SetShow(FALSE); + } + + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + float fVal; + + if(ucAlpha<80) + { + // if we are in a menu, set the minimum opacity for tooltips to 15% + if(ui.GetMenuDisplayed(i) && (ucAlpha<15)) + { + ucAlpha=15; + } + + // check if we have the timer running for the opacity + unsigned int uiOpacityTimer=app.GetOpacityTimer(i); + if(uiOpacityTimer!=0) + { + if(uiOpacityTimer<10) + { + float fStep=(80.0f-(float)ucAlpha)/10.0f; + fVal=0.01f*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep)); + } + else + { + fVal=0.01f*80.0f; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + } + else + { + // if we are in a menu, set the minimum opacity for tooltips to 15% + if(ui.GetMenuDisplayed(i) && (ucAlpha<15)) + { + ucAlpha=15; + } + fVal=0.01f*(float)ucAlpha; + } + XuiElementSetOpacity(app.GetCurrentHUDScene(i),fVal); + + XUIMessage xuiMsg; + CustomMessage_TickScene( &xuiMsg ); + XuiSendMessage( app.GetCurrentHUDScene(i), &xuiMsg ); + + bool bDisplayGui=app.GetGameStarted() && !ui.GetMenuDisplayed(i) && !(app.GetXuiAction(i)==eAppAction_AutosaveSaveGameCapturedThumbnail) && app.GetGameSettings(i,eGameSetting_DisplayHUD)!=0; + if(bDisplayGui && pMinecraft->localplayers[i] != NULL) + { + XuiElementSetShow(app.GetCurrentHUDScene(i),TRUE); + } + else + { + XuiElementSetShow(app.GetCurrentHUDScene(i),FALSE); + } + } +} + +HRESULT CXuiSceneBase::_SetEnableTooltips( unsigned int iPad, BOOL bVal ) +{ + for(int i=0;i<BUTTONS_TOOLTIP_MAX;i++) + { + //XuiElementSetShow(m_Buttons[iPad][i].m_hObj,bVal); + XuiControlSetEnable(m_Buttons[iPad][i].m_hObj,bVal); + } + return S_OK; +} + + +HRESULT CXuiSceneBase::_SetTooltipText( unsigned int iPad, unsigned int uiTooltip, int iTextID ) +{ + ASSERT( uiTooltip < BUTTONS_TOOLTIP_MAX ); + + XUIRect xuiRect, xuiRectSmall; + HRESULT hr=S_OK; + LPCWSTR pString=NULL; + float fWidth,fHeight; + + // Want to be able to show just a button (for RB LB) + if(iTextID>=0) + { + pString=app.GetString(iTextID); + } + + if(hTooltipText[iPad][uiTooltip]==NULL) + { + HXUIOBJ hObj=NULL; + hr=XuiControlGetVisual(m_Buttons[iPad][uiTooltip].m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"text_ButtonText",&hTooltipText[iPad][uiTooltip]); + hr=XuiElementGetPosition(hTooltipText[iPad][uiTooltip],&m_vPosTextInTooltip[uiTooltip]); + } + + if(hTooltipTextSmall[iPad][uiTooltip]==NULL) + { + HXUIOBJ hObj=NULL; + hr=XuiControlGetVisual(m_ButtonsSmall[iPad][uiTooltip].m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"text_ButtonText",&hTooltipTextSmall[iPad][uiTooltip]); + hr=XuiElementGetPosition(hTooltipTextSmall[iPad][uiTooltip],&m_vPosTextInTooltipSmall[uiTooltip]); + } + + if(iTextID>=0) + { + hr=XuiTextPresenterMeasureText(hTooltipText[iPad][uiTooltip], pString, &xuiRect); + + // Change the size of the whole button to be the width of the measured text, plus the position the text element starts in the visual (which is the offset by the size of the button graphic) + XuiElementGetBounds(m_Buttons[iPad][uiTooltip].m_hObj,&fWidth, &fHeight); + XuiElementSetBounds(m_Buttons[iPad][uiTooltip].m_hObj,xuiRect.right+1+m_vPosTextInTooltip[uiTooltip].x,fHeight); + + // Change the width of the text element to be the width of the measured text + XuiElementGetBounds(hTooltipText[iPad][uiTooltip],&fWidth, &fHeight); + XuiElementSetBounds(hTooltipText[iPad][uiTooltip],xuiRect.right,fHeight); + + + hr=XuiTextPresenterMeasureText(hTooltipTextSmall[iPad][uiTooltip], pString, &xuiRectSmall); + + // Change the size of the whole button to be the width of the measured text, plus the position the text element starts in the visual (which is the offset by the size of the button graphic) + XuiElementGetBounds(m_ButtonsSmall[iPad][uiTooltip].m_hObj,&fWidth, &fHeight); + XuiElementSetBounds(m_ButtonsSmall[iPad][uiTooltip].m_hObj,xuiRectSmall.right+1+m_vPosTextInTooltipSmall[uiTooltip].x,fHeight); + + // Change the width of the text element to be the width of the measured text + XuiElementGetBounds(hTooltipTextSmall[iPad][uiTooltip],&fWidth, &fHeight); + XuiElementSetBounds(hTooltipTextSmall[iPad][uiTooltip],xuiRectSmall.right,fHeight); + + m_Buttons[iPad][uiTooltip].SetText(pString); + m_ButtonsSmall[iPad][uiTooltip].SetText(pString); + } + else + { + m_Buttons[iPad][uiTooltip].SetText(L""); + XuiElementGetBounds(m_Buttons[iPad][uiTooltip].m_hObj,&fWidth, &fHeight); + XuiElementSetBounds(m_Buttons[iPad][uiTooltip].m_hObj,m_vPosTextInTooltip[uiTooltip].x,fHeight); + + m_ButtonsSmall[iPad][uiTooltip].SetText(L""); + XuiElementGetBounds(m_ButtonsSmall[iPad][uiTooltip].m_hObj,&fWidth, &fHeight); + XuiElementSetBounds(m_ButtonsSmall[iPad][uiTooltip].m_hObj,m_vPosTextInTooltipSmall[uiTooltip].x,fHeight); + } + + m_iCurrentTooltipTextID[iPad][uiTooltip]=iTextID; + + ReLayout(iPad); + + return hr; +} + +HRESULT CXuiSceneBase::_RefreshTooltips( unsigned int iPad) +{ + // if the tooltip is showing, refresh it to update the opacity + for(int tooltip=0;tooltip<BUTTONS_TOOLTIP_MAX;tooltip++) + { + if(m_Buttons[iPad][tooltip].IsShown()==TRUE) + { + _ShowTooltip(iPad,tooltip,TRUE); + } + } + + return S_OK; +} + +HRESULT CXuiSceneBase::_ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show ) +{ + ASSERT( tooltip < BUTTONS_TOOLTIP_MAX ); + HRESULT hr; + + if ( (ProfileManager.GetLockedProfile()!=-1) && app.GetGameSettings(iPad,eGameSetting_DisplayHUD)==0 ) + { + //hr = m_Buttons[iPad][tooltip].SetShow( FALSE ); + //hr = m_ButtonsSmall[iPad][tooltip].SetShow( FALSE ); + + // turn off gamertag display in splitscreens + XuiElementSetShow(m_hGamerTagA[iPad],FALSE); + + //m_visible[iPad][ tooltip ] = false; + } + //else + { + // check the app setting first (only if there is a player) + if((ProfileManager.GetLockedProfile()==-1) || ui.GetMenuDisplayed(iPad) || (app.GetGameSettings(iPad,eGameSetting_Tooltips)==1 && app.GetGameSettings(iPad,eGameSetting_DisplayHUD)!=0)) + { + hr = m_Buttons[iPad][tooltip].SetShow( show?TRUE:FALSE ); + hr = m_ButtonsSmall[iPad][tooltip].SetShow( show?TRUE:FALSE ); + + m_visible[iPad][ tooltip ] = show; + + // if we have a player, use their opacity to set the tooltip + if(show && (ProfileManager.GetLockedProfile()!=-1)) + { + // set the opacity of the tooltip items + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + float fVal; + + if(ucAlpha<80) + { + // if we are in a menu, set the minimum opacity for tooltips to 15% + if(ui.GetMenuDisplayed(iPad) && (ucAlpha<15)) + { + ucAlpha=15; + } + + // check if we have the timer running for the opacity + unsigned int uiOpacityTimer=app.GetOpacityTimer(iPad); + if(uiOpacityTimer!=0) + { + if(uiOpacityTimer<10) + { + float fStep=(80.0f-(float)ucAlpha)/10.0f; + fVal=0.01f*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep)); + } + else + { + fVal=0.01f*80.0f; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + } + else + { + // if we are in a menu, set the minimum opacity for tooltips to 15% + if(ui.GetMenuDisplayed(iPad) && (ucAlpha<15)) + { + ucAlpha=15; + } + fVal=0.01f*(float)ucAlpha; + } + + m_Buttons[iPad][tooltip].SetOpacity(fVal); + m_ButtonsSmall[iPad][tooltip].SetOpacity(fVal); + } + } + else + { + hr = m_Buttons[iPad][tooltip].SetShow( FALSE ); + hr = m_ButtonsSmall[iPad][tooltip].SetShow( FALSE ); + + m_visible[iPad][ tooltip ] = false; + } + + //also set the gamertags and the 4th quadrant logo + if(ProfileManager.GetLockedProfile()!=-1) + { + if(app.GetGameSettings(iPad,eGameSetting_DisplaySplitscreenGamertags)==1) + { + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + float fVal; + + if(ucAlpha<80) + { + // check if we have the timer running for the opacity + unsigned int uiOpacityTimer=app.GetOpacityTimer(iPad); + if(uiOpacityTimer!=0) + { + if(uiOpacityTimer<10) + { + float fStep=(80.0f-(float)ucAlpha)/10.0f; + fVal=0.01f*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep)); + } + else + { + fVal=0.01f*80.0f; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + XuiElementSetOpacity(m_hGamerTagA[iPad],fVal); + } + + if(iPad==ProfileManager.GetPrimaryPad()) + { + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + XuiElementSetOpacity(m_hEmptyQuadrantLogo,0.01f*(float)ucAlpha); + } + } + } + + ReLayout(iPad); + + return hr; +} + +HRESULT CXuiSceneBase::_ShowSafeArea( BOOL bShow ) +{ + return m_SafeArea.SetShow(bShow); +} + +HRESULT CXuiSceneBase::_ShowOtherPlayersBaseScene(int iPad, bool show) +{ + for( int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( i == iPad ) + { + m_BasePlayerScene[i].SetShow(TRUE); + + // Fix for #61051 - TU7: Content: UI: Player specific unresponsive state may be triggered during the Save Game process in the splitscreen mode + m_BasePlayerScene[i].EnableInput(TRUE); + } + else + { + m_BasePlayerScene[i].SetShow(show?TRUE:FALSE); + + // Fix for #61051 - TU7: Content: UI: Player specific unresponsive state may be triggered during the Save Game process in the splitscreen mode + m_BasePlayerScene[i].EnableInput(show?TRUE:FALSE); + } + } + return S_OK; +} + +HRESULT CXuiSceneBase::_SetTooltipsEnabled( unsigned int iPad, bool bA, bool bB, bool bX, bool bY, bool bLT, bool bRT, bool bLB, bool bRB, bool bLS) +{ + m_Buttons[iPad][BUTTON_TOOLTIP_A].SetEnable( bA ); + m_Buttons[iPad][BUTTON_TOOLTIP_B].SetEnable( bB ); + m_Buttons[iPad][BUTTON_TOOLTIP_X].SetEnable( bX ); + m_Buttons[iPad][BUTTON_TOOLTIP_Y].SetEnable( bY ); + m_Buttons[iPad][BUTTON_TOOLTIP_LT].SetEnable( bLT ); + m_Buttons[iPad][BUTTON_TOOLTIP_RT].SetEnable( bRT ); + m_Buttons[iPad][BUTTON_TOOLTIP_LB].SetEnable( bLB ); + m_Buttons[iPad][BUTTON_TOOLTIP_RB].SetEnable( bRB ); + m_Buttons[iPad][BUTTON_TOOLTIP_LS].SetEnable( bLS ); + + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_A].SetEnable( bA ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_B].SetEnable( bB ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_X].SetEnable( bX ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_Y].SetEnable( bY ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_LT].SetEnable( bLT ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_RT].SetEnable( bRT ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_LB].SetEnable( bLB ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_RB].SetEnable( bRB ); + m_ButtonsSmall[iPad][BUTTON_TOOLTIP_LS].SetEnable( bLS ); + return S_OK; +} + +HRESULT CXuiSceneBase::_EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable ) +{ + ASSERT( tooltip < BUTTONS_TOOLTIP_MAX ); + + m_Buttons[iPad][tooltip].SetEnable( enable ); + + return S_OK; +} + +HRESULT CXuiSceneBase::_AnimateKeyPress(DWORD userIndex, DWORD dwKeyCode) +{ + if(m_playerBaseScenePosition[userIndex] == e_BaseScene_NotSet) + { + userIndex = DEFAULT_XUI_MENU_USER; + } + switch(dwKeyCode) + { + case VK_PAD_A: + m_Buttons[userIndex][BUTTON_TOOLTIP_A].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_A].Press(); + break; + case VK_PAD_B: + m_Buttons[userIndex][BUTTON_TOOLTIP_B].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_B].Press(); + break; + case VK_PAD_X: + m_Buttons[userIndex][BUTTON_TOOLTIP_X].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_X].Press(); + break; + case VK_PAD_Y: + m_Buttons[userIndex][BUTTON_TOOLTIP_Y].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_Y].Press(); + break; + case VK_PAD_LTRIGGER: + m_Buttons[userIndex][BUTTON_TOOLTIP_LT].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_LT].Press(); + break; + case VK_PAD_RTRIGGER: + m_Buttons[userIndex][BUTTON_TOOLTIP_RT].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_RT].Press(); + break; + case VK_PAD_LSHOULDER: + m_Buttons[userIndex][BUTTON_TOOLTIP_LB].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_LB].Press(); + break; + case VK_PAD_RSHOULDER: + m_Buttons[userIndex][BUTTON_TOOLTIP_RB].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_RB].Press(); + break; + case VK_PAD_LTHUMB_UP: + case VK_PAD_LTHUMB_DOWN: + case VK_PAD_LTHUMB_LEFT: + case VK_PAD_LTHUMB_RIGHT: + m_Buttons[userIndex][BUTTON_TOOLTIP_LS].Press(); + m_ButtonsSmall[userIndex][BUTTON_TOOLTIP_LS].Press(); + break; +#ifndef _CONTENT_PACKAGE + case VK_PAD_LTHUMB_PRESS: + app.ToggleFontRenderer(); + break; +#endif + } + return S_OK; +} + +HRESULT CXuiSceneBase::_ShowSavingMessage( unsigned int iPad, C4JStorage::ESavingMessage eVal ) +{ + switch(eVal) + { + case C4JStorage::ESavingMessage_None: + XuiElementSetShow(m_SavingIcon,FALSE ); + break; + case C4JStorage::ESavingMessage_Short: + case C4JStorage::ESavingMessage_Long: + XuiElementSetShow(m_SavingIcon,TRUE ); + break; + } + + // Not needed - ReLayout(iPad); + + return S_OK; +} + +HRESULT CXuiSceneBase::_ShowBackground( unsigned int iPad, BOOL bShow ) +{ + HRESULT hr; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + //if(app.GetGameSettingsDebugMask(iPad) && app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_LightDarkBackground)) + { + // get the visual + HXUIOBJ hVisual,hNight,hDay; + hr=XuiControlGetVisual(m_Background[iPad],&hVisual); + hr=XuiElementGetChildById(hVisual,L"NightGroup",&hNight); + hr=XuiElementGetChildById(hVisual,L"DayGroup",&hDay); + + if(bShow && pMinecraft->level!=NULL) + { + __int64 i64TimeOfDay =0; + // are we in the Nether? - Leave the time as 0 if we are, so we show daylight + if(pMinecraft->level->dimension->id==0) + { + i64TimeOfDay = pMinecraft->level->getLevelData()->getTime() % 24000; + } + + if(i64TimeOfDay>14000) + { + hr=XuiElementSetShow(hNight,TRUE); + hr=XuiElementSetShow(hDay,FALSE); + } + else + { + hr=XuiElementSetShow(hNight,FALSE); + hr=XuiElementSetShow(hDay,TRUE); + } + } + else + { + hr=XuiElementSetShow(hNight,FALSE); + hr=XuiElementSetShow(hDay,TRUE); + } + } + hr=XuiElementSetShow(m_Background[iPad],bShow); + + return hr; +} + +HRESULT CXuiSceneBase::_ShowDarkOverlay( unsigned int iPad, BOOL bShow ) +{ + return XuiElementSetShow(m_DarkOverlay[iPad],bShow); +} + +HRESULT CXuiSceneBase::_ShowLogo( unsigned int iPad, BOOL bShow ) +{ + return XuiElementSetShow(m_Logo[iPad],bShow); +} + +HRESULT CXuiSceneBase::_ShowPressStart(unsigned int iPad) +{ + XUIRect xuiRect; + LPCWSTR pString=app.GetString(IDS_PRESS_START_TO_JOIN);; + float fWidth,fHeight,fWidthChange; + + XuiSetTimer( m_hObj,PRESS_START_TIMER,3000); + m_iQuadrantsMask|=1<<iPad; + + m_PressStart.SetShow(TRUE); + // retrieve the visual for this quadrant + + HXUIOBJ hObj=NULL,hQuadrant; + HRESULT hr=XuiControlGetVisual(m_PressStart.m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"text_ButtonText",&hQuadrant); + memset(&xuiRect, 0, sizeof(xuiRect)); + hr=XuiTextPresenterMeasureText(hQuadrant, pString, &xuiRect); + + XuiElementGetBounds(hQuadrant,&fWidth, &fHeight); + fWidthChange=xuiRect.right-fWidth; + + // get the size of the button, and apply the change in size due to the text to the whole button + XuiElementGetBounds(m_PressStart.m_hObj,&fWidth, &fHeight); + + XuiElementSetBounds(m_PressStart.m_hObj,fWidth+fWidthChange,fHeight); + + switch(iPad) + { + case 0: + hr=XuiElementGetChildById(hObj,L"Quadrant1",&hQuadrant); + break; + case 1: + hr=XuiElementGetChildById(hObj,L"Quadrant2",&hQuadrant); + break; + case 2: + hr=XuiElementGetChildById(hObj,L"Quadrant3",&hQuadrant); + break; + case 3: + hr=XuiElementGetChildById(hObj,L"Quadrant4",&hQuadrant); + break; + } + + XuiElementSetShow(hQuadrant,TRUE); + int nStart, nEnd; +// XuiElementFindNamedFrame( m_hObj, L"StartFlash", &nStart ); +// XuiElementFindNamedFrame( m_hObj, L"EndFlash", &nEnd ); +// XuiElementPlayTimeline( m_hObj, nStart, nStart, nEnd, TRUE, TRUE ); + XuiElementFindNamedFrame( hObj, L"StartFlash", &nStart ); + XuiElementFindNamedFrame( hObj, L"EndFlash", &nEnd ); + XuiElementPlayTimeline( hObj, nStart, nStart, nEnd, TRUE, TRUE ); + + return S_OK; +} + +HRESULT CXuiSceneBase::_HidePressStart() +{ + return m_PressStart.SetShow(FALSE); +} + +HRESULT CXuiSceneBase::_UpdateAutosaveCountdownTimer(unsigned int uiSeconds) +{ + WCHAR wcAutosaveCountdown[100]; + swprintf( wcAutosaveCountdown, 100, app.GetString(IDS_AUTOSAVE_COUNTDOWN),uiSeconds); + m_TrialTimer.SetText(wcAutosaveCountdown); + return S_OK; +} + +HRESULT CXuiSceneBase::_ShowAutosaveCountdownTimer(BOOL bVal) +{ + m_TrialTimer.SetShow(bVal); + return S_OK; +} + +HRESULT CXuiSceneBase::_UpdateTrialTimer(unsigned int iPad) +{ + WCHAR wcTime[20]; + + DWORD dwTimeTicks=(DWORD)app.getTrialTimer(); + + if(dwTimeTicks>m_dwTrialTimerLimitSecs) + { + dwTimeTicks=m_dwTrialTimerLimitSecs; + } + + dwTimeTicks=m_dwTrialTimerLimitSecs-dwTimeTicks; + +#ifndef _CONTENT_PACKAGE + if(true) +#else + // display the time - only if there's less than 3 minutes + if(dwTimeTicks<180) +#endif + { + int iMins=dwTimeTicks/60; + int iSeconds=dwTimeTicks%60; + swprintf( wcTime, 20, L"%d:%02d",iMins,iSeconds); + m_TrialTimer.SetText(wcTime); + } + else + { + m_TrialTimer.SetText(L""); + } + + // are we out of time? + if(dwTimeTicks==0) + { + // Trial over + app.SetAction(iPad,eAppAction_TrialOver); + } + + return S_OK; +} + +void CXuiSceneBase::_ReduceTrialTimerValue() +{ + DWORD dwTimeTicks=(int)app.getTrialTimer(); + + if(dwTimeTicks>m_dwTrialTimerLimitSecs) + { + dwTimeTicks=m_dwTrialTimerLimitSecs; + } + + m_dwTrialTimerLimitSecs-=dwTimeTicks; +} + +HRESULT CXuiSceneBase::_ShowTrialTimer(BOOL bVal) +{ + m_TrialTimer.SetShow(bVal); + return S_OK; +} + +bool CXuiSceneBase::_PressStartPlaying(unsigned int iPad) +{ + return m_iQuadrantsMask&(1<<iPad)?true:false; +} + +HRESULT CXuiSceneBase::_SetPlayerBaseScenePosition( unsigned int iPad, EBaseScenePosition position ) +{ + // turn off the empty quadrant logo + if(m_hEmptyQuadrantLogo!=NULL) + { + XuiElementSetShow(m_hEmptyQuadrantLogo,FALSE); + } + + // No changes + if( m_playerBaseScenePosition[iPad] == position ) + return S_OK; + + m_selectedItemA[iPad].SetShow(FALSE); + m_selectedItemSmallA[iPad].SetShow(FALSE); + + if(position == e_BaseScene_NotSet) + { + m_playerBaseScenePosition[iPad] = position; + return S_OK; + } + + D3DXVECTOR3 scale,pos;//,currentpos; + // Shift the tooltips + D3DXVECTOR3 tooltipsPos,crouchIconPos,saveIconPos,vBackPos,vGamertagPos,vBossHealthPos; + tooltipsPos.z=crouchIconPos.z=saveIconPos.z=vBackPos.z=vBossHealthPos.z=0.0f; + vBackPos.x=0.0f; + vBackPos.y=0.0f; + + m_playerBaseScenePosition[iPad] = position; + float fTempWidth, fTooltipHeight, fTooltipHeightSmall,fGamertagWidth,fGamertagHeight,fBossHealthWidth, fBossHealthHeight; + float fBackWidth, fBackHeight; + // Reset the players base scene before we make any other adjustments + pos.x = 0.0f; pos.y = 0.0f; pos.z = 0.0f; + XuiElementSetPosition(m_BasePlayerScene[iPad], &pos ); + XuiElementGetBounds(m_TooltipGroup[iPad].m_hObj,&fTempWidth, &fTooltipHeight); + XuiElementGetBounds(m_TooltipGroupSmall[iPad].m_hObj,&fTempWidth, &fTooltipHeightSmall); + XuiElementGetBounds(m_Background[iPad].m_hObj,&fBackWidth, &fBackHeight); + XuiElementGetBounds(m_hGamerTagA[iPad],&fGamertagWidth, &fGamertagHeight); + XuiElementGetBounds(m_BossHealthGroup[iPad],&fBossHealthWidth, &fBossHealthHeight); + + if( position == e_BaseScene_Fullscreen && (RenderManager.IsHiDef() || RenderManager.IsWidescreen()) ) + { + XuiElementSetShow( m_TooltipGroup[iPad].m_hObj, TRUE); + XuiElementSetShow( m_TooltipGroupSmall[iPad].m_hObj, FALSE); + } + else + { + XuiElementSetShow( m_TooltipGroup[iPad].m_hObj, FALSE); + XuiElementSetShow( m_TooltipGroupSmall[iPad].m_hObj, TRUE); + } + + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + //640x480 ->1280x720 + scale.x = 2.0f; scale.y = 1.5f; scale.z = 1.0f; + XuiElementSetScale(m_hObj, &scale); + + return S_OK; + } + + + if( position != e_BaseScene_Fullscreen ) + { + // Scale up the tooltips so we can read them + /* + scale.x = 0.75f; scale.y = 0.75f; scale.z = 1.0f; + XuiElementSetScale(m_TooltipGroup[iPad], &scale); + fTooltipHeight*=scale.y; + */ + fTooltipHeight = fTooltipHeightSmall; + + scale.x = 0.5f; scale.y = 0.5f; scale.z = 1.0f; + XuiElementSetScale(m_CrouchIcon[iPad], &scale); + XuiElementSetScale(m_Logo[iPad].m_hObj, &scale); + } + else + { + // if we are not in high def mode, then we need to scale the m_BasePlayerScene scene by 2 (we're using the 640x360 scenes) + scale.x = 1.0f; scale.y = 1.0f; scale.z = 1.0f; + XuiElementSetScale(m_BasePlayerScene[iPad], &scale ); + XuiElementSetScale(m_TooltipGroup[iPad], &scale); + XuiElementSetScale(m_CrouchIcon[iPad], &scale); + XuiElementSetScale(m_Logo[iPad].m_hObj, &scale); + } + + + // The move applies to the whole scene, so we'll need to move tooltips back in some cases + switch( position ) + { + // No position adjustment + case e_BaseScene_Fullscreen: + tooltipsPos.x=SAFEZONE_HALF_WIDTH; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackWidth=XUI_BASE_SCENE_WIDTH; + fBackHeight=XUI_BASE_SCENE_HEIGHT; + + XuiElementGetPosition(m_selectedItemA[iPad], &vBossHealthPos); + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_HALF-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Top_Left: + tooltipsPos.x=SAFEZONE_HALF_WIDTH; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth - 10.0f; + vGamertagPos.y=SAFEZONE_HALF_HEIGHT; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Top: // Top & Bottom - indent by a quarter screen + pos.x += XUI_BASE_SCENE_WIDTH_QUARTER; + tooltipsPos.x=SAFEZONE_HALF_WIDTH - XUI_BASE_SCENE_WIDTH_QUARTER; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH-XUI_BASE_SCENE_WIDTH_QUARTER; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + fBackWidth=XUI_BASE_SCENE_WIDTH; + vBackPos.x=-XUI_BASE_SCENE_WIDTH_QUARTER; + vBackPos.y=0.0f; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH - XUI_BASE_SCENE_WIDTH_QUARTER - fGamertagWidth - SAFEZONE_HALF_WIDTH; + vGamertagPos.y=SAFEZONE_HALF_HEIGHT; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Bottom: + pos.x += XUI_BASE_SCENE_WIDTH_QUARTER; + pos.y += XUI_BASE_SCENE_HEIGHT_HALF; + tooltipsPos.x=SAFEZONE_HALF_WIDTH - XUI_BASE_SCENE_WIDTH_QUARTER; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH-XUI_BASE_SCENE_WIDTH_QUARTER; + crouchIconPos.y=0.0f; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + fBackWidth=XUI_BASE_SCENE_WIDTH; + vBackPos.x=-XUI_BASE_SCENE_WIDTH_QUARTER; + vBackPos.y=0.0f; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH - XUI_BASE_SCENE_WIDTH_QUARTER - fGamertagWidth - SAFEZONE_HALF_WIDTH; + vGamertagPos.y=0.0f; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = 0.0f; + break; + case e_BaseScene_Bottom_Left: + pos.y += XUI_BASE_SCENE_HEIGHT_HALF; + tooltipsPos.x=SAFEZONE_HALF_WIDTH; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH; + crouchIconPos.y=0.0f; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth- 10.0f; + vGamertagPos.y=0.0f; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = 0.0f; + break; + case e_BaseScene_Bottom_Right: + pos.x += XUI_BASE_SCENE_WIDTH_HALF; + pos.y += XUI_BASE_SCENE_HEIGHT_HALF; + tooltipsPos.x=0.0f; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=0.0f; + crouchIconPos.y=0.0f; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth-SAFEZONE_HALF_WIDTH; + vGamertagPos.y=0.0f; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = 0.0f; + break; + case e_BaseScene_Left: + pos.y += XUI_BASE_SCENE_HEIGHT_QUARTER; + tooltipsPos.x=SAFEZONE_HALF_WIDTH; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF+XUI_BASE_SCENE_HEIGHT_QUARTER-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=SAFEZONE_HALF_WIDTH; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT; + vBackPos.x=0.0f; + vBackPos.y=-XUI_BASE_SCENE_HEIGHT_QUARTER; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth- 10.0f; + vGamertagPos.y=SAFEZONE_HALF_HEIGHT - XUI_BASE_SCENE_HEIGHT_QUARTER; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT-XUI_BASE_SCENE_HEIGHT_QUARTER; + break; + case e_BaseScene_Right: + pos.x += XUI_BASE_SCENE_WIDTH_HALF; + pos.y += XUI_BASE_SCENE_HEIGHT_QUARTER; + tooltipsPos.x=0.0f; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF+XUI_BASE_SCENE_HEIGHT_QUARTER-SAFEZONE_HALF_HEIGHT-fTooltipHeight; + crouchIconPos.x=0.0f; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT; + vBackPos.x=0.0f; + vBackPos.y=-XUI_BASE_SCENE_HEIGHT_QUARTER; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth-SAFEZONE_HALF_WIDTH; + vGamertagPos.y=SAFEZONE_HALF_HEIGHT - XUI_BASE_SCENE_HEIGHT_QUARTER; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT-XUI_BASE_SCENE_HEIGHT_QUARTER; + break; + case e_BaseScene_Top_Right: + pos.x += XUI_BASE_SCENE_WIDTH_HALF; + tooltipsPos.x=0.0f; + tooltipsPos.y=XUI_BASE_SCENE_HEIGHT_HALF-fTooltipHeight; + crouchIconPos.x=0.0f; + crouchIconPos.y=SAFEZONE_HALF_HEIGHT; + fBackWidth=XUI_BASE_SCENE_WIDTH_HALF; + fBackHeight=XUI_BASE_SCENE_HEIGHT_HALF; + vGamertagPos.x=XUI_BASE_SCENE_WIDTH_HALF-fGamertagWidth-SAFEZONE_HALF_WIDTH; + vGamertagPos.y=SAFEZONE_HALF_HEIGHT; + vBossHealthPos.x = XUI_BASE_SCENE_WIDTH_QUARTER-(fBossHealthWidth/2); + vBossHealthPos.y = SAFEZONE_HALF_HEIGHT; + break; + } + + XuiElementSetPosition(m_BasePlayerScene[iPad], &pos ); + XuiElementSetPosition( m_TooltipGroup[iPad].m_hObj, &tooltipsPos); + XuiElementSetPosition( m_TooltipGroupSmall[iPad].m_hObj, &tooltipsPos); + XuiElementSetPosition( m_CrouchIcon[iPad].m_hObj, &crouchIconPos); + XuiElementSetPosition( m_DarkOverlay[iPad].m_hObj, &vBackPos ); + XuiElementSetBounds( m_DarkOverlay[iPad].m_hObj, fBackWidth, fBackHeight); + XuiElementSetPosition( m_Background[iPad].m_hObj, &vBackPos ); + XuiElementSetBounds( m_Background[iPad].m_hObj, fBackWidth, fBackHeight ); + vGamertagPos.z=0.0f; + XuiElementSetPosition( m_hGamerTagA[iPad], &vGamertagPos ); + XuiElementSetPosition( m_BossHealthGroup[iPad], &vBossHealthPos ); + + + // 4J Stu - If we already have some scenes open, then call this to update their positions + // Fix for #10960 - All Lang: UI: Split-screen: Changing split screen mode (vertical/horizontal) make window layout strange + if(Minecraft::GetInstance() != NULL && Minecraft::GetInstance()->localplayers[iPad]!=NULL) + { + // 4J-PB - Can only do this once we know what the player's UI settings are, so we need to have the player game settings read + _UpdateSelectedItemPos(iPad); + XUIMessage xuiMsg; + CustomMessage_Splitscreenplayer_Struct myMsgData; + CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, false); + XuiBroadcastMessage( GetPlayerBaseScene(iPad), &xuiMsg ); + } + // tell the xui scenes that the base position has changed + XUIMessage xuiMsg; + CustomMessage_BasePositionChanged( &xuiMsg ); + XuiBroadcastMessage( GetPlayerBaseScene(iPad), &xuiMsg ); + + return S_OK; +} + +// The function uses the game mode to decide the offsets for the select item. It needs to be called after the game has loaded. +void CXuiSceneBase::_UpdateSelectedItemPos(unsigned int iPad) +{ + D3DXVECTOR3 selectedItemPos; + selectedItemPos.x = selectedItemPos.y = selectedItemPos.z = 0.0f; + float fSelectedItemWidth, fSelectedItemHeight; + XuiElementGetBounds(m_selectedItemSmallA[iPad],&fSelectedItemWidth, &fSelectedItemHeight); + + float yOffset = 0.0f; + + if( m_bossHealthVisible[iPad] == TRUE ) + { + float tempWidth; + XuiElementGetBounds(m_BossHealthGroup[iPad],&tempWidth, &yOffset); + } + + + // Only adjust if fullscreen for now, leaving code to move others if required, but it's too far up the screen when on the bottom quadrants + if( (m_playerBaseScenePosition[iPad] == e_BaseScene_Fullscreen) && + (RenderManager.IsHiDef() || RenderManager.IsWidescreen()) ) + { + D3DXVECTOR3 selectedItemPos; + selectedItemPos.z=0.0f; + float scale, fTempWidth, fTooltipHeight, fTooltipHeightSmall, fSelectedItemWidth, fSelectedItemHeight, fSelectedItemSmallWidth, fSelectedItemSmallHeight; + XuiElementGetBounds(m_TooltipGroup[iPad].m_hObj,&fTempWidth, &fTooltipHeight); + XuiElementGetBounds(m_TooltipGroupSmall[iPad].m_hObj,&fTempWidth, &fTooltipHeightSmall); + XuiElementGetBounds(m_selectedItemA[iPad],&fSelectedItemWidth, &fSelectedItemHeight); + XuiElementGetBounds(m_selectedItemSmallA[iPad],&fSelectedItemSmallWidth, &fSelectedItemSmallHeight); + if( m_playerBaseScenePosition[iPad] != e_BaseScene_Fullscreen ) + { + fTooltipHeight = fTooltipHeightSmall; + fSelectedItemHeight = fSelectedItemSmallHeight; + + scale = 0.5f; + } + else + { + // if we are not in high def mode, then we need to scale the m_BasePlayerScene scene by 2 (we're using the 640x360 scenes) + scale = 1.0f; + } + + // The move applies to the whole scene, so we'll need to move tooltips back in some cases + + selectedItemPos.y=XUI_BASE_SCENE_HEIGHT-SAFEZONE_HALF_HEIGHT-fTooltipHeight - fSelectedItemHeight; + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_HALF - (fSelectedItemWidth/2.0f); + + // Adjust selectedItemPos based on what gui is displayed + + + // 4J-PB - selected the gui scale based on the slider settings, and on whether we're in Creative or Survival + float fYOffset=0.0f; + + unsigned char ucGuiScale=app.GetGameSettings(iPad,eGameSetting_UISize) + 2; + + if(Minecraft::GetInstance() != NULL && Minecraft::GetInstance()->localgameModes[iPad] != NULL && Minecraft::GetInstance()->localgameModes[iPad]->canHurtPlayer()) + { + // SURVIVAL MODE - Move up further because of hearts, shield and xp + switch(ucGuiScale) + { + case 3: + fYOffset = -130.0f; + break; + case 4: + fYOffset = -168.0f; + break; + default: // 2 + fYOffset = -94.0f; + break; + } + } + else + { + switch(ucGuiScale) + { + case 3: + fYOffset = -83.0f; + break; + case 4: + fYOffset = -114.0f; + break; + default: // 2 + fYOffset = -58.0f; + break; + } + } + + + selectedItemPos.y+=fYOffset - 40.0f; // 40 for the XP display + + XuiElementSetPosition( m_selectedItemA[iPad].m_hObj, &selectedItemPos ); + + //XuiElementSetPosition( m_selectedItemSmallA[iPad].m_hObj, &selectedItemPos ); + } + else + { + // The move applies to the whole scene, so we'll need to move tooltips back in some cases + switch( m_playerBaseScenePosition[iPad] ) + { + case e_BaseScene_Fullscreen: + // 480 non-widescreen + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = SAFEZONE_HALF_HEIGHT + yOffset; + break; + case e_BaseScene_Top_Left: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = SAFEZONE_HALF_HEIGHT + yOffset; + break; + case e_BaseScene_Top: // Top & Bottom - indent by a quarter screen + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = SAFEZONE_HALF_HEIGHT + yOffset; + break; + case e_BaseScene_Bottom: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = 0.0f + yOffset; + break; + case e_BaseScene_Bottom_Left: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = 0.0f + yOffset; + break; + case e_BaseScene_Bottom_Right: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = 0.0f + yOffset; + break; + case e_BaseScene_Left: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = XUI_BASE_SCENE_HEIGHT_HALF;// + yOffset; - don't need the offset for the boss health since we're displaying the item at the bottom of the screen, not the top + break; + case e_BaseScene_Right: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = XUI_BASE_SCENE_HEIGHT_HALF;// + yOffset; - don't need the offset for the boss health since we're displaying the item at the bottom of the screen, not the top + break; + case e_BaseScene_Top_Right: + selectedItemPos.x = XUI_BASE_SCENE_WIDTH_QUARTER - (fSelectedItemWidth/2.0f); + selectedItemPos.y = SAFEZONE_HALF_HEIGHT + yOffset; + break; + } + + // 4J-PB - If it's in split screen vertical, adjust the position + // Adjust selectedItemPos based on what gui is displayed + if((m_playerBaseScenePosition[iPad]==e_BaseScene_Left) || (m_playerBaseScenePosition[iPad]==e_BaseScene_Right)) + { + float scale=0.5f; + selectedItemPos.y -= (scale * 88.0f); + if(Minecraft::GetInstance() != NULL && Minecraft::GetInstance()->localgameModes[iPad] != NULL && Minecraft::GetInstance()->localgameModes[iPad]->canHurtPlayer()) + { + selectedItemPos.y -= (scale * 80.0f); + } + + // 4J-PB - selected the gui scale based on the slider settings + unsigned char ucGuiScale; + float fYOffset=0.0f; + if(m_playerBaseScenePosition[iPad]==e_BaseScene_Fullscreen) + { + ucGuiScale=app.GetGameSettings(iPad,eGameSetting_UISize) + 2; + } + else + { + ucGuiScale=app.GetGameSettings(iPad,eGameSetting_UISizeSplitscreen) + 2; + } + switch(ucGuiScale) + { + case 3: + fYOffset = 55.0f; + break; + case 4: + fYOffset = 45.0f; + break; + default: // 2 + fYOffset = 85.0f; + break; + } + selectedItemPos.y+=fYOffset; + } + + XuiElementSetPosition( m_selectedItemSmallA[iPad].m_hObj, &selectedItemPos ); + XuiElementSetPosition( m_selectedItemA[iPad].m_hObj, &selectedItemPos ); + } +} + +CXuiSceneBase::EBaseScenePosition CXuiSceneBase::_GetPlayerBasePosition(int iPad) +{ + return m_playerBaseScenePosition[iPad]; +} + +void CXuiSceneBase::_SetEmptyQuadrantLogo(int iPad,EBaseScenePosition ePos) +{ + if(m_hEmptyQuadrantLogo!=NULL) + { + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(m_playerBaseScenePosition[i] == e_BaseScene_Fullscreen) + { + // Someone is fullscreen, so don't show this + XuiElementSetShow(m_hEmptyQuadrantLogo,FALSE); + return; + } + } + + D3DXVECTOR3 pos; + + // get the bounds of the logo + + pos.z=0.0f; + switch( ePos ) + { + case e_BaseScene_Top_Left: + pos.x=64.0f; + pos.y=36.0f; + break; + case e_BaseScene_Top_Right: + pos.x=640.0+64.0f; + pos.y=36.0f; + break; + case e_BaseScene_Bottom_Left: + pos.x=64.0f; + pos.y=360.0f+36.0f; + break; + case e_BaseScene_Bottom_Right: + pos.x=640.0+64.0f; + pos.y=360.0f+36.0f; + break; + } + + // set the opacity of the logo + if(ProfileManager.GetLockedProfile()!=-1) + { + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + XuiElementSetOpacity(m_hEmptyQuadrantLogo,0.01f*(float)ucAlpha); + } + + XuiElementSetPosition(m_hEmptyQuadrantLogo, &pos ); + XuiElementSetShow(m_hEmptyQuadrantLogo,TRUE); + } +} + + +HRESULT CXuiSceneBase::_PlayUISFX(ESoundEffect eSound) +{ + HRESULT hr; + bool bUsingTexturepackWithAudio=false; + + // are we using a mash-up pack? + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + if(tPack->hasAudio()) + { + bUsingTexturepackWithAudio=true; + } + } + + /*if(bUsingTexturepackWithAudio) + { + switch(eSound) + { + case eSFX_Back: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_Craft: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_CraftFail: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_Focus: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_Press: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_Scroll: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + default: + hr=S_OK; + break; + } + } + else*/ + { + + switch(eSound) + { + case eSFX_Back: + hr=XuiSoundPlay(m_SFXA[eSFX_Back]); + break; + case eSFX_Craft: + hr=XuiSoundPlay(m_SFXA[eSFX_Craft]); + break; + case eSFX_CraftFail: + hr=XuiSoundPlay(m_SFXA[eSFX_CraftFail]); + break; + case eSFX_Focus: + hr=XuiSoundPlay(m_SFXA[eSFX_Focus]); + break; + case eSFX_Press: + hr=XuiSoundPlay(m_SFXA[eSFX_Press]); + break; + case eSFX_Scroll: + hr=XuiSoundPlay(m_SFXA[eSFX_Scroll]); + break; + default: + hr=S_OK; + break; + } + } + return hr; +} + + +HRESULT CXuiSceneBase::_DisplayGamertag( unsigned int iPad, BOOL bDisplay ) +{ + + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + XuiControlSetText(m_hGamerTagA[iPad],L"WWWWWWWWWWWWWWWW"); + } + else + { + // The host decides whether these are on or off + if(app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_DisplaySplitscreenGamertags)!=0) + { + if(Minecraft::GetInstance() != NULL && Minecraft::GetInstance()->localplayers[iPad]!=NULL) + { + wstring wsGamertag = convStringToWstring( ProfileManager.GetGamertag(iPad)); + XuiControlSetText(m_hGamerTagA[iPad],wsGamertag.c_str()); + + } + else + { + XuiControlSetText(m_hGamerTagA[iPad],L""); + } + } + } + // The host decides whether these are on or off + if(app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_DisplaySplitscreenGamertags)!=0) + { + XuiElementSetShow(m_hGamerTagA[iPad],bDisplay); + + // set the opacity of the gamertag + if((bDisplay==TRUE) &&(ProfileManager.GetLockedProfile()!=-1)) + { + unsigned char ucAlpha=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_InterfaceOpacity); + float fVal; + + if(ucAlpha<80) + { + // check if we have the timer running for the opacity + unsigned int uiOpacityTimer=app.GetOpacityTimer(ProfileManager.GetPrimaryPad()); + if(uiOpacityTimer!=0) + { + if(uiOpacityTimer<10) + { + float fStep=(80.0f-(float)ucAlpha)/10.0f; + fVal=0.01f*(80.0f-((10.0f-(float)uiOpacityTimer)*fStep)); + } + else + { + fVal=0.01f*80.0f; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + } + else + { + fVal=0.01f*(float)ucAlpha; + } + XuiElementSetOpacity(m_hGamerTagA[iPad],0.01f*fVal); + } + } + else + { + XuiElementSetShow(m_hGamerTagA[iPad],FALSE); + } + + return S_OK; +} + +void CXuiSceneBase::_SetSelectedItem( unsigned int iPad, const wstring& name) +{ + if(app.GetGameSettings(eGameSetting_Hints) == 0 || name.empty()) + { + m_selectedItemA[iPad].SetShow(FALSE); + m_selectedItemSmallA[iPad].SetShow(FALSE); + } + else + { + m_uiSelectedItemOpacityCountDown[iPad] = SharedConstants::TICKS_PER_SECOND * 3; + if(m_playerBaseScenePosition[iPad] == e_BaseScene_Fullscreen) + { + m_selectedItemSmallA[iPad].SetShow(FALSE); + m_selectedItemA[iPad].SetShow(TRUE); + m_selectedItemA[iPad].SetText(name.c_str()); + +// D3DXVECTOR3 vPos; +// XuiElementGetPosition( m_selectedItemA[iPad].m_hObj, &vPos ); +// XuiElementSetPosition( m_selectedItemA[iPad].m_hObj, &vPos ); + + float fVal=0.8f;//0.01f*(float)80; + XuiElementSetOpacity(m_selectedItemA[iPad].m_hObj,fVal); + } + else + { + m_selectedItemA[iPad].SetShow(FALSE); + m_selectedItemSmallA[iPad].SetShow(TRUE); + m_selectedItemSmallA[iPad].SetText(name.c_str()); + +// D3DXVECTOR3 vPos; +// XuiElementGetPosition( m_selectedItemSmallA[iPad].m_hObj, &vPos ); +// XuiElementSetPosition( m_selectedItemSmallA[iPad].m_hObj, &vPos ); + + float fVal=0.8f;//0.01f*(float)80; + XuiElementSetOpacity(m_selectedItemSmallA[iPad].m_hObj,fVal); + } + } +} + +void CXuiSceneBase::_HideAllGameUIElements() +{ + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + m_uiSelectedItemOpacityCountDown[i] = 0; + m_selectedItemA[i].SetShow(FALSE); + m_selectedItemSmallA[i].SetShow(FALSE); + + m_BossHealthGroup[i].SetShow(FALSE); + m_bossHealthVisible[i] = FALSE; + + XuiElementSetShow(app.GetCurrentHUDScene(i),FALSE); + + _DisplayGamertag(i,FALSE); + } +} + +bool CXuiSceneBase::_GetBaseSceneSafeZone( unsigned int iPad, D3DXVECTOR2 &origin, float &width, float &height) +{ + if(m_playerBaseScenePosition[iPad] == e_BaseScene_NotSet) return false; + + D3DXMATRIX baseSceneMatrix; + XuiElementGetFullXForm( m_BasePlayerScene[iPad], &baseSceneMatrix); + + origin.x = baseSceneMatrix._41; + origin.y = baseSceneMatrix._42; + + XuiElementGetBounds( m_BasePlayerScene[iPad], &width, &height); + + switch( m_playerBaseScenePosition[iPad] ) + { + // No position adjustment + case e_BaseScene_Fullscreen: + origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH * 2; + + origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT * 2; + break; + case e_BaseScene_Top_Left: + width = XUI_BASE_SCENE_WIDTH_HALF; + height = XUI_BASE_SCENE_HEIGHT_HALF; + + origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT * 2; + break; + case e_BaseScene_Top: // Top & Bottom - indent by a quarter screen + height = XUI_BASE_SCENE_HEIGHT_HALF; + + //origin.x += SAFEZONE_HALF_WIDTH; + //width -= SAFEZONE_HALF_WIDTH * 2; + + origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Bottom: + height = XUI_BASE_SCENE_HEIGHT_HALF; + + //origin.x += SAFEZONE_HALF_WIDTH; + //width -= SAFEZONE_HALF_WIDTH * 2; + + //origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Bottom_Left: + width = XUI_BASE_SCENE_WIDTH_HALF; + height = XUI_BASE_SCENE_HEIGHT_HALF; + + origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + //origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Bottom_Right: + width = XUI_BASE_SCENE_WIDTH_HALF; + height = XUI_BASE_SCENE_HEIGHT_HALF; + + //origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + //origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT; + break; + case e_BaseScene_Left: + width = XUI_BASE_SCENE_WIDTH_HALF; + + origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + //origin.y += SAFEZONE_HALF_HEIGHT; + //height -= SAFEZONE_HALF_HEIGHT * 2; + break; + case e_BaseScene_Right: + width = XUI_BASE_SCENE_WIDTH_HALF; + + //origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + //origin.y += SAFEZONE_HALF_HEIGHT; + //height -= SAFEZONE_HALF_HEIGHT * 2; + break; + case e_BaseScene_Top_Right: + width = XUI_BASE_SCENE_WIDTH_HALF; + height = XUI_BASE_SCENE_HEIGHT_HALF; + + //origin.x += SAFEZONE_HALF_WIDTH; + width -= SAFEZONE_HALF_WIDTH; + + origin.y += SAFEZONE_HALF_HEIGHT; + height -= SAFEZONE_HALF_HEIGHT; + break; + } + + return true; +} + +void CXuiSceneBase::ReLayout( unsigned int iPad ) +{ + D3DXVECTOR3 lastPos, lastPosSmall; + int lastVisible = -1; + + // Buttons are at 0,0 within the tooltip group + lastPos.x = 0.0f; + lastPos.y = 0.0f; + lastPos.z = 0.0f; + lastPosSmall.x = 0.0f; + lastPosSmall.y = 0.0f; + lastPosSmall.z = 0.0f; + + for( unsigned int i = 0; i < BUTTONS_TOOLTIP_MAX; ++i ) + { + if( m_visible[iPad][ i ] == TRUE ) + { + if( i>0 && lastVisible!=-1 ) + { + float width, height; + XuiElementGetBounds(m_Buttons[iPad][lastVisible].m_hObj, &width, &height); + + // 4J Stu - This is for horizontal layout, will need changed if we do vertical layout + lastPos.x += width + m_iTooltipSpacingGap; + + XuiElementGetBounds(m_ButtonsSmall[iPad][lastVisible].m_hObj, &width, &height); + // 4J Stu - This is for horizontal layout, will need changed if we do vertical layout + lastPosSmall.x += width + m_iTooltipSpacingGapSmall; + } + XuiElementSetPosition( m_Buttons[iPad][i].m_hObj, &lastPos); + XuiElementSetPosition( m_ButtonsSmall[iPad][i].m_hObj, &lastPosSmall); + + lastVisible = i; + } + } +} + +void CXuiSceneBase::TickAllBaseScenes() +{ + if( CXuiSceneBase::Instance != NULL ) + { + CXuiSceneBase::Instance->_TickAllBaseScenes(); + } +} + +HRESULT CXuiSceneBase::SetEnableTooltips( unsigned int iPad, BOOL bVal ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_SetEnableTooltips(iPad, bVal ); + } + return S_OK; +} + +HRESULT CXuiSceneBase::SetTooltipText( unsigned int iPad, unsigned int tooltip, int iTextID ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_SetTooltipText(iPad, tooltip, iTextID ); + } + return S_OK; +} + +HRESULT CXuiSceneBase::RefreshTooltips( unsigned int iPad) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_RefreshTooltips(iPad); + } + return S_OK; +} + +HRESULT CXuiSceneBase::ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_ShowTooltip(iPad, tooltip, show ); + } + return S_OK; +} + +HRESULT CXuiSceneBase::ShowSafeArea( BOOL bShow ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_ShowSafeArea(bShow ); + } + return S_OK; +} + +HRESULT CXuiSceneBase::SetTooltips( unsigned int iPad, int iA, int iB, int iX, int iY , int iLT, int iRT, int iRB, int iLB, int iLS, bool forceUpdate /*= false*/ ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + // Enable all the tooltips. We should disable them in the scenes as required + CXuiSceneBase::Instance->_SetTooltipsEnabled( iPad ); + + int iTooptipsA[BUTTONS_TOOLTIP_MAX]; + iTooptipsA[BUTTON_TOOLTIP_A]=iA; + iTooptipsA[BUTTON_TOOLTIP_B]=iB; + iTooptipsA[BUTTON_TOOLTIP_X]=iX; + iTooptipsA[BUTTON_TOOLTIP_Y]=iY; + iTooptipsA[BUTTON_TOOLTIP_LT]=iLT; + iTooptipsA[BUTTON_TOOLTIP_RT]=iRT; + iTooptipsA[BUTTON_TOOLTIP_LB]=iRB; + iTooptipsA[BUTTON_TOOLTIP_RB]=iLB; + iTooptipsA[BUTTON_TOOLTIP_LS]=iLS; + + for(int i=0;i<BUTTONS_TOOLTIP_MAX;i++) + { + if(iTooptipsA[i]==-1) + { + CXuiSceneBase::Instance->SetTooltipText(iPad, i, -1 ); + CXuiSceneBase::Instance->_ShowTooltip(iPad, i, false ); + //CXuiSceneBase::Instance->m_iCurrentTooltipTextID[iPad][i]=-1; + } + else if(iTooptipsA[i]==-2) + { + CXuiSceneBase::Instance->_ShowTooltip(iPad, i, true ); + CXuiSceneBase::Instance->SetTooltipText(iPad, i, -2 ); + } + else + { + // does the tooltip need to change? + if(CXuiSceneBase::Instance->m_iCurrentTooltipTextID[iPad][i]!=iTooptipsA[i] || forceUpdate) + { + CXuiSceneBase::Instance->SetTooltipText(iPad, i, iTooptipsA[i] ); + } + CXuiSceneBase::Instance->_ShowTooltip(iPad, i, true ); + } + } + + } + return S_OK; +} + +HRESULT CXuiSceneBase::SetTooltipsEnabled( unsigned int iPad, bool bA, bool bB, bool bX, bool bY,bool bLT, bool bRT, bool bLB, bool bRB, bool bLS) +{ + return CXuiSceneBase::Instance->_SetTooltipsEnabled(iPad, bA, bB, bX, bY, bLT, bRT, bLB, bRB, bLS ); +} + +HRESULT CXuiSceneBase::EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable ) +{ + return CXuiSceneBase::Instance->_EnableTooltip(iPad, tooltip, enable); +} + +HRESULT CXuiSceneBase::AnimateKeyPress(DWORD userIndex, DWORD dwKeyCode) +{ + return CXuiSceneBase::Instance->_AnimateKeyPress(userIndex, dwKeyCode ); +} + +HRESULT CXuiSceneBase::ShowSavingMessage( unsigned int iPad, C4JStorage::ESavingMessage eVal ) +{ + if( CXuiSceneBase::Instance != NULL ) + { + return CXuiSceneBase::Instance->_ShowSavingMessage(iPad, eVal); + } + + return S_OK; +} + +HRESULT CXuiSceneBase::ShowBackground( unsigned int iPad, BOOL bShow ) +{ + return CXuiSceneBase::Instance->_ShowBackground(iPad, bShow ); +} + +HRESULT CXuiSceneBase::ShowDarkOverlay( unsigned int iPad, BOOL bShow ) +{ + return CXuiSceneBase::Instance->_ShowDarkOverlay(iPad, bShow ); +} + +HRESULT CXuiSceneBase::ShowLogo( unsigned int iPad, BOOL bShow ) +{ + return CXuiSceneBase::Instance->_ShowLogo(iPad, bShow ); +} + +HRESULT CXuiSceneBase::ShowPressStart(unsigned int iPad) +{ + CXuiSceneBase::Instance->_ShowPressStart(iPad); + return S_OK; +} + +HRESULT CXuiSceneBase::ShowOtherPlayersBaseScene(int iPad, bool show) +{ + CXuiSceneBase::Instance->_ShowOtherPlayersBaseScene(iPad, show); + return S_OK; +} + +HRESULT CXuiSceneBase::UpdateAutosaveCountdownTimer(unsigned int uiSeconds) +{ + CXuiSceneBase::Instance->_UpdateAutosaveCountdownTimer(uiSeconds); + return S_OK; +} + +HRESULT CXuiSceneBase::ShowAutosaveCountdownTimer(BOOL bVal) +{ + CXuiSceneBase::Instance->_ShowAutosaveCountdownTimer(bVal); + return S_OK; +} + +HRESULT CXuiSceneBase::UpdateTrialTimer(unsigned int iPad) +{ + CXuiSceneBase::Instance->_UpdateTrialTimer(iPad); + return S_OK; +} +HRESULT CXuiSceneBase::ShowTrialTimer(BOOL bVal) +{ + CXuiSceneBase::Instance->_ShowTrialTimer(bVal); + return S_OK; +} + +void CXuiSceneBase::ReduceTrialTimerValue() +{ + CXuiSceneBase::Instance->_ReduceTrialTimerValue(); +} + +bool CXuiSceneBase::PressStartPlaying(unsigned int iPad) +{ + return CXuiSceneBase::Instance->_PressStartPlaying(iPad); +} + +HRESULT CXuiSceneBase::HidePressStart() +{ + return CXuiSceneBase::Instance->_HidePressStart(); +} + +HRESULT CXuiSceneBase::SetPlayerBaseScenePosition( unsigned int iPad, EBaseScenePosition position ) +{ + return CXuiSceneBase::Instance->_SetPlayerBaseScenePosition(iPad, position ); +} + +HRESULT CXuiSceneBase::SetPlayerBasePositions(EBaseScenePosition pad0, EBaseScenePosition pad1, EBaseScenePosition pad2, EBaseScenePosition pad3) +{ + SetPlayerBaseScenePosition( 0, pad0 ); + SetPlayerBaseScenePosition( 1, pad1 ); + SetPlayerBaseScenePosition( 2, pad2 ); + SetPlayerBaseScenePosition( 3, pad3 ); + + return S_OK; +} + +HRESULT CXuiSceneBase::UpdatePlayerBasePositions() +{ + EBaseScenePosition padPositions[XUSER_MAX_COUNT]; + + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + padPositions[idx] = e_BaseScene_NotSet; + } + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + // If the game is not started (or is being held paused for a bit) then display all scenes fullscreen + if( pMinecraft == NULL ) + { + for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + padPositions[idx] = e_BaseScene_Fullscreen; + } + } + + // If the game is not in split-screen, then display the primary pad at fullscreen + else if(app.GetLocalPlayerCount()<2) + { + int primaryPad = ProfileManager.GetPrimaryPad(); + padPositions[primaryPad] = e_BaseScene_Fullscreen; + + // May need to turn off the player who just left + for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + DisplayGamertag(idx,FALSE); + } + } + + // We are in splitscreen so work out where each player should be + else + { + + for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(pMinecraft->localplayers[idx] != NULL) + { + if(pMinecraft->localplayers[idx]->m_iScreenSection==C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + DisplayGamertag(idx,FALSE); + } + else + { + DisplayGamertag(idx,TRUE); + } + + switch( pMinecraft->localplayers[idx]->m_iScreenSection) + { + case C4JRender::VIEWPORT_TYPE_FULLSCREEN: + padPositions[idx] = e_BaseScene_Fullscreen; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + padPositions[idx] = e_BaseScene_Top; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + padPositions[idx] = e_BaseScene_Bottom; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + padPositions[idx] = e_BaseScene_Left; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: + padPositions[idx] = e_BaseScene_Right; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: + padPositions[idx] = e_BaseScene_Top_Left; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + padPositions[idx] = e_BaseScene_Top_Right; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + padPositions[idx] = e_BaseScene_Bottom_Left; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + padPositions[idx] = e_BaseScene_Bottom_Right; + break; + } + } + else + { + padPositions[idx] = e_BaseScene_NotSet; + DisplayGamertag(idx,FALSE); + } + } + } + + return SetPlayerBasePositions(padPositions[0], padPositions[1], padPositions[2], padPositions[3]); +} + +CXuiSceneBase::EBaseScenePosition CXuiSceneBase::GetPlayerBasePosition(int iPad) +{ + return CXuiSceneBase::Instance->_GetPlayerBasePosition(iPad); +} + +void CXuiSceneBase::UpdateSelectedItemPos(int iPad) +{ + CXuiSceneBase::Instance->_UpdateSelectedItemPos(iPad); +} + +HXUIOBJ CXuiSceneBase::GetPlayerBaseScene(int iPad) +{ + return CXuiSceneBase::Instance->_GetPlayerBaseScene(iPad); +} + +HRESULT CXuiSceneBase::PlayUISFX(ESoundEffect eSound) +{ + return CXuiSceneBase::Instance->_PlayUISFX(eSound); +} + +void CXuiSceneBase::SetEmptyQuadrantLogo(int iScreenSection) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + EBaseScenePosition ePos=e_BaseScene_Top_Left; + int iPad; + // find the empty player + for( iPad = 0; iPad < XUSER_MAX_COUNT; ++iPad) + { + if(pMinecraft->localplayers[iPad] == NULL) + { + switch( iScreenSection) + { + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: + ePos = e_BaseScene_Top_Left; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + ePos = e_BaseScene_Top_Right; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + ePos = e_BaseScene_Bottom_Left; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + ePos = e_BaseScene_Bottom_Right; + break; + } + break; + } + } + + CXuiSceneBase::Instance->_SetEmptyQuadrantLogo(iPad,ePos); +} + +HRESULT CXuiSceneBase::DisplayGamertag( unsigned int iPad, BOOL bDisplay ) +{ + + CXuiSceneBase::Instance->_DisplayGamertag(iPad,bDisplay); + return S_OK; +} + +void CXuiSceneBase::SetSelectedItem( unsigned int iPad, const wstring &name) +{ + CXuiSceneBase::Instance->_SetSelectedItem(iPad,name); +} + +void CXuiSceneBase::HideAllGameUIElements() +{ + CXuiSceneBase::Instance->_HideAllGameUIElements(); +} + +bool CXuiSceneBase::GetBaseSceneSafeZone( unsigned int iPad, D3DXVECTOR2 &origin, float &width, float &height ) +{ + return CXuiSceneBase::Instance->_GetBaseSceneSafeZone(iPad,origin,width,height); +} + + +#ifndef _XBOX +void CXuiSceneBase::CreateBaseSceneInstance() +{ + CXuiSceneBase *sceneBase = new CXuiSceneBase(); + BOOL handled; + sceneBase->OnInit(NULL,handled); +} +#endif
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Base.h b/Minecraft.Client/Common/XUI/XUI_Scene_Base.h new file mode 100644 index 00000000..1a5b5d87 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Base.h @@ -0,0 +1,432 @@ +#pragma once + +#include "../media/xuiscene_base.h" +#include "XUI_Ctrl_SlotItem.h" +#include "XUI_CustomMessages.h" +#include "..\UI\UIEnums.h" +#include "..\..\..\Minecraft.World\SoundTypes.h" + +#define BUTTON_TOOLTIP_A 0 +#define BUTTON_TOOLTIP_B 1 +#define BUTTON_TOOLTIP_X 2 +#define BUTTON_TOOLTIP_Y 3 +#define BUTTON_TOOLTIP_LT 4 +#define BUTTON_TOOLTIP_RT 5 +#define BUTTON_TOOLTIP_LB 6 +#define BUTTON_TOOLTIP_RB 7 +#define BUTTON_TOOLTIP_LS 8 +#define BUTTONS_TOOLTIP_MAX 9 + +#define SFX_BACK 0 +#define SFX_CRAFT 1 +#define SFX_CRAFTFAIL 2 +#define SFX_FOCUS 3 +#define SFX_PRESS 4 +#define SFX_SCROLL 5 +#define SFX_MAX 6 + + +// This should be our target screen height and width +#define XUI_BASE_SCENE_WIDTH 1280.0f +#define XUI_BASE_SCENE_HEIGHT 720.0f + +#define XUI_BASE_SCENE_WIDTH_HALF 640.0f +#define XUI_BASE_SCENE_HEIGHT_HALF 360.0f +#define XUI_BASE_SCENE_WIDTH_QUARTER 320.0f +#define XUI_BASE_SCENE_HEIGHT_QUARTER 180.0f +#define SAFEZONE_HALF_HEIGHT 36.0f +#define SAFEZONE_HALF_WIDTH 64.0f + +// How much we scale each base for splitscreen (should be 0.5f) +#define XUI_BASE_SPLITSCREEN_SCALE 1.0f//0.5f // 4J-PB - TODO - move scenes instead + +// We make the tooltips bigger as they are unreadable when scaled by the above +#define XUI_BASE_SPLIT_TOOLTIPS_SCALE 1.0f//1.5f + +// The percentage of starting size that the tooltips grow by +#define XUI_BASE_SPLIT_TOOLTIPS_DIFF (XUI_BASE_SPLIT_TOOLTIPS_SCALE - 1.0f) + +class CXuiSceneBase : public CXuiSceneImpl +{ +public: + enum EBaseScenePosition + { + e_BaseScene_NotSet, + + // 1 player + e_BaseScene_Fullscreen, + + // 2 Player split-screen + e_BaseScene_Top, + e_BaseScene_Bottom, + e_BaseScene_Left, + e_BaseScene_Right, + + // 3/4 Player split-screen + e_BaseScene_Top_Left, + e_BaseScene_Top_Right, + e_BaseScene_Bottom_Left, + e_BaseScene_Bottom_Right, + }; + +protected: + static const int m_iTooltipSpacingGap=10; + static const int m_iTooltipSpacingGapSmall=5; + D3DXVECTOR3 m_vPosTextInTooltip[BUTTONS_TOOLTIP_MAX]; + D3DXVECTOR3 m_vPosTextInTooltipSmall[BUTTONS_TOOLTIP_MAX]; + D3DXVECTOR3 vLogoPosA[XUSER_MAX_COUNT]; + + // We have a group of these per player + CXuiScene m_BasePlayerScene[XUSER_MAX_COUNT]; + // Control and Element wrapper objects. + CXuiControl m_TooltipGroup[XUSER_MAX_COUNT]; + CXuiControl m_Buttons[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + CXuiControl m_TooltipGroupSmall[XUSER_MAX_COUNT]; + CXuiControl m_ButtonsSmall[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + CXuiControl m_bottomLeftAnchorPoint[XUSER_MAX_COUNT]; + CXuiControl m_topLeftAnchorPoint[XUSER_MAX_COUNT]; + CXuiControl m_SavingIcon; + CXuiControl m_Background[XUSER_MAX_COUNT]; + CXuiControl m_DarkOverlay[XUSER_MAX_COUNT]; + CXuiControl m_Logo[XUSER_MAX_COUNT]; + CXuiControl m_CrouchIcon[XUSER_MAX_COUNT]; + CXuiControl m_PressStart; + CXuiControl m_TrialTimer; + CXuiControl m_SafeArea; + CXuiControl m_BossHealthGroup[XUSER_MAX_COUNT]; + CXuiControl m_BossHealthText[XUSER_MAX_COUNT]; + CXuiProgressBar *m_pBossHealthProgress; + CXuiProgressBar m_BossHealthProgress1[XUSER_MAX_COUNT]; + CXuiProgressBar m_BossHealthProgress2[XUSER_MAX_COUNT]; + CXuiProgressBar m_BossHealthProgress3[XUSER_MAX_COUNT]; + CXuiProgressBar m_BossHealthProgress1_small[XUSER_MAX_COUNT]; + CXuiProgressBar m_BossHealthProgress2_small[XUSER_MAX_COUNT]; + CXuiProgressBar m_BossHealthProgress3_small[XUSER_MAX_COUNT]; + int m_ticksWithNoBoss; + CXuiSound m_SFXA[SFX_MAX]; + HXUIOBJ m_hEmptyQuadrantLogo; + HXUIOBJ m_hGamerTagA[XUSER_MAX_COUNT]; + CXuiControl m_selectedItemA[XUSER_MAX_COUNT]; + CXuiControl m_selectedItemSmallA[XUSER_MAX_COUNT]; + + BOOL m_visible[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + BOOL m_bossHealthVisible[XUSER_MAX_COUNT]; + int m_iWrongTexturePackTickC; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_SKIN_CHANGED( OnSkinChanged ) +// XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) +// XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiPressStartMessage, m_PressStart) + MAP_CONTROL(IDC_XuiTrialTimer, m_TrialTimer) + MAP_CONTROL(IDC_XuiSavingIcon, m_SavingIcon) + MAP_CONTROL(IDC_SafeArea, m_SafeArea) + MAP_CONTROL(IDC_XuiSoundXACTBack, m_SFXA[SFX_BACK]) + MAP_CONTROL(IDC_XuiSoundXACTCraft,m_SFXA[SFX_CRAFT]) + MAP_CONTROL(IDC_XuiSoundXACTCraftFail,m_SFXA[SFX_CRAFTFAIL]) + MAP_CONTROL(IDC_XuiSoundXACTPress,m_SFXA[SFX_PRESS]) + MAP_CONTROL(IDC_XuiSoundXACTFocus,m_SFXA[SFX_FOCUS]) + MAP_CONTROL(IDC_XuiSoundXACTScroll,m_SFXA[SFX_SCROLL]) + + //MAP_CONTROL(IDC_BossHealth, m_BossHealthGroup) + //BEGIN_MAP_CHILD_CONTROLS(m_BossHealthGroup) + // MAP_CONTROL(IDC_TitleText, m_BossHealthText) + // MAP_CONTROL(IDC_ProgressBar, m_BossHealthProgress) + //END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_BasePlayer0, m_BasePlayerScene[0]) + BEGIN_MAP_CHILD_CONTROLS(m_BasePlayerScene[0]) + MAP_CONTROL(IDC_BottomLeftAnchorPoint, m_bottomLeftAnchorPoint[0]) + MAP_CONTROL(IDC_TopLeftAnchorPoint, m_topLeftAnchorPoint[0]) + MAP_CONTROL(IDC_Tooltips, m_TooltipGroup[0]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroup[0]) + MAP_CONTROL(IDC_AButton, m_Buttons[0][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_Buttons[0][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_Buttons[0][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_Buttons[0][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_Buttons[0][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_Buttons[0][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_Buttons[0][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_Buttons[0][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_Buttons[0][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TooltipsSmall, m_TooltipGroupSmall[0]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroupSmall[0]) + MAP_CONTROL(IDC_AButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_ButtonsSmall[0][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_ButtonsSmall[0][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_ButtonsSmall[0][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_ButtonsSmall[0][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Background, m_Background[0]) + MAP_CONTROL(IDC_XuiDarkOverlay, m_DarkOverlay[0]) + MAP_CONTROL(IDC_Logo, m_Logo[0]) + MAP_CONTROL(IDC_SelectedItem, m_selectedItemA[0]) + MAP_CONTROL(IDC_SelectedItemSmall, m_selectedItemSmallA[0]) + MAP_CONTROL(IDC_BossHealth, m_BossHealthGroup[0]) + BEGIN_MAP_CHILD_CONTROLS(m_BossHealthGroup[0]) + MAP_CONTROL(IDC_TitleText, m_BossHealthText[0]) + MAP_CONTROL(IDC_ProgressBar1, m_BossHealthProgress1[0]) + MAP_CONTROL(IDC_ProgressBar2, m_BossHealthProgress2[0]) + MAP_CONTROL(IDC_ProgressBar3, m_BossHealthProgress3[0]) + MAP_CONTROL(IDC_ProgressBar1_small, m_BossHealthProgress1_small[0]) + MAP_CONTROL(IDC_ProgressBar2_small, m_BossHealthProgress2_small[0]) + MAP_CONTROL(IDC_ProgressBar3_small, m_BossHealthProgress3_small[0]) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_BasePlayer1, m_BasePlayerScene[1]) + BEGIN_MAP_CHILD_CONTROLS(m_BasePlayerScene[1]) + MAP_CONTROL(IDC_BottomLeftAnchorPoint, m_bottomLeftAnchorPoint[1]) + MAP_CONTROL(IDC_TopLeftAnchorPoint, m_topLeftAnchorPoint[1]) + MAP_CONTROL(IDC_Tooltips, m_TooltipGroup[1]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroup[1]) + MAP_CONTROL(IDC_AButton, m_Buttons[1][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_Buttons[1][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_Buttons[1][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_Buttons[1][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_Buttons[1][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_Buttons[1][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_Buttons[1][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_Buttons[1][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_Buttons[1][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TooltipsSmall, m_TooltipGroupSmall[1]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroupSmall[1]) + MAP_CONTROL(IDC_AButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_ButtonsSmall[1][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_ButtonsSmall[1][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_ButtonsSmall[1][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_ButtonsSmall[1][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Background, m_Background[1]) + MAP_CONTROL(IDC_XuiDarkOverlay, m_DarkOverlay[1]) + MAP_CONTROL(IDC_Logo, m_Logo[1]) + MAP_CONTROL(IDC_SelectedItem, m_selectedItemA[1]) + MAP_CONTROL(IDC_SelectedItemSmall, m_selectedItemSmallA[1]) + MAP_CONTROL(IDC_BossHealth, m_BossHealthGroup[1]) + BEGIN_MAP_CHILD_CONTROLS(m_BossHealthGroup[1]) + MAP_CONTROL(IDC_TitleText, m_BossHealthText[1]) + MAP_CONTROL(IDC_ProgressBar1, m_BossHealthProgress1[1]) + MAP_CONTROL(IDC_ProgressBar2, m_BossHealthProgress2[1]) + MAP_CONTROL(IDC_ProgressBar3, m_BossHealthProgress3[1]) + MAP_CONTROL(IDC_ProgressBar1_small, m_BossHealthProgress1_small[1]) + MAP_CONTROL(IDC_ProgressBar2_small, m_BossHealthProgress2_small[1]) + MAP_CONTROL(IDC_ProgressBar3_small, m_BossHealthProgress3_small[1]) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_BasePlayer2, m_BasePlayerScene[2]) + BEGIN_MAP_CHILD_CONTROLS(m_BasePlayerScene[2]) + MAP_CONTROL(IDC_BottomLeftAnchorPoint, m_bottomLeftAnchorPoint[2]) + MAP_CONTROL(IDC_TopLeftAnchorPoint, m_topLeftAnchorPoint[2]) + MAP_CONTROL(IDC_Tooltips, m_TooltipGroup[2]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroup[2]) + MAP_CONTROL(IDC_AButton, m_Buttons[2][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_Buttons[2][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_Buttons[2][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_Buttons[2][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_Buttons[2][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_Buttons[2][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_Buttons[2][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_Buttons[2][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_Buttons[2][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TooltipsSmall, m_TooltipGroupSmall[2]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroupSmall[2]) + MAP_CONTROL(IDC_AButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_ButtonsSmall[2][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_ButtonsSmall[2][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_ButtonsSmall[2][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_ButtonsSmall[2][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Background, m_Background[2]) + MAP_CONTROL(IDC_XuiDarkOverlay, m_DarkOverlay[2]) + MAP_CONTROL(IDC_Logo, m_Logo[2]) + MAP_CONTROL(IDC_SelectedItem, m_selectedItemA[2]) + MAP_CONTROL(IDC_SelectedItemSmall, m_selectedItemSmallA[2]) + MAP_CONTROL(IDC_BossHealth, m_BossHealthGroup[2]) + BEGIN_MAP_CHILD_CONTROLS(m_BossHealthGroup[2]) + MAP_CONTROL(IDC_TitleText, m_BossHealthText[2]) + MAP_CONTROL(IDC_ProgressBar1, m_BossHealthProgress1[2]) + MAP_CONTROL(IDC_ProgressBar2, m_BossHealthProgress2[2]) + MAP_CONTROL(IDC_ProgressBar3, m_BossHealthProgress3[2]) + MAP_CONTROL(IDC_ProgressBar1_small, m_BossHealthProgress1_small[2]) + MAP_CONTROL(IDC_ProgressBar2_small, m_BossHealthProgress2_small[2]) + MAP_CONTROL(IDC_ProgressBar3_small, m_BossHealthProgress3_small[2]) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_BasePlayer3, m_BasePlayerScene[3]) + BEGIN_MAP_CHILD_CONTROLS(m_BasePlayerScene[3]) + MAP_CONTROL(IDC_BottomLeftAnchorPoint, m_bottomLeftAnchorPoint[3]) + MAP_CONTROL(IDC_TopLeftAnchorPoint, m_topLeftAnchorPoint[3]) + MAP_CONTROL(IDC_Tooltips, m_TooltipGroup[3]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroup[3]) + MAP_CONTROL(IDC_AButton, m_Buttons[3][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_Buttons[3][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_Buttons[3][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_Buttons[3][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_Buttons[3][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_Buttons[3][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_Buttons[3][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_Buttons[3][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_Buttons[3][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_TooltipsSmall, m_TooltipGroupSmall[3]) + BEGIN_MAP_CHILD_CONTROLS(m_TooltipGroupSmall[3]) + MAP_CONTROL(IDC_AButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_A]) + MAP_CONTROL(IDC_BButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_B]) + MAP_CONTROL(IDC_XButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_X]) + MAP_CONTROL(IDC_YButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_Y]) + MAP_CONTROL(IDC_LTrigger, m_ButtonsSmall[3][BUTTON_TOOLTIP_LT]) + MAP_CONTROL(IDC_RTrigger, m_ButtonsSmall[3][BUTTON_TOOLTIP_RT]) + MAP_CONTROL(IDC_RBButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_RB]) + MAP_CONTROL(IDC_LBButton, m_ButtonsSmall[3][BUTTON_TOOLTIP_LB]) + MAP_CONTROL(IDC_LStick, m_Buttons[3][BUTTON_TOOLTIP_LS]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Background, m_Background[3]) + MAP_CONTROL(IDC_XuiDarkOverlay, m_DarkOverlay[3]) + MAP_CONTROL(IDC_Logo, m_Logo[3]) + MAP_CONTROL(IDC_SelectedItem, m_selectedItemA[3]) + MAP_CONTROL(IDC_SelectedItemSmall, m_selectedItemSmallA[3]) + MAP_CONTROL(IDC_BossHealth, m_BossHealthGroup[3]) + BEGIN_MAP_CHILD_CONTROLS(m_BossHealthGroup[3]) + MAP_CONTROL(IDC_TitleText, m_BossHealthText[3]) + MAP_CONTROL(IDC_ProgressBar1, m_BossHealthProgress1[3]) + MAP_CONTROL(IDC_ProgressBar2, m_BossHealthProgress2[3]) + MAP_CONTROL(IDC_ProgressBar3, m_BossHealthProgress3[3]) + MAP_CONTROL(IDC_ProgressBar1_small, m_BossHealthProgress1_small[3]) + MAP_CONTROL(IDC_ProgressBar2_small, m_BossHealthProgress2_small[3]) + MAP_CONTROL(IDC_ProgressBar3_small, m_BossHealthProgress3_small[3]) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + HRESULT OnSkinChanged(BOOL& bHandled); +// HRESULT OnCustomMessage_DLCInstalled(); +// HRESULT OnCustomMessage_DLCMountingComplete(); + +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneBase, L"CXuiSceneBase", XUI_CLASS_SCENE ) + +private: + void _TickAllBaseScenes(); + HRESULT _SetTooltipText( unsigned int iPad, unsigned int tooltip, int iTextID ); + HRESULT _SetEnableTooltips( unsigned int iPad, BOOL bVal ); + HRESULT _ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show ); + HRESULT _SetTooltipsEnabled( unsigned int iPad, bool bA = true, bool bB = true, bool bX = true, bool bY = true, bool bLT = true, bool bRT = true, bool bLB=true, bool bRB = true, bool bLS = true); + HRESULT _RefreshTooltips( unsigned int iPad); + HRESULT _EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable ); + HRESULT _ShowSavingMessage( unsigned int iPad, C4JStorage::ESavingMessage eVal ); + HRESULT _ShowBackground( unsigned int iPad, BOOL bShow ); + HRESULT _ShowDarkOverlay( unsigned int iPad, BOOL bShow ); + HRESULT _ShowLogo( unsigned int iPad, BOOL bShow ); + HRESULT _ShowPressStart(unsigned int iPad); + HRESULT _UpdateAutosaveCountdownTimer(unsigned int uiSeconds); + HRESULT _ShowAutosaveCountdownTimer(BOOL bVal); + HRESULT _UpdateTrialTimer(unsigned int iPad); + HRESULT _ShowTrialTimer(BOOL bVal); + void _ReduceTrialTimerValue(); + HRESULT _HidePressStart(); + HRESULT _ShowSafeArea( BOOL bShow ); + HRESULT _ShowOtherPlayersBaseScene(int iPad, bool show); + bool _PressStartPlaying(unsigned int iPad); + HRESULT _SetPlayerBaseScenePosition( unsigned int iPad, EBaseScenePosition position ); + void _UpdateSelectedItemPos( unsigned int iPad); + EBaseScenePosition _GetPlayerBasePosition(int iPad); + HRESULT _AnimateKeyPress(DWORD userIndex, DWORD dwKeyCode); + HXUIOBJ _GetPlayerBaseScene(int iPad) {return m_BasePlayerScene[iPad].m_hObj;} + HRESULT _PlayUISFX(ESoundEffect eSound); + void _SetEmptyQuadrantLogo(int iPad,EBaseScenePosition ePos); + HRESULT _DisplayGamertag( unsigned int iPad, BOOL bDisplay ); + void _SetSelectedItem( unsigned int iPad, const wstring& name); + void _HideAllGameUIElements(); + bool _GetBaseSceneSafeZone( unsigned int iPad, D3DXVECTOR2 &origin, float &width, float &height); + + void ReLayout( unsigned int iPad ); + +private: + static CXuiSceneBase *Instance; + int m_iCurrentTooltipTextID[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + HXUIOBJ hTooltipText[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + HXUIOBJ hTooltipTextSmall[XUSER_MAX_COUNT][BUTTONS_TOOLTIP_MAX]; + EBaseScenePosition m_playerBaseScenePosition[XUSER_MAX_COUNT]; + bool m_bCrouching[XUSER_MAX_COUNT]; + int m_iQuadrantsMask; + unsigned int m_uiSelectedItemOpacityCountDown[XUSER_MAX_COUNT]; + +public: + static DWORD m_dwTrialTimerLimitSecs; + +public: + static CXuiSceneBase *GetInstance() { return Instance; } + static void TickAllBaseScenes(); + static HRESULT SetTooltipText( unsigned int iPad, unsigned int tooltip, int iTextID ); + static HRESULT SetEnableTooltips( unsigned int iPad, BOOL bVal ); + static HRESULT ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show ); + static HRESULT SetTooltips( unsigned int iPad, int iA, int iB=-1, int iX=-1, int iY=-1 , int iLT=-1, int iRT=-1, int iLB=-1, int iRB=-1, int iLS=-1, bool forceUpdate = false); + static HRESULT RefreshTooltips( unsigned int iPad); + static HRESULT EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable ); + static HRESULT SetTooltipsEnabled( unsigned int iPad, bool bA = true, bool bB = true, bool bX = true, bool bY = true, bool bLT = true, bool bRT = true, bool bLB = true, bool bRB=true, bool bLS=true); + static HRESULT AnimateKeyPress(DWORD userIndex, DWORD dwKeyCode); + static HRESULT ShowSavingMessage( unsigned int iPad, C4JStorage::ESavingMessage eVal); + static HRESULT ShowBackground( unsigned int iPad, BOOL bShow ); + static HRESULT ShowDarkOverlay( unsigned int iPad, BOOL bShow ); + static HRESULT ShowLogo( unsigned int iPad, BOOL bShow ); + static HRESULT UpdateAutosaveCountdownTimer(unsigned int uiSeconds); + static HRESULT ShowAutosaveCountdownTimer(BOOL bVal); + static HRESULT UpdateTrialTimer(unsigned int iPad); + static HRESULT ShowTrialTimer(BOOL bVal); + static void ReduceTrialTimerValue(); + static HRESULT HidePressStart(); + static HRESULT ShowSafeArea( BOOL bShow ); + static HRESULT ShowOtherPlayersBaseScene(int iPad, bool show); + + static HRESULT ShowPressStart(unsigned int iPad); + static bool PressStartPlaying(unsigned int iPad); + static HRESULT SetPlayerBaseScenePosition( unsigned int iPad, EBaseScenePosition position ); + static HRESULT SetPlayerBasePositions(EBaseScenePosition pad0, EBaseScenePosition pad1, EBaseScenePosition pad2, EBaseScenePosition pad3); + static HRESULT UpdatePlayerBasePositions(); + static EBaseScenePosition GetPlayerBasePosition(int iPad); + static void UpdateSelectedItemPos(int iPad); + + + static HXUIOBJ GetPlayerBaseScene(int iPad); + static HRESULT PlayUISFX(ESoundEffect eSound); + static void SetEmptyQuadrantLogo(int iSection); + static HRESULT DisplayGamertag( unsigned int iPad, BOOL bDisplay ); + static void SetSelectedItem( unsigned int iPad, const wstring &name); + static void HideAllGameUIElements(); + + // Returns details on the fully transformed (ie screen space) base scene position, adjusted for safe zones + static bool GetBaseSceneSafeZone( unsigned int iPad, D3DXVECTOR2 &origin, float &width, float &height); + +#ifndef _XBOX + static void CreateBaseSceneInstance(); +#endif +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.cpp new file mode 100644 index 00000000..cf600966 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.cpp @@ -0,0 +1,156 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_BrewingStand.h" +#include "XUI_Ctrl_BrewProgress.h" +#include "XUI_Ctrl_BubblesProgress.h" + + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneBrewingStand::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneBrewingStand::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_BrewingStandText,app.GetString(IDS_BREWING_STAND)); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + BrewingScreenInput* initData = (BrewingScreenInput*)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Brewing_Menu, this); + } +#endif + + BrewingStandMenu* menu = new BrewingStandMenu( initData->inventory, initData->brewingStand ); + + + InitDataAssociations(m_iPad, menu); + + m_progressControl->SetUserData( initData->brewingStand.get() ); + + m_bubbleProgress->SetUserData( initData->brewingStand.get() ); + + delete initData; + + CXuiSceneAbstractContainer::Initialize( m_iPad, menu, true, BrewingStandMenu::INV_SLOT_START, eSectionBrewingUsing, eSectionBrewingMax ); + + //app.SetRichPresenceContextValue(m_iPad,CONTEXT_GAME_STATE_FORGING); + + return S_OK; +} + +HRESULT CXuiSceneBrewingStand::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +CXuiControl* CXuiSceneBrewingStand::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionBrewingBottle1: + return (CXuiControl *)m_bottle1Control; + break; + case eSectionBrewingBottle2: + return (CXuiControl *)m_bottle2Control; + break; + case eSectionBrewingBottle3: + return (CXuiControl *)m_bottle3Control; + break; + case eSectionBrewingIngredient: + return (CXuiControl *)m_ingredientControl; + break; + case eSectionBrewingInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionBrewingUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneBrewingStand::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionBrewingBottle1: + return m_bottle1Control; + break; + case eSectionBrewingBottle2: + return m_bottle2Control; + break; + case eSectionBrewingBottle3: + return m_bottle3Control; + break; + case eSectionBrewingIngredient: + return m_ingredientControl; + break; + case eSectionBrewingInventory: + return m_inventoryControl; + break; + case eSectionBrewingUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneBrewingStand::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + // TODO Inventory dimensions need defined as constants + m_ingredientControl->SetData( iPad, menu, 1, 1, BrewingStandMenu::INGREDIENT_SLOT ); + + m_bottle1Control->SetData( iPad, menu, 1, 1, BrewingStandMenu::BOTTLE_SLOT_START ); + m_bottle2Control->SetData( iPad, menu, 1, 1, BrewingStandMenu::BOTTLE_SLOT_START + 1); + m_bottle3Control->SetData( iPad, menu, 1, 1, BrewingStandMenu::BOTTLE_SLOT_START + 2); + + //m_litProgressControl->SetUserData( initData->furnace.get() ); + + //m_burnProgress->SetUserData( initData->furnace.get() ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, BrewingStandMenu::INV_SLOT_START); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.h b/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.h new file mode 100644 index 00000000..370b6b18 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.h @@ -0,0 +1,75 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_brewingstand.h" +#include "XUI_Scene_AbstractContainer.h" +#include "..\UI\IUIScene_BrewingMenu.h" + +class CXuiCtrlSlotList; +class CXuiCtrlBrewProgress; +class CXuiCtrlBubblesProgress; + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneBrewingStand : public CXuiSceneAbstractContainer, public IUIScene_BrewingMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneBrewingStand, L"CXuiSceneBrewingStand", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Ingredient, m_ingredientControl) + MAP_OVERRIDE(IDC_Bottle1, m_bottle1Control) + MAP_OVERRIDE(IDC_Bottle2, m_bottle2Control) + MAP_OVERRIDE(IDC_Bottle3, m_bottle3Control) + + MAP_OVERRIDE(IDC_Progress, m_progressControl) + MAP_OVERRIDE(IDC_Bubbles, m_bubbleProgress) + MAP_CONTROL(IDC_BrewingStandText,m_BrewingStandText) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); +// HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + +private: + CXuiCtrlSlotList *m_ingredientControl; + CXuiCtrlSlotList *m_bottle1Control; + CXuiCtrlSlotList *m_bottle2Control; + CXuiCtrlSlotList *m_bottle3Control; + + CXuiCtrlBrewProgress *m_progressControl; + CXuiCtrlBubblesProgress *m_bubbleProgress; + CXuiControl m_BrewingStandText; + + CXuiControl m_sceneGroup; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Container.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Container.cpp new file mode 100644 index 00000000..39b836d2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Container.cpp @@ -0,0 +1,162 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\Container.h" +#include "..\..\..\Minecraft.World\ContainerMenu.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_Container.h" +#include "XUI_Ctrl_SlotItemListItem.h" +#include "XUI_Ctrl_SlotItem.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" + +// The height of one row of slots +//#define ROW_HEIGHT 42.0f - comes from the pointer height in the xui + +// The number of container rows that are visible in the Xui file at it's default size +#define CONTAINER_DEFAULT_ROWS 3 + + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneContainer::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneContainer::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + D3DXVECTOR3 vec; + MapChildControls(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + ContainerScreenInput* initData = (ContainerScreenInput*)pInitData->pvInitData; + + XuiControlSetText(m_ChestText,app.GetString(initData->container->getName())); + + ContainerMenu* menu = new ContainerMenu( initData->inventory, initData->container ); + + shared_ptr<Container> container = initData->container; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + +#ifdef _XBOX + if( pMinecraft->localgameModes[initData->iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[initData->iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Container_Menu, this); + } +#endif + + // if we are in splitscreen, then we need to figure out if we want to move this scene + int rows = container->getContainerSize() / 9; + // use the pointer size in the xui to set the row height + float fPointerWidth,fPointerHeight; + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + m_pointerControl->GetBounds(&fPointerWidth, &fPointerHeight); + + // Adjust the height to show the correct number of container rows + float height, width; + this->GetBounds( &width, &height ); + int rowDiff = CONTAINER_DEFAULT_ROWS - rows; + //height = height - (rowDiff * ROW_HEIGHT); + height = height - (rowDiff * fPointerHeight); + this->SetBounds( width, height ); + + // Update the position after the height change so that we are still centred + D3DXVECTOR3 vPos; + this->GetPosition( &vPos ); + vPos.y = vPos.y + ( (rowDiff * fPointerHeight) / 2 ); + // Make sure that the y offset is even for SD modes, as the y in xui coordinates will end up being scaled by a factor of 1.5 + // to get it into actual back buffer coordinates, and we need those to remain whole numbers to avoid issues with point sampling + if(!RenderManager.IsHiDef()) + { + int iY = (int)(vPos.y); + iY &= 0xfffffffe; + vPos.y = (float)iY; + } + this->SetPosition( &vPos ); + + InitDataAssociations(initData->iPad, menu); + + CXuiSceneAbstractContainer::Initialize( initData->iPad, menu, true, container->getContainerSize(), eSectionContainerUsing, eSectionContainerMax ); + + delete initData; + + return S_OK; +} + +HRESULT CXuiSceneContainer::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +CXuiControl* CXuiSceneContainer::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionContainerChest: + return (CXuiControl *)m_containerControl; + break; + case eSectionContainerInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionContainerUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneContainer::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionContainerChest: + return m_containerControl; + break; + case eSectionContainerInventory: + return m_inventoryControl; + break; + case eSectionContainerUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneContainer::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + int containerSize = menu->getSize() - (27 + 9); + int rows = containerSize / 9; + + // TODO Inventory dimensions need defined as constants + m_containerControl->SetData( iPad, menu, rows, 9, 0 ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, containerSize); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Container.h b/Minecraft.Client/Common/XUI/XUI_Scene_Container.h new file mode 100644 index 00000000..475a6974 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Container.h @@ -0,0 +1,57 @@ +#pragma once +#include "..\Media\xuiscene_container.h" +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_CustomMessages.h" +#include "..\UI\IUIScene_ContainerMenu.h" + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneContainer : public CXuiSceneAbstractContainer, public IUIScene_ContainerMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneContainer, L"CXuiSceneContainer", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + // Common to all abstract container scenes + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Container, m_containerControl) + MAP_CONTROL(IDC_ChestText,m_ChestText) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + //HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) { return S_OK;} + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + +private: + CXuiCtrlSlotList* m_containerControl; + CXuiControl m_sceneGroup; + CXuiControl m_ChestText; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.cpp new file mode 100644 index 00000000..a5dc6584 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.cpp @@ -0,0 +1,636 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.crafting.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\Tile.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "XUI_Ctrl_SlotList.h" + +#define IGNORE_KEYPRESS_TIMERID 0 +#define IGNORE_KEYPRESS_TIME 100 + +////////////////////////////////////////////////////////////////////////// +// +// +// +////////////////////////////////////////////////////////////////////////// +CXuiSceneCraftingPanel::CXuiSceneCraftingPanel() +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// OnInit +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneCraftingPanel::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_bIgnoreKeyPresses=true; + + D3DXVECTOR3 vec; + VOID *pObj; + CraftingPanelScreenInput* pCraftingPanelData = (CraftingPanelScreenInput*)pInitData->pvInitData; + m_iContainerType=pCraftingPanelData->iContainerType; + m_pPlayer=pCraftingPanelData->player; + m_iPad=pCraftingPanelData->iPad; + m_bSplitscreen=pCraftingPanelData->bSplitscreen; + + HRESULT hr = S_OK; + + MapChildControls(); + + if(m_iContainerType==RECIPE_TYPE_2x2) + { + // TODO Inventory dimensions need defined as constants + m_inventoryControl->SetData( m_iPad, m_pPlayer->inventoryMenu, 3, 9, InventoryMenu::INV_SLOT_START, InventoryMenu::INV_SLOT_END ); + + // TODO Inventory dimensions need defined as constants + m_useRowControl->SetData( m_iPad, m_pPlayer->inventoryMenu, 1, 9, InventoryMenu::USE_ROW_SLOT_START, InventoryMenu::USE_ROW_SLOT_END ); + } + else + { + CraftingMenu *menu = new CraftingMenu(m_pPlayer->inventory, m_pPlayer->level, pCraftingPanelData->x, pCraftingPanelData->y, pCraftingPanelData->z); + Minecraft::GetInstance()->localplayers[m_iPad]->containerMenu = menu; + // TODO Inventory dimensions need defined as constants + m_inventoryControl->SetData( m_iPad, menu, 3, 9, CraftingMenu::INV_SLOT_START, CraftingMenu::INV_SLOT_END ); + + // TODO Inventory dimensions need defined as constants + m_useRowControl->SetData( m_iPad, menu, 1, 9, CraftingMenu::USE_ROW_SLOT_START, CraftingMenu::USE_ROW_SLOT_END ); + } + + delete pCraftingPanelData; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + XuiElementSetShow(m_hGrid,TRUE); + XuiElementSetShow(m_hPanel,TRUE); + + // Set up the CXuiCtrlCraftIngredientSlots + if(m_iContainerType==RECIPE_TYPE_3x3) + { + m_pCursors=m_pHSlotsCraftingTableCursors; + + m_iIngredientsMaxSlotC = m_iIngredients3x3SlotC; + for(int i=0;i<m_iIngredients3x3SlotC;i++) + { + XuiObjectFromHandle( m_hCraftIngredientA[i], &pObj ); + m_pCraftingIngredientA[i] = (CXuiCtrlCraftIngredientSlot *)pObj; + } + XuiObjectFromHandle( m_hCraftOutput, &pObj ); + m_pCraftingOutput = (CXuiCtrlCraftIngredientSlot *)pObj; + m_pGroupA=(Recipy::_eGroupType *)&m_GroupTypeMapping9GridA; + m_pGroupTabA=(CXuiSceneCraftingPanel::_eGroupTab *)&m_GroupTabBkgMapping3x3A; + + m_iCraftablesMaxHSlotC=m_iMaxHSlot3x3C; + + // set up the ingredients descriptions + for(int i=0;i<4;i++) + { + XuiObjectFromHandle( m_hCraftIngredientDescA[i], &pObj ); + m_pCraftIngredientDescA[i] = (CXuiCtrlCraftIngredientSlot *)pObj; + } + } + else + { + m_pCursors=m_pHSlotsCraftingCursors; + + m_iIngredientsMaxSlotC = m_iIngredients2x2SlotC; + for(int i=0;i<m_iIngredients2x2SlotC;i++) + { + XuiObjectFromHandle( m_hCraftIngredientA[i], &pObj ); + m_pCraftingIngredientA[i] = (CXuiCtrlCraftIngredientSlot *)pObj; + } + + XuiObjectFromHandle( m_hCraftOutput, &pObj ); + m_pCraftingOutput = (CXuiCtrlCraftIngredientSlot *)pObj; + m_pGroupA=(Recipy::_eGroupType *)&m_GroupTypeMapping4GridA; + m_pGroupTabA=(CXuiSceneCraftingPanel::_eGroupTab *)&m_GroupTabBkgMapping2x2A; + + m_iCraftablesMaxHSlotC=m_iMaxHSlot2x2C; + + // set up the ingredients descriptions + for(int i=0;i<4;i++) + { + XuiObjectFromHandle( m_hCraftIngredientDescA[i], &pObj ); + m_pCraftIngredientDescA[i] = (CXuiCtrlCraftIngredientSlot *)pObj; + } + } + + // display the first group tab + m_hTabGroupA[m_iGroupIndex].SetShow(TRUE); + + // store the slot 0 position + m_pHSlotsBrushImageControl[0]->GetPosition(&m_vSlot0Pos); + m_pHSlotsBrushImageControl[1]->GetPosition(&vec); + m_fSlotSize=vec.x-m_vSlot0Pos.x; + + // store the slot 0 highlight position + m_hHighlight.GetPosition(&m_vSlot0HighlightPos); + // Store the V slot position + m_hScrollBar2.GetPosition(&m_vSlot0V2ScrollPos); + m_hScrollBar3.GetPosition(&m_vSlot0V3ScrollPos); + + // get the position of the slot from the xui, and apply any offset needed + for(int i=0;i<m_iCraftablesMaxHSlotC;i++) + { + m_pHSlotsBrushImageControl[i]->SetShow(FALSE); + } + + XuiElementSetShow(m_hGridInventory,FALSE); + + m_hScrollBar2.SetShow(FALSE); + m_hScrollBar3.SetShow(FALSE); + + app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_CRAFTING); + m_GroupName.SetText(GetGroupNameText(m_pGroupA[m_iGroupIndex])); + + UpdateTooltips(); + + // Update the tutorial state + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + if(m_iContainerType==RECIPE_TYPE_2x2) + { + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_2x2Crafting_Menu, this); + } + else + { + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_3x3Crafting_Menu, this); + } + } +#endif + + XuiSetTimer(m_hObj,IGNORE_KEYPRESS_TIMERID,IGNORE_KEYPRESS_TIME); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +// +// OnTransitionEnd +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneCraftingPanel::OnTransitionEnd( XUIMessageTransition *pTransData, BOOL& bHandled ) +{ + // are we being destroyed? If so, don't do anything + if(pTransData->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) + { + return S_OK; + } + + // Fix for issue caused by autosave while crafting is up + if(pTransData->dwTransType == XUI_TRANSITION_TO || pTransData->dwTransType == XUI_TRANSITION_BACKTO) + { + // Update the tab icons + if(m_iContainerType==RECIPE_TYPE_3x3) + { + for(int i=0;i<m_iMaxGroup3x3;i++) + { + m_hGroupIconA[i].PlayVisualRange(m_GroupIconNameA[m_pGroupA[i]],NULL,m_GroupIconNameA[m_pGroupA[i]]); + XuiElementSetShow(m_hGroupIconA[i].m_hObj,TRUE); + } + } + else + { + for(int i=0;i<m_iMaxGroup2x2;i++) + { + m_hGroupIconA[i].PlayVisualRange(m_GroupIconNameA[m_pGroupA[i]],NULL,m_GroupIconNameA[m_pGroupA[i]]); + XuiElementSetShow(m_hGroupIconA[i].m_hObj,TRUE); + } + } + + + // Display the tooltips + ui.SetTooltips(m_iPad, IDS_TOOLTIPS_CREATE,IDS_TOOLTIPS_EXIT, IDS_TOOLTIPS_SHOW_INVENTORY,-1,-1,-1,-2, IDS_TOOLTIPS_CHANGE_GROUP); + CXuiSceneBase::EnableTooltip(m_iPad, BUTTON_TOOLTIP_A, FALSE ); + + // Check which recipes are available with the resources we have + CheckRecipesAvailable(); + // reset the vertical slots + iVSlotIndexA[0]=CanBeMadeA[m_iCurrentSlotHIndex].iCount-1; + iVSlotIndexA[1]=0; + iVSlotIndexA[2]=1; + UpdateVerticalSlots(); + UpdateHighlight(); + } + + return S_OK; +} + +HRESULT CXuiSceneCraftingPanel::OnCustomMessage_InventoryUpdated() +{ + // Display the tooltips + ui.SetTooltips(m_iPad, IDS_TOOLTIPS_CREATE,IDS_TOOLTIPS_EXIT, IDS_TOOLTIPS_SHOW_INVENTORY,-1,-1,-1,-2, IDS_TOOLTIPS_CHANGE_GROUP); + CXuiSceneBase::EnableTooltip(m_iPad, BUTTON_TOOLTIP_A, FALSE ); + + // Check which recipes are available with the resources we have + CheckRecipesAvailable(); + UpdateVerticalSlots(); + UpdateHighlight(); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +// +// OnKeyDown +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneCraftingPanel::OnKeyDown(XUIMessageInput* pInputData, BOOL& bHandled) +{ + bHandled = handleKeyDown(pInputData->UserIndex, mapVKToAction(pInputData->dwKeyCode), (pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT) != 0); + + return S_OK; +} + +int CXuiSceneCraftingPanel::mapVKToAction(int vk) +{ + int action = MINECRAFT_ACTION_MAX; + switch(vk) + { + case VK_PAD_A: + action = ACTION_MENU_A; + break; + case VK_PAD_B: + case VK_PAD_START: + action = ACTION_MENU_B; + break; + case VK_PAD_X: + action = ACTION_MENU_X; + break; + case VK_PAD_Y: + action = ACTION_MENU_Y; + break; + case VK_PAD_DPAD_LEFT: + case VK_PAD_LTHUMB_LEFT: + action = ACTION_MENU_LEFT; + break; + case VK_PAD_DPAD_RIGHT: + case VK_PAD_LTHUMB_RIGHT: + action = ACTION_MENU_RIGHT; + break; + case VK_PAD_LTHUMB_UP: + case VK_PAD_DPAD_UP: + action = ACTION_MENU_UP; + break; + case VK_PAD_LTHUMB_DOWN: + case VK_PAD_DPAD_DOWN: + action = ACTION_MENU_DOWN; + break; + case VK_PAD_LTRIGGER: + action = ACTION_MENU_PAGEUP; + break; + case VK_PAD_RTRIGGER: + action = ACTION_MENU_PAGEDOWN; + break; + case VK_PAD_LSHOULDER: + action = ACTION_MENU_LEFT_SCROLL; + break; + case VK_PAD_RSHOULDER: + action = ACTION_MENU_RIGHT_SCROLL; + break; + case VK_PAD_RTHUMB_UP: + action = ACTION_MENU_OTHER_STICK_UP; + break; + case VK_PAD_RTHUMB_DOWN: + action = ACTION_MENU_OTHER_STICK_DOWN; + break; + case VK_PAD_RTHUMB_RIGHT: + action = ACTION_MENU_OTHER_STICK_RIGHT; + break; + case VK_PAD_RTHUMB_LEFT: + action = ACTION_MENU_OTHER_STICK_LEFT; + break; + }; + + return action; +} + +////////////////////////////////////////////////////////////////////////// +// +// OnGetSourceImage +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneCraftingPanel::OnGetSourceImage(XUIMessageGetSourceImage* pData, BOOL& rfHandled) +{ + HRESULT hr = S_OK; + //int iId=pData->iItem; + int iId=(pData->iData>>22)&0x1FF; + pData->szPath = NULL; + pData->bDirty=true; + rfHandled = TRUE; + return hr; +} + +////////////////////////////////////////////////////////////////////////// +// +// OnDestroy +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneCraftingPanel::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + + return S_OK; +} + +HRESULT CXuiSceneCraftingPanel::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +HRESULT CXuiSceneCraftingPanel::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if(pData->nId==IGNORE_KEYPRESS_TIMERID) + { + XuiKillTimer(m_hObj,IGNORE_KEYPRESS_TIMERID); + m_bIgnoreKeyPresses=false; + } + + return S_OK; +} + +HRESULT CXuiSceneCraftingPanel::OnKillFocus(HXUIOBJ hObjGettingFocus, BOOL& bHandled) +{ + return S_OK; +} + +int CXuiSceneCraftingPanel::getPad() +{ + return m_iPad; +} + +void CXuiSceneCraftingPanel::hideAllHSlots() +{ + for(int i=0;i<m_iMaxHSlotC;i++) + { + m_pHSlotsBrushImageControl[i]->SetShow(FALSE); + } +} + +void CXuiSceneCraftingPanel::hideAllVSlots() +{ + for(int i=0;i<m_iMaxDisplayedVSlotC;i++) + { + m_pVSlotsBrushImageControl[i]->SetShow(FALSE); + } +} + + +void CXuiSceneCraftingPanel::hideAllIngredientsSlots() +{ + for(int i=0;i<m_iIngredientsC;i++) + { + m_pCraftIngredientDescA[i]->SetShow(FALSE); + } +} + +void CXuiSceneCraftingPanel::setCraftHSlotItem(int iPad, int iIndex, shared_ptr<ItemInstance> item, unsigned int uiAlpha) +{ + m_pHSlotsBrushImageControl[iIndex]->SetIcon(iPad, item, 9, uiAlpha, false); + //m_pHSlotsBrushImageControl[iIndex]->SetPassThroughDataAssociation(MAKE_SLOTDISPLAY_ITEM_BITMASK(item->id,item->getAuxValue(),item->isFoil()),MAKE_SLOTDISPLAY_DATA_BITMASK (iPad, uiAlpha, false, item->GetCount(), 9,0) ); + //m_pHSlotsBrushImageControl[iIndex]->SetShow(TRUE); +} + +void CXuiSceneCraftingPanel::setCraftVSlotItem(int iPad, int iIndex, shared_ptr<ItemInstance> item, unsigned int uiAlpha) +{ + m_pVSlotsBrushImageControl[iIndex]->SetIcon(iPad, item, 9, uiAlpha, false); + //m_pVSlotsBrushImageControl[iIndex]->SetPassThroughDataAssociation(MAKE_SLOTDISPLAY_ITEM_BITMASK(item->id,item->getAuxValue(),item->isFoil()),MAKE_SLOTDISPLAY_DATA_BITMASK (iPad, uiAlpha, false, item->GetCount(), 9,0) ); + //m_pVSlotsBrushImageControl[iIndex]->SetShow(TRUE); +} + +void CXuiSceneCraftingPanel::setCraftingOutputSlotItem(int iPad, shared_ptr<ItemInstance> item) +{ + if(item == NULL) + { + m_pCraftingOutput->SetIcon(iPad, 0,0,0,0,0,false); + } + else + { + m_pCraftingOutput->SetIcon(iPad, item->id,item->getAuxValue(),item->GetCount(),12,31,true,item->isFoil()); + } +} + +void CXuiSceneCraftingPanel::setCraftingOutputSlotRedBox(bool show) +{ + m_pCraftingOutput->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneCraftingPanel::setIngredientSlotItem(int iPad, int index, shared_ptr<ItemInstance> item) +{ + if(item == NULL) + { + m_pCraftingIngredientA[index]->SetIcon(iPad, 0,0,0,0,0,false); + } + else + { + m_pCraftingIngredientA[index]->SetIcon(m_iPad, item->id,item->getAuxValue(),0,8,31,false); + } +} + +void CXuiSceneCraftingPanel::setIngredientSlotRedBox(int index, bool show) +{ + m_pCraftingIngredientA[index]->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneCraftingPanel::setIngredientDescriptionItem(int iPad, int index, shared_ptr<ItemInstance> item) +{ + m_pCraftIngredientDescA[index]->SetIcon(iPad, item->id,item->getAuxValue(),item->GetCount(),8,31,TRUE,item->isFoil(),FALSE); +} + +void CXuiSceneCraftingPanel::setIngredientDescriptionRedBox(int index, bool show) +{ + m_pCraftIngredientDescA[index]->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneCraftingPanel::setIngredientDescriptionText(int index, LPCWSTR text) +{ + m_pCraftIngredientDescA[index]->SetDescription(text); +} + +void CXuiSceneCraftingPanel::setShowCraftHSlot(int iIndex, bool show) +{ + m_pHSlotsBrushImageControl[iIndex]->SetShow(show?TRUE:FALSE); +} + +void CXuiSceneCraftingPanel::showTabHighlight(int iIndex, bool show) +{ + m_hTabGroupA[iIndex].SetShow(show?TRUE:FALSE); +} + +void CXuiSceneCraftingPanel::setGroupText(LPCWSTR text) +{ + m_GroupName.SetText(text); +} + +void CXuiSceneCraftingPanel::setDescriptionText(LPCWSTR text) +{ + m_DescriptionText.SetText(text); +} + +void CXuiSceneCraftingPanel::setItemText(LPCWSTR text) +{ + m_ItemName.SetText(text); +} + +void CXuiSceneCraftingPanel::UpdateMultiPanel() +{ + switch(m_iDisplayDescription) + { + case DISPLAY_INVENTORY: + // turn off all the ingredients display + for(int i=0;i<4;i++) + { + m_pCraftIngredientDescA[i]->SetShow(FALSE); + } + + XuiElementSetShow(m_hGridInventory,TRUE); + XuiControlSetText(m_InventoryText,app.GetString(IDS_INVENTORY)); + XuiElementSetShow(m_InventoryText,TRUE); + break; + case DISPLAY_DESCRIPTION: + // turn off the inventory + XuiElementSetShow(m_hGridInventory,FALSE); + XuiElementSetShow(m_DescriptionText,TRUE); + XuiElementSetShow(m_InventoryText,FALSE); + break; + case DISPLAY_INGREDIENTS: + // turn off all the descriptions + XuiElementSetShow(m_DescriptionText,FALSE); + + // display the ingredients + for(int i=0;i<m_iIngredientsC;i++) + { + m_pCraftIngredientDescA[i]->SetShow(TRUE); + } + + if(m_iIngredientsC==0) + { + XuiElementSetShow(m_InventoryText,FALSE); + } + else + { + XuiControlSetText(m_InventoryText,app.GetString(IDS_INGREDIENTS)); + XuiElementSetShow(m_InventoryText,TRUE); + } + break; + } +} + +void CXuiSceneCraftingPanel::scrollDescriptionUp() +{ + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_DescriptionText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_DescriptionText.m_hObj,-1); + } +} + +void CXuiSceneCraftingPanel::scrollDescriptionDown() +{ + XUIHtmlScrollInfo ScrollInfo; + + XuiHtmlControlGetVScrollInfo(m_DescriptionText.m_hObj,&ScrollInfo); + if(!ScrollInfo.bScrolling) + { + XuiHtmlControlVScrollBy(m_DescriptionText.m_hObj,1); + } +} + +void CXuiSceneCraftingPanel::updateHighlightAndScrollPositions() +{ + D3DXVECTOR3 vec; + + vec.z=0.0f; + vec.x=m_vSlot0HighlightPos.x + (m_iCurrentSlotHIndex*m_fSlotSize); + vec.y=m_vSlot0HighlightPos.y + ((m_iCurrentSlotVIndex-1)*m_fSlotSize); // vslot 1 is the centred one + m_hHighlight.SetPosition(&vec); + + // Update the scroll icons for all h boxes + for(int i=0;i<m_iCraftablesMaxHSlotC;i++) + { + if((i!=m_iCurrentSlotHIndex) &&(CanBeMadeA[i].iCount>1)) + { + m_pCursors[i].SetShow(TRUE); + } + else + { + m_pCursors[i].SetShow(FALSE); + } + } + + if(CanBeMadeA[m_iCurrentSlotHIndex].iCount<2) + { + m_hScrollBar2.SetShow(FALSE); + m_hScrollBar3.SetShow(FALSE); + } + else if(CanBeMadeA[m_iCurrentSlotHIndex].iCount<3) + { + // 2 slot + vec.x=m_vSlot0V2ScrollPos.x + (m_iCurrentSlotHIndex*m_fSlotSize); + vec.y=m_vSlot0V2ScrollPos.y; + m_hScrollBar2.SetPosition(&vec); + m_hScrollBar2.SetShow(TRUE); + m_hScrollBar3.SetShow(FALSE); + } + else + { + // 3 slot + vec.x=m_vSlot0V3ScrollPos.x + (m_iCurrentSlotHIndex*m_fSlotSize); + vec.y=m_vSlot0V3ScrollPos.y;//+m_fSlotSize; + + m_hScrollBar3.SetPosition(&vec); + m_hScrollBar2.SetShow(FALSE); + m_hScrollBar3.SetShow(TRUE); + } +} + +void CXuiSceneCraftingPanel::updateVSlotPositions(int iSlots, int i) +{ + D3DXVECTOR3 vec; + if(iSlots==2) + { + vec.y=m_vSlot0Pos.y + (1-i)*m_fSlotSize; + } + else + { + vec.y=m_vSlot0Pos.y + (i-1)*m_fSlotSize; + } + vec.x=m_vSlot0Pos.x + m_iCurrentSlotHIndex*m_fSlotSize; + vec.z=0.0f; + m_pVSlotsBrushImageControl[i]->SetPosition(&vec); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.h b/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.h new file mode 100644 index 00000000..0c6e22ff --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.h @@ -0,0 +1,205 @@ +#pragma once +using namespace std; + +#include "../media/xuiscene_craftingpanel_2x2.h" +#include "XUI_Ctrl_MinecraftSlot.h" +#include "..\..\..\Minecraft.World\Recipy.h" +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "..\..\..\Minecraft.World\Item.h" +#include "XUI_CustomMessages.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\UI\IUIScene_CraftingMenu.h" + +class CXuiCtrlSlotList; + +class CXuiSceneCraftingPanel : public CXuiSceneImpl, public IUIScene_CraftingMenu +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneCraftingPanel, L"CXuiSceneCraftingPanel", XUI_CLASS_SCENE ) + + protected: + // Control and Element wrapper objects. + + CXuiImageElement m_hPanel; + CXuiImageElement m_hHighlight; + CXuiImageElement m_hScrollBar3; + CXuiImageElement m_hScrollBar2; + CXuiControl m_GroupName; + CXuiHtmlControl m_DescriptionText; + CXuiControl m_ItemName,m_InventoryText; + CXuiElement m_Group; + CXuiElement m_hGrid; + CXuiElement m_hGridInventory; + CXuiImageElement m_hTabGroupA[m_iMaxGroup3x3]; + CXuiControl m_hGroupIconA[m_iMaxGroup3x3]; + CXuiControl m_pHSlotsCraftingCursors[m_iMaxHCraftingSlotC]; + CXuiControl m_pHSlotsCraftingTableCursors[m_iMaxHSlotC]; + CXuiControl *m_pCursors; + CXuiControl m_hCraftIngredientA[m_iIngredients3x3SlotC]; + CXuiControl m_hCraftIngredientDescA[4]; // Max ingredients is 4 for bread + CXuiControl m_hCraftOutput; + CXuiControl m_sceneGroup; + + CXuiCtrlSlotList* m_inventoryControl; + CXuiCtrlSlotList* m_useRowControl; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TRANSITION_END( OnTransitionEnd) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceImage) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_KILL_FOCUS( OnKillFocus) + XUI_ON_XM_INVENTORYUPDATED_MESSAGE( OnCustomMessage_InventoryUpdated ) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS(m_sceneGroup) + MAP_CONTROL(IDC_MainPanel,m_hPanel) + MAP_CONTROL(IDC_XuiGroupName,m_GroupName) + + MAP_CONTROL(IDC_SceneCraftScrollGroup, m_Group) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_XuiHighlight,m_hHighlight) + MAP_CONTROL(IDC_XuiImageScrollBar,m_hScrollBar3) + MAP_CONTROL(IDC_XuiImageScrollBar2Slot,m_hScrollBar2) + MAP_OVERRIDE(IDC_XuiHSlot0, m_pHSlotsBrushImageControl[0]) + MAP_OVERRIDE(IDC_XuiHSlot1, m_pHSlotsBrushImageControl[1]) + MAP_OVERRIDE(IDC_XuiHSlot2, m_pHSlotsBrushImageControl[2]) + MAP_OVERRIDE(IDC_XuiHSlot3, m_pHSlotsBrushImageControl[3]) + MAP_OVERRIDE(IDC_XuiHSlot4, m_pHSlotsBrushImageControl[4]) + MAP_OVERRIDE(IDC_XuiHSlot5, m_pHSlotsBrushImageControl[5]) + MAP_OVERRIDE(IDC_XuiHSlot6, m_pHSlotsBrushImageControl[6]) + MAP_OVERRIDE(IDC_XuiHSlot7, m_pHSlotsBrushImageControl[7]) + MAP_OVERRIDE(IDC_XuiHSlot8, m_pHSlotsBrushImageControl[8]) + MAP_OVERRIDE(IDC_XuiHSlot9, m_pHSlotsBrushImageControl[9]) + MAP_OVERRIDE(IDC_XuiHSlot10, m_pHSlotsBrushImageControl[10]) + MAP_OVERRIDE(IDC_XuiHSlot11, m_pHSlotsBrushImageControl[11]) + + + MAP_OVERRIDE(IDC_XuiVSlot0, m_pVSlotsBrushImageControl[0]) + MAP_OVERRIDE(IDC_XuiVSlot1, m_pVSlotsBrushImageControl[1]) + MAP_OVERRIDE(IDC_XuiVSlot2, m_pVSlotsBrushImageControl[2]) + + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_Group_Tab_Icons, m_Group) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_Icon_1,m_hGroupIconA[0]) + MAP_CONTROL(IDC_Icon_2,m_hGroupIconA[1]) + MAP_CONTROL(IDC_Icon_3,m_hGroupIconA[2]) + MAP_CONTROL(IDC_Icon_4,m_hGroupIconA[3]) + MAP_CONTROL(IDC_Icon_5,m_hGroupIconA[4]) + MAP_CONTROL(IDC_Icon_6,m_hGroupIconA[5]) + MAP_CONTROL(IDC_Icon_7,m_hGroupIconA[6]) + + END_MAP_CHILD_CONTROLS() + + + MAP_CONTROL(IDC_Group_Tab_Images, m_Group) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_TabImage1,m_hTabGroupA[0]) + MAP_CONTROL(IDC_TabImage2,m_hTabGroupA[1]) + MAP_CONTROL(IDC_TabImage3,m_hTabGroupA[2]) + MAP_CONTROL(IDC_TabImage4,m_hTabGroupA[3]) + MAP_CONTROL(IDC_TabImage5,m_hTabGroupA[4]) + MAP_CONTROL(IDC_TabImage6,m_hTabGroupA[5]) + MAP_CONTROL(IDC_TabImage7,m_hTabGroupA[6]) + + END_MAP_CHILD_CONTROLS() + + + MAP_CONTROL(IDC_Grid, m_hGrid) + BEGIN_MAP_CHILD_CONTROLS(m_hGrid) + MAP_CONTROL(IDC_XuiHTMLText,m_DescriptionText) + MAP_CONTROL(IDC_Inventory,m_InventoryText) + MAP_CONTROL(IDC_XuiItemName,m_ItemName) + MAP_CONTROL(IDC_CraftingInput1,m_hCraftIngredientA[0]) + MAP_CONTROL(IDC_CraftingInput2,m_hCraftIngredientA[1]) + MAP_CONTROL(IDC_CraftingInput3,m_hCraftIngredientA[2]) + MAP_CONTROL(IDC_CraftingInput4,m_hCraftIngredientA[3]) + MAP_CONTROL(IDC_CraftingInput5,m_hCraftIngredientA[4]) + MAP_CONTROL(IDC_CraftingInput6,m_hCraftIngredientA[5]) + MAP_CONTROL(IDC_CraftingInput7,m_hCraftIngredientA[6]) + MAP_CONTROL(IDC_CraftingInput8,m_hCraftIngredientA[7]) + MAP_CONTROL(IDC_CraftingInput9,m_hCraftIngredientA[8]) + MAP_CONTROL(IDC_Ingredient1,m_hCraftIngredientDescA[0]) + MAP_CONTROL(IDC_Ingredient2,m_hCraftIngredientDescA[1]) + MAP_CONTROL(IDC_Ingredient3,m_hCraftIngredientDescA[2]) + MAP_CONTROL(IDC_Ingredient4,m_hCraftIngredientDescA[3]) + + MAP_CONTROL(IDC_CraftingOutputRed,m_hCraftOutput) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_InventoryGrid, m_hGridInventory) + BEGIN_MAP_CHILD_CONTROLS(m_hGridInventory) + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransData, BOOL& bHandled); + HRESULT OnGetSourceImage(XUIMessageGetSourceImage* pData, BOOL& rfHandled); + HRESULT OnDestroy(); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + HRESULT OnKillFocus(HXUIOBJ hObjGettingFocus, BOOL& bHandled); + HRESULT OnCustomMessage_InventoryUpdated(); + + CXuiSceneCraftingPanel(); + ~CXuiSceneCraftingPanel() { } + +private: + float m_fSlotSize; + D3DXVECTOR3 m_vSlot0Pos; + D3DXVECTOR3 m_vSlot0HighlightPos; + D3DXVECTOR3 m_vSlot0V2ScrollPos; + D3DXVECTOR3 m_vSlot0V3ScrollPos; + + CXuiCtrlCraftIngredientSlot *m_pCraftingOutput; + CXuiCtrlCraftIngredientSlot *m_pCraftingIngredientA[m_iIngredients3x3SlotC]; + CXuiCtrlCraftIngredientSlot *m_pCraftIngredientDescA[4]; + CXuiCtrlMinecraftSlot *m_pHSlotsBrushImageControl[m_iMaxHSlotC]; + CXuiCtrlMinecraftSlot *m_pVSlotsBrushImageControl[m_iMaxDisplayedVSlotC]; + CXuiControl *GroupTypeIconA[Recipy::eGroupType_Max]; + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + + int mapVKToAction(int vk); + +protected: + virtual int getPad(); + virtual void hideAllHSlots(); + virtual void hideAllVSlots(); + virtual void hideAllIngredientsSlots(); + virtual void setCraftHSlotItem(int iPad, int iIndex, shared_ptr<ItemInstance> item, unsigned int uiAlpha); + virtual void setCraftVSlotItem(int iPad, int iIndex, shared_ptr<ItemInstance> item, unsigned int uiAlpha); + virtual void setCraftingOutputSlotItem(int iPad, shared_ptr<ItemInstance> item); + virtual void setCraftingOutputSlotRedBox(bool show); + virtual void setIngredientSlotItem(int iPad, int index, shared_ptr<ItemInstance> item); + virtual void setIngredientSlotRedBox(int index, bool show); + virtual void setIngredientDescriptionItem(int iPad, int index, shared_ptr<ItemInstance> item); + virtual void setIngredientDescriptionRedBox(int index, bool show); + virtual void setIngredientDescriptionText(int index, LPCWSTR text); + virtual void setShowCraftHSlot(int iIndex, bool show); + virtual void showTabHighlight(int iIndex, bool show); + virtual void setGroupText(LPCWSTR text); + virtual void setDescriptionText(LPCWSTR text); + virtual void setItemText(LPCWSTR text); + virtual void scrollDescriptionUp(); + virtual void scrollDescriptionDown(); + virtual void updateHighlightAndScrollPositions(); + virtual void updateVSlotPositions(int iSlots, int i); + + virtual void UpdateMultiPanel(); +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.cpp new file mode 100644 index 00000000..5b3c7226 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.cpp @@ -0,0 +1,144 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\AbstractContainerMenu.h" +#include "..\..\..\Minecraft.World\Slot.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.dimension.h" + +//#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_SlotList.h" + +#include "XUI_Scene_Enchant.h" +#include "XUI_Scene_Inventory.h" +#include "XUI_Ctrl_EnchantButton.h" + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneEnchant::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneEnchant::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + D3DXVECTOR3 vec; + MapChildControls(); + + XuiControlSetText(m_EnchantText,app.GetString(IDS_ENCHANT)); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + EnchantingScreenInput *initData = (EnchantingScreenInput *) pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Enchanting_Menu, this); + } +#endif + + EnchantmentMenu *menu = new EnchantmentMenu(initData->inventory, initData->level, initData->x, initData->y, initData->z); + + InitDataAssociations(initData->iPad, menu); + + m_enchant1->SetEnable(FALSE); + m_enchant2->SetEnable(FALSE); + m_enchant3->SetEnable(FALSE); + m_enchant1->SetData(m_iPad, 0); + m_enchant2->SetData(m_iPad, 1); + m_enchant3->SetData(m_iPad, 2); + + CXuiSceneAbstractContainer::Initialize( initData->iPad, menu, false, EnchantmentMenu::INV_SLOT_START, CXuiSceneAbstractContainer::eSectionEnchantUsing, CXuiSceneAbstractContainer::eSectionEnchantMax ); + + delete initData; + + return S_OK; +} + +HRESULT CXuiSceneEnchant::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +CXuiControl* CXuiSceneEnchant::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case CXuiSceneAbstractContainer::eSectionEnchantInventory: + return (CXuiControl *)m_inventoryControl; + break; + case CXuiSceneAbstractContainer::eSectionEnchantUsing: + return (CXuiControl *)m_useRowControl; + break; + case CXuiSceneAbstractContainer::eSectionEnchantSlot: + return (CXuiControl *)m_ingredientControl; + break; + case eSectionEnchantButton1: + return m_enchant1; + break; + case eSectionEnchantButton2: + return m_enchant2; + break; + case eSectionEnchantButton3: + return m_enchant3; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneEnchant::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case CXuiSceneAbstractContainer::eSectionEnchantInventory: + return m_inventoryControl; + break; + case CXuiSceneAbstractContainer::eSectionEnchantUsing: + return m_useRowControl; + break; + case CXuiSceneAbstractContainer::eSectionEnchantSlot: + return m_ingredientControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneEnchant::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + m_ingredientControl->SetData( iPad, menu, 1, 1, EnchantmentMenu::INGREDIENT_SLOT ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, EnchantmentMenu::INV_SLOT_START); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.h b/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.h new file mode 100644 index 00000000..5cab04a4 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Enchant.h @@ -0,0 +1,78 @@ +#pragma once +using namespace std; + +#include "..\Media\xuiscene_enchant.h" + +#include "..\..\BookModel.h" + +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Ctrl_EnchantmentBook.h" +#include "XUI_Scene_AbstractContainer.h" +#include "..\UI\IUIScene_EnchantingMenu.h" +#include "XUI_CustomMessages.h" + +#include "XUI_Scene_Enchant.h" + +#include "..\..\..\Minecraft.World\AbstractContainerMenu.h" +#include "..\..\..\Minecraft.World\SimpleContainer.h" + +class Level; +class CXuiCtrlEnchantmentButton; +class EnchantmentMenu; + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneEnchant : public CXuiSceneAbstractContainer, public IUIScene_EnchantingMenu +{ + friend class CXuiCtrlEnchantmentButtonText; +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneEnchant, L"CXuiSceneEnchant", XUI_CLASS_SCENE ) + +protected: + CXuiCtrlEnchantmentButton *m_enchant1; + CXuiCtrlEnchantmentButton *m_enchant2; + CXuiCtrlEnchantmentButton *m_enchant3; + CXuiControl m_sceneGroup; + CXuiCtrlSlotList* m_ingredientControl; + CXuiControl m_EnchantText; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Ingredient, m_ingredientControl) + MAP_OVERRIDE(IDC_EnchantButton1, m_enchant1) + MAP_OVERRIDE(IDC_EnchantButton2, m_enchant2) + MAP_OVERRIDE(IDC_EnchantButton3, m_enchant3) + MAP_CONTROL(IDC_EnchantText,m_EnchantText) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + +private: + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.cpp new file mode 100644 index 00000000..832d6b4c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.cpp @@ -0,0 +1,153 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\FurnaceMenu.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_Furnace.h" +#include "XUI_Ctrl_BurnProgress.h" +#include "XUI_Ctrl_FireProgress.h" + + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneFurnace::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneFurnace::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_FurnaceText,app.GetString(IDS_FURNACE)); + XuiControlSetText(m_IngredientText,app.GetString(IDS_INGREDIENT)); + XuiControlSetText(m_FuelText,app.GetString(IDS_FUEL)); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + FurnaceScreenInput* initData = (FurnaceScreenInput*)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Furnace_Menu, this); + } +#endif + + FurnaceMenu* menu = new FurnaceMenu( initData->inventory, initData->furnace ); + + + InitDataAssociations(m_iPad, menu); + + m_litProgressControl->SetUserData( initData->furnace.get() ); + + m_burnProgress->SetUserData( initData->furnace.get() ); + + CXuiSceneAbstractContainer::Initialize( m_iPad, menu, true, FurnaceMenu::INV_SLOT_START, eSectionFurnaceUsing, eSectionFurnaceMax ); + + app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_FORGING); + + delete initData; + + return S_OK; +} + +HRESULT CXuiSceneFurnace::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +CXuiControl* CXuiSceneFurnace::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionFurnaceResult: + return (CXuiControl *)m_resultControl; + break; + case eSectionFurnaceFuel: + return (CXuiControl *)m_fuelControl; + break; + case eSectionFurnaceIngredient: + return (CXuiControl *)m_ingredientControl; + break; + case eSectionFurnaceInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionFurnaceUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneFurnace::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionFurnaceResult: + return m_resultControl; + break; + case eSectionFurnaceFuel: + return m_fuelControl; + break; + case eSectionFurnaceIngredient: + return m_ingredientControl; + break; + case eSectionFurnaceInventory: + return m_inventoryControl; + break; + case eSectionFurnaceUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneFurnace::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + // TODO Inventory dimensions need defined as constants + m_ingredientControl->SetData( iPad, menu, 1, 1, FurnaceMenu::INGREDIENT_SLOT ); + + m_fuelControl->SetData( iPad, menu, 1, 1, FurnaceMenu::FUEL_SLOT ); + + m_resultControl->SetData( iPad, menu, 1, 1, FurnaceMenu::RESULT_SLOT ); + + //m_litProgressControl->SetUserData( initData->furnace.get() ); + + //m_burnProgress->SetUserData( initData->furnace.get() ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, FurnaceMenu::INV_SLOT_START); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.h b/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.h new file mode 100644 index 00000000..22cbf262 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Furnace.h @@ -0,0 +1,79 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_furnace.h" +#include "XUI_Scene_AbstractContainer.h" +#include "..\UI\IUIScene_FurnaceMenu.h" + +class CXuiCtrlSlotList; +class CXuiCtrlFireProgress; +class CXuiCtrlBurnProgress; + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneFurnace : public CXuiSceneAbstractContainer, public IUIScene_FurnaceMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneFurnace, L"CXuiSceneFurnace", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Ingredient, m_ingredientControl) + MAP_OVERRIDE(IDC_Fuel, m_fuelControl) + MAP_OVERRIDE(IDC_Result, m_resultControl) + + MAP_OVERRIDE(IDC_Lit, m_litProgressControl) + MAP_OVERRIDE(IDC_Burn, m_burnProgress) + + MAP_CONTROL(IDC_FurnaceText,m_FurnaceText) + MAP_CONTROL(IDC_IngredientText,m_IngredientText) + MAP_CONTROL(IDC_FuelText,m_FuelText) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); +// HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + +private: + CXuiCtrlSlotList *m_ingredientControl; + CXuiCtrlSlotList *m_fuelControl; + CXuiCtrlSlotList *m_resultControl; + + CXuiCtrlFireProgress *m_litProgressControl; + CXuiCtrlBurnProgress *m_burnProgress; + + CXuiControl m_FurnaceText; + CXuiControl m_IngredientText; + CXuiControl m_FuelText; + + CXuiControl m_sceneGroup; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.cpp new file mode 100644 index 00000000..04e77e5e --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.cpp @@ -0,0 +1,234 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.effect.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Controls.h" +#include "XUI_Scene_Inventory.h" + + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneInventory::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneInventory::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + D3DXVECTOR3 vec; + MapChildControls(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + InventoryScreenInput *initData = (InventoryScreenInput *)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + } + +#ifdef _XBOX + if( pMinecraft->localgameModes[initData->iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[initData->iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Inventory_Menu, this); + } +#endif + + InventoryMenu *menu = dynamic_cast<InventoryMenu *>( initData->player->inventoryMenu ); + +#if 0 + // TODO Inventory dimensions need defined as constants + m_armorGroup->SetData( initData->iPad, menu, 4, 1, InventoryMenu::ARMOR_SLOT_START ); +#endif + InitDataAssociations(initData->iPad, menu); + + initData->player->awardStat(GenericStats::openInventory(), GenericStats::param_noArgs()); + + CXuiSceneAbstractContainer::Initialize( initData->iPad, menu, false, InventoryMenu::INV_SLOT_START, eSectionInventoryUsing, eSectionInventoryMax, initData->bNavigateBack ); + + delete initData; + + float fWidth; + m_effectsGroup.GetBounds(&fWidth, &m_effectAreaHeight); // Get total height available for effects display + m_hEffectDisplayA[0]->GetBounds(&fWidth, &m_effectDisplayHeight); // Get height of one effect + + D3DXVECTOR3 firstEffectPos, secondEffectPos; + m_hEffectDisplayA[0]->GetPosition(&firstEffectPos); + m_hEffectDisplayA[1]->GetPosition(&secondEffectPos); + m_effectDisplaySpacing = firstEffectPos.y - secondEffectPos.y; // Stack from the bottom + + updateEffectsDisplay(); + XuiSetTimer(m_hObj,INVENTORY_UPDATE_EFFECTS_TIMER_ID,INVENTORY_UPDATE_EFFECTS_TIMER_TIME); + + return S_OK; +} + +HRESULT CXuiSceneInventory::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +HRESULT CXuiSceneInventory::handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + if(pTimer->nId == INVENTORY_UPDATE_EFFECTS_TIMER_ID) + { + updateEffectsDisplay(); + bHandled = TRUE; + } + return S_OK; +} + +CXuiControl* CXuiSceneInventory::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionInventoryArmor: + return (CXuiControl *)m_armorGroup; + break; + case eSectionInventoryInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionInventoryUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneInventory::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionInventoryArmor: + return m_armorGroup; + break; + case eSectionInventoryInventory: + return m_inventoryControl; + break; + case eSectionInventoryUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneInventory::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + // TODO Inventory dimensions need defined as constants + m_armorGroup->SetData( iPad, menu, 4, 1, InventoryMenu::ARMOR_SLOT_START ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, InventoryMenu::INV_SLOT_START); +} + +void CXuiSceneInventory::updateEffectsDisplay() +{ + // Update with the current effects + Minecraft *pMinecraft = Minecraft::GetInstance(); + shared_ptr<LocalPlayer> player = pMinecraft->localplayers[m_iPad]; + + if(player == NULL) return; + + vector<MobEffectInstance *> *activeEffects = player->getActiveEffects(); + + // Work out how to arrange the effects + int effectCount = (int)activeEffects->size(); + + // Total size of all effects + spacing, minus spacing for the last effect + float fHeight = (effectCount * m_effectDisplaySpacing) - (m_effectDisplaySpacing - m_effectDisplayHeight); + float fNextEffectYOffset = m_effectDisplaySpacing; + + if(fHeight > m_effectAreaHeight) + { + fNextEffectYOffset = (m_effectAreaHeight + 1) / effectCount; + fNextEffectYOffset = floor(fNextEffectYOffset); + } + + // Fill out details for display + D3DXVECTOR3 position; + m_hEffectDisplayA[0]->GetPosition(&position); + AUTO_VAR(it, activeEffects->begin()); + for(unsigned int i = 0; i < MAX_EFFECTS; ++i) + { + if(it != activeEffects->end()) + { + m_hEffectDisplayA[i]->SetShow(TRUE); + + if(i > 0) position.y -= fNextEffectYOffset; // Stack from the bottom + m_hEffectDisplayA[i]->SetPosition(&position); + + MobEffectInstance *effect = *it; + + MobEffect *mobEffect = MobEffect::effects[effect->getId()]; + if (mobEffect->hasIcon()) + { + m_hEffectDisplayA[i]->setIcon(mobEffect->getIcon()); + } + + wstring effectString = app.GetString( effect->getDescriptionId() );//I18n.get(effect.getDescriptionId()).trim(); + if (effect->getAmplifier() > 0) + { + wstring potencyString = L""; + switch(effect->getAmplifier()) + { + case 1: + potencyString = L" "; + potencyString += app.GetString( IDS_POTION_POTENCY_1 ); + break; + case 2: + potencyString = L" "; + potencyString += app.GetString( IDS_POTION_POTENCY_2 ); + break; + case 3: + potencyString = L" "; + potencyString += app.GetString( IDS_POTION_POTENCY_3 ); + break; + default: + potencyString = app.GetString( IDS_POTION_POTENCY_0 ); + break; + } + effectString += potencyString; + } + m_hEffectDisplayA[i]->setName(effectString); + + wstring durationString = MobEffect::formatDuration(effect); + m_hEffectDisplayA[i]->setDuration(durationString); + + ++it; + } + else + { + m_hEffectDisplayA[i]->SetShow(FALSE); + } + } + delete activeEffects; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.h b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.h new file mode 100644 index 00000000..2a7b305c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory.h @@ -0,0 +1,89 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_inventory.h" +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_CustomMessages.h" +#include "..\UI\IUIScene_InventoryMenu.h" + +#define INVENTORY_UPDATE_EFFECTS_TIMER_ID (10) +#define INVENTORY_UPDATE_EFFECTS_TIMER_TIME (1000) // 1 second + +class CXuiCtrlMobEffect; + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneInventory : public CXuiSceneAbstractContainer, public IUIScene_InventoryMenu +{ +private: + static const int MAX_EFFECTS = 10; +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneInventory, L"CXuiSceneInventory", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_OVERRIDE(IDC_Armor, m_armorGroup) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_EffectsGroup, m_effectsGroup) + BEGIN_MAP_CHILD_CONTROLS( m_effectsGroup ) + MAP_OVERRIDE(IDC_Effect1, m_hEffectDisplayA[0]) + MAP_OVERRIDE(IDC_Effect2, m_hEffectDisplayA[1]) + MAP_OVERRIDE(IDC_Effect3, m_hEffectDisplayA[2]) + MAP_OVERRIDE(IDC_Effect4, m_hEffectDisplayA[3]) + MAP_OVERRIDE(IDC_Effect5, m_hEffectDisplayA[4]) + MAP_OVERRIDE(IDC_Effect6, m_hEffectDisplayA[5]) + MAP_OVERRIDE(IDC_Effect7, m_hEffectDisplayA[6]) + MAP_OVERRIDE(IDC_Effect8, m_hEffectDisplayA[7]) + MAP_OVERRIDE(IDC_Effect9, m_hEffectDisplayA[8]) + MAP_OVERRIDE(IDC_Effect10, m_hEffectDisplayA[9]) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + //HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) {return S_OK;} + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); + + virtual HRESULT handleCustomTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + +private: + float m_effectDisplayHeight; + float m_effectDisplaySpacing; + float m_effectAreaHeight; + + CXuiCtrlSlotList* m_armorGroup; + + CXuiControl m_sceneGroup; + + CXuiControl m_effectsGroup; + CXuiCtrlMobEffect *m_hEffectDisplayA[MAX_EFFECTS]; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); + + void updateEffectsDisplay(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.cpp new file mode 100644 index 00000000..0793fc9e --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.cpp @@ -0,0 +1,209 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" + +#include "..\..\..\Minecraft.World\Container.h" +#include "..\..\..\Minecraft.World\Slot.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" + +#include "..\..\..\Minecraft.World\net.minecraft.stats.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Minecraft.h" + +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_Ctrl_SlotItem.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Ctrl_SlotItemListItem.h" + +#include "..\..\Common\Potion_macros.h" + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneInventoryCreative::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneInventoryCreative::OnInit( XUIMessageInit *pInitData, BOOL &bHandled ) +{ + D3DXVECTOR3 vec; + MapChildControls(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + InventoryScreenInput *initData = (InventoryScreenInput *)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + } + +#ifdef _XBOX + if( pMinecraft->localgameModes[initData->iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[initData->iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Creative_Inventory_Menu, this); + } +#endif + + // 4J JEV - Does this still count as opening the inventory? + initData->player->awardStat(GenericStats::openInventory(), GenericStats::param_noArgs()); + + // 4J JEV - Item Picker Menu + shared_ptr<SimpleContainer> creativeContainer = shared_ptr<SimpleContainer>(new SimpleContainer( 0, TabSpec::MAX_SIZE + 9 )); + itemPickerMenu = new ItemPickerMenu(creativeContainer, initData->player->inventory); + + // 4J JEV - InitDataAssociations. + m_containerControl->SetData( initData->iPad, itemPickerMenu, TabSpec::rows, TabSpec::columns, 0, TabSpec::MAX_SIZE ); + m_useRowControl->SetData( initData->iPad, itemPickerMenu, 1, 9, TabSpec::MAX_SIZE, TabSpec::MAX_SIZE + 9 ); + m_pointerControl->SetUserIndex(m_pointerControl->m_hObj, initData->iPad); + + // Initialize superclass. + CXuiSceneAbstractContainer::Initialize( initData->iPad, itemPickerMenu, false, -1, eSectionInventoryCreativeUsing, eSectionInventoryCreativeMax, initData->bNavigateBack ); + + delete initData; + + // Change the point at which the cursor stops so we can't move the pointer over the tabs + D3DXVECTOR3 containerPos; + m_containerControl->GetPosition(&containerPos); + m_fPointerMinY += containerPos.y; + + // 4J JEV - Settup Tabs + for (int i = 0; i < eCreativeInventoryTab_COUNT; i++) + { + m_hTabGroupA[i].SetShow(FALSE); + } + + m_curTab = eCreativeInventoryTab_COUNT; + switchTab(eCreativeInventoryTab_BuildingBlocks); + + return S_OK; +} + +HRESULT CXuiSceneInventoryCreative::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +// +// OnTransitionEnd +// +////////////////////////////////////////////////////////////////////////// +HRESULT CXuiSceneInventoryCreative::OnTransitionEnd( XUIMessageTransition *pTransData, BOOL& bHandled ) +{ + // are we being destroyed? If so, don't do anything + if(pTransData->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) + { + return S_OK; + } + + // Fix for issue caused by autosave while crafting is up + if(pTransData->dwTransType == XUI_TRANSITION_TO || pTransData->dwTransType == XUI_TRANSITION_BACKTO) + { + for(int i=0;i<eCreativeInventoryTab_COUNT;i++) + { + m_hGroupIconA[i].PlayVisualRange(specs[i]->m_icon,NULL,specs[i]->m_icon); + XuiElementSetShow(m_hGroupIconA[i].m_hObj,TRUE); + } + } + + return S_OK; +} + +CXuiControl* CXuiSceneInventoryCreative::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionInventoryCreativeUsing: + return (CXuiControl *)m_useRowControl; + break; + case eSectionInventoryCreativeSelector: + return (CXuiControl *)m_containerControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneInventoryCreative::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionInventoryCreativeUsing: + return m_useRowControl; + break; + case eSectionInventoryCreativeSelector: + return m_containerControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +void CXuiSceneInventoryCreative::updateTabHighlightAndText(ECreativeInventoryTabs tab) +{ + if (m_curTab < eCreativeInventoryTab_COUNT) + { + m_hTabGroupA[m_curTab].SetShow(FALSE); + } + + m_hTabGroupA[tab].SetShow(TRUE); + wstring wsText=app.GetString(specs[tab]->m_descriptionId); + m_GroupDescription.SetText(wsText.c_str()); + m_GroupDescription.SetShow(TRUE); +} + +void CXuiSceneInventoryCreative::updateScrollCurrentPage(int currentPage, int pageCount) +{ + m_pageSlider.SetEnable(pageCount > 1); + + if(pageCount == 1) + { + m_pageSlider.SetRange(0,1); + m_pageSlider.SetValue(0); + } + else + { + m_pageSlider.SetRange(0,pageCount - 1); + m_pageSlider.SetValue(currentPage - 1); + } + + m_scrollUp.SetShow(currentPage > 1); + m_scrollUp.PlayOptionalVisual(L"ScrollMore",L"EndScrollMore"); + + + m_scrollDown.SetShow(currentPage < pageCount); + m_scrollDown.PlayOptionalVisual(L"ScrollMore",L"EndScrollMore"); + + //wchar_t pageNum[10]; + //swprintf(pageNum,10,L"%d/%d",currentPage,pageCount); + //m_pageNumber.SetText(pageNum); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.h b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.h new file mode 100644 index 00000000..bb3ff976 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.h @@ -0,0 +1,104 @@ +#pragma once +using namespace std; + +#include "..\Media\xuiscene_inventory_creative.h" +#include "XUI_Scene_AbstractContainer.h" +#include "XUI_CustomMessages.h" +#include "..\..\..\Minecraft.World\AbstractContainerMenu.h" +#include "..\..\..\Minecraft.World\SimpleContainer.h" + +#include "..\UI\IUIScene_CreativeMenu.h" + +#include <vector> + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneInventoryCreative : public CXuiSceneAbstractContainer, public IUIScene_CreativeMenu +{ +public: + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneInventoryCreative, L"CXuiSceneInventoryCreative", XUI_CLASS_SCENE ) + +protected: + + CXuiControl m_hTabGroupA[eCreativeInventoryTab_COUNT]; + CXuiControl m_hGroupIconA[eCreativeInventoryTab_COUNT]; + CXuiElement m_Group; + CXuiControl m_GroupDescription; + + CXuiSlider m_pageSlider; + CXuiControl m_scrollUp, m_scrollDown;//, m_pageNumber; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_TRANSITION_END( OnTransitionEnd) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + // Common to all abstract container scenes + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_OVERRIDE(IDC_Container, m_containerControl) + + MAP_CONTROL(IDC_XuiSlider,m_pageSlider) + //MAP_CONTROL(IDC_PageNumber,m_pageNumber) + MAP_CONTROL(IDC_ScrollDown,m_scrollDown) + MAP_CONTROL(IDC_ScrollUp,m_scrollUp) + + MAP_CONTROL(IDC_InventoryText,m_GroupDescription) + + // 4J JEV - Tabs + MAP_CONTROL(IDC_Group_Tab_Icons, m_Group) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_Icon_1,m_hGroupIconA[0]) + MAP_CONTROL(IDC_Icon_2,m_hGroupIconA[1]) + MAP_CONTROL(IDC_Icon_3,m_hGroupIconA[2]) + MAP_CONTROL(IDC_Icon_4,m_hGroupIconA[3]) + MAP_CONTROL(IDC_Icon_5,m_hGroupIconA[4]) + MAP_CONTROL(IDC_Icon_6,m_hGroupIconA[5]) + MAP_CONTROL(IDC_Icon_7,m_hGroupIconA[6]) + MAP_CONTROL(IDC_Icon_8,m_hGroupIconA[7]) + END_MAP_CHILD_CONTROLS() + MAP_CONTROL(IDC_Group_Tab_Images, m_Group) + BEGIN_MAP_CHILD_CONTROLS(m_Group) + MAP_CONTROL(IDC_TabImage1,m_hTabGroupA[0]) + MAP_CONTROL(IDC_TabImage2,m_hTabGroupA[1]) + MAP_CONTROL(IDC_TabImage3,m_hTabGroupA[2]) + MAP_CONTROL(IDC_TabImage4,m_hTabGroupA[3]) + MAP_CONTROL(IDC_TabImage5,m_hTabGroupA[4]) + MAP_CONTROL(IDC_TabImage6,m_hTabGroupA[5]) + MAP_CONTROL(IDC_TabImage7,m_hTabGroupA[6]) + MAP_CONTROL(IDC_TabImage8,m_hTabGroupA[7]) + END_MAP_CHILD_CONTROLS() + + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnTransitionEnd( XUIMessageTransition *pTransData, BOOL& bHandled); + //HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) {return S_OK;} + +private: + CXuiControl m_sceneGroup; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); + + CXuiCtrlSlotList* m_containerControl; + +private: + // IUIScene_CreativeMenu + void updateTabHighlightAndText(ECreativeInventoryTabs tab); + void updateScrollCurrentPage(int currentPage, int pageCount); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Trading.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Trading.cpp new file mode 100644 index 00000000..fec13460 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Trading.cpp @@ -0,0 +1,320 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.trading.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" +#include "..\..\Minecraft.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_Trading.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\JavaMath.h" + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneTrading::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneTrading::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + //XuiControlSetText(m_villagerText,app.GetString(IDS_VILLAGER)); + XuiControlSetText(m_inventoryLabel,app.GetString(IDS_INVENTORY)); + XuiControlSetText(m_requiredLabel,app.GetString(IDS_REQUIRED_ITEMS_FOR_TRADE)); + + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + TradingScreenInput* initData = (TradingScreenInput *)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + m_merchant = initData->trader; + + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Trading_Menu, this); + } + + m_menu = new MerchantMenu( initData->inventory, initData->trader, initData->level ); + Minecraft::GetInstance()->localplayers[m_iPad]->containerMenu = m_menu; + + // TODO Inventory dimensions need defined as constants + m_inventoryControl->SetData( m_iPad, m_menu, 3, 9, MerchantMenu::INV_SLOT_START, MerchantMenu::INV_SLOT_END ); + + // TODO Inventory dimensions need defined as constants + m_useRowControl->SetData( m_iPad, m_menu, 1, 9, MerchantMenu::USE_ROW_SLOT_START, MerchantMenu::USE_ROW_SLOT_END ); + + delete initData; + + D3DXVECTOR3 vec; + // store the slot 0 position + m_tradeHSlots[0]->GetPosition(&m_vTradeSlot0Pos); + m_tradeHSlots[1]->GetPosition(&vec); + m_fSlotSize=vec.x-m_vTradeSlot0Pos.x; + + // store the slot 0 highlight position + m_tradingSelector.GetPosition(&m_vSelectorInitialPos); + + //app.SetRichPresenceContextValue(m_iPad,CONTEXT_GAME_STATE_FORGING); + + XuiSetTimer(m_hObj,TRADING_UPDATE_TIMER_ID,TRADING_UPDATE_TIMER_TIME); + + ui.SetTooltips(m_iPad, -1, IDS_TOOLTIPS_EXIT); + + return S_OK; +} + +HRESULT CXuiSceneTrading::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +HRESULT CXuiSceneTrading::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + HXUIOBJ hObj=NULL; + HRESULT hr=XuiControlGetVisual(m_offerInfoControl.m_hObj,&hObj); + hr=XuiElementGetChildById(hObj,L"text_measurer",&m_hOfferInfoTextMeasurer); + hr=XuiElementGetChildById(hObj,L"text_name",&m_hOfferInfoText); + hr=XuiElementGetChildById(hObj,L"text_panel",&m_hOfferInfoTextBkg); + } + + return S_OK; +} + +HRESULT CXuiSceneTrading::OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled) +{ + bHandled = handleKeyDown(pInputData->UserIndex, mapVKToAction(pInputData->dwKeyCode), (pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT) != 0); + + return S_OK; +} + +HRESULT CXuiSceneTrading::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +HRESULT CXuiSceneTrading::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + if(pTimer->nId == TRADING_UPDATE_TIMER_ID) + { + handleTick(); + bHandled = TRUE; + } + return S_OK; +} + +int CXuiSceneTrading::mapVKToAction(int vk) +{ + int action = MINECRAFT_ACTION_MAX; + switch(vk) + { + case VK_PAD_A: + action = ACTION_MENU_A; + break; + case VK_PAD_B: + case VK_PAD_START: + action = ACTION_MENU_B; + break; + case VK_PAD_X: + action = ACTION_MENU_X; + break; + case VK_PAD_Y: + action = ACTION_MENU_Y; + break; + case VK_PAD_DPAD_LEFT: + case VK_PAD_LTHUMB_LEFT: + action = ACTION_MENU_LEFT; + break; + case VK_PAD_DPAD_RIGHT: + case VK_PAD_LTHUMB_RIGHT: + action = ACTION_MENU_RIGHT; + break; + case VK_PAD_LTHUMB_UP: + case VK_PAD_DPAD_UP: + action = ACTION_MENU_UP; + break; + case VK_PAD_LTHUMB_DOWN: + case VK_PAD_DPAD_DOWN: + action = ACTION_MENU_DOWN; + break; + case VK_PAD_LTRIGGER: + action = ACTION_MENU_PAGEUP; + break; + case VK_PAD_RTRIGGER: + action = ACTION_MENU_PAGEDOWN; + break; + case VK_PAD_LSHOULDER: + action = ACTION_MENU_LEFT_SCROLL; + break; + case VK_PAD_RSHOULDER: + action = ACTION_MENU_RIGHT_SCROLL; + break; + case VK_PAD_RTHUMB_UP: + action = ACTION_MENU_OTHER_STICK_UP; + break; + case VK_PAD_RTHUMB_DOWN: + action = ACTION_MENU_OTHER_STICK_DOWN; + break; + case VK_PAD_RTHUMB_RIGHT: + action = ACTION_MENU_OTHER_STICK_RIGHT; + break; + case VK_PAD_RTHUMB_LEFT: + action = ACTION_MENU_OTHER_STICK_LEFT; + break; + }; + + return action; +} + +void CXuiSceneTrading::showScrollRightArrow(bool show) +{ + m_scrollRight.SetShow(show?TRUE:FALSE); + m_scrollRight.PlayOptionalVisual(L"ScrollMore",L"EndScrollMore"); +} + +void CXuiSceneTrading::showScrollLeftArrow(bool show) +{ + m_scrollLeft.SetShow(show?TRUE:FALSE); + m_scrollLeft.PlayOptionalVisual(L"ScrollMore",L"EndScrollMore"); +} + +void CXuiSceneTrading::moveSelector(bool right) +{ + D3DXVECTOR3 vec; + + vec.z=0.0f; + vec.x=m_vSelectorInitialPos.x + (m_selectedSlot*m_fSlotSize); + vec.y=m_vSelectorInitialPos.y; + m_tradingSelector.SetPosition(&vec); +} + +void CXuiSceneTrading::setTitle(const wstring &name) +{ + XuiControlSetText(m_villagerText,name.c_str()); +} + +void CXuiSceneTrading::setRequest1Name(const wstring &name) +{ + m_request1Label.SetText(name.c_str()); +} + +void CXuiSceneTrading::setRequest2Name(const wstring &name) +{ + m_request2Label.SetText(name.c_str()); +} + +void CXuiSceneTrading::setRequest1RedBox(bool show) +{ + m_request1Control->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneTrading::setRequest2RedBox(bool show) +{ + m_request2Control->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneTrading::setTradeRedBox(int index, bool show) +{ + m_tradeHSlots[index]->SetRedBox(show?TRUE:FALSE); +} + +void CXuiSceneTrading::setRequest1Item(shared_ptr<ItemInstance> item) +{ + m_request1Control->SetIcon(getPad(), item, 12, 31, true); +} + +void CXuiSceneTrading::setRequest2Item(shared_ptr<ItemInstance> item) +{ + m_request2Control->SetIcon(getPad(), item, 12, 31, true); +} + +void CXuiSceneTrading::setTradeItem(int index, shared_ptr<ItemInstance> item) +{ + m_tradeHSlots[index]->SetIcon(getPad(), item, 12, 31, true); +} + +void CXuiSceneTrading::setOfferDescription(const wstring &name, vector<wstring> &unformattedStrings) +{ + if(name.empty()) + { + m_offerInfoControl.SetText(L""); + m_offerInfoControl.SetShow(FALSE); + return; + } + + bool smallPointer = m_bSplitscreen || (!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()); + wstring desc = L"<font size=\"" + _toString<int>(smallPointer ? 12 :14) + L"\">" + name + L"</font>"; + + XUIRect tempXuiRect, xuiRect; + HRESULT hr; + xuiRect.right = 0; + + for(AUTO_VAR(it, unformattedStrings.begin()); it != unformattedStrings.end(); ++it) + { + XuiTextPresenterMeasureText(m_hOfferInfoTextMeasurer, (*it).c_str(), &tempXuiRect); + if(tempXuiRect.right > xuiRect.right) xuiRect = tempXuiRect; + } + + // Set size with the new width so that the HTML height check is correct + XuiElementSetBounds(m_hOfferInfoTextBkg,xuiRect.right+4.0f+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge + XuiElementSetBounds(m_hOfferInfoText,xuiRect.right+4.0f+4.0f,xuiRect.bottom); // edge graphics are 8 pixels, text is centred + + XuiHtmlSetText(m_hOfferInfoText, desc.c_str() ); + + // Check if we need to resize the box + XUIContentDims contentDims; + XuiHtmlGetContentDims(m_hOfferInfoText,&contentDims); + xuiRect.bottom = contentDims.nContentHeight; + + // Set the new height + float backgroundWidth = xuiRect.right+4.0f+4.0f+4.0f; + XuiElementSetBounds(m_hOfferInfoTextBkg,backgroundWidth,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, with 4 for the border, extra 4 for the background is fudge + XuiElementSetBounds(m_hOfferInfoText,xuiRect.right+4.0f+4.0f,xuiRect.bottom+4.0f+4.0f); // edge graphics are 8 pixels, text is centred + + m_offerInfoControl.SetShow(TRUE); + + D3DXVECTOR3 highlightPos, offerInfoPos; + float highlightWidth, highlightHeight; + m_tradingSelector.GetPosition(&highlightPos); + m_tradingSelector.GetBounds(&highlightWidth,&highlightHeight); + m_offerInfoControl.GetPosition(&offerInfoPos); + + if(m_selectedSlot < DISPLAY_TRADES_COUNT/2) + { + // Display on the right + offerInfoPos.x = Math::round(highlightPos.x + highlightWidth * 1.1); + } + else + { + // Display on the left + offerInfoPos.x = Math::round(highlightPos.x - backgroundWidth - highlightWidth * 0.1); + } + m_offerInfoControl.SetPosition(&offerInfoPos); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Trading.h b/Minecraft.Client/Common/XUI/XUI_Scene_Trading.h new file mode 100644 index 00000000..72194cbc --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Trading.h @@ -0,0 +1,128 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_trading.h" +#include "..\UI\IUIScene_TradingMenu.h" + +#define TRADING_UPDATE_TIMER_ID (10) +#define TRADING_UPDATE_TIMER_TIME (50) + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneTrading : public CXuiSceneImpl, public IUIScene_TradingMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneTrading, L"CXuiSceneTrading", XUI_CLASS_SCENE ) + +private: + CXuiCtrlCraftIngredientSlot *m_request1Control; + CXuiCtrlCraftIngredientSlot *m_request2Control; + + CXuiCtrlCraftIngredientSlot *m_tradeHSlots[7]; + + CXuiControl m_request1Label, m_request2Label; + CXuiControl m_inventoryLabel, m_requiredLabel; + + CXuiControl m_villagerText; + CXuiControl m_scrollLeft, m_scrollRight, m_tradingSelector; + + CXuiControl m_sceneGroup; + CXuiElement m_hGridInventory; + + CXuiCtrlSlotList* m_inventoryControl; + CXuiCtrlSlotList* m_useRowControl; + + CXuiControl m_offerInfoControl; + HXUIOBJ m_hOfferInfoTextMeasurer; + HXUIOBJ m_hOfferInfoText; + HXUIOBJ m_hOfferInfoTextBkg; + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + MAP_OVERRIDE(IDC_Request1, m_request1Control) + MAP_OVERRIDE(IDC_Request2, m_request2Control) + + MAP_OVERRIDE(IDC_TradingBar0, m_tradeHSlots[0]) + MAP_OVERRIDE(IDC_TradingBar1, m_tradeHSlots[1]) + MAP_OVERRIDE(IDC_TradingBar2, m_tradeHSlots[2]) + MAP_OVERRIDE(IDC_TradingBar3, m_tradeHSlots[3]) + MAP_OVERRIDE(IDC_TradingBar4, m_tradeHSlots[4]) + MAP_OVERRIDE(IDC_TradingBar5, m_tradeHSlots[5]) + MAP_OVERRIDE(IDC_TradingBar6, m_tradeHSlots[6]) + + MAP_CONTROL(IDC_Offer1Label, m_request1Label) + MAP_CONTROL(IDC_Offer2Label, m_request2Label) + + MAP_CONTROL(IDC_VillagerText,m_villagerText) + MAP_CONTROL(IDC_InventoryLabel,m_inventoryLabel) + MAP_CONTROL(IDC_RequiredLabel,m_requiredLabel) + + MAP_CONTROL(IDC_ScrollLeftArrow,m_scrollLeft) + MAP_CONTROL(IDC_ScrollRightArrow,m_scrollRight) + MAP_CONTROL(IDC_TradingSelector,m_tradingSelector) + + MAP_CONTROL(IDC_HtmlTextPanel,m_offerInfoControl) + + MAP_CONTROL(IDC_InventoryGrid, m_hGridInventory) + BEGIN_MAP_CHILD_CONTROLS(m_hGridInventory) + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + END_MAP_CHILD_CONTROLS() + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnDestroy(); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + +protected: + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + bool m_bSplitscreen; + +public: + int getPad() { return m_iPad; } + +private: + + float m_fSlotSize; + D3DXVECTOR3 m_vTradeSlot0Pos; + D3DXVECTOR3 m_vSelectorInitialPos; + + int mapVKToAction(int vk); +protected: + virtual void showScrollRightArrow(bool show); + virtual void showScrollLeftArrow(bool show); + virtual void moveSelector(bool right); + virtual void setRequest1Name(const wstring &name); + virtual void setRequest2Name(const wstring &name); + virtual void setTitle(const wstring &name); + + virtual void setRequest1RedBox(bool show); + virtual void setRequest2RedBox(bool show); + virtual void setTradeRedBox(int index, bool show); + + virtual void setRequest1Item(shared_ptr<ItemInstance> item); + virtual void setRequest2Item(shared_ptr<ItemInstance> item); + virtual void setTradeItem(int index, shared_ptr<ItemInstance> item); + + virtual void setOfferDescription(const wstring &name, vector<wstring> &unformattedStrings); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Trap.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Trap.cpp new file mode 100644 index 00000000..99dc6e4c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Trap.cpp @@ -0,0 +1,122 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\DispenserTileEntity.h" +#include "..\..\..\Minecraft.World\TrapMenu.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "XUI_Ctrl_SlotList.h" +#include "XUI_Scene_Trap.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Common\Tutorial\TutorialEnum.h" + +//-------------------------------------------------------------------------------------- +// Name: CXuiSceneTrap::OnInit +// Desc: Message handler for XM_INIT +//-------------------------------------------------------------------------------------- +HRESULT CXuiSceneTrap::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + D3DXVECTOR3 vec; + MapChildControls(); + + XuiControlSetText(m_DispenserText,app.GetString(IDS_DISPENSER)); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + TrapScreenInput* initData = (TrapScreenInput*)pInitData->pvInitData; + m_iPad=initData->iPad; + m_bSplitscreen=initData->bSplitscreen; + +#ifdef _XBOX + if( pMinecraft->localgameModes[initData->iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[initData->iPad]; + m_previousTutorialState = gameMode->getTutorial()->getCurrentState(); + gameMode->getTutorial()->changeTutorialState(e_Tutorial_State_Trap_Menu, this); + } +#endif + // if we are in splitscreen, then we need to figure out if we want to move this scene + + if(m_bSplitscreen) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + TrapMenu* menu = new TrapMenu( initData->inventory, initData->trap ); + + InitDataAssociations(initData->iPad, menu); + + CXuiSceneAbstractContainer::Initialize( initData->iPad, menu, true, initData->trap->getContainerSize(), eSectionTrapUsing, eSectionTrapMax ); + + delete initData; + + return S_OK; +} + +HRESULT CXuiSceneTrap::OnDestroy() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + +#ifdef _XBOX + if( pMinecraft->localgameModes[m_iPad] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)pMinecraft->localgameModes[m_iPad]; + if(gameMode != NULL) gameMode->getTutorial()->changeTutorialState(m_previousTutorialState); + } +#endif + + // 4J Stu - Fix for #11302 - TCR 001: Network Connectivity: Host crashed after being killed by the client while accessing a chest during burst packet loss. + // We need to make sure that we call closeContainer() anytime this menu is closed, even if it is forced to close by some other reason (like the player dying) + if(Minecraft::GetInstance()->localplayers[m_iPad] != NULL) Minecraft::GetInstance()->localplayers[m_iPad]->closeContainer(); + return S_OK; +} + +CXuiControl* CXuiSceneTrap::GetSectionControl( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionTrapTrap: + return (CXuiControl *)m_trapControl; + break; + case eSectionTrapInventory: + return (CXuiControl *)m_inventoryControl; + break; + case eSectionTrapUsing: + return (CXuiControl *)m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +CXuiCtrlSlotList* CXuiSceneTrap::GetSectionSlotList( ESceneSection eSection ) +{ + switch( eSection ) + { + case eSectionTrapTrap: + return m_trapControl; + break; + case eSectionTrapInventory: + return m_inventoryControl; + break; + case eSectionTrapUsing: + return m_useRowControl; + break; + default: + assert( false ); + break; + } + return NULL; +} + +// 4J Stu - Added to support auto-save. Need to re-associate on a navigate back +void CXuiSceneTrap::InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex /*= 0*/) +{ + int containerSize = menu->getSize() - (27 + 9); + + // TODO Inventory dimensions need defined as constants + m_trapControl->SetData( iPad, menu, 3, 3, 0 ); + + CXuiSceneAbstractContainer::InitDataAssociations(iPad, menu, containerSize); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Trap.h b/Minecraft.Client/Common/XUI/XUI_Scene_Trap.h new file mode 100644 index 00000000..3008a7ca --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Trap.h @@ -0,0 +1,62 @@ +#pragma once +using namespace std; +#include "..\Media\xuiscene_trap.h" +#include "XUI_Scene_AbstractContainer.h" +#include "..\UI\IUIScene_DispenserMenu.h" +#include "XUI_CustomMessages.h" + +class Container; +class DispenserTileEntity; + +//-------------------------------------------------------------------------------------- +// Scene implementation class. +//-------------------------------------------------------------------------------------- +class CXuiSceneTrap : public CXuiSceneAbstractContainer, public IUIScene_DispenserMenu +{ +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CXuiSceneTrap, L"CXuiSceneTrap", XUI_CLASS_SCENE ) + +protected: + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_TIMER( OnTimer ) // Poll stick input on a timer. + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + // Common to all abstract container scenes + MAP_CONTROL(IDC_Group, m_sceneGroup) + BEGIN_MAP_CHILD_CONTROLS( m_sceneGroup ) + + MAP_OVERRIDE(IDC_Inventory, m_inventoryControl) + MAP_OVERRIDE(IDC_UseRow, m_useRowControl) + MAP_OVERRIDE(IDC_Pointer, m_pointerControl) + MAP_CONTROL(IDC_InventoryText,m_InventoryText) + + MAP_CONTROL(IDC_DispenserText,m_DispenserText) + MAP_OVERRIDE(IDC_Trap, m_trapControl) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + //HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) {return S_OK;} + + virtual void InitDataAssociations(int iPad, AbstractContainerMenu *menu, int startIndex = 0); +private: + CXuiCtrlSlotList* m_trapControl; + CXuiControl m_sceneGroup; + CXuiControl m_DispenserText; + + virtual CXuiControl* GetSectionControl( ESceneSection eSection ); + virtual CXuiCtrlSlotList* GetSectionSlotList( ESceneSection eSection ); + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Win.cpp b/Minecraft.Client/Common/XUI/XUI_Scene_Win.cpp new file mode 100644 index 00000000..0f0c678b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Win.cpp @@ -0,0 +1,302 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\..\Minecraft.h" +#include "..\..\Common\Tutorial\TutorialMode.h" +#include "..\..\Font.h" +#include "..\..\..\Minecraft.World\Random.h" +#include "..\..\..\Minecraft.World\SharedConstants.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "XUI_Scene_Win.h" + +BYTE CScene_Win::s_winUserIndex = 0; + +const float CScene_Win::AUTO_SCROLL_SPEED = 1.0f; +const float CScene_Win::PLAYER_SCROLL_SPEED = 3.0f; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Win::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + m_bIgnoreInput = false; + + MapChildControls(); + + // Display the tooltips + ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_CONTINUE); + + wstring halfScreenLineBreaks; + + if(RenderManager.IsHiDef()) + { + // HD - 17 line page + halfScreenLineBreaks = L"<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>"; + } + else + { + // 480 - 14 line page + halfScreenLineBreaks = L"<br/><br/><br/><br/><br/><br/><br/><br/>"; + } + + noNoiseString = L"<font size=\"24\"><ds>"; + noNoiseString.append(halfScreenLineBreaks); + noNoiseString.append(halfScreenLineBreaks); + noNoiseString.append( app.GetString(IDS_WIN_TEXT) ); + noNoiseString.append( app.GetString(IDS_WIN_TEXT_PART_2) ); + noNoiseString.append( app.GetString(IDS_WIN_TEXT_PART_3) ); + + noNoiseString.append(halfScreenLineBreaks); + + noNoiseString.append( L"</ds></font>" ); + + noNoiseString = app.FormatHTMLString(m_iPad, noNoiseString, 0xff000000); + + Random random(8124371); + int found=(int)noNoiseString.find_first_of(L"{"); + int length; + while (found!=string::npos) + { + length = random.nextInt(4) + 3; + m_noiseLengths.push_back(length); + found=(int)noNoiseString.find_first_of(L"{",found+1); + } + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if(pMinecraft->localplayers[s_winUserIndex] != NULL) + { + noNoiseString = replaceAll(noNoiseString,L"{*PLAYER*}",pMinecraft->localplayers[s_winUserIndex]->name); + } + else + { + noNoiseString = replaceAll(noNoiseString,L"{*PLAYER*}",pMinecraft->localplayers[ProfileManager.GetPrimaryPad()]->name); + } + + updateNoise(); + + m_htmlControl.SetText(noiseString.c_str()); + + //wstring result = m_htmlControl.GetText(); + + //wcout << result.c_str(); + + m_scrollDir = 1; + HRESULT hr = XuiHtmlControlSetSmoothScroll(m_htmlControl.m_hObj, XUI_SMOOTHSCROLL_VERTICAL,TRUE,AUTO_SCROLL_SPEED,1.0f,AUTO_SCROLL_SPEED); + XuiHtmlControlVScrollBy(m_htmlControl.m_hObj,m_scrollDir * 1000); + + SetTimer(0,200); + + return S_OK; +} + +HRESULT CScene_Win::OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled) +{ + if(!TreeHasFocus()) return S_OK; + + // This is required to animate the "noise" strings in the text, however this makes scrolling really jumpy + // as well as causing line lengths to change as we do not have a monspaced font. Disabling for now. +#if 0 + updateNoise(); + + XUIHtmlScrollInfo scrollInfo; + HRESULT hr = m_htmlControl.GetVScrollInfo(&scrollInfo); + m_htmlControl.SetText(noiseString.c_str()); + //wcout << noiseString.c_str(); + //hr = m_htmlControl.SetVScrollPos(scrollInfo.nPos+2); + hr = m_htmlControl.SetVScrollPos(scrollInfo.nPos); +#endif + XuiHtmlControlVScrollBy(m_htmlControl.m_hObj,m_scrollDir * 1000); + + return S_OK; +} + +HRESULT CScene_Win::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_START: + case VK_ESCAPE: + { + KillTimer(0); + m_bIgnoreInput = true; + Minecraft *pMinecraft = Minecraft::GetInstance(); + app.CloseAllPlayersXuiScenes(); + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(pMinecraft->localplayers[i] != NULL) + { + app.SetAction(i,eAppAction_Respawn); + } + } + + // Show the other players scenes + CXuiSceneBase::ShowOtherPlayersBaseScene(pInputData->UserIndex, true); + // This just allows it to be shown + if(pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(true); + ui.UpdatePlayerBasePositions(); + + rfHandled = TRUE; + } + break; + case VK_PAD_RTHUMB_UP: + case VK_PAD_LTHUMB_UP: + m_scrollDir = -1; + // Fall through + case VK_PAD_RTHUMB_DOWN: + case VK_PAD_LTHUMB_DOWN: + { + HRESULT hr = XuiHtmlControlSetSmoothScroll(m_htmlControl.m_hObj, XUI_SMOOTHSCROLL_VERTICAL,TRUE,AUTO_SCROLL_SPEED,1.0f,PLAYER_SCROLL_SPEED); + } + break; + } + + return S_OK; +} + +HRESULT CScene_Win::OnKeyUp(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + switch(pInputData->dwKeyCode) + { + case VK_PAD_RTHUMB_UP: + case VK_PAD_LTHUMB_UP: + case VK_PAD_RTHUMB_DOWN: + case VK_PAD_LTHUMB_DOWN: + { + m_scrollDir = 1; + HRESULT hr = XuiHtmlControlSetSmoothScroll(m_htmlControl.m_hObj, XUI_SMOOTHSCROLL_VERTICAL,TRUE,AUTO_SCROLL_SPEED,1.0f,AUTO_SCROLL_SPEED); + } + break; + } + + return S_OK; +} + +HRESULT CScene_Win::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +void CScene_Win::updateNoise() +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + noiseString = noNoiseString; + + int length = 0; + wchar_t replacements[64]; + wstring replaceString = L""; + wchar_t randomChar = L'a'; + Random *random = pMinecraft->font->random; + + bool darken = false; + + wstring tag = L"{*NOISE*}"; + + AUTO_VAR(it, m_noiseLengths.begin()); + int found=(int)noiseString.find_first_of(L"{"); + while (found!=string::npos && it != m_noiseLengths.end() ) + { + length = *it; + ++it; + + replaceString = L""; + for(int i = 0; i < length; ++i) + { + randomChar = SharedConstants::acceptableLetters[random->nextInt((int)SharedConstants::acceptableLetters.length())]; + + wstring randomCharStr = L""; + randomCharStr.push_back(randomChar); + if(randomChar == L'<') + { + randomCharStr = L"<"; + } + else if (randomChar == L'>' ) + { + randomCharStr = L">"; + } + else if(randomChar == L'"') + { + randomCharStr = L"""; + } + else if(randomChar == L'&') + { + randomCharStr = L"&"; + } + else if(randomChar == L'\\') + { + randomCharStr = L"\\\\"; + } + else if(randomChar == L'{') + { + randomCharStr = L"}"; + } + + int randomVal = random->nextInt(2); + eMinecraftColour colour = eHTMLColor_8; + if(randomVal == 1) colour = eHTMLColor_9; + else if(randomVal == 2) colour = eHTMLColor_a; + ZeroMemory(replacements,64*sizeof(wchar_t)); + swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#80000000\">%ls</font>",app.GetHTMLColour(colour),randomCharStr.c_str()); + replaceString.append(replacements); + } + + noiseString.replace( found, tag.length(), replaceString ); + + //int pos = 0; + //do { + // pos = random->nextInt(SharedConstants::acceptableLetters.length()); + //} while (pMinecraft->font->charWidths[ch + 32] != pMinecraft->font->charWidths[pos + 32]); + //ib.put(listPos + 256 + random->nextInt(2) + 8 + (darken ? 16 : 0)); + //ib.put(listPos + pos + 32); + + found=(int)noiseString.find_first_of(L"{",found+1); + } +} + +HRESULT CScene_Win::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + SetTimer(0,200); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + CXuiSceneBase::HideAllGameUIElements(); + + // Hide the other players scenes + CXuiSceneBase::ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); + + // This just allows it to be shown + if(Minecraft::GetInstance()->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) Minecraft::GetInstance()->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); + + // Temporarily make this scene fullscreen + CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen ); + + // Display the tooltips + ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_CONTINUE); + + XuiHtmlControlVScrollBy(m_htmlControl.m_hObj,m_scrollDir * 1000); + + return S_OK; +} + +HRESULT CScene_Win::OnNavForward(XUIMessageNavForward *pNavForwardData, BOOL& bHandled) +{ + XuiHtmlControlVScrollBy(m_htmlControl.m_hObj,0); + XUIHtmlScrollInfo scrollInfo; + HRESULT hr = m_htmlControl.GetVScrollInfo(&scrollInfo); + hr = m_htmlControl.SetVScrollPos(scrollInfo.nPos); + KillTimer(0); + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Scene_Win.h b/Minecraft.Client/Common/XUI/XUI_Scene_Win.h new file mode 100644 index 00000000..7a5e9da0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Scene_Win.h @@ -0,0 +1,58 @@ +#pragma once + +#include "../media/xuiscene_Win.h" +#include "XUI_CustomMessages.h" + +class CScene_Win : public CXuiSceneImpl +{ +private: + static const float AUTO_SCROLL_SPEED; + static const float PLAYER_SCROLL_SPEED; +protected: + CXuiHtmlControl m_htmlControl; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TIMER( OnTimer ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_KEYUP(OnKeyUp) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_NAV_FORWARD(OnNavForward) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_HtmlControl, m_htmlControl) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnKeyUp(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnNavForward(XUIMessageNavForward *pNavForwardData, BOOL& bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Win, L"CScene_Win", XUI_CLASS_SCENE ) + +private: + bool m_bIgnoreInput; + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + wstring noNoiseString; + wstring noiseString; + int m_scrollDir; + + vector<int> m_noiseLengths; + + void updateNoise(); + +public: + static BYTE s_winUserIndex; + static void setWinUserIndex(BYTE winUserIndex) { s_winUserIndex = winUserIndex; } +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsAll.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsAll.cpp new file mode 100644 index 00000000..c6dc7118 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsAll.cpp @@ -0,0 +1,227 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_SettingsAll.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsAll::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + //WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + MapChildControls(); + + XuiControlSetText(m_Buttons[BUTTON_ALL_OPTIONS],app.GetString(IDS_OPTIONS)); + XuiControlSetText(m_Buttons[BUTTON_ALL_AUDIO],app.GetString(IDS_AUDIO)); + XuiControlSetText(m_Buttons[BUTTON_ALL_CONTROL],app.GetString(IDS_CONTROL)); + XuiControlSetText(m_Buttons[BUTTON_ALL_GRAPHICS],app.GetString(IDS_GRAPHICS)); + XuiControlSetText(m_Buttons[BUTTON_ALL_UI],app.GetString(IDS_USER_INTERFACE)); + XuiControlSetText(m_Buttons[BUTTON_ALL_RESETTODEFAULTS],app.GetString(IDS_RESET_TO_DEFAULTS)); + + if(ProfileManager.GetPrimaryPad()!=m_iPad) + { + D3DXVECTOR3 vec,vecControl; + m_Buttons[BUTTON_ALL_AUDIO].SetShow(FALSE); + m_Buttons[BUTTON_ALL_AUDIO].SetEnable(FALSE); + m_Buttons[BUTTON_ALL_GRAPHICS].SetShow(FALSE); + m_Buttons[BUTTON_ALL_GRAPHICS].SetEnable(FALSE); + + float fButtonWidth, fButtonHeight; + m_Buttons[BUTTON_ALL_GRAPHICS].GetPosition(&vecControl); + m_Buttons[BUTTON_ALL_RESETTODEFAULTS].GetBounds(&fButtonWidth, &fButtonHeight); + m_Buttons[BUTTON_ALL_RESETTODEFAULTS].SetPosition(&vecControl); + + m_Buttons[BUTTON_ALL_CONTROL].GetPosition(&vec); + m_Buttons[BUTTON_ALL_UI].SetPosition(&vec); + + m_Buttons[BUTTON_ALL_AUDIO].GetPosition(&vec); + m_Buttons[BUTTON_ALL_CONTROL].SetPosition(&vec); + + // Resize the whole scene + float fWidth, fHeight; + GetBounds(&fWidth, &fHeight); + SetBounds(fWidth, vecControl.y+fButtonHeight); + } + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + + + + +HRESULT CScene_SettingsAll::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +HRESULT CScene_SettingsAll::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsAll::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //HRESULT hr; + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + } + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsAll::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + unsigned int uiButtonCounter=0; + + while((uiButtonCounter<BUTTONS_ALL_MAX) && (m_Buttons[uiButtonCounter]!=hObjPressed)) uiButtonCounter++; + + switch(uiButtonCounter) + { + case BUTTON_ALL_OPTIONS: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsOptionsMenu); + break; + case BUTTON_ALL_AUDIO: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsAudioMenu); + break; + case BUTTON_ALL_CONTROL: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsControlMenu); + break; + case BUTTON_ALL_GRAPHICS: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsGraphicsMenu); + break; + case BUTTON_ALL_UI: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_SettingsUIMenu); + break; + case BUTTON_ALL_RESETTODEFAULTS: + { + // check they really want to do this + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + + StorageManager.RequestMessageBox(IDS_DEFAULTS_TITLE, IDS_DEFAULTS_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_SettingsAll::ResetDefaultsDialogReturned,this, app.GetStringTable()); + } + break; + + } + + rfHandled=TRUE; + return S_OK; +} + +HRESULT CScene_SettingsAll::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + if(!RenderManager.IsHiDef() || app.GetLocalPlayerCount()>1) + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsAll::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +int CScene_SettingsAll::ResetDefaultsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CScene_SettingsAll* pClass = (CScene_SettingsAll*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + app.SetDefaultOptions(ProfileManager.GetDashboardProfileSettings(iPad),iPad); + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + app.CheckGameSettingsChanged(true,iPad); + } + return 0; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsAll.h b/Minecraft.Client/Common/XUI/XUI_SettingsAll.h new file mode 100644 index 00000000..217f6c73 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsAll.h @@ -0,0 +1,59 @@ +#pragma once + +#include "../media/xuiscene_settings_all.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + +#define BUTTON_ALL_OPTIONS 0 +#define BUTTON_ALL_AUDIO 1 +#define BUTTON_ALL_CONTROL 2 +#define BUTTON_ALL_GRAPHICS 4 +#define BUTTON_ALL_UI 5 +#define BUTTON_ALL_RESETTODEFAULTS 6 +#define BUTTONS_ALL_MAX BUTTON_ALL_RESETTODEFAULTS + 1 + +class CScene_SettingsAll : public CXuiSceneImpl +{ +protected: + + CXuiControl m_Buttons[BUTTONS_ALL_MAX]; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiButtonOptions, m_Buttons[BUTTON_ALL_OPTIONS]) + MAP_CONTROL(IDC_XuiButtonAudio, m_Buttons[BUTTON_ALL_AUDIO]) + MAP_CONTROL(IDC_XuiButtonControl, m_Buttons[BUTTON_ALL_CONTROL]) + MAP_CONTROL(IDC_XuiButtonGraphics, m_Buttons[BUTTON_ALL_GRAPHICS]) + MAP_CONTROL(IDC_XuiButtonUI, m_Buttons[BUTTON_ALL_UI]) + MAP_CONTROL(IDC_XuiButtonResetToDefaults, m_Buttons[BUTTON_ALL_RESETTODEFAULTS]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + static int ResetDefaultsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + int m_iPad; + + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsAll, L"CScene_SettingsAll", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsAudio.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsAudio.cpp new file mode 100644 index 00000000..0f0fe2e3 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsAudio.cpp @@ -0,0 +1,263 @@ +#include "stdafx.h" +#include "..\XUI\XUI_SettingsAudio.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsAudio::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + MapChildControls(); + + // Display the tooltips + HRESULT hr = S_OK; + HXUIOBJ hSlider; + + m_SliderA[SLIDER_SETTINGS_MUSIC].SetValue(app.GetGameSettings(m_iPad,eGameSetting_MusicVolume)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_MUSIC ),app.GetGameSettings(m_iPad,eGameSetting_MusicVolume)); + m_SliderA[SLIDER_SETTINGS_MUSIC].SetText(TempString); + + m_SliderA[SLIDER_SETTINGS_SOUND].SetValue(app.GetGameSettings(m_iPad,eGameSetting_SoundFXVolume)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SOUND ),app.GetGameSettings(m_iPad,eGameSetting_SoundFXVolume)); + m_SliderA[SLIDER_SETTINGS_SOUND].SetText(TempString); + + // only the primary player gets to change the music and sound settings + // only the primary player gets to change the gamma and splitscreen settings + // only the primary player gets to change the difficulty settings + if(ProfileManager.GetPrimaryPad()!=m_iPad) + { + D3DXVECTOR3 vec; + + m_SliderA[SLIDER_SETTINGS_MUSIC].GetPosition(&vec); + m_SliderA[SLIDER_SETTINGS_MUSIC].SetEnable(FALSE); + m_SliderA[SLIDER_SETTINGS_MUSIC].SetShow(FALSE); + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_MUSIC].m_hObj,L"XuiSlider",&hSlider); + XuiElementSetShow(hSlider,FALSE); + XuiControlSetEnable(hSlider,FALSE); + m_SliderA[SLIDER_SETTINGS_SOUND].SetEnable(FALSE); + m_SliderA[SLIDER_SETTINGS_SOUND].SetShow(FALSE); + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_SOUND].m_hObj,L"XuiSlider",&hSlider); + XuiElementSetShow(hSlider,FALSE); + XuiControlSetEnable(hSlider,FALSE); + } + + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsAudio::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderA[SLIDER_SETTINGS_MUSIC].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_MusicVolume,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_MUSIC ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_MUSIC].SetText(TempString); + } + else if(hObjSource==m_SliderA[SLIDER_SETTINGS_SOUND].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_SoundFXVolume,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SOUND ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_SOUND].SetText(TempString); + } + + + return S_OK; +} + + +HRESULT CScene_SettingsAudio::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + // Not in this scene - app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsAudio::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SettingsAudio::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsAudio::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + HRESULT hr; + WCHAR TempString[256]; + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fMaxLen=0.0f; + + // sliders first + HXUIOBJ hSlider,hVisual,hText;//,hCheckboxText; + XUIRect xuiRect; + float fWidth,fHeight,fTemp; + D3DXVECTOR3 vec,vecCheckboxText,vSlider,vecCheckbox; + + // don't display values on these - we handle that + for(int i=0;i<SLIDER_SETTINGS_AUDIO_MAX;i++) + { + m_SliderA[i].SetValueDisplay(FALSE); + } + + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_MUSIC].m_hObj,L"XuiSlider",&hSlider); + hr=XuiControlGetVisual(hSlider,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Label",&hText); + hr=XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_MUSIC].m_hObj,&vSlider); + + for(int i=0;i<SLIDER_SETTINGS_AUDIO_MAX;i++) + { + switch(i) + { + case SLIDER_SETTINGS_MUSIC: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_MUSIC ),999); + break; + case SLIDER_SETTINGS_SOUND: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SOUND ),999); + break; + } + + hr=XuiTextPresenterMeasureText(hText, TempString, &xuiRect); + // 4J-PB - the text measuring doesn't seem to be long enough - add a fudge + xuiRect.right+=25.0f; + m_SliderA[i].GetBounds(&fWidth,&fHeight); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + if(fWidth>fMaxLen) fMaxLen=fWidth; + } + + if(fMaxLen<fMaxTextLen) + { + float fWidth; + XuiElementGetPosition(m_hObj,&vec); + XuiElementGetBounds(m_hObj,&fWidth,&fHeight); + + // need to centre the scene now the size has changed + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + // scene width needs to be more that the text width on buttons + fWidth=vSlider.x; + vec.x=floorf((640.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + else + { + fWidth=vSlider.x; + vec.x=floorf((1280.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + // Need to refresh the scenes visual since the object size has now changed + XuiControlAttachVisual(m_hObj); + + // centre is vec.x+(fWidth/2) + for(int i=0;i<SLIDER_SETTINGS_AUDIO_MAX;i++) + { + hr=XuiElementGetChildById(m_SliderA[i].m_hObj,L"XuiSlider",&hSlider); + XuiElementGetPosition(hSlider,&vec); + XuiElementGetBounds(hSlider,&fTemp,&fHeight); + XuiElementSetBounds(hSlider,fMaxTextLen,fHeight); + } + } + } + + return S_OK; +} + +HRESULT CScene_SettingsAudio::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + return S_OK; +} + +HRESULT CScene_SettingsAudio::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsAudio.h b/Minecraft.Client/Common/XUI/XUI_SettingsAudio.h new file mode 100644 index 00000000..c77f5798 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsAudio.h @@ -0,0 +1,53 @@ +#pragma once + +#include "../media/xuiscene_settings_audio.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + +#define SLIDER_SETTINGS_MUSIC 0 +#define SLIDER_SETTINGS_SOUND 1 + +#define SLIDER_SETTINGS_AUDIO_MAX SLIDER_SETTINGS_SOUND + 1 +class CScene_SettingsAudio : public CXuiSceneImpl +{ +protected: + CXuiCtrlSliderWrapper m_SliderA[SLIDER_SETTINGS_AUDIO_MAX]; + + CXuiControl m_ButtonOptions; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiSliderMusic, m_SliderA[SLIDER_SETTINGS_MUSIC]) + MAP_CONTROL(IDC_XuiSliderSound, m_SliderA[SLIDER_SETTINGS_SOUND]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsAudio, L"CScene_SettingsAudio", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsControl.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsControl.cpp new file mode 100644 index 00000000..7e2835a2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsControl.cpp @@ -0,0 +1,241 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_SettingsControl.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsControl::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + MapChildControls(); + + // Display the tooltips + + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].SetValue(app.GetGameSettings(m_iPad,eGameSetting_Sensitivity_InGame)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INGAME ),app.GetGameSettings(m_iPad,eGameSetting_Sensitivity_InGame)); + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].SetText(TempString); + + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INMENU].SetValue(app.GetGameSettings(m_iPad,eGameSetting_Sensitivity_InMenu)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INMENU ),app.GetGameSettings(m_iPad,eGameSetting_Sensitivity_InMenu)); + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INMENU].SetText(TempString); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsControl::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Sensitivity_InGame,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INGAME ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].SetText(TempString); + } + else if(hObjSource==m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INMENU].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Sensitivity_InMenu,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INMENU ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INMENU].SetText(TempString); + } + + return S_OK; +} + + +HRESULT CScene_SettingsControl::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + // not in this scene - app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsControl::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SettingsControl::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsControl::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + HRESULT hr; + WCHAR TempString[256]; + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fMaxLen=0.0f; + + // sliders first + HXUIOBJ hSlider,hVisual,hText;//,hCheckboxText; + XUIRect xuiRect; + float fWidth,fHeight,fTemp; + D3DXVECTOR3 vec,vecCheckboxText,vSlider,vecCheckbox; + + // don't display values on these - we handle that + for(int i=0;i<SLIDER_SETTINGS_CONTROL_MAX;i++) + { + m_SliderA[i].SetValueDisplay(FALSE); + } + + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].m_hObj,L"XuiSlider",&hSlider); + hr=XuiControlGetVisual(hSlider,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Label",&hText); + hr=XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME].m_hObj,&vSlider); + + for(int i=0;i<SLIDER_SETTINGS_CONTROL_MAX;i++) + { + switch(i) + { + case SLIDER_SETTINGS_SENSITIVITY_INGAME: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INGAME ),999); + break; + case SLIDER_SETTINGS_SENSITIVITY_INMENU: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_SENSITIVITY_INMENU ),999); + break; + } + hr=XuiTextPresenterMeasureText(hText, TempString, &xuiRect); + // 4J-PB - the text measuring doesn't seem to be long enough - add a fudge + xuiRect.right+=25.0f; + m_SliderA[i].GetBounds(&fWidth,&fHeight); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + if(fWidth>fMaxLen) fMaxLen=fWidth; + } + + if(fMaxLen<fMaxTextLen) + { + float fWidth; + XuiElementGetPosition(m_hObj,&vec); + XuiElementGetBounds(m_hObj,&fWidth,&fHeight); + + // need to centre the scene now the size has changed + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + // scene width needs to be more that the text width on buttons + fWidth=vSlider.x; + vec.x=floorf((640.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + else + { + fWidth=vSlider.x; + vec.x=floorf((1280.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + + // centre is vec.x+(fWidth/2) + for(int i=0;i<SLIDER_SETTINGS_CONTROL_MAX;i++) + { + hr=XuiElementGetChildById(m_SliderA[i].m_hObj,L"XuiSlider",&hSlider); + XuiElementGetPosition(hSlider,&vec); + XuiElementGetBounds(hSlider,&fTemp,&fHeight); + XuiElementSetBounds(hSlider,fMaxTextLen,fHeight); + } + // Need to refresh the scenes visual since the object size has now changed + XuiControlAttachVisual(m_hObj); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsControl::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + return S_OK; +} + +HRESULT CScene_SettingsControl::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsControl.h b/Minecraft.Client/Common/XUI/XUI_SettingsControl.h new file mode 100644 index 00000000..67e43699 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsControl.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../media/xuiscene_settings_control.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + +#define SLIDER_SETTINGS_SENSITIVITY_INGAME 0 +#define SLIDER_SETTINGS_SENSITIVITY_INMENU 1 + +#define SLIDER_SETTINGS_CONTROL_MAX SLIDER_SETTINGS_SENSITIVITY_INMENU + 1 +class CScene_SettingsControl : public CXuiSceneImpl +{ +protected: + CXuiCtrlSliderWrapper m_SliderA[SLIDER_SETTINGS_CONTROL_MAX]; + + CXuiControl m_ButtonOptions; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiSliderSensitivityInGame, m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INGAME]) + MAP_CONTROL(IDC_XuiSliderSensitivityInMenu, m_SliderA[SLIDER_SETTINGS_SENSITIVITY_INMENU]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsControl, L"CScene_SettingsControl", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.cpp new file mode 100644 index 00000000..48a933e2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.cpp @@ -0,0 +1,333 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_SettingsGraphics.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsGraphics::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + bool bIsPrimaryPad=(ProfileManager.GetPrimaryPad()==m_iPad); + + MapChildControls(); + + // Display the tooltips + + m_Clouds.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_Clouds)!=0)?TRUE:FALSE); + m_Clouds.SetText(app.GetString( IDS_CHECKBOX_RENDER_CLOUDS )); + + m_SliderA[SLIDER_SETTINGS_GAMMA].SetValue(app.GetGameSettings(m_iPad,eGameSetting_Gamma)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),app.GetGameSettings(m_iPad,eGameSetting_Gamma)); + m_SliderA[SLIDER_SETTINGS_GAMMA].SetText(TempString); + + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].SetValue(app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity)); + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].SetText(TempString); + + m_BedrockFog.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_BedrockFog)!=0)?TRUE:FALSE); + m_BedrockFog.SetText(app.GetString( IDS_CHECKBOX_RENDER_BEDROCKFOG )); + + m_CustomSkinAnim.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_CustomSkinAnim)!=0)?TRUE:FALSE); + m_CustomSkinAnim.SetText(app.GetString( IDS_CHECKBOX_CUSTOM_SKIN_ANIM )); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + // If the game has started, then you need to be the host to change the in-game gamertags + if(bIsPrimaryPad) + { + // are we the game host? If not, we need to remove the bedrockfog setting + if(!g_NetworkManager.IsHost()) + { + // we are the primary player on this machine, but not the game host + D3DXVECTOR3 vec; + // hide the in-game bedrock fog setting + m_BedrockFog.SetShow(FALSE); + + // m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY] -> m_SliderA[SLIDER_SETTINGS_GAMMA] + // m_SliderA[SLIDER_SETTINGS_GAMMA] -> m_CustomSkinAnim + // m_CustomSkinAnim -> m_BedrockFog + + XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_GAMMA],&vec); + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].SetPosition(&vec); + + XuiElementGetPosition(m_CustomSkinAnim,&vec); + m_SliderA[SLIDER_SETTINGS_GAMMA].SetPosition(&vec); + + XuiElementGetPosition(m_BedrockFog,&vec); + m_CustomSkinAnim.SetPosition(&vec); + + // reduce the size of the background + float fWidth, fHeight, fbgnWidth, fBgnHeight; + m_BedrockFog.GetBounds(&fWidth, &fHeight); + GetBounds(&fbgnWidth, &fBgnHeight); + fBgnHeight-=fHeight; + SetBounds(fbgnWidth, fBgnHeight); + } + } + else + { + // We shouldn't have the bedrock fog option, or the m_CustomSkinAnim option + m_BedrockFog.SetShow(FALSE); + m_CustomSkinAnim.SetShow(FALSE); + + D3DXVECTOR3 vec,vecGamma,vecOpacity; + float fSliderYDiff; + + // m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY] -> m_BedrockFog + // m_SliderA[SLIDER_SETTINGS_GAMMA] -> m_BedrockFog + + m_SliderA[SLIDER_SETTINGS_GAMMA].GetPosition(&vecGamma); + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].GetPosition(&vecOpacity); + fSliderYDiff=vecOpacity.y-vecGamma.y; + + XuiElementGetPosition(m_BedrockFog,&vec); + m_SliderA[SLIDER_SETTINGS_GAMMA].SetPosition(&vec); + vec.y+=fSliderYDiff; + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].SetPosition(&vec); + + // reduce the size of the background + float fWidth, fHeight, fbgnWidth, fBgnHeight; + GetBounds(&fbgnWidth, &fBgnHeight); + m_BedrockFog.GetBounds(&fWidth, &fHeight); + fBgnHeight-=fHeight; + m_CustomSkinAnim.GetBounds(&fWidth, &fHeight); + fBgnHeight-=fHeight; + SetBounds(fbgnWidth, fBgnHeight); + } + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsGraphics::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderA[SLIDER_SETTINGS_GAMMA].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Gamma,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_GAMMA].SetText(TempString); + } + else if(hObjSource==m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_InterfaceOpacity,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY].SetText(TempString); + } + + return S_OK; +} + + +HRESULT CScene_SettingsGraphics::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + // not in this scene - app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + // check the checkboxes + app.SetGameSettings(m_iPad,eGameSetting_Clouds,m_Clouds.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_BedrockFog,m_BedrockFog.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_CustomSkinAnim,m_CustomSkinAnim.IsChecked()?1:0); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsGraphics::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SettingsGraphics::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsGraphics::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + HRESULT hr; + WCHAR TempString[256]; + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fMaxLen=0.0f; + + // sliders first + HXUIOBJ hSlider,hVisual,hText,hCheckboxText; + XUIRect xuiRect; + float fWidth,fHeight,fTemp; + D3DXVECTOR3 vec,vecCheckboxText,vSlider,vecCheckbox; + + // don't display values on these - we handle that + for(int i=0;i<SLIDER_SETTINGS_GRAPHICS_MAX;i++) + { + m_SliderA[i].SetValueDisplay(FALSE); + } + + hr=XuiControlGetVisual(m_Clouds.m_hObj,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Button",&hCheckboxText); + + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_GAMMA].m_hObj,L"XuiSlider",&hSlider); + hr=XuiControlGetVisual(hSlider,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Label",&hText); + hr=XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_GAMMA].m_hObj,&vSlider); + + for(int i=0;i<SLIDER_SETTINGS_GRAPHICS_MAX;i++) + { + switch(i) + { + case SLIDER_SETTINGS_GAMMA: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),999); + break; + case SLIDER_SETTINGS_INTERFACE_OPACITY: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),999); + break; + } + hr=XuiTextPresenterMeasureText(hText, TempString, &xuiRect); + // 4J-PB - the text measuring doesn't seem to be long enough - add a fudge + xuiRect.right+=25.0f; + m_SliderA[i].GetBounds(&fWidth,&fHeight); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + if(fWidth>fMaxLen) fMaxLen=fWidth; + } + + // now the clouds checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hText, m_Clouds.GetText(), &xuiRect); + hr=XuiTextPresenterMeasureText(hCheckboxText, m_Clouds.GetText(), &xuiRect); + m_Clouds.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + if(fMaxLen<fMaxTextLen) + { + float fWidth; + XuiElementGetPosition(m_hObj,&vec); + XuiElementGetBounds(m_hObj,&fWidth,&fHeight); + + // need to centre the scene now the size has changed + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + // scene width needs to be more that the text width on buttons + fWidth=vSlider.x; + vec.x=floorf((640.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + else + { + fWidth=vSlider.x; + vec.x=floorf((1280.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + // Need to refresh the scenes visual since the object size has now changed + XuiControlAttachVisual(m_hObj); + + // centre is vec.x+(fWidth/2) + for(int i=0;i<SLIDER_SETTINGS_GRAPHICS_MAX;i++) + { + hr=XuiElementGetChildById(m_SliderA[i].m_hObj,L"XuiSlider",&hSlider); + XuiElementGetPosition(hSlider,&vec); + XuiElementGetBounds(hSlider,&fTemp,&fHeight); + XuiElementSetBounds(hSlider,fMaxTextLen,fHeight); + } + + m_Clouds.SetBounds(fMaxTextLen,fHeight); + + } + } + + return S_OK; +} + +HRESULT CScene_SettingsGraphics::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + return S_OK; +} + +HRESULT CScene_SettingsGraphics::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.h b/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.h new file mode 100644 index 00000000..224dedd7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsGraphics.h @@ -0,0 +1,60 @@ +#pragma once + +#include "../media/xuiscene_settings_graphics.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + + +#define SLIDER_SETTINGS_GAMMA 0 +#define SLIDER_SETTINGS_INTERFACE_OPACITY 1 + + +#define SLIDER_SETTINGS_GRAPHICS_MAX SLIDER_SETTINGS_INTERFACE_OPACITY + 1 +class CScene_SettingsGraphics : public CXuiSceneImpl +{ +protected: + CXuiCtrlSliderWrapper m_SliderA[SLIDER_SETTINGS_GRAPHICS_MAX]; + CXuiCheckbox m_Clouds; + CXuiCheckbox m_BedrockFog; + CXuiCheckbox m_CustomSkinAnim; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiClouds, m_Clouds) + MAP_CONTROL(IDC_XuiBedrockFog, m_BedrockFog) + MAP_CONTROL(IDC_XuiCustomSkinAnim, m_CustomSkinAnim) + MAP_CONTROL(IDC_XuiSliderGamma, m_SliderA[SLIDER_SETTINGS_GAMMA]) + MAP_CONTROL(IDC_XuiSliderInterfaceOpacity, m_SliderA[SLIDER_SETTINGS_INTERFACE_OPACITY]) + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsGraphics, L"CScene_SettingsGraphics", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsOptions.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsOptions.cpp new file mode 100644 index 00000000..526847c7 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsOptions.cpp @@ -0,0 +1,508 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_SettingsOptions.h" + +int CScene_SettingsOptions::m_iDifficultySettingA[4]= +{ + IDS_DIFFICULTY_PEACEFUL, + IDS_DIFFICULTY_EASY, + IDS_DIFFICULTY_NORMAL, + IDS_DIFFICULTY_HARD +}; + +int CScene_SettingsOptions::m_iDifficultyTitleSettingA[4]= +{ + IDS_DIFFICULTY_TITLE_PEACEFUL, + IDS_DIFFICULTY_TITLE_EASY, + IDS_DIFFICULTY_TITLE_NORMAL, + IDS_DIFFICULTY_TITLE_HARD +}; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsOptions::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + bool bPrimaryPlayer = ProfileManager.GetPrimaryPad()==m_iPad; + + MapChildControls(); + + XuiControlSetText(m_ViewBob,app.GetString(IDS_VIEW_BOBBING)); + XuiControlSetText(m_Hints,app.GetString(IDS_HINTS)); + XuiControlSetText(m_Tooltips,app.GetString(IDS_IN_GAME_TOOLTIPS)); + XuiControlSetText(m_InGameGamertags,app.GetString(IDS_IN_GAME_GAMERTAGS)); + XuiControlSetText(m_MashUpWorlds,app.GetString(IDS_UNHIDE_MASHUP_WORLDS)); + + // check if we should display the mash-up option + if(bNotInGame && app.GetMashupPackWorlds(m_iPad)!=0xFFFFFFFF) + { + // the mash-up option is needed + m_bMashUpWorldsUnhideOption=true; + m_MashUpWorlds.SetShow(TRUE); + } + else + { + m_bMashUpWorldsUnhideOption=false; + m_MashUpWorlds.SetShow(FALSE); + } + + // Display the tooltips + HRESULT hr = S_OK; + HXUIOBJ hSlider; + + unsigned char ucValue=app.GetGameSettings(m_iPad,eGameSetting_Autosave); + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetValue(ucValue); + if(ucValue==0) + { + swprintf( (WCHAR *)TempString, 256, L"%ls", app.GetString( IDS_SLIDER_AUTOSAVE_OFF )); + } + else + { + swprintf( (WCHAR *)TempString, 256, L"%ls: %d %ls", app.GetString( IDS_SLIDER_AUTOSAVE ),ucValue*15, app.GetString( IDS_MINUTES )); + } + + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetText(TempString); + + + m_ViewBob.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_ViewBob)!=0)?TRUE:FALSE); + m_InGameGamertags.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_GamertagsVisible)!=0)?TRUE:FALSE); + m_Hints.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_Hints)!=0)?TRUE:FALSE); + m_Tooltips.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_Tooltips)!=0)?TRUE:FALSE); + + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetValue(app.GetGameSettings(m_iPad,eGameSetting_Difficulty)); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[app.GetGameSettings(m_iPad,eGameSetting_Difficulty)])); + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetText(TempString); + + + wstring wsText=app.GetString(m_iDifficultySettingA[app.GetGameSettings(m_iPad,eGameSetting_Difficulty)]); + int size = 14; + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + size = 12; + } + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=%d>",app.GetHTMLColour(eHTMLColor_White),size); + wsText= startTags + wsText; + + m_DifficultyText.SetText(wsText.c_str()); + + + // If you are in-game, only the game host can change in-game gamertags, and you can't change difficulty + // only the primary player gets to change the autosave and difficulty settings + + bool bRemoveDifficulty=false; + bool bRemoveAutosave=false; + bool bRemoveInGameGamertags=false; + float fRemoveHeight=0.0f,fWidth,fHeight; + float fSlidersMoveUp=0.0f; + + if(!bPrimaryPlayer) + { + bRemoveDifficulty=true; + bRemoveAutosave=true; + bRemoveInGameGamertags=true; + } + + if(!bNotInGame) // in the game + { + bRemoveDifficulty=true; + if(!g_NetworkManager.IsHost()) + { + bRemoveAutosave=true; + bRemoveInGameGamertags=true; + } + } + + D3DXVECTOR3 vec1,vec2; + XuiElementGetPosition(m_ViewBob,&vec1); + XuiElementGetPosition(m_Hints,&vec2); + + float fCheckboxHeight=vec2.y-vec1.y; + + if(bRemoveDifficulty) + { + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetEnable(FALSE); + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetShow(FALSE); + m_DifficultyText.SetShow(FALSE); + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_DIFFICULTY].m_hObj,L"XuiSlider",&hSlider); + XuiElementSetShow(hSlider,FALSE); + XuiControlSetEnable(hSlider,FALSE); + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].GetBounds(&fWidth,&fHeight); + fRemoveHeight+=fHeight+4.0f; // add padding + } + else + { + wstring wsText=app.GetString(m_iDifficultySettingA[app.GetGameSettings(m_iPad,eGameSetting_Difficulty)]); + int size = 14; + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + size = 12; + } + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=%d>",app.GetHTMLColour(eHTMLColor_White),size); + wsText= startTags + wsText; + + m_DifficultyText.SetText(wsText.c_str()); + } + + if(bRemoveAutosave) + { + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetEnable(FALSE); + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetShow(FALSE); + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_AUTOSAVE].m_hObj,L"XuiSlider",&hSlider); + XuiElementSetShow(hSlider,FALSE); + XuiControlSetEnable(hSlider,FALSE); + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].GetBounds(&fWidth,&fHeight); + fRemoveHeight+=fHeight+4.0f; // add padding + } + + if(bRemoveInGameGamertags) + { + m_InGameGamertags.SetShow(FALSE); + m_InGameGamertags.SetEnable(FALSE); + m_InGameGamertags.GetBounds(&fWidth, &fHeight); + + // move the mash-up worlds option up + if(m_bMashUpWorldsUnhideOption) + { + D3DXVECTOR3 vec; + XuiElementGetPosition(m_InGameGamertags,&vec); + m_MashUpWorlds.SetPosition(&vec); + } + fRemoveHeight+=fCheckboxHeight;//fHeight+4.0f; // add padding + fSlidersMoveUp+=fCheckboxHeight; + } + + if(!m_bMashUpWorldsUnhideOption) + { + m_MashUpWorlds.SetShow(FALSE); + m_MashUpWorlds.SetEnable(FALSE); + m_MashUpWorlds.GetBounds(&fWidth, &fHeight); + fRemoveHeight+=fCheckboxHeight; + fSlidersMoveUp+=fCheckboxHeight; + } + + + if(fRemoveHeight>0.0f) + { + D3DXVECTOR3 vec; + // autosave should move up by the height of the number of checkboxes hidden + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].GetPosition(&vec); + vec.y-=fSlidersMoveUp; + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetPosition(&vec); + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].GetPosition(&vec); + vec.y-=fSlidersMoveUp; + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetPosition(&vec); + m_DifficultyText.GetPosition(&vec); + vec.y-=fSlidersMoveUp; + m_DifficultyText.SetPosition(&vec); + + float fbgnWidth, fBgnHeight; + GetBounds(&fbgnWidth, &fBgnHeight); + fBgnHeight-=fRemoveHeight; + SetBounds(fbgnWidth, fBgnHeight); + } + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + // can't show the logo for 480 mode + if(!RenderManager.IsHiDef()) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + } + else + { + // can't show the logo for 480 mode + if(!RenderManager.IsHiDef()) + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + } + + return S_OK; +} + +HRESULT CScene_SettingsOptions::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderA[SLIDER_SETTINGS_AUTOSAVE].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Autosave,pNotifyValueChanged->nValue); + // Update the autosave timer + app.SetAutosaveTimerTime(); + + if(pNotifyValueChanged->nValue==0) + { + swprintf( (WCHAR *)TempString, 256, L"%ls", app.GetString( IDS_SLIDER_AUTOSAVE_OFF )); + } + else + { + app.SetAutosaveTimerTime(); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d %ls", app.GetString( IDS_SLIDER_AUTOSAVE ),pNotifyValueChanged->nValue*15, app.GetString( IDS_MINUTES )); + } + m_SliderA[SLIDER_SETTINGS_AUTOSAVE].SetText(TempString); + } + else if(hObjSource==m_SliderA[SLIDER_SETTINGS_DIFFICULTY].GetSlider() ) + { + app.SetGameSettings(m_iPad,eGameSetting_Difficulty,pNotifyValueChanged->nValue); + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(m_iDifficultyTitleSettingA[pNotifyValueChanged->nValue])); + m_SliderA[SLIDER_SETTINGS_DIFFICULTY].SetText(TempString); + + wstring wsText=app.GetString(m_iDifficultySettingA[pNotifyValueChanged->nValue]); + int size = 14; + if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) + { + size = 12; + } + wchar_t startTags[64]; + swprintf(startTags,64,L"<font color=\"#%08x\" size=%d>",app.GetHTMLColour(eHTMLColor_White),size); + wsText= startTags + wsText; + m_DifficultyText.SetText(wsText.c_str()); + } + return S_OK; +} + + +HRESULT CScene_SettingsOptions::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + // check the checkboxes + app.SetGameSettings(m_iPad,eGameSetting_ViewBob,m_ViewBob.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_GamertagsVisible,m_InGameGamertags.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_Hints,m_Hints.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_Tooltips,m_Tooltips.IsChecked()?1:0); + + // the mashup option will only be shown if some worlds have been previously hidden + if(m_bMashUpWorldsUnhideOption && m_MashUpWorlds.IsChecked()) + { + // unhide all worlds + app.EnableMashupPackWorlds(m_iPad); + } + + // 4J-PB - don't action changes here or we might write to the profile on backing out here and then get a change in the settings all, and write again on backing out there + //app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsOptions::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SettingsOptions::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsOptions::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + HRESULT hr; + WCHAR TempString[256]; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fMaxLen=0.0f; + + + // sliders first + HXUIOBJ hSlider,hVisual,hText,hCheckboxText; + XUIRect xuiRect; + float fWidth,fHeight;//,fTemp; + D3DXVECTOR3 vec,vSlider,vecCheckboxText,vecCheckbox; + + // don't display values on these - we handle that + for(int i=0;i<OPTIONS_SLIDER_SETTINGS_MAX;i++) + { + m_SliderA[i].SetValueDisplay(FALSE); + } + + + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_AUTOSAVE].m_hObj,L"XuiSlider",&hSlider); + hr=XuiControlGetVisual(hSlider,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Label",&hText); + hr=XuiControlGetVisual(m_InGameGamertags.m_hObj,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Button",&hCheckboxText); + hr=XuiElementGetPosition(hCheckboxText,&vecCheckboxText); + hr=XuiElementGetPosition(m_InGameGamertags.m_hObj,&vecCheckbox); + hr=XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_AUTOSAVE].m_hObj,&vSlider); + + + for(int i=0;i<OPTIONS_SLIDER_SETTINGS_MAX;i++) + { + switch(i) + { + case SLIDER_SETTINGS_AUTOSAVE: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d %ls", app.GetString( IDS_SLIDER_AUTOSAVE ),999, app.GetString( IDS_MINUTES )); + break; + case SLIDER_SETTINGS_DIFFICULTY: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %ls", app.GetString( IDS_SLIDER_DIFFICULTY ),app.GetString(IDS_DIFFICULTY_TITLE_PEACEFUL)); + break; + } + + //LPCWSTR temp=m_SliderA[i].GetText(); + hr=XuiTextPresenterMeasureText(hText, TempString, &xuiRect); + // 4J-PB - the text measuring doesn't seem to be long enough - add a fudge + xuiRect.right+=25.0f; + m_SliderA[i].GetBounds(&fWidth,&fHeight); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + if(fWidth>fMaxLen) fMaxLen=fWidth; + } + + // now the VisibleOnMaps checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hCheckboxText, m_InGameGamertags.GetText(), &xuiRect); + m_InGameGamertags.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + // now the m_Hints checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hCheckboxText, m_Hints.GetText(), &xuiRect); + m_Hints.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + // now the m_Tooltips checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hCheckboxText, m_Tooltips.GetText(), &xuiRect); + m_Tooltips.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + if(fMaxLen<fMaxTextLen) + { + float fWidth; + XuiElementGetPosition(m_hObj,&vec); + XuiElementGetBounds(m_hObj,&fWidth,&fHeight); + + // need to centre the scene now the size has changed + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + // scene width needs to be more that the text width on buttons + fWidth=vSlider.x; + vec.x=floorf((640.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + else + { + fWidth=vSlider.x; + vec.x=floorf((1280.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + // Need to refresh the scenes visual since the object size has now changed + XuiControlAttachVisual(m_hObj); + + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + if(bNotInGame) + { + float fDiffTextW; + // reposition the difficulty text - this is positioned from the scene, so will be a negative value + m_DifficultyText.GetPosition(&vec); + m_DifficultyText.GetBounds(&fDiffTextW,&fHeight); + vec.x=floor((fMaxTextLen+(fWidth*2.0f)-fDiffTextW)/2.0f); + m_DifficultyText.SetPosition(&vec); + } + + // centre is vec.x+(fWidth/2) + //for(int i=0;i<OPTIONS_SLIDER_SETTINGS_MAX;i++) + //{ + // hr=XuiElementGetChildById(m_SliderA[i].m_hObj,L"XuiSlider",&hSlider); + // XuiElementGetPosition(hSlider,&vec); + // XuiElementGetBounds(hSlider,&fTemp,&fHeight); + // XuiElementSetBounds(hSlider,fMaxTextLen,fHeight); + //} + + // the checkboxes are left aligned - put them at the same position as the sliders + m_ViewBob.SetBounds(fMaxTextLen,fHeight); + m_InGameGamertags.SetBounds(fMaxTextLen,fHeight); + m_Hints.SetBounds(fMaxTextLen,fHeight); + m_Tooltips.SetBounds(fMaxTextLen,fHeight); + + } + } + + return S_OK; +} + + +HRESULT CScene_SettingsOptions::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsOptions.h b/Minecraft.Client/Common/XUI/XUI_SettingsOptions.h new file mode 100644 index 00000000..020e7653 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsOptions.h @@ -0,0 +1,67 @@ +#pragma once + +#include "../media/xuiscene_settings_options.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + +#define SLIDER_SETTINGS_AUTOSAVE 0 +#define SLIDER_SETTINGS_DIFFICULTY 1 + +#define OPTIONS_SLIDER_SETTINGS_MAX SLIDER_SETTINGS_DIFFICULTY + 1 +class CScene_SettingsOptions : public CXuiSceneImpl +{ +protected: + CXuiCtrlSliderWrapper m_SliderA[OPTIONS_SLIDER_SETTINGS_MAX]; + CXuiControl m_DifficultyText; + CXuiCheckbox m_ViewBob; + CXuiCheckbox m_InGameGamertags; + CXuiCheckbox m_Hints; + CXuiCheckbox m_Tooltips; + CXuiCheckbox m_MashUpWorlds; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiViewBob, m_ViewBob) + MAP_CONTROL(IDC_XuiInGameGamertags, m_InGameGamertags) + MAP_CONTROL(IDC_XuiShowHints, m_Hints) + MAP_CONTROL(IDC_XuiShowTooltips, m_Tooltips) + MAP_CONTROL(IDC_XuiSliderAutosave, m_SliderA[SLIDER_SETTINGS_AUTOSAVE]) + MAP_CONTROL(IDC_XuiSliderDifficulty, m_SliderA[SLIDER_SETTINGS_DIFFICULTY]) + MAP_CONTROL(IDC_XuiDifficultyText, m_DifficultyText) + MAP_CONTROL(IDC_XuiMashUpWorlds, m_MashUpWorlds) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + int m_iPad; + static int m_iDifficultySettingA[4]; + static int m_iDifficultyTitleSettingA[4]; + static int m_iAutosaveSettingA[4]; + + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsOptions, L"CScene_SettingsOptions", XUI_CLASS_SCENE ) + +private: + bool m_bMashUpWorldsUnhideOption; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsUI.cpp b/Minecraft.Client/Common/XUI/XUI_SettingsUI.cpp new file mode 100644 index 00000000..da95d084 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsUI.cpp @@ -0,0 +1,376 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "..\XUI\XUI_SettingsUI.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsUI::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + WCHAR TempString[256]; + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + bool bPrimaryPlayer = ProfileManager.GetPrimaryPad()==m_iPad; + + MapChildControls(); + + m_SplitScreen.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_SplitScreenVertical)!=0)?TRUE:FALSE); + m_SplitScreen.SetText(app.GetString( IDS_CHECKBOX_VERTICAL_SPLIT_SCREEN ) ); + + m_SplitScreenGamertags.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_DisplaySplitscreenGamertags)!=0)?TRUE:FALSE); + m_SplitScreenGamertags.SetText(app.GetString( IDS_CHECKBOX_DISPLAY_SPLITSCREENGAMERTAGS )); + + m_SliderA[SLIDER_SETTINGS_UISIZE].SetValue(app.GetGameSettings(m_iPad,eGameSetting_UISize)+1); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZE ),app.GetGameSettings(m_iPad,eGameSetting_UISize)+1); + m_SliderA[SLIDER_SETTINGS_UISIZE].SetText(TempString); + + m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].SetValue(app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1); + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZESPLITSCREEN ),app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1); + m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].SetText(TempString); + + m_DisplayHUD.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_DisplayHUD)!=0)?TRUE:FALSE); + m_DisplayHUD.SetText(app.GetString( IDS_CHECKBOX_DISPLAY_HUD )); + + m_DisplayHand.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_DisplayHand)!=0)?TRUE:FALSE); + m_DisplayHand.SetText(app.GetString( IDS_CHECKBOX_DISPLAY_HAND )); + + m_DeathMessages.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_DeathMessages)!=0)?TRUE:FALSE); + m_DeathMessages.SetText(app.GetString( IDS_CHECKBOX_DEATH_MESSAGES )); + + m_AnimatedCharacter.SetCheck( (app.GetGameSettings(m_iPad,eGameSetting_AnimatedCharacter)!=0)?TRUE:FALSE); + m_AnimatedCharacter.SetText(app.GetString( IDS_CHECKBOX_ANIMATED_CHARACTER )); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + // If the game has started, then you need to be the host to change the in-game gamertags + if(!bPrimaryPlayer) + { + // hide things we don't want the splitscreen player changing + m_SplitScreen.SetShow(FALSE); + m_SplitScreen.SetEnable(FALSE); + m_SplitScreenGamertags.SetShow(FALSE); + m_SplitScreenGamertags.SetEnable(FALSE); + + // move the sliders up, and resize the scene + float fRemoveHeight=0.0f, fHeight, fWidth; + D3DXVECTOR3 vec; + + m_SplitScreen.GetBounds(&fWidth, &fHeight); + fRemoveHeight+=fHeight+4.0f; // add padding + m_SplitScreenGamertags.GetBounds(&fWidth, &fHeight); + fRemoveHeight+=fHeight+4.0f; // add padding + + m_SliderA[SLIDER_SETTINGS_UISIZE].GetPosition(&vec); + vec.y-=fRemoveHeight; + m_SliderA[SLIDER_SETTINGS_UISIZE].SetPosition(&vec); + m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].GetPosition(&vec); + vec.y-=fRemoveHeight; + m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].SetPosition(&vec); + + GetBounds(&fWidth, &fHeight); + fHeight-=fRemoveHeight; + SetBounds(fWidth, fHeight); + } + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + } + + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, TRUE ); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsUI::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + WCHAR TempString[256]; + + if(hObjSource==m_SliderA[SLIDER_SETTINGS_UISIZE].GetSlider() ) + { + // slider is 1 to 3 + + // is this different from the current value? + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZE ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_UISIZE].SetText(TempString); + if(pNotifyValueChanged->nValue != app.GetGameSettings(m_iPad,eGameSetting_UISize)+1) + { + app.SetGameSettings(m_iPad,eGameSetting_UISize,pNotifyValueChanged->nValue-1); + // Apply the changes to the selected text position + CXuiSceneBase::UpdateSelectedItemPos(m_iPad); + } + } + else if(hObjSource==m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].GetSlider() ) + { + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZESPLITSCREEN ),pNotifyValueChanged->nValue); + m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].SetText(TempString); + + if(pNotifyValueChanged->nValue != app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1) + { + // slider is 1 to 3 + app.SetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen,pNotifyValueChanged->nValue-1); + // Apply the changes to the selected text position + CXuiSceneBase::UpdateSelectedItemPos(m_iPad); + } + } + + return S_OK; +} + + +HRESULT CScene_SettingsUI::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + + // not in this scene - app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + // check the checkboxes + app.SetGameSettings(m_iPad,eGameSetting_DisplayHUD,m_DisplayHUD.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_DisplayHand,m_DisplayHand.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_DisplaySplitscreenGamertags,m_SplitScreenGamertags.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_DeathMessages,m_DeathMessages.IsChecked()?1:0); + app.SetGameSettings(m_iPad,eGameSetting_AnimatedCharacter,m_AnimatedCharacter.IsChecked()?1:0); + + // if the splitscreen vertical/horizontal has changed, need to update the scenes + if(app.GetGameSettings(m_iPad,eGameSetting_SplitScreenVertical)!=(m_SplitScreen.IsChecked()?1:0)) + { + // changed + app.SetGameSettings(m_iPad,eGameSetting_SplitScreenVertical,m_SplitScreen.IsChecked()?1:0); + + // close the xui scenes, so we don't have the navigate backed to menu at the wrong place + if(app.GetLocalPlayerCount()==2) + { + app.CloseAllPlayersXuiScenes(); + } + else + { + app.NavigateBack(pInputData->UserIndex); + } + } + else + { + app.NavigateBack(pInputData->UserIndex); + } + + + rfHandled = TRUE; + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SettingsUI::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SettingsUI::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + // added so we can skip greyed out items + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest!=NULL) + { + bHandled=TRUE; + } + + return S_OK; +} + +HRESULT CScene_SettingsUI::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + HRESULT hr; + WCHAR TempString[256]; + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + // 4J-PB - Going to resize buttons if the text is too big to fit on any of them (Br-pt problem with the length of Unlock Full Game) + + float fMaxTextLen=0.0f; + float fMaxLen=0.0f; + + // sliders first + HXUIOBJ hSlider,hVisual,hText,hCheckboxText; + XUIRect xuiRect; + float fWidth,fHeight;//,fTemp; + D3DXVECTOR3 vec,vecCheckboxText,vSlider,vecCheckbox; + + hr=XuiControlGetVisual(m_SplitScreen.m_hObj,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Button",&hCheckboxText); + hr=XuiElementGetPosition(hCheckboxText,&vecCheckboxText); + hr=XuiElementGetPosition(m_SplitScreen.m_hObj,&vecCheckbox); + hr=XuiElementGetChildById(m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN].m_hObj,L"XuiSlider",&hSlider); + hr=XuiControlGetVisual(hSlider,&hVisual); + hr=XuiElementGetChildById(hVisual,L"text_Label",&hText); + hr=XuiElementGetPosition(m_SliderA[SLIDER_SETTINGS_UISIZE].m_hObj,&vSlider); + + + // don't display values on these - we handle that + for(int i=0;i<SLIDER_SETTINGS_UI_MAX;i++) + { + m_SliderA[i].SetValueDisplay(FALSE); + } + + for(int i=0;i<SLIDER_SETTINGS_UI_MAX;i++) + { + switch(i) + { + case SLIDER_SETTINGS_UISIZE: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZE ),3); + break; + case SLIDER_SETTINGS_UISIZESPLITSCREEN: // 3 digits + swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZESPLITSCREEN ),3); + break; + } + + //LPCWSTR temp=m_SliderA[i].GetText(); + hr=XuiTextPresenterMeasureText(hText, TempString, &xuiRect); + // 4J-PB - the text measuring doesn't seem to be long enough - add a fudge + xuiRect.right+=25.0f; + m_SliderA[i].GetBounds(&fWidth,&fHeight); + if(xuiRect.right>fMaxTextLen) fMaxTextLen=xuiRect.right; + if(fWidth>fMaxLen) fMaxLen=fWidth; + } + + // now the m_SplitScreen checkbox - let's just use the visual we already have... + + hr=XuiTextPresenterMeasureText(hCheckboxText, m_SplitScreen.GetText(), &xuiRect); + m_SplitScreen.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + // now the m_SplitScreenGamertags checkbox - let's just use the visual we already have... + + hr=XuiTextPresenterMeasureText(hCheckboxText, m_SplitScreenGamertags.GetText(), &xuiRect); + m_SplitScreenGamertags.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + // now the m_DisplayHUD checkbox - let's just use the visual we already have... + + hr=XuiTextPresenterMeasureText(hCheckboxText, m_DisplayHUD.GetText(), &xuiRect); + m_DisplayHUD.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + + // now the m_DisplayHand checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hCheckboxText, m_DisplayHand.GetText(), &xuiRect); + m_DisplayHand.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + + // now the m_DeathMessages checkbox - let's just use the visual we already have... + hr=XuiTextPresenterMeasureText(hCheckboxText, m_DeathMessages.GetText(), &xuiRect); + m_DeathMessages.GetBounds(&fWidth,&fHeight); + // need to add the size of the checkbox graphic + if((xuiRect.right+vecCheckbox.x+vecCheckboxText.x)>fMaxTextLen) fMaxTextLen=xuiRect.right+vecCheckbox.x+vecCheckboxText.x; + if(fWidth>fMaxLen) fMaxLen=fWidth; + + if(fMaxLen<fMaxTextLen) + { + float fWidth; + XuiElementGetPosition(m_hObj,&vec); + XuiElementGetBounds(m_hObj,&fWidth,&fHeight); + + // need to centre the scene now the size has changed + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + // scene width needs to be more that the text width on buttons + fWidth=vSlider.x; + vec.x=floorf((640.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + else + { + fWidth=vSlider.x; + vec.x=floorf((1280.0f-(fMaxTextLen+fWidth))/2.0f); + XuiElementSetPosition(m_hObj,&vec); + XuiElementSetBounds(m_hObj,fMaxTextLen+(fWidth*2.0f),fHeight); + } + + m_SplitScreen.SetBounds(fMaxTextLen,fHeight); + m_SplitScreenGamertags.SetBounds(fMaxTextLen,fHeight); + m_DisplayHUD.SetBounds(fMaxTextLen,fHeight); + m_DisplayHand.SetBounds(fMaxTextLen,fHeight); + m_DeathMessages.SetBounds(fMaxTextLen,fHeight); + + // Need to refresh the scenes visual since the object size has now changed + XuiControlAttachVisual(m_hObj); + } + } + + return S_OK; +} + +HRESULT CScene_SettingsUI::OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled) +{ + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + } + + return S_OK; +} + +HRESULT CScene_SettingsUI::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + diff --git a/Minecraft.Client/Common/XUI/XUI_SettingsUI.h b/Minecraft.Client/Common/XUI/XUI_SettingsUI.h new file mode 100644 index 00000000..12bffead --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SettingsUI.h @@ -0,0 +1,65 @@ +#pragma once + +#include "../media/xuiscene_settings_UI.h" +#include "XUI_Ctrl_SliderWrapper.h" +#include "XUI_CustomMessages.h" + + +#define SLIDER_SETTINGS_UISIZE 0 +#define SLIDER_SETTINGS_UISIZESPLITSCREEN 1 + + +#define SLIDER_SETTINGS_UI_MAX SLIDER_SETTINGS_UISIZESPLITSCREEN + 1 +class CScene_SettingsUI : public CXuiSceneImpl +{ +protected: + CXuiCtrlSliderWrapper m_SliderA[SLIDER_SETTINGS_UI_MAX]; + CXuiCheckbox m_DisplayHUD; + CXuiCheckbox m_DisplayHand; + CXuiCheckbox m_DeathMessages; + CXuiCheckbox m_AnimatedCharacter; + CXuiCheckbox m_SplitScreen; + CXuiCheckbox m_SplitScreenGamertags; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_VALUE_CHANGED( OnNotifyValueChanged ) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_NAV_RETURN(OnNavReturn) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiSplitScreen, m_SplitScreen) + MAP_CONTROL(IDC_XuiShowSplitscreenGamertags, m_SplitScreenGamertags) + MAP_CONTROL(IDC_XuiDisplayHUD, m_DisplayHUD) + MAP_CONTROL(IDC_XuiDisplayHand, m_DisplayHand) + MAP_CONTROL(IDC_XuiDisplayDeathMessages, m_DeathMessages) + MAP_CONTROL(IDC_XuiShowAnimatedCharacter, m_AnimatedCharacter) + MAP_CONTROL(IDC_XuiSliderUISize, m_SliderA[SLIDER_SETTINGS_UISIZE]) + MAP_CONTROL(IDC_XuiSliderUISizeSplitscreen, m_SliderA[SLIDER_SETTINGS_UISIZESPLITSCREEN]) + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SettingsUI, L"CScene_SettingsUI", XUI_CLASS_SCENE ) +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SignEntry.cpp b/Minecraft.Client/Common/XUI/XUI_SignEntry.cpp new file mode 100644 index 00000000..378ac147 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SignEntry.cpp @@ -0,0 +1,113 @@ +#include "stdafx.h" +#include "..\..\..\MultiplayerLevel.h" +#include "..\..\..\Minecraft.World\SignTileEntity.h" +#include "..\..\..\Minecraft.World\Entity.h" +#include "..\..\..\Minecraft.World\Level.h" +#include "..\..\..\Minecraft.Client\LocalPlayer.h" +#include "..\..\..\Minecraft.Client\ClientConnection.h" +#include "..\..\..\Minecraft.Client\MultiPlayerLocalPlayer.h" +#include "XUI_SignEntry.h" + +HRESULT CScene_SignEntry::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + + XuiControlSetText(m_ButtonDone,app.GetString(IDS_DONE)); + XuiControlSetText(m_labelEditSign,app.GetString(IDS_EDIT_SIGN_MESSAGE)); + + SignEntryScreenInput* initData = (SignEntryScreenInput*)pInitData->pvInitData; + m_sign = initData->sign; + + CXuiSceneBase::ShowDarkOverlay( initData->iPad, TRUE ); + CXuiSceneBase::ShowLogo( initData->iPad, FALSE); + ui.SetTooltips( initData->iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,initData->iPad); + } + + + for(unsigned int i = 0; i<SIGN_ENTRY_ROWS_MAX; ++i) + { + // Have to have the Latin alphabet here, since that's what we have on the sign in-game + // but because the JAP/KOR/CHN fonts don't have extended European characters, let's restrict those languages to not having the extended character set, since they can't see what they are typing + switch(XGetLanguage()) + { + case XC_LANGUAGE_JAPANESE: + case XC_LANGUAGE_TCHINESE: + case XC_LANGUAGE_KOREAN: + m_signRows[i].SetKeyboardType(C_4JInput::EKeyboardMode_Alphabet); + break; + default: + m_signRows[i].SetKeyboardType(C_4JInput::EKeyboardMode_Full); + break; + } + + m_signRows[i].SetText( m_sign->GetMessage(i).c_str() ); + m_signRows[i].SetTextLimit(15); + // Set the title and desc for the edit keyboard popup + m_signRows[i].SetTitleAndText(IDS_SIGN_TITLE,IDS_SIGN_TITLE_TEXT); + } + + + return S_OK; +} + +HRESULT CScene_SignEntry::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_ButtonDone) + { + // Set the sign text here so we on;y call the verify once it has been set, not while we're typing in to it + for(int i=0;i<4;i++) + { + wstring temp=m_signRows[i].GetText(); + m_sign->SetMessage(i,temp); + } + + m_sign->setChanged(); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + // need to send the new data + if (pMinecraft->level->isClientSide) + { + shared_ptr<MultiplayerLocalPlayer> player = pMinecraft->localplayers[pNotifyPressData->UserIndex]; + if(player != NULL && player->connection && player->connection->isStarted()) + { + player->connection->send( shared_ptr<SignUpdatePacket>( new SignUpdatePacket(m_sign->x, m_sign->y, m_sign->z, m_sign->IsVerified(), m_sign->IsCensored(), m_sign->GetMessages()) ) ); + } + } + app.CloseXuiScenes(pNotifyPressData->UserIndex); + } + return S_OK; +} + +HRESULT CScene_SignEntry::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + // user backed out, so wipe the sign + wstring temp=L""; + + for(int i=0;i<4;i++) + { + m_sign->SetMessage(i,temp); + } + + app.CloseXuiScenes(pInputData->UserIndex); + rfHandled = TRUE; + + CXuiSceneBase::PlayUISFX(eSFX_Back); + break; + } + + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SignEntry.h b/Minecraft.Client/Common/XUI/XUI_SignEntry.h new file mode 100644 index 00000000..4f8c44d2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SignEntry.h @@ -0,0 +1,49 @@ +#pragma once +#include "../media/xuiscene_signentry.h" +#include "XUI_Ctrl_4JEdit.h" +#include "XUI_CustomMessages.h" + +#define SIGN_ENTRY_ROWS_MAX 4 + +class SignTileEntity; + +class CScene_SignEntry : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiCtrl4JEdit m_signRows[4]; + CXuiControl m_ButtonDone; + CXuiControl m_labelEditSign; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_EditSignMessage, m_labelEditSign) + MAP_CONTROL(IDC_ButtonDone, m_ButtonDone) + MAP_CONTROL(IDC_EditLineOne, m_signRows[0]) + MAP_CONTROL(IDC_EditLineTwo, m_signRows[1]) + MAP_CONTROL(IDC_EditLineThree, m_signRows[2]) + MAP_CONTROL(IDC_EditLineFour, m_signRows[3]) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SignEntry, L"CScene_SignEntry", XUI_CLASS_SCENE ) + +private: + shared_ptr<SignTileEntity> m_sign; + D3DXVECTOR3 m_OriginalPosition; + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SkinSelect.cpp b/Minecraft.Client/Common/XUI/XUI_SkinSelect.cpp new file mode 100644 index 00000000..ee706610 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SkinSelect.cpp @@ -0,0 +1,1444 @@ +#include "stdafx.h" +#include "XUI_SkinSelect.h" +#include "XUI_Ctrl_MinecraftSkinPreview.h" + +#define SKIN_SELECT_PACK_DEFAULT 0 +#define SKIN_SELECT_PACK_FAVORITES 1 +//#define SKIN_SELECT_PACK_PLAYER_CUSTOM 1 +#define SKIN_SELECT_MAX_DEFAULTS 2 + +WCHAR *CScene_SkinSelect::wchDefaultNamesA[]= +{ + L"USE LOCALISED VERSION", // Server selected + L"Steve", + L"Tennis Steve", + L"Tuxedo Steve", + L"Athlete Steve", + L"Scottish Steve", + L"Prisoner Steve", + L"Cyclist Steve", + L"Boxer Steve", +}; + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SkinSelect::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad=*(int *)pInitData->pvInitData; + // if we're not in the game, we need to use basescene 0 + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + m_bIgnoreInput=false; + + // 4J Stu - Added this so that we have skins loaded + // 4J-PB - Need to check for installed DLC + //if( (!app.DLCInstalled() || app.m_dlcManager.NeedsUpdated()) && !app.DLCInstallPending()) app.StartInstallDLCProcess(m_iPad); + + // StartInstallDLCProcess will check for all conditions within the call + MapChildControls(); + + m_selectedText.SetText( app.GetString( IDS_SELECTED ) ); + + updateClipping(); + + m_packIndex = SKIN_SELECT_PACK_DEFAULT; + m_skinIndex = 0; + m_currentSkinPath = app.GetPlayerSkinName(m_iPad); + m_originalSkinId = app.GetPlayerSkinId(m_iPad); + m_currentPack = NULL; + m_bSlidingSkins = false; + m_bAnimatingMove = false; + currentPackCount = 0; + + m_currentNavigation = eSkinNavigation_Skin; + m_normalTabs.SetShow( TRUE ); + m_selectedTabs.SetShow( FALSE ); + m_packLeft.SetEnable(FALSE); + m_packRight.SetEnable(FALSE); + + + for(BYTE i = 0; i < sidePreviewControls; ++i) + { + //m_previewNextControl->SetAutoRotate(true); + m_previewNextControls[i]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Left); + //m_previewPreviousControl->SetAutoRotate(true); + m_previewPreviousControls[i]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Right); + } + + // block input if we're waiting for DLC to install. The end of dlc mounting custom message will fill the save list + if(app.StartInstallDLCProcess(m_iPad)) + { + // DLC mounting in progress, so disable input + m_bIgnoreInput=true; + m_timer.SetShow( TRUE ); + m_charactersGroup.SetShow( FALSE ); + m_skinDetails.SetShow( FALSE ); + m_imagePadlock.SetShow( FALSE ); + m_selectedGroup.SetShow( FALSE ); + } + else + { + m_timer.SetShow( FALSE ); + + if(app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin)>0) + { + // Change to display the favorites if there are any. The current skin will be in there (probably) - need to check for it + m_currentPack = app.m_dlcManager.getPackContainingSkin(m_currentSkinPath); + bool bFound; + if(m_currentPack != NULL) + { + m_packIndex = app.m_dlcManager.getPackIndex(m_currentPack,bFound,DLCManager::e_DLCType_Skin) + SKIN_SELECT_MAX_DEFAULTS; + } + } + + // If we have any favourites, set this to the favourites + // first validate the favorite skins - we might have uninstalled the DLC needed for them + app.ValidateFavoriteSkins(m_iPad); + + if(app.GetPlayerFavoriteSkinsCount(m_iPad)>0) + { + m_packIndex = SKIN_SELECT_PACK_FAVORITES; + } + + handlePackIndexChanged(); + updateCurrentFocus(); + } + + // Display the tooltips + + // if we're not in the game, we need to use basescene 0 + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT_SKIN,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT_SKIN,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + } + + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad, false); + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + else + { + if(bNotInGame) + { + CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, FALSE ); + } + else + { + CXuiSceneBase::ShowLogo( m_iPad, FALSE ); + } + } + + return S_OK; +} + + +HRESULT CScene_SkinSelect::OnKeyUp(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + switch(pInputData->dwKeyCode) + { + case VK_PAD_RTHUMB_LEFT: + m_previewControl->m_incYRot = false; + break; + case VK_PAD_RTHUMB_RIGHT: + m_previewControl->m_decYRot = false; + break; + case VK_PAD_RTHUMB_UP: + //m_previewControl->m_incXRot = false; + break; + case VK_PAD_RTHUMB_DOWN: + //m_previewControl->m_decXRot = false; + break; + case VK_PAD_RTHUMB_UPLEFT: + m_previewControl->m_incYRot = false; + //m_previewControl->m_incXRot = false; + break; + case VK_PAD_RTHUMB_UPRIGHT: + m_previewControl->m_decYRot = false; + //m_previewControl->m_incXRot = false; + break; + case VK_PAD_RTHUMB_DOWNRIGHT: + m_previewControl->m_decYRot = false; + //m_previewControl->m_decXRot = false; + break; + case VK_PAD_RTHUMB_DOWNLEFT: + m_previewControl->m_incYRot = false; + //m_previewControl->m_decXRot = false; + break; + } + return S_OK; +} + + +HRESULT CScene_SkinSelect::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // 4J Stu - We don't want the press anim to play for the scrolling unless we are actually scrolling + //ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // ignore any key press if we are animating a move + //if(m_bAnimatingMove) return S_OK; + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_A: + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + app.SetPlayerSkin(pInputData->UserIndex, m_skinIndex); + app.SetPlayerCape(pInputData->UserIndex, 0); + m_currentSkinPath = app.GetPlayerSkinName(m_iPad); + m_originalSkinId = app.GetPlayerSkinId(m_iPad); + m_selectedGroup.SetShow( TRUE ); + CXuiSceneBase::PlayUISFX(eSFX_Press); + break; + case SKIN_SELECT_PACK_FAVORITES: + if(app.GetPlayerFavoriteSkinsCount(m_iPad)>0) + { + // get the pack number from the skin id + wchar_t chars[256]; + swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(m_iPad,m_skinIndex)); + + DLCPack *Pack=app.m_dlcManager.getPackContainingSkin(chars); + + if(Pack) + { + DLCSkinFile *skinFile = Pack->getSkinFile(chars); + app.SetPlayerSkin(pInputData->UserIndex, skinFile->getPath()); + app.SetPlayerCape(pInputData->UserIndex, skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape)); + m_selectedGroup.SetShow( TRUE ); + m_currentSkinPath = app.GetPlayerSkinName(m_iPad); + m_originalSkinId = app.GetPlayerSkinId(m_iPad); + app.SetPlayerFavoriteSkinsPos(m_iPad,m_skinIndex); + } + } + break; + default: + if( m_currentPack != NULL ) + { + DLCSkinFile *skinFile = m_currentPack->getSkinFile(m_skinIndex); + + // Is this a free skin? + + if(!skinFile->getParameterAsBool( DLCManager::e_DLCParamType_Free )) + { + // do we have a license? + if(!m_currentPack->hasPurchasedFile( DLCManager::e_DLCType_Skin, skinFile->getPath() )) + { + // no + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + + // We need to upsell the full version + if(ProfileManager.IsGuest(m_iPad)) + { + // can't buy + StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); + } + // are we online? + else if(!ProfileManager.IsSignedInLive(pInputData->UserIndex)) + { + // need to be signed in to live + StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); + } + else + { + // upsell + + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(m_currentPack->getPurchaseOfferId()); + ULONGLONG ullOfferID_Full; + + if(pDLCInfo!=NULL) + { + ullOfferID_Full=pDLCInfo->ullOfferID_Full; + } + else + { + ullOfferID_Full=m_currentPack->getPurchaseOfferId(); + } + + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(pInputData->UserIndex, eSet_UpsellID_Skin_DLC, ullOfferID_Full & 0xFFFFFFFF); + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + StorageManager.RequestMessageBox(IDS_UNLOCK_DLC_TITLE, IDS_UNLOCK_DLC_SKIN, uiIDA, 2, pInputData->UserIndex,&CScene_SkinSelect::UnlockSkinReturned,this,app.GetStringTable()); + } + } + else + { + app.SetPlayerSkin(pInputData->UserIndex, skinFile->getPath()); + app.SetPlayerCape(pInputData->UserIndex, skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape)); + m_selectedGroup.SetShow( TRUE ); + m_currentSkinPath = app.GetPlayerSkinName(m_iPad); + m_originalSkinId = app.GetPlayerSkinId(m_iPad); + + // push this onto the favorite list + AddFavoriteSkin(m_iPad,GET_DLC_SKIN_ID_FROM_BITMASK(m_originalSkinId)); + } + } + else + { + app.SetPlayerSkin(pInputData->UserIndex, skinFile->getPath()); + app.SetPlayerCape(pInputData->UserIndex, skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape)); + m_selectedGroup.SetShow( TRUE ); + m_currentSkinPath = app.GetPlayerSkinName(m_iPad); + m_originalSkinId = app.GetPlayerSkinId(m_iPad); + + // push this onto the favorite list + AddFavoriteSkin(m_iPad,GET_DLC_SKIN_ID_FROM_BITMASK(m_originalSkinId)); + + } + } + + CXuiSceneBase::PlayUISFX(eSFX_Press); + break; + } + + break; + case VK_PAD_B: + case VK_ESCAPE: + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + app.CheckGameSettingsChanged(true,pInputData->UserIndex); + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; +#if 0 + case VK_PAD_RSHOULDER: + { + DWORD startingIndex = m_packIndex; + m_packIndex = getNextPackIndex(m_packIndex); + if(startingIndex != m_packIndex) + { + handlePackIndexChanged(); + } + } + break; + case VK_PAD_LSHOULDER: + { + DWORD startingIndex = m_packIndex; + m_packIndex = getPreviousPackIndex(m_packIndex); + if(startingIndex != m_packIndex) + { + handlePackIndexChanged(); + } + } + break; +#endif + case VK_PAD_DPAD_UP: + case VK_PAD_LTHUMB_UP: + case VK_PAD_DPAD_DOWN: + case VK_PAD_LTHUMB_DOWN: + { + if(m_packIndex==SKIN_SELECT_PACK_FAVORITES) + { + if(app.GetPlayerFavoriteSkinsCount(m_iPad)==0) + { + // ignore this, since there are no skins being displayed + break; + } + } + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + switch(m_currentNavigation) + { + case eSkinNavigation_Pack: + m_currentNavigation = eSkinNavigation_Skin; + break; + case eSkinNavigation_Skin: + m_currentNavigation = eSkinNavigation_Pack; + break; + }; + updateCurrentFocus(); + } + break; + case VK_PAD_DPAD_LEFT: + case VK_PAD_LTHUMB_LEFT: + { + if( m_currentNavigation == eSkinNavigation_Skin ) + { + if(!m_bAnimatingMove) + { + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + + m_skinIndex = getPreviousSkinIndex(m_skinIndex); + //handleSkinIndexChanged(); + + m_bSlidingSkins = true; + m_bAnimatingMove = true; + + m_previewControl->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Left, true); + m_previewPreviousControls[0]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Forward, true); + + int startFrame, endFrame; + HRESULT hr = m_charactersGroup.FindNamedFrame(L"CycleRight", &startFrame); + hr = m_charactersGroup.FindNamedFrame( L"EndCycleRight", &endFrame); + hr = m_charactersGroup.PlayTimeline(startFrame, startFrame,endFrame,FALSE,FALSE); + } + } + else if( m_currentNavigation == eSkinNavigation_Pack ) + { + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + DWORD startingIndex = m_packIndex; + m_packIndex = getPreviousPackIndex(m_packIndex); + if(startingIndex != m_packIndex) + { + handlePackIndexChanged(); + } + } + } + break; + case VK_PAD_DPAD_RIGHT: + case VK_PAD_LTHUMB_RIGHT: + { + if( m_currentNavigation == eSkinNavigation_Skin ) + { + if(!m_bAnimatingMove) + { + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + m_skinIndex = getNextSkinIndex(m_skinIndex); + //handleSkinIndexChanged(); + + m_bSlidingSkins = true; + m_bAnimatingMove = true; + + m_previewControl->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Right, true); + m_previewNextControls[0]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Forward, true); + + int startFrame, endFrame; + HRESULT hr = m_charactersGroup.FindNamedFrame(L"CycleLeft", &startFrame); + hr = m_charactersGroup.FindNamedFrame( L"EndCycleLeft", &endFrame); + hr = m_charactersGroup.PlayTimeline(startFrame, startFrame,endFrame,FALSE,FALSE); + } + } + else if( m_currentNavigation == eSkinNavigation_Pack ) + { + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + DWORD startingIndex = m_packIndex; + m_packIndex = getNextPackIndex(m_packIndex); + if(startingIndex != m_packIndex) + { + handlePackIndexChanged(); + } + } + } + break; + case VK_PAD_RTHUMB_PRESS: + CXuiSceneBase::PlayUISFX(eSFX_Press); + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->ResetRotation(); + } + break; + case VK_PAD_RTHUMB_LEFT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_incYRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_RIGHT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_decYRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_UP: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + //m_previewControl->m_incXRot = true; + m_previewControl->CyclePreviousAnimation(); + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_DOWN: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + //m_previewControl->m_decXRot = true; + m_previewControl->CycleNextAnimation(); + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_UPLEFT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_incYRot = true; + //m_previewControl->m_incXRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_UPRIGHT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_decYRot = true; + //m_previewControl->m_incXRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_DOWNRIGHT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_decYRot = true; + //m_previewControl->m_decXRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + case VK_PAD_RTHUMB_DOWNLEFT: + if( m_currentNavigation == eSkinNavigation_Skin ) + { + m_previewControl->m_incYRot = true; + //m_previewControl->m_decXRot = true; + } + else + { + CXuiSceneBase::PlayUISFX(eSFX_Scroll); + } + break; + } + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SkinSelect::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + return S_OK; +} + +HRESULT CScene_SkinSelect::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) + { + + } + + return S_OK; +} + +HRESULT CScene_SkinSelect::OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled) +{ + if( hObjSource == m_charactersGroup ) + { + if(m_bSlidingSkins) + { + m_bSlidingSkins = false; + + int startFrame, endFrame; + HRESULT hr = m_charactersGroup.FindNamedFrame(L"Normal", &startFrame); + hr = m_charactersGroup.FindNamedFrame( L"Normal", &endFrame); + hr = m_charactersGroup.PlayTimeline(startFrame, startFrame,endFrame,FALSE,FALSE); + } + else + { + m_previewControl->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Forward, false); + m_previewNextControls[0]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Left, false); + m_previewPreviousControls[0]->SetFacing(CXuiCtrlMinecraftSkinPreview::e_SkinPreviewFacing_Right, false); + + handleSkinIndexChanged(); + + m_bAnimatingMove = false; + + bHandled = TRUE; + } + } + return S_OK; +} + + +HRESULT CScene_SkinSelect::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,false); +} + + + + +HRESULT CScene_SkinSelect::OnBasePositionChanged() +{ + updateClipping(); + + return S_OK; +} + +void CScene_SkinSelect::handleSkinIndexChanged() +{ + BOOL showPrevious = FALSE, showNext = FALSE; + DWORD previousIndex = 0, nextIndex = 0; + wstring skinName = L""; + wstring skinOrigin = L""; + bool bSkinIsFree=false; + bool bLicensed=false; + DLCSkinFile *skinFile=NULL; + DLCPack *Pack=NULL; + BYTE sidePreviewControlsL,sidePreviewControlsR; + bool bNoSkinsToShow=false; + + TEXTURE_NAME backupTexture = TN_MOB_CHAR; + m_selectedGroup.SetShow( FALSE ); + m_skinDetails.SetShow( FALSE ); + + if( m_currentPack != NULL ) + { + skinFile = m_currentPack->getSkinFile(m_skinIndex); + m_selectedSkinPath = skinFile->getPath(); + m_selectedCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + m_vAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + + skinName = skinFile->getParameterAsString( DLCManager::e_DLCParamType_DisplayName ); + skinOrigin = skinFile->getParameterAsString( DLCManager::e_DLCParamType_ThemeName ); + + if( m_selectedSkinPath.compare( m_currentSkinPath ) == 0 ) + { + m_selectedGroup.SetShow( TRUE ); + } + else + { + m_selectedGroup.SetShow( FALSE ); + } + + bSkinIsFree = skinFile->getParameterAsBool( DLCManager::e_DLCParamType_Free ); + bLicensed = m_currentPack->hasPurchasedFile( DLCManager::e_DLCType_Skin, m_selectedSkinPath ); + + m_imagePadlock.SetShow( (bSkinIsFree || bLicensed) ?FALSE:TRUE ); + m_previewControl->SetShow(TRUE); + m_skinDetails.SetShow( TRUE ); + } + else + { + m_selectedSkinPath = L""; + m_selectedCapePath = L""; + m_vAdditionalSkinBoxes = NULL; + + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + backupTexture = getTextureId(m_skinIndex); + + if( m_skinIndex == eDefaultSkins_ServerSelected ) + { + skinName = app.GetString(IDS_DEFAULT_SKINS); + } + else + { + skinName = wchDefaultNamesA[m_skinIndex]; + } + + if( m_originalSkinId == m_skinIndex ) + { + m_selectedGroup.SetShow( TRUE ); + } + else + { + m_selectedGroup.SetShow( FALSE ); + } + m_imagePadlock.SetShow( FALSE ); + m_previewControl->SetShow(TRUE); + m_skinDetails.SetShow( TRUE ); + + break; + case SKIN_SELECT_PACK_FAVORITES: + + if(app.GetPlayerFavoriteSkinsCount(m_iPad)>0) + { + // get the pack number from the skin id + wchar_t chars[256]; + swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(m_iPad,m_skinIndex)); + + Pack=app.m_dlcManager.getPackContainingSkin(chars); + if(Pack) + { + skinFile = Pack->getSkinFile(chars); + + m_selectedSkinPath = skinFile->getPath(); + m_selectedCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + m_vAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + + skinName = skinFile->getParameterAsString( DLCManager::e_DLCParamType_DisplayName ); + skinOrigin = skinFile->getParameterAsString( DLCManager::e_DLCParamType_ThemeName ); + + if( m_selectedSkinPath.compare( m_currentSkinPath ) == 0 ) + { + m_selectedGroup.SetShow( TRUE ); + } + else + { + m_selectedGroup.SetShow( FALSE ); + } + + bSkinIsFree = skinFile->getParameterAsBool( DLCManager::e_DLCParamType_Free ); + bLicensed = Pack->hasPurchasedFile( DLCManager::e_DLCType_Skin, m_selectedSkinPath ); + + m_imagePadlock.SetShow( (bSkinIsFree || bLicensed) ?FALSE:TRUE ); + m_skinDetails.SetShow( TRUE ); + } + else + { + m_selectedGroup.SetShow( FALSE ); + m_imagePadlock.SetShow( FALSE ); + } + } + else + { + //disable the display + m_previewControl->SetShow(FALSE); + // change the tooltips + bNoSkinsToShow=true; + } + break; + + } + } + m_text.SetText(skinName.c_str()); + m_originText.SetText(skinOrigin.c_str()); + + if(m_vAdditionalSkinBoxes && m_vAdditionalSkinBoxes->size()!=0) + { + // add the boxes to the humanoid model, but only if we've not done this already + vector<ModelPart *> *pAdditionalModelParts = app.GetAdditionalModelParts(skinFile->getSkinID()); + if(pAdditionalModelParts==NULL) + { + pAdditionalModelParts = app.SetAdditionalSkinBoxes(skinFile->getSkinID(),m_vAdditionalSkinBoxes); + } + } + + if(skinFile!=NULL) + { + app.SetAnimOverrideBitmask(skinFile->getSkinID(),skinFile->getAnimOverrideBitmask()); + } + + m_previewControl->SetTexture(m_selectedSkinPath, backupTexture); + m_previewControl->SetCapeTexture(m_selectedCapePath); + + showNext = TRUE; + showPrevious = TRUE; + nextIndex = getNextSkinIndex(m_skinIndex); + previousIndex = getPreviousSkinIndex(m_skinIndex); + + wstring otherSkinPath = L""; + wstring otherCapePath = L""; + vector<SKIN_BOX *> *othervAdditionalSkinBoxes=NULL; + wchar_t chars[256]; + + // turn off all displays + for(BYTE i = 0; i < sidePreviewControls; ++i) + { + m_previewNextControls[i]->SetShow(FALSE); + m_previewPreviousControls[i]->SetShow(FALSE); + } + + unsigned int uiCurrentFavoriteC=app.GetPlayerFavoriteSkinsCount(m_iPad); + + if(m_packIndex==SKIN_SELECT_PACK_FAVORITES) + { + // might not be enough to cycle through + if(uiCurrentFavoriteC<((sidePreviewControls*2)+1)) + { + if(uiCurrentFavoriteC==0) + { + sidePreviewControlsL=sidePreviewControlsR=0; + } + // might be an odd number + else if((uiCurrentFavoriteC-1)%2==1) + { + sidePreviewControlsL=1+(uiCurrentFavoriteC-1)/2; + sidePreviewControlsR=(uiCurrentFavoriteC-1)/2; + } + else + { + sidePreviewControlsL=sidePreviewControlsR=(uiCurrentFavoriteC-1)/2; + } + } + else + { + sidePreviewControlsL=sidePreviewControlsR=sidePreviewControls; + } + } + else + { + sidePreviewControlsL=sidePreviewControlsR=sidePreviewControls; + } + + for(BYTE i = 0; i < sidePreviewControlsR; ++i) + { + if(showNext) + { + skinFile=NULL; + m_previewNextControls[i]->SetShow(TRUE); + + if( m_currentPack != NULL ) + { + skinFile = m_currentPack->getSkinFile(nextIndex); + otherSkinPath = skinFile->getPath(); + otherCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + othervAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + backupTexture = TN_MOB_CHAR; + } + else + { + otherSkinPath = L""; + otherCapePath = L""; + othervAdditionalSkinBoxes=NULL; + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + backupTexture = getTextureId(nextIndex); + break; + case SKIN_SELECT_PACK_FAVORITES: + if(uiCurrentFavoriteC>0) + { + // get the pack number from the skin id + swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(m_iPad,nextIndex)); + + Pack=app.m_dlcManager.getPackContainingSkin(chars); + if(Pack) + { + skinFile = Pack->getSkinFile(chars); + + otherSkinPath = skinFile->getPath(); + otherCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + othervAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + backupTexture = TN_MOB_CHAR; + } + } + break; + default: + break; + } + + } + if(othervAdditionalSkinBoxes && othervAdditionalSkinBoxes->size()!=0) + { + vector<ModelPart *> *pAdditionalModelParts = app.GetAdditionalModelParts(skinFile->getSkinID()); + if(pAdditionalModelParts==NULL) + { + pAdditionalModelParts = app.SetAdditionalSkinBoxes(skinFile->getSkinID(),othervAdditionalSkinBoxes); + } + } + // 4J-PB - anim override needs set before SetTexture + if(skinFile!=NULL) + { + app.SetAnimOverrideBitmask(skinFile->getSkinID(),skinFile->getAnimOverrideBitmask()); + } + m_previewNextControls[i]->SetTexture(otherSkinPath, backupTexture); + m_previewNextControls[i]->SetCapeTexture(otherCapePath); + + + } + + nextIndex = getNextSkinIndex(nextIndex); + } + + + + for(BYTE i = 0; i < sidePreviewControlsL; ++i) + { + if(showPrevious) + { + skinFile=NULL; + m_previewPreviousControls[i]->SetShow(TRUE); + + if( m_currentPack != NULL ) + { + skinFile = m_currentPack->getSkinFile(previousIndex); + otherSkinPath = skinFile->getPath(); + otherCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + othervAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + backupTexture = TN_MOB_CHAR; + } + else + { + otherSkinPath = L""; + otherCapePath = L""; + othervAdditionalSkinBoxes=NULL; + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + backupTexture = getTextureId(previousIndex); + break; + case SKIN_SELECT_PACK_FAVORITES: + if(uiCurrentFavoriteC>0) + { + // get the pack number from the skin id + swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(m_iPad,previousIndex)); + + Pack=app.m_dlcManager.getPackContainingSkin(chars); + if(Pack) + { + skinFile = Pack->getSkinFile(chars); + + otherSkinPath = skinFile->getPath(); + otherCapePath = skinFile->getParameterAsString(DLCManager::e_DLCParamType_Cape); + othervAdditionalSkinBoxes = skinFile->getAdditionalBoxes(); + backupTexture = TN_MOB_CHAR; + } + } + + break; + default: + break; + } + } + if(othervAdditionalSkinBoxes && othervAdditionalSkinBoxes->size()!=0) + { + vector<ModelPart *> *pAdditionalModelParts = app.GetAdditionalModelParts(skinFile->getSkinID()); + if(pAdditionalModelParts==NULL) + { + pAdditionalModelParts = app.SetAdditionalSkinBoxes(skinFile->getSkinID(),othervAdditionalSkinBoxes); + } + } + // 4J-PB - anim override needs set before SetTexture + if(skinFile) + { + app.SetAnimOverrideBitmask(skinFile->getSkinID(),skinFile->getAnimOverrideBitmask()); + } + m_previewPreviousControls[i]->SetTexture(otherSkinPath, backupTexture); + m_previewPreviousControls[i]->SetCapeTexture(otherCapePath); + } + + previousIndex = getPreviousSkinIndex(previousIndex); + } + + // update the tooltips + bool bNotInGame=(Minecraft::GetInstance()->level==NULL); + + if(bNoSkinsToShow) + { + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT_SKIN,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + } + + } + else + { + if(bNotInGame) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT_SKIN,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( DEFAULT_XUI_MENU_USER, TRUE ); + } + else + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT_SKIN,IDS_TOOLTIPS_CANCEL,-1,-1,-1,-1,-1,-1,IDS_TOOLTIPS_NAVIGATE); + CXuiSceneBase::ShowBackground( m_iPad, FALSE ); + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + } + + } + + updateCurrentFocus(); +} + +void CScene_SkinSelect::handlePackIndexChanged() +{ + if(m_packIndex >= SKIN_SELECT_MAX_DEFAULTS) + { + m_currentPack = app.m_dlcManager.getPack(m_packIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin); + } + else + { + m_currentPack = NULL; + } + m_skinIndex = 0; + if(m_currentPack != NULL) + { + bool found; + DWORD currentSkinIndex = m_currentPack->getSkinIndexAt(m_currentSkinPath, found); + if(found) m_skinIndex = currentSkinIndex; + } + else + { + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + if( !GET_IS_DLC_SKIN_FROM_BITMASK(m_originalSkinId) ) + { + DWORD ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(m_originalSkinId); + DWORD defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(m_originalSkinId); + if( ugcSkinIndex == 0 ) + { + m_skinIndex = (EDefaultSkins) defaultSkinIndex; + } + } + break; + case SKIN_SELECT_PACK_FAVORITES: + if(app.GetPlayerFavoriteSkinsCount(m_iPad)>0) + { + bool found; + wchar_t chars[256]; + // get the pack number from the skin id + swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(m_iPad,app.GetPlayerFavoriteSkinsPos(m_iPad))); + + DLCPack *Pack=app.m_dlcManager.getPackContainingSkin(chars); + if(Pack) + { + DWORD currentSkinIndex = Pack->getSkinIndexAt(m_currentSkinPath, found); + if(found) m_skinIndex = app.GetPlayerFavoriteSkinsPos(m_iPad); + } + } + break; + default: + break; + } + } + handleSkinIndexChanged(); + updatePackDisplay(); +} + +void CScene_SkinSelect::updatePackDisplay() +{ + currentPackCount = app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) + SKIN_SELECT_MAX_DEFAULTS; + + m_packLeft.SetShow(TRUE); + m_packRight.SetShow(TRUE); + + if(m_packIndex >= SKIN_SELECT_MAX_DEFAULTS) + { + DLCPack *thisPack = app.m_dlcManager.getPack(m_packIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin); + m_packCenter.SetText(thisPack->getName().c_str()); + } + else + { + switch(m_packIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + m_packCenter.SetText(app.GetString(IDS_NO_SKIN_PACK)); + break; + case SKIN_SELECT_PACK_FAVORITES: + m_packCenter.SetText(app.GetString(IDS_FAVORITES_SKIN_PACK)); + break; + } + } + + int nextPackIndex = getNextPackIndex(m_packIndex); + if(nextPackIndex >= SKIN_SELECT_MAX_DEFAULTS) + { + DLCPack *thisPack = app.m_dlcManager.getPack(nextPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin); + m_packRight.SetText(thisPack->getName().c_str()); + } + else + { + switch(nextPackIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + m_packRight.SetText(app.GetString(IDS_NO_SKIN_PACK)); + break; + case SKIN_SELECT_PACK_FAVORITES: + m_packRight.SetText(app.GetString(IDS_FAVORITES_SKIN_PACK)); + break; + } + } + + int previousPackIndex = getPreviousPackIndex(m_packIndex); + if(previousPackIndex >= SKIN_SELECT_MAX_DEFAULTS) + { + DLCPack *thisPack = app.m_dlcManager.getPack(previousPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin); + m_packLeft.SetText(thisPack->getName().c_str()); + } + else + { + switch(previousPackIndex) + { + case SKIN_SELECT_PACK_DEFAULT: + m_packLeft.SetText(app.GetString(IDS_NO_SKIN_PACK)); + break; + case SKIN_SELECT_PACK_FAVORITES: + m_packLeft.SetText(app.GetString(IDS_FAVORITES_SKIN_PACK)); + break; + } + } + +} + +void CScene_SkinSelect::updateCurrentFocus() +{ + XUITimeline *timeline; + XUINamedFrame *startFrame; + XuiElementGetTimeline( m_skinDetails.m_hObj, &timeline); + switch(m_currentNavigation) + { + case eSkinNavigation_Pack: + XuiElementSetUserFocus( m_packCenter.m_hObj, m_iPad ); + startFrame = timeline->FindNamedFrame( L"Unselected" ); + m_normalTabs.SetShow( FALSE ); + m_selectedTabs.SetShow( TRUE ); + m_packLeft.SetEnable(TRUE); + m_packRight.SetEnable(TRUE); + break; + case eSkinNavigation_Skin: + XuiElementSetUserFocus( m_skinDetails.m_hObj, m_iPad ); + startFrame = timeline->FindNamedFrame( L"Selected" ); + m_normalTabs.SetShow( TRUE ); + m_selectedTabs.SetShow( FALSE ); + m_packLeft.SetEnable(FALSE); + m_packRight.SetEnable(FALSE); + break; + }; + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, startFrame->m_dwFrame, FALSE, FALSE ); +} + +TEXTURE_NAME CScene_SkinSelect::getTextureId(int skinIndex) +{ + TEXTURE_NAME texture = TN_MOB_CHAR; + switch(skinIndex) + { + case eDefaultSkins_ServerSelected: + case eDefaultSkins_Skin0: + texture = TN_MOB_CHAR; + break; + case eDefaultSkins_Skin1: + texture = TN_MOB_CHAR1; + break; + case eDefaultSkins_Skin2: + texture = TN_MOB_CHAR2; + break; + case eDefaultSkins_Skin3: + texture = TN_MOB_CHAR3; + break; + case eDefaultSkins_Skin4: + texture = TN_MOB_CHAR4; + break; + case eDefaultSkins_Skin5: + texture = TN_MOB_CHAR5; + break; + case eDefaultSkins_Skin6: + texture = TN_MOB_CHAR6; + break; + case eDefaultSkins_Skin7: + texture = TN_MOB_CHAR7; + break; + }; + + return texture; +} + +int CScene_SkinSelect::getNextSkinIndex(DWORD sourceIndex) +{ + int nextSkin = sourceIndex; + + // special case for favourites + switch(m_packIndex) + { + + case SKIN_SELECT_PACK_FAVORITES: + ++nextSkin; + if(nextSkin>=app.GetPlayerFavoriteSkinsCount(m_iPad)) + { + nextSkin=0; + } + + break; + default: + ++nextSkin; + + if(m_packIndex == SKIN_SELECT_PACK_DEFAULT && nextSkin >= eDefaultSkins_Count) + { + nextSkin = eDefaultSkins_ServerSelected; + } + else if(m_currentPack != NULL && nextSkin>=m_currentPack->getSkinCount()) + { + nextSkin = 0; + } + break; + } + + + return nextSkin; +} + +int CScene_SkinSelect::getPreviousSkinIndex(DWORD sourceIndex) +{ + int previousSkin = sourceIndex; + switch(m_packIndex) + { + + case SKIN_SELECT_PACK_FAVORITES: + if(previousSkin==0) + { + previousSkin = app.GetPlayerFavoriteSkinsCount(m_iPad) - 1; + } + else + { + --previousSkin; + } + break; + default: + if(previousSkin==0) + { + if(m_packIndex == SKIN_SELECT_PACK_DEFAULT) + { + previousSkin = eDefaultSkins_Count - 1; + } + else if(m_currentPack != NULL) + { + previousSkin = m_currentPack->getSkinCount()-1; + } + } + else + { + --previousSkin; + } + break; + } + + + return previousSkin; +} + +int CScene_SkinSelect::getNextPackIndex(DWORD sourceIndex) +{ + int nextPack = sourceIndex; + ++nextPack; + if(nextPack > app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) - 1 + SKIN_SELECT_MAX_DEFAULTS) + { + nextPack = SKIN_SELECT_PACK_DEFAULT; + } + + return nextPack; +} + +int CScene_SkinSelect::getPreviousPackIndex(DWORD sourceIndex) +{ + int previousPack = sourceIndex; + if(previousPack == SKIN_SELECT_PACK_DEFAULT) + { + if(app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) > 0) + { + previousPack = app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) - 1 + SKIN_SELECT_MAX_DEFAULTS; + } + else + { + previousPack = SKIN_SELECT_MAX_DEFAULTS - 1; + } + } + else + { + --previousPack; + } + + return previousPack; +} + +void CScene_SkinSelect::updateClipping() +{ + DWORD dwPropertyId; + XUIElementPropVal propertyVal; + propertyVal.Clear(); + HRESULT hr = XuiObjectGetPropertyId( m_charactersGroup.m_hObj, L"ClipChildren", &dwPropertyId); + switch( CXuiSceneBase::GetPlayerBasePosition(m_iPad) ) + { + case CXuiSceneBase::e_BaseScene_Left: + case CXuiSceneBase::e_BaseScene_Right: + case CXuiSceneBase::e_BaseScene_Top_Left: + case CXuiSceneBase::e_BaseScene_Top_Right: + case CXuiSceneBase::e_BaseScene_Bottom_Left: + case CXuiSceneBase::e_BaseScene_Bottom_Right: + case CXuiSceneBase::e_BaseScene_Top: + case CXuiSceneBase::e_BaseScene_Bottom: + propertyVal.SetBoolVal(TRUE); + break; + case CXuiSceneBase::e_BaseScene_Fullscreen: + default: + propertyVal.SetBoolVal(FALSE); + break; + }; + hr = XuiObjectSetProperty(m_charactersGroup.m_hObj,dwPropertyId,0,&propertyVal); +} + +int CScene_SkinSelect::UnlockSkinReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CScene_SkinSelect* pScene = (CScene_SkinSelect*)pParam; +#ifdef _XBOX + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedIn(iPad)) + { + ULONGLONG ullIndexA[1]; + DLC_INFO *pDLCInfo = app.GetDLCInfoForTrialOfferID(pScene->m_currentPack->getPurchaseOfferId()); + + if(pDLCInfo!=NULL) + { + ullIndexA[0]=pDLCInfo->ullOfferID_Full; + } + else + { + ullIndexA[0]=pScene->m_currentPack->getPurchaseOfferId(); + } + + // If we're in-game, then we need to enable DLC downloads. They'll be set back to Auto on leaving the pause menu + if(Minecraft::GetInstance()->level!=NULL) + { + // need to allow downloads here, or the player would need to quit the game to let the download of a skin pack happen. This might affect the network traffic, since the download could take all the bandwidth... + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + } + + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + + // the license change coming in when the offer has been installed will cause this scene to refresh + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Skin_DLC, ( pScene->m_currentPack->getPurchaseOfferId() & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined); + } +#endif + return 0; +} + +HRESULT CScene_SkinSelect::OnCustomMessage_DLCInstalled() +{ + // mounted DLC may have changed + if(app.StartInstallDLCProcess(m_iPad)==false) + { + // not doing a mount, so re-enable input + m_bIgnoreInput=false; + } + else + { + m_bIgnoreInput=true; + m_timer.SetShow( TRUE ); + m_charactersGroup.SetShow( FALSE ); + m_skinDetails.SetShow( FALSE ); + } + + // this will send a CustomMessage_DLCMountingComplete when done + return S_OK; +} + +HRESULT CScene_SkinSelect::OnCustomMessage_DLCMountingComplete() +{ + + m_timer.SetShow( FALSE ); + m_charactersGroup.SetShow( TRUE ); + m_skinDetails.SetShow( TRUE ); + m_packIndex = SKIN_SELECT_PACK_DEFAULT; + + if(app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin)>0) + { + m_currentPack = app.m_dlcManager.getPackContainingSkin(m_currentSkinPath); + if(m_currentPack != NULL) + { + bool bFound = false; + m_packIndex = app.m_dlcManager.getPackIndex(m_currentPack,bFound,DLCManager::e_DLCType_Skin) + SKIN_SELECT_MAX_DEFAULTS; + } + } + + // If we have any favourites, set this to the favourites + // first validate the favorite skins - we might have uninstalled the DLC needed for them + app.ValidateFavoriteSkins(m_iPad); + + if(app.GetPlayerFavoriteSkinsCount(m_iPad)>0) + { + m_packIndex = SKIN_SELECT_PACK_FAVORITES; + } + + handlePackIndexChanged(); + updateCurrentFocus(); + m_bIgnoreInput=false; + app.m_dlcManager.checkForCorruptDLCAndAlert(); + bool bInGame=(Minecraft::GetInstance()->level!=NULL); + + if(bInGame) XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); + + return S_OK; +} + +void CScene_SkinSelect::AddFavoriteSkin(int iPad,int iSkinID) +{ + // Is this favorite skin already in the array? + unsigned int uiCurrentFavoriteSkinsCount=app.GetPlayerFavoriteSkinsCount(m_iPad); + + for(int i=0;i<uiCurrentFavoriteSkinsCount;i++) + { + if(app.GetPlayerFavoriteSkin(m_iPad,i)==iSkinID) + { + app.SetPlayerFavoriteSkinsPos(m_iPad,i); + return; + } + } + + unsigned char ucPos=app.GetPlayerFavoriteSkinsPos(m_iPad); + if(ucPos==(MAX_FAVORITE_SKINS-1)) + { + ucPos=0; + } + else + { + if(uiCurrentFavoriteSkinsCount>0) + { + ucPos++; + } + else + { + ucPos=0; + } + } + + app.SetPlayerFavoriteSkin(iPad,(int)ucPos,iSkinID); + app.SetPlayerFavoriteSkinsPos(m_iPad,ucPos); + +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SkinSelect.h b/Minecraft.Client/Common/XUI/XUI_SkinSelect.h new file mode 100644 index 00000000..dbbb388c --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SkinSelect.h @@ -0,0 +1,150 @@ +#pragma once + +#include "../media/xuiscene_skinselect.h" +#include "XUI_CustomMessages.h" +#include "..\..\..\Minecraft.World\Definitions.h" +#include "..\..\Textures.h" + +class DLCPack; + +class CXuiCtrlMinecraftSkinPreview; + +class CScene_SkinSelect : public CXuiSceneImpl +{ +private: + static WCHAR *wchDefaultNamesA[eDefaultSkins_Count]; + + // 4J Stu - How many to show on each side of the main control + static const BYTE sidePreviewControls = 4; + + enum ESkinSelectNavigation + { + eSkinNavigation_Pack, + eSkinNavigation_Skin, + + eSkinNavigation_Count, + }; + +protected: + CXuiControl m_skinDetails, m_text, m_originText; + CXuiCtrlMinecraftSkinPreview *m_previewControl; + CXuiCtrlMinecraftSkinPreview *m_previewPreviousControls[sidePreviewControls]; + CXuiCtrlMinecraftSkinPreview *m_previewNextControls[sidePreviewControls]; + CXuiControl m_packGroup, m_charactersGroup; + CXuiControl m_packLeft, m_packRight, m_packCenter; + CXuiImageElement m_imagePadlock; + CXuiElement m_selectedGroup; + CXuiControl m_selectedText; + CXuiControl m_timer; + CXuiElement m_tabGroup; + CXuiElement m_normalTabs, m_selectedTabs; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN( OnKeyDown ) + XUI_ON_XM_KEYUP( OnKeyUp ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_TIMELINE_END( OnTimelineEnd ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_ON_XM_DLCLOADED_MESSAGE(OnCustomMessage_DLCMountingComplete) + XUI_ON_XM_BASE_POSITION_CHANGED_MESSAGE(OnBasePositionChanged) + XUI_ON_XM_DLCINSTALLED_MESSAGE(OnCustomMessage_DLCInstalled) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Timer, m_timer) + + MAP_CONTROL(IDC_PackGroup, m_packGroup) + BEGIN_MAP_CHILD_CONTROLS( m_packGroup) + MAP_CONTROL(IDC_Left, m_packLeft) + MAP_CONTROL(IDC_Center, m_packCenter) + MAP_CONTROL(IDC_Right, m_packRight) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_TabBar, m_tabGroup) + BEGIN_MAP_CHILD_CONTROLS( m_tabGroup ) + MAP_CONTROL(IDC_Selected, m_selectedTabs ) + MAP_CONTROL(IDC_Normal, m_normalTabs ) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_SelectedGroup, m_selectedGroup) + BEGIN_MAP_CHILD_CONTROLS( m_selectedGroup ) + MAP_CONTROL(IDC_SelectedText, m_selectedText) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_Locked, m_imagePadlock) + + MAP_CONTROL(IDC_SkinDetails, m_skinDetails) + BEGIN_MAP_CHILD_CONTROLS( m_skinDetails) + MAP_CONTROL(IDC_SkinName, m_text) + MAP_CONTROL(IDC_OriginName, m_originText) + END_MAP_CHILD_CONTROLS() + + MAP_CONTROL(IDC_Characters, m_charactersGroup) + BEGIN_MAP_CHILD_CONTROLS( m_charactersGroup ) + MAP_OVERRIDE(IDC_Character, m_previewControl) + MAP_OVERRIDE(IDC_CharacterPrevious1, m_previewPreviousControls[0]) + MAP_OVERRIDE(IDC_CharacterPrevious2, m_previewPreviousControls[1]) + MAP_OVERRIDE(IDC_CharacterPrevious3, m_previewPreviousControls[2]) + MAP_OVERRIDE(IDC_CharacterPrevious4, m_previewPreviousControls[3]) + MAP_OVERRIDE(IDC_CharacterNext1, m_previewNextControls[0]) + MAP_OVERRIDE(IDC_CharacterNext2, m_previewNextControls[1]) + MAP_OVERRIDE(IDC_CharacterNext3, m_previewNextControls[2]) + MAP_OVERRIDE(IDC_CharacterNext4, m_previewNextControls[3]) + END_MAP_CHILD_CONTROLS() + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyUp(XUIMessageInput *pInputData, BOOL& bHandled); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + HRESULT OnCustomMessage_DLCInstalled(); + HRESULT OnCustomMessage_DLCMountingComplete(); + HRESULT OnBasePositionChanged(); + + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + wstring m_currentSkinPath, m_selectedSkinPath, m_selectedCapePath; + vector<SKIN_BOX *> *m_vAdditionalSkinBoxes; + //vector<ModelPart *> *m_vAdditionalModelParts; + DWORD m_originalSkinId; + + DLCPack *m_currentPack; + DWORD m_packIndex, m_skinIndex; +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SkinSelect, L"CScene_SkinSelect", XUI_CLASS_SCENE ) + +private: + void handleSkinIndexChanged(); + void handlePackIndexChanged(); + void updatePackDisplay(); + void updateCurrentFocus(); + TEXTURE_NAME getTextureId(int skinIndex); + + int getNextSkinIndex(DWORD sourceIndex); + int getPreviousSkinIndex(DWORD sourceIndex); + + int getNextPackIndex(DWORD sourceIndex); + int getPreviousPackIndex(DWORD sourceIndex); + + void updateClipping(); + + static int UnlockSkinReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + void AddFavoriteSkin(int iPad,int iSkinID); + + bool m_bSlidingSkins, m_bAnimatingMove; + + DWORD currentPackCount; + + ESkinSelectNavigation m_currentNavigation; + bool m_bIgnoreInput; +}; diff --git a/Minecraft.Client/Common/XUI/XUI_SocialPost.cpp b/Minecraft.Client/Common/XUI/XUI_SocialPost.cpp new file mode 100644 index 00000000..f237e7d8 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SocialPost.cpp @@ -0,0 +1,147 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "..\XUI\XUI_SocialPost.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\SharedConstants.h" +#include "..\..\..\Minecraft.World\Random.h" +#include "..\..\..\Minecraft.Client\SurvivalMode.h" +#include "..\..\..\Minecraft.Client\CreateWorldScreen.h" +#include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\LocalPlayer.h" + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_SocialPost::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad = *(int *)pInitData->pvInitData; + + MapChildControls(); + + XuiControlSetText(m_text,app.GetString(IDS_SOCIAL_TEXT)); + XuiControlSetText(m_LabelCaption,app.GetString(IDS_SOCIAL_LABEL_CAPTION)); + XuiControlSetText(m_EditCaption,app.GetString(IDS_SOCIAL_DEFAULT_CAPTION)); + XuiControlSetText(m_LabelDescription,app.GetString(IDS_SOCIAL_LABEL_DESCRIPTION)); + XuiControlSetText(m_EditDesc,app.GetString(IDS_SOCIAL_DEFAULT_DESCRIPTION)); + XuiControlSetText(m_OK,app.GetString(IDS_CONFIRM_OK)); + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + + m_EditCaption.SetTextLimit(MAX_SOCIALPOST_CAPTION); + m_EditDesc.SetTextLimit(MAX_SOCIALPOST_DESC); + + // Hardcoded so posts will have this in + m_wTitle = L"Minecraft: Xbox 360 Edition"; + + m_EditCaption.SetTitleAndText(IDS_NAME_CAPTION,IDS_NAME_CAPTION_TEXT); + m_EditDesc.SetTitleAndText(IDS_NAME_DESC,IDS_NAME_DESC_TEXT); + + wstring wCaption = m_EditCaption.GetText(); + wstring wDesc = m_EditDesc.GetText(); + + // set the caret to the end of the default text + m_EditCaption.SetCaretPosition((int)wCaption.length()); + m_EditDesc.SetCaretPosition((int)wDesc.length()); + + BOOL bHasAllText = /*( wTitle.length()!=0) && */(wCaption.length()!=0) && (wDesc.length()!=0); + + m_OK.SetEnable(bHasAllText); + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad,false); + } + + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_SocialPost, 0); + + return S_OK; +} + + +HRESULT CScene_SocialPost::OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) +{ wstring wCaption = m_EditCaption.GetText(); +wstring wDesc = m_EditDesc.GetText(); + + + if(/*(hObjSource == m_EditTitle) || */(hObjSource == m_EditCaption) || (hObjSource == m_EditDesc)) + { + // Enable the done button when we have all of the necessary information + //wstring wTitle = m_EditTitle.GetText(); + wstring wCaption = m_EditCaption.GetText(); + wstring wDesc = m_EditDesc.GetText(); + + BOOL bHasAllText = /*( wTitle.length()!=0) &&*/ (wCaption.length()!=0) && (wDesc.length()!=0); + m_OK.SetEnable(bHasAllText); + } + + return S_OK; +} + +HRESULT CScene_SocialPost::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + pControlNavigateData->hObjDest=XuiControlGetNavigation(pControlNavigateData->hObjSource,pControlNavigateData->nControlNavigate,TRUE,TRUE); + + if(pControlNavigateData->hObjDest==NULL) + { + pControlNavigateData->hObjDest=pControlNavigateData->hObjSource; + } + + bHandled=TRUE; + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_SocialPost::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_OK) + { + CSocialManager::Instance()->SetSocialPostText(m_wTitle.c_str(),m_EditCaption.GetText(),m_EditDesc.GetText()); + + CSocialManager::Instance()->PostImageToSocialNetwork( eFacebook, pNotifyPressData->UserIndex, false); + + app.NavigateBack(pNotifyPressData->UserIndex); + } + + return S_OK; +} + + +HRESULT CScene_SocialPost::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + //HXUIOBJ hFocus=XuiElementGetFocus(); + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + + break; + } + + + return S_OK; +} + + +HRESULT CScene_SocialPost::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining,false); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_SocialPost.h b/Minecraft.Client/Common/XUI/XUI_SocialPost.h new file mode 100644 index 00000000..0dd37fa6 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_SocialPost.h @@ -0,0 +1,59 @@ +#pragma once + +#include "../media\xuiscene_socialpost.h" +#include "XUI_Ctrl_4JEdit.h" +#include "XUI_CustomMessages.h" + + +class CScene_SocialPost : public CXuiSceneImpl +{ + protected: + // Control and Element wrapper objects. + CXuiControl m_OK; + CXuiCtrl4JEdit m_EditCaption; + CXuiCtrl4JEdit m_EditDesc; + CXuiControl m_text, m_LabelCaption, m_LabelDescription; + wstring m_wTitle; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_ON_XM_CONTROL_NAVIGATE( OnControlNavigate ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + //MAP_CONTROL(IDC_XuiEditTitle, m_EditTitle) + MAP_CONTROL(IDC_XuiLabelText, m_text) + MAP_CONTROL(IDC_XuiLabelCaption, m_LabelCaption) + MAP_CONTROL(IDC_XuiLabelDescription, m_LabelDescription) + MAP_CONTROL(IDC_XuiEditCaption, m_EditCaption) + MAP_CONTROL(IDC_XuiEditDescription, m_EditDesc) + MAP_CONTROL(IDC_XuiOK, m_OK) + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled); + HRESULT OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + D3DXVECTOR3 m_OriginalPosition; + int m_iPad; + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_SocialPost, L"CScene_SocialPost", XUI_CLASS_SCENE ) + + + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_Teleport.cpp b/Minecraft.Client/Common/XUI/XUI_Teleport.cpp new file mode 100644 index 00000000..1d6ac3bf --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Teleport.cpp @@ -0,0 +1,312 @@ +#include "stdafx.h" + +#include <assert.h> +#include "XUI_Teleport.h" +#include "..\..\ServerPlayer.h" +#include "..\..\PlayerConnection.h" +#include "..\..\PlayerList.h" +#include "..\..\MinecraftServer.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\PlayerRenderer.h" +#include "XUI_InGamePlayerOptions.h" +#include "..\..\Minecraft.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\ClientConnection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" +#include "..\..\Xbox\Network\NetworkPlayerXbox.h" +#include "TeleportCommand.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Teleport::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + TeleportMenuInitData *initParam = (TeleportMenuInitData *)pInitData->pvInitData; + + m_iPad = initParam->iPad; + m_teleportToPlayer = initParam->teleportToPlayer; + + delete initParam; + + MapChildControls(); + + if(m_teleportToPlayer) + { + m_title.SetText(app.GetString(IDS_TELEPORT_TO_PLAYER)); + } + else + { + m_title.SetText(app.GetString(IDS_TELEPORT_TO_ME)); + } + + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + DWORD playerCount = g_NetworkManager.GetPlayerCount(); + + m_playersCount = 0; + for(DWORD i = 0; i < playerCount; ++i) + { + INetworkPlayer *player = g_NetworkManager.GetPlayerByIndex( i ); + + if( player != NULL && !(player->IsLocal() && player->GetUserIndex() == m_iPad) ) + { + m_players[m_playersCount] = player->GetSmallId(); + ++m_playersCount; + } + } + + g_NetworkManager.RegisterPlayerChangedCallback(m_iPad, &CScene_Teleport::OnPlayerChanged, this); + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); + + CXuiSceneBase::ShowDarkOverlay( m_iPad, TRUE ); + + return S_OK; +} + +HRESULT CScene_Teleport::OnDestroy() +{ + g_NetworkManager.UnRegisterPlayerChangedCallback(m_iPad, &CScene_Teleport::OnPlayerChanged, this); + return S_OK; +} + +HRESULT CScene_Teleport::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr = S_OK; + switch(pInputData->dwKeyCode) + { + + case VK_PAD_B: + case VK_PAD_BACK: + case VK_ESCAPE: + CXuiSceneBase::PlayUISFX(eSFX_Back); + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + + break; + } + + + return hr; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Teleport::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if( hObjPressed == playersList ) + { + INetworkPlayer *selectedPlayer = g_NetworkManager.GetPlayerBySmallId( m_players[ playersList.GetCurSel() ] ); + INetworkPlayer *thisPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(m_iPad); + + shared_ptr<GameCommandPacket> packet; + if(m_teleportToPlayer) + { + packet = TeleportCommand::preparePacket(thisPlayer->GetUID(),selectedPlayer->GetUID()); + } + else + { + packet = TeleportCommand::preparePacket(selectedPlayer->GetUID(),thisPlayer->GetUID()); + } + ClientConnection *conn = Minecraft::GetInstance()->getConnection(m_iPad); + conn->send( packet ); + } + return S_OK; +} + +void CScene_Teleport::OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving) +{ + CScene_Teleport *scene = (CScene_Teleport *)callbackParam; + bool playerFound = false; + + for(int i = 0; i < scene->m_playersCount; ++i) + { + if(playerFound) + { + scene->m_players[i-1] = scene->m_players[i]; + } + else if( scene->m_players[i] == pPlayer->GetSmallId() ) + { + if( scene->playersList.GetCurSel() == scene->playersList.GetItemCount() - 1 ) + { + scene->playersList.SetCurSel( scene->playersList.GetItemCount() - 2 ); + } + // Player removed + playerFound = true; + } + } + + if( playerFound ) + { + --scene->m_playersCount; + scene->playersList.DeleteItems( scene->playersList.GetItemCount() - 1, 1 ); + } + + if( !playerFound ) + { + // Player added + scene->m_players[scene->m_playersCount] = pPlayer->GetSmallId(); + ++scene->m_playersCount; + scene->playersList.InsertItems( scene->playersList.GetItemCount(), 1 ); + } +} + +HRESULT CScene_Teleport::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled) +{ + if( pGetSourceTextData->bItemData ) + { + if( pGetSourceTextData->iItem < m_playersCount ) + { + INetworkPlayer *player = g_NetworkManager.GetPlayerBySmallId( m_players[pGetSourceTextData->iItem] ); + if( player != NULL ) + { +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) + { + pGetSourceTextData->szText = L"WWWWWWWWWWWWWWWW"; + } + else +#endif + { + pGetSourceTextData->szText = player->GetOnlineName(); + } + } + else + { + pGetSourceTextData->szText = L""; + } + + HRESULT hr; + HXUIOBJ hButton, hVisual, hPlayerIcon, hVoiceIcon; + hButton = playersList.GetItemControl(pGetSourceTextData->iItem); + hr=XuiControlGetVisual(hButton,&hVisual); + + // Set the players icon + hr=XuiElementGetChildById(hVisual,L"IconGroup",&hPlayerIcon); + short colourIndex = app.GetPlayerColour( m_players[pGetSourceTextData->iItem] ); + int playFrame = 0; + switch(colourIndex) + { + case 1: + XuiElementFindNamedFrame(hPlayerIcon, L"P1", &playFrame); + break; + case 2: + XuiElementFindNamedFrame(hPlayerIcon, L"P2", &playFrame); + break; + case 3: + XuiElementFindNamedFrame(hPlayerIcon, L"P3", &playFrame); + break; + case 4: + XuiElementFindNamedFrame(hPlayerIcon, L"P4", &playFrame); + break; + case 5: + XuiElementFindNamedFrame(hPlayerIcon, L"P5", &playFrame); + break; + case 6: + XuiElementFindNamedFrame(hPlayerIcon, L"P6", &playFrame); + break; + case 7: + XuiElementFindNamedFrame(hPlayerIcon, L"P7", &playFrame); + break; + case 8: + XuiElementFindNamedFrame(hPlayerIcon, L"P8", &playFrame); + break; + case 9: + XuiElementFindNamedFrame(hPlayerIcon, L"P9", &playFrame); + break; + case 10: + XuiElementFindNamedFrame(hPlayerIcon, L"P10", &playFrame); + break; + case 11: + XuiElementFindNamedFrame(hPlayerIcon, L"P11", &playFrame); + break; + case 12: + XuiElementFindNamedFrame(hPlayerIcon, L"P12", &playFrame); + break; + case 13: + XuiElementFindNamedFrame(hPlayerIcon, L"P13", &playFrame); + break; + case 14: + XuiElementFindNamedFrame(hPlayerIcon, L"P14", &playFrame); + break; + case 15: + XuiElementFindNamedFrame(hPlayerIcon, L"P15", &playFrame); + break; + case 0: + default: + XuiElementFindNamedFrame(hPlayerIcon, L"P0", &playFrame); + break; + }; + if(playFrame < 0) playFrame = 0; + XuiElementPlayTimeline(hPlayerIcon,playFrame,playFrame,playFrame,FALSE,FALSE); + + // Set the voice icon + hr=XuiElementGetChildById(hVisual,L"VoiceGroup",&hVoiceIcon); + + playFrame = -1; + if(player != NULL && player->HasVoice() ) + { + if( player->IsMutedByLocalUser(m_iPad) ) + { + // Muted image + XuiElementFindNamedFrame(hVoiceIcon, L"Muted", &playFrame); + } + else if( player->IsTalking() ) + { + // Talking image + XuiElementFindNamedFrame(hVoiceIcon, L"Speaking", &playFrame); + } + else + { + // Not talking image + XuiElementFindNamedFrame(hVoiceIcon, L"NotSpeaking", &playFrame); + } + } + + if(playFrame < 0) + { + XuiElementFindNamedFrame(hVoiceIcon, L"Normal", &playFrame); + } + XuiElementPlayTimeline(hVoiceIcon,playFrame,playFrame,playFrame,FALSE,FALSE); + + pGetSourceTextData->bDisplay = TRUE; + + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_Teleport::OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled) +{ + if( pGetSourceImageData->bItemData ) + { + if( pGetSourceImageData->iItem < m_playersCount ) + { + bHandled = TRUE; + } + } + return S_OK; +} + +HRESULT CScene_Teleport::OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled) +{ + pGetItemCountData->cItems = m_playersCount; + bHandled = TRUE; + return S_OK; +} + +HRESULT CScene_Teleport::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_Teleport.h b/Minecraft.Client/Common/XUI/XUI_Teleport.h new file mode 100644 index 00000000..cf60eab0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_Teleport.h @@ -0,0 +1,64 @@ +#pragma once +using namespace std; +#include "../media/xuiscene_teleportmenu.h" +#include "XUI_CustomMessages.h" + +class INetworkPlayer; + +#define VOICE_ICON_DATA_ID 0 +#define MAP_ICON_DATA_ID 1 +#define OPS_ICON_DATA_ID 2 + +class CScene_Teleport : public CXuiSceneImpl +{ +protected: + // Control and Element wrapper objects. + CXuiList playersList; + CXuiControl m_title; + + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_KEYDOWN(OnKeyDown) + + XUI_ON_XM_GET_SOURCE_TEXT(OnGetSourceDataText) + XUI_ON_XM_GET_SOURCE_IMAGE(OnGetSourceDataImage) + XUI_ON_XM_GET_ITEMCOUNT_ALL(OnGetItemCountAll) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_GamePlayers, playersList) + MAP_CONTROL(IDC_Title, m_title) + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); + + HRESULT OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceTextData, BOOL& bHandled); + HRESULT OnGetSourceDataImage(XUIMessageGetSourceImage *pGetSourceImageData,BOOL& bHandled); + HRESULT OnGetItemCountAll(XUIMessageGetItemCount *pGetItemCountData, BOOL& bHandled); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_Teleport, L"CScene_Teleport", XUI_CLASS_SCENE ) + + static void OnPlayerChanged(void *callbackParam, INetworkPlayer *pPlayer, bool leaving); + +private: + int m_iPad; + D3DXVECTOR3 m_OriginalPosition; + bool m_teleportToPlayer; + + int m_playersCount; + BYTE m_players[MINECRAFT_NET_MAX_PLAYERS]; // An array of QNet small-id's +}; diff --git a/Minecraft.Client/Common/XUI/XUI_TextEntry.cpp b/Minecraft.Client/Common/XUI/XUI_TextEntry.cpp new file mode 100644 index 00000000..8934350d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TextEntry.cpp @@ -0,0 +1,172 @@ +#include "stdafx.h" +#include "XUI_TextEntry.h" +#include "..\..\MultiplayerLocalPlayer.h" + + +CScene_TextEntry::CommandParams CScene_TextEntry::CommandA[CScene_TextEntry::eCommand_MAX]= +{ + { L"goto", L"%s%c%d%c%d" }, + { L"give", L"%s%c%s" } +}; + +HRESULT CScene_TextEntry::Init_Commands() +{ + for(int i=0;i<eCommand_MAX;i++) + { + m_CommandSet[CommandA[i].wchCommand]=i; + } + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_TextEntry::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + MapChildControls(); + XuiTextInputParams *params = (XuiTextInputParams *)pInitData->pvInitData; + m_iPad=params->iPad; + m_wchInitialChar=params->wch; + delete params; + + WCHAR wchEditText[40]; + + Init_Commands(); + + ZeroMemory(wchEditText,sizeof(WCHAR)*40); + wchEditText[0]=tolower(m_wchInitialChar); + + m_EditText.SetTextLimit(40); + m_EditText.SetText(wchEditText); + // set the caret to the end of the default text + m_EditText.SetCaretPosition(1); + + m_EditText.SetTitleAndText(IDS_NAME_WORLD,IDS_NAME_WORLD_TEXT); + + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_EXECUTE_COMMAND, IDS_TOOLTIPS_BACK); + return S_OK; +} + +HRESULT CScene_TextEntry::OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) +{ + // If the user presses return, interpret the string, and exit + if(pValueChangedData->nValue==10) + { + LPCWSTR pText = m_EditText.GetText(); + + if(pText) + { + wstring wText = pText; + InterpretString(wText); + } + + app.NavigateBack(m_iPad); + rfHandled = TRUE; + } + + return S_OK; +} + +HRESULT CScene_TextEntry::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_A: + { + LPCWSTR pText = m_EditText.GetText(); + + if(pText) + { + wstring wText = pText; + InterpretString(wText); + } + + app.NavigateBack(m_iPad); + rfHandled = TRUE; + } + break; + + case VK_PAD_B: + case VK_ESCAPE: + + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + } + return S_OK; +} + +HRESULT CScene_TextEntry::InterpretString(wstring &wsText) +{ + wstring wsFormat; + WCHAR wchCommand[40]; + int iCommand=-1; + WCHAR wchSep[2]; + +#ifdef __PS3__ + // 4J Stu - The Xbox version uses swscanf_s which isn't available in GCC. + swscanf(wsText.c_str(), L"%40s", wchCommand); +#else + swscanf_s(wsText.c_str(), L"%s", wchCommand,40); +#endif + + AUTO_VAR(it, m_CommandSet.find(wchCommand)); + if(it != m_CommandSet.end()) + { + // found it + + iCommand=it->second; + + switch(iCommand) + { + case eCommand_Teleport: + { + int x,z; + +#ifdef __PS3__ + // 4J Stu - The Xbox version uses swscanf_s which isn't available in GCC. + swscanf(wsText.c_str(), L"%40s%c%d%c%d", wchCommand,wchSep,&x,wchSep,&z); +#else + swscanf_s(wsText.c_str(), L"%s%c%d%c%d", wchCommand,40,wchSep,2,&x,wchSep,2, &z); +#endif + + app.DebugPrintf("eCommand_Teleport x=%d z=%d\n",x,z); + + // check the bounds + int iBound=54*16; + if( (x>-iBound) && (x<iBound) && (z>-iBound) && (z<iBound) ) + { + // valid numbers + Minecraft *pMinecraft=Minecraft::GetInstance(); + pMinecraft->localplayers[m_iPad]->teleportTo(x,pMinecraft->localplayers[m_iPad]->y,z); + } + } + break; + case eCommand_Give: + { + int iItem,iCount; + +#ifdef __PS3__ + // 4J Stu - The Xbox version uses swscanf_s which isn't available in GCC. + swscanf(wsText.c_str(), L"%40s%c%d%c%d", wchCommand,wchSep,&iItem,wchSep,&iCount); +#else + swscanf_s(wsText.c_str(), L"%s%c%d%c%d", wchCommand,40,wchSep,2,&iItem,wchSep,2, &iCount); +#endif + app.DebugPrintf("eCommand_Give, item=%d count=%d\n",iItem,iCount); + Minecraft *pMinecraft=Minecraft::GetInstance(); + for(int i=0;i<iCount;i++) + pMinecraft->localplayers[m_iPad]->drop(); // shared_ptr<ItemInstance>(new ItemInstance( iItem, 1, 0 )) ); + } + + break; + default: + app.DebugPrintf("Unknown command\n"); + break; + } + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_TextEntry.h b/Minecraft.Client/Common/XUI/XUI_TextEntry.h new file mode 100644 index 00000000..70dcf30b --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TextEntry.h @@ -0,0 +1,64 @@ +#pragma once +#include "..\Media\xuiscene_text_entry.h" +#include "XUI_Ctrl_4JEdit.h" + + +class CScene_TextEntry : public CXuiSceneImpl +{ +public: + typedef struct _XuiTextInputParams + { + int iPad; + WCHAR wch; + } + XuiTextInputParams; + + typedef struct _CommamndParams + { + WCHAR wchCommand[40]; + WCHAR wchFormat[40]; + } + CommandParams; + + enum + { + eCommand_Teleport=0, + eCommand_Give, + eCommand_MAX + } + eCommands; + +protected: + CXuiCtrl4JEdit m_EditText; + + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_NOTIFY_VALUE_CHANGED(OnNotifyValueChanged) + XUI_ON_XM_KEYDOWN(OnKeyDown) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiEditText, m_EditText) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnNotifyValueChanged (HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + + HRESULT InterpretString(wstring &wsText); + HRESULT Init_Commands(); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_TextEntry, L"CScene_TextEntry", XUI_CLASS_SCENE ) + +private: + int m_iPad; + WCHAR m_wchInitialChar; + static CommandParams CommandA[eCommand_MAX]; + unordered_map<wstring, int> m_CommandSet; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.cpp b/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.cpp new file mode 100644 index 00000000..5a2e67b4 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.cpp @@ -0,0 +1,569 @@ +#include "stdafx.h" +#include <xuiresource.h> +#include <xuiapp.h> +#include <assert.h> + +#include "XUI_Ctrl_4JList.h" +#include "XUI_Ctrl_4JIcon.h" +#include "XUI_LoadSettings.h" +#include "..\..\ProgressRenderer.h" +#include "XUI_TransferToXboxOne.h" + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_TransferToXboxOne::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iX=-1; + m_params = (LoadMenuInitData *)pInitData->pvInitData; + + m_iPad=m_params->iPad; + + m_bRetrievingSaveInfo=false; + m_bIgnoreInput=false; + MapChildControls(); + + VOID *pObj; + XuiObjectFromHandle( m_SavesSlotList, &pObj ); + m_pSavesSlotList = (CXuiCtrl4JList *)pObj; + + m_pbImageData=NULL; + m_dwImageBytes=0; + + StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,m_XContentData); + StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,&m_pbImageData,&m_dwImageBytes); + + + m_SavesSlotListTimer.SetShow(TRUE); + + + XuiControlSetText(m_SavesSlotList,app.GetString(IDS_XBONE_SELECTSLOT)); + + // insert the current save slot names + m_MaxSlotC=app.m_uiTransferSlotC; + m_pSlotDataA = new SLOTDATA [m_MaxSlotC]; + ZeroMemory(m_pSlotDataA,sizeof(SLOTDATA)*m_MaxSlotC); + + + // saves will be called slot1 to slotx + // there will be a details file with the names and png of each slot + m_pbSlotListFile=NULL; + m_uiSlotListFileBytes=0; + + if(StorageManager.TMSPP_InFileList(C4JStorage::eGlobalStorage_TitleUser,m_iPad,L"XboxOne/SlotList")) + { + // there is a slot list file with details of the saves + C4JStorage::ETMSStatus status=StorageManager.TMSPP_ReadFile(m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,"XboxOne/SlotList",&CScene_TransferToXboxOne::TMSPPSlotListReturned,this); + m_iX=IDS_TOOLTIPS_CLEARSLOTS; + } + else + { + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + + // create dummy slots + for(int i=0;i<m_MaxSlotC;i++) + { + memcpy(m_pSlotDataA[i].wchSaveTitle,app.GetString(IDS_XBONE_EMPTYSLOT),sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); + ListInfo.pwszText = app.GetString(IDS_XBONE_EMPTYSLOT); + ListInfo.fEnabled = TRUE; + ListInfo.iData = -1; + m_pSavesSlotList->AddData(ListInfo); + } + m_SavesSlotListTimer.SetShow(FALSE); + } + + + CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// TMSPPSlotListReturned callback +//---------------------------------------------------------------------------------- +int CScene_TransferToXboxOne::TMSPPWriteReturned(LPVOID pParam,int iPad,int iUserData) +{ + CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; + pClass->m_bWaitingForWrite=false; + + return 0; +} + +//---------------------------------------------------------------------------------- +// TMSPPSlotListReturned callback +//---------------------------------------------------------------------------------- +int CScene_TransferToXboxOne::TMSPPDeleteReturned(LPVOID pParam,int iPad,int iUserData) +{ + CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; + pClass->m_SavesSlotListTimer.SetShow(FALSE); + pClass->m_bIgnoreInput=false; + + // update the slots + delete pClass->m_pbSlotListFile; + pClass->m_pbSlotListFile=NULL; + pClass->m_uiSlotListFileBytes=0; + pClass->m_pSavesSlotList->RemoveAllData(); + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + // clear our slot info + ZeroMemory(pClass->m_pSlotDataA,sizeof(SLOTDATA)*pClass->m_MaxSlotC); + + for(int i=0;i<pClass->m_MaxSlotC;i++) + { + memcpy(pClass->m_pSlotDataA[i].wchSaveTitle,app.GetString(IDS_XBONE_EMPTYSLOT),sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); + ListInfo.pwszText = app.GetString(IDS_XBONE_EMPTYSLOT); + ListInfo.fEnabled = TRUE; + ListInfo.iData = -1; + pClass->m_pSavesSlotList->AddData(ListInfo); + } + + return 0; +} + +//---------------------------------------------------------------------------------- +// TMSPPSlotListReturned callback +//---------------------------------------------------------------------------------- +int CScene_TransferToXboxOne::TMSPPSlotListReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename) +{ + CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; + unsigned int uiSlotListFileSlots=*((unsigned int *)pFileData->pbData); + pClass->m_pbSlotListFile=pFileData->pbData; + pClass->m_uiSlotListFileBytes=pFileData->dwSize; + + // clear our slot info + ZeroMemory(pClass->m_pSlotDataA,sizeof(SLOTDATA)*pClass->m_MaxSlotC); + // set the empty slot strings + for(int i=0;i<pClass->m_MaxSlotC;i++) + { + memcpy(pClass->m_pSlotDataA[i].wchSaveTitle,app.GetString(IDS_XBONE_EMPTYSLOT),sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); + } + // update our slot info with the data from the file - might have less slots + unsigned int uiNewSlotsC=(pClass->m_MaxSlotC<uiSlotListFileSlots)?pClass->m_MaxSlotC:uiSlotListFileSlots; + memcpy(pClass->m_pSlotDataA,pClass->m_pbSlotListFile + sizeof(unsigned int),sizeof(SLOTDATA)*uiNewSlotsC); + + CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; + + ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); + PBYTE pbImageData=pClass->m_pbSlotListFile + sizeof(unsigned int) + sizeof(SLOTDATA)*uiSlotListFileSlots; + + // fill out the slot info + for(int i=0;i<pClass->m_MaxSlotC;i++) + { + if(i<uiNewSlotsC) + { + ListInfo.pwszText = pClass->m_pSlotDataA[i].wchSaveTitle; + ListInfo.fEnabled = TRUE; + ListInfo.iData = -1; + pClass->m_pSavesSlotList->AddData(ListInfo); + + if(pClass->m_pSlotDataA[i].uiImageLength!=0) + { + XuiCreateTextureBrushFromMemory(pbImageData,pClass->m_pSlotDataA[i].uiImageLength,&pClass->m_hXuiBrush); + pClass->m_pSavesSlotList->UpdateGraphic(i,pClass->m_hXuiBrush); + // increment the image data pointer + pbImageData+=pClass->m_pSlotDataA[i].uiImageLength; + } + } + else + { + // make it blank + ListInfo.pwszText = app.GetString(IDS_XBONE_EMPTYSLOT); + ListInfo.fEnabled = TRUE; + ListInfo.iData = -1; + pClass->m_pSavesSlotList->AddData(ListInfo); + } + } + pClass->m_SavesSlotListTimer.SetShow(FALSE); + return 0; + +} + +//---------------------------------------------------------------------------------- +// Handler for OnDestroy +//---------------------------------------------------------------------------------- +HRESULT CScene_TransferToXboxOne::OnDestroy() +{ + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_TransferToXboxOne::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // if we're retrieving save info, ignore key presses + if(m_bRetrievingSaveInfo) + { + return S_OK; + } + + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + if(hObjPressed==m_SavesSlotList) + { + m_bIgnoreInput=true; + + // update the info in the SlotList file + CXuiControl pItem; + int iIndex; + + // get the selected item + iIndex=m_SavesSlotList.GetCurSel(&pItem); + + // check if there is a save there + + CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesSlotList->GetData(iIndex); + if(info.pwszImage!=NULL) + { + // we have a save here + // Are you sure, etc. + } + + // update the data + memcpy(m_pSlotDataA[iIndex].wchSaveTitle,m_XContentData.szDisplayName,sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); + m_pSavesSlotList->UpdateText(iIndex,m_pSlotDataA[iIndex].wchSaveTitle); + + // if there is no thumbnail, retrieve the default one from the file. + // Don't delete the image data after creating the xuibrush, since we'll use it in the rename of the save + bool bHostOptionsRead = false; + unsigned int uiHostOptions = 0; + + XuiCreateTextureBrushFromMemory(m_pbImageData,m_dwImageBytes,&m_hXuiBrush); + m_pSavesSlotList->UpdateGraphic(iIndex,m_hXuiBrush); + + m_pSlotDataA[iIndex].uiImageLength=m_dwImageBytes; + + m_bIgnoreInput=false; + + // finished so navigate back + //app.NavigateBack(XUSER_INDEX_ANY); + BuildSlotFile(iIndex,m_pbImageData,m_dwImageBytes); + } + + return S_OK; +} + +HRESULT CScene_TransferToXboxOne::BuildSlotFile(int iIndexBeingUpdated,PBYTE pbImageData,DWORD dwImageBytes ) +{ + SLOTDATA *pCurrentSlotData=NULL; + PBYTE pbCurrentSlotDataPtr=NULL; + // there may be no slot file yet + if(m_pbSlotListFile!=NULL) + { + pCurrentSlotData=(SLOTDATA *)(m_pbSlotListFile+sizeof(unsigned int)); + pbCurrentSlotDataPtr=m_pbSlotListFile + sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC; + } + + m_uiSlotID=iIndexBeingUpdated; + + // memory required - first int is the number of slots in this file, in case that changes later + unsigned int uiBytesRequired=sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC; + for(int i=0;i<m_MaxSlotC;i++) + { + if(i==iIndexBeingUpdated) + { + uiBytesRequired+=dwImageBytes; + } + else + { + uiBytesRequired+=m_pSlotDataA[i].uiImageLength; + } + } + + PBYTE pbNewSlotFileData= new BYTE [uiBytesRequired]; + *((unsigned int *)pbNewSlotFileData)=m_MaxSlotC; + PBYTE pbNewSlotFileDataSlots=pbNewSlotFileData + sizeof(unsigned int); + PBYTE pbNewSlotImageDataPtr=pbNewSlotFileData + sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC; + SLOTDATA *pNewSlotData=(SLOTDATA *)pbNewSlotFileDataSlots; + + // copy the slot info into the new memory, just after the first int + memcpy(pbNewSlotFileDataSlots,m_pSlotDataA,sizeof(SLOTDATA)*m_MaxSlotC); + + for(int i=0;i<m_MaxSlotC;i++) + { + if(i==iIndexBeingUpdated) + { + memcpy(pbNewSlotImageDataPtr,pbImageData,dwImageBytes); + pbNewSlotImageDataPtr+=dwImageBytes; + // update the fields + pNewSlotData[i].uiImageLength=dwImageBytes; + // save title is already correct + } + else + { + if(pbCurrentSlotDataPtr!=NULL) + { + memcpy(pbNewSlotImageDataPtr,pbCurrentSlotDataPtr,pCurrentSlotData[i].uiImageLength); + pbNewSlotImageDataPtr+=pCurrentSlotData[i].uiImageLength; + } + // fields are already correct + } + + // move to the next image data in the current slot file + if(pbCurrentSlotDataPtr!=NULL) + { + pbCurrentSlotDataPtr+=pCurrentSlotData[i].uiImageLength; + } + } + + // free the previous file data and the current file data + delete m_pbSlotListFile; + + // reset the pointer until we have the exit from this scene running + m_pbSlotListFile = pbNewSlotFileData; + m_uiSlotListFileBytes = uiBytesRequired; + m_pSlotDataA = (SLOTDATA *)pbNewSlotFileDataSlots; + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CScene_TransferToXboxOne::UploadSaveForXboxOneThreadProc; + loadingParams->lpParam = (LPVOID)this; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->iPad = m_iPad; + completionData->type = e_ProgressCompletion_NavigateBackToScene; + completionData->scene = eUIScene_LoadMenu; + loadingParams->completionData = completionData; + + app.NavigateToScene(m_iPad,eUIScene_FullscreenProgress, loadingParams); + + return S_OK; +} + +int CScene_TransferToXboxOne::UploadSaveForXboxOneThreadProc( LPVOID lpParameter ) +{ + HRESULT hr = S_OK; + char szFilename[32]; + CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) lpParameter; + Minecraft *pMinecraft = Minecraft::GetInstance(); + unsigned int uiComplete=0; + pClass->m_bWaitingForWrite=true; + pMinecraft->progressRenderer->progressStart(IDS_XBONE_UPLOAD_SAVE_TITLE); + pMinecraft->progressRenderer->progressStage( IDS_XBONE_UPLOAD_METADATA ); + // now write the new slot data file to global storage, and then write the save data + C4JStorage::ETMSStatus eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,"XboxOne/SlotList",(PCHAR) pClass->m_pbSlotListFile, pClass->m_uiSlotListFileBytes, + &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); + + if(eStatus!=C4JStorage::ETMSStatus_WriteInProgress) + { + // failed + pClass->m_bWaitingForWrite=false; + } + else + { + // loop waiting for the write to complete + uiComplete=0; + while(pClass->m_bWaitingForWrite && (hr == S_OK)) + { + Sleep(50); + uiComplete++; + if(uiComplete>100) uiComplete=100; + + pMinecraft->progressRenderer->progressStagePercentage(uiComplete); + + if(app.GetChangingSessionType()) + { + // 4J Stu - This causes the fullscreenprogress scene to ignore the action it was given + hr = ERROR_CANCELLED; + } + } + + if(hr!=S_OK) return -1; + + // finish the bar + for(int i=uiComplete;i<100;i++) + { + Sleep(5); + pMinecraft->progressRenderer->progressStagePercentage(i); + } + + + // now upload the save data + pMinecraft->progressRenderer->progressStage( IDS_XBONE_UPLOAD_SAVE ); + + // write the save file, and increment the progress percentage + pMinecraft->progressRenderer->progressStagePercentage(25); + pClass->m_bSaveDataReceived=false; + C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&pClass->m_XContentData,CScene_TransferToXboxOne::LoadSaveDataReturned,lpParameter); + + // sleep until we have the data + while(pClass->m_bSaveDataReceived==false) + { + Sleep(50); + } + + // write the save to user TMS + + // break the file up into 256K chunks + unsigned int uiChunkSize=262144; + unsigned int uiBytesLeft=pClass->m_uiStorageLength; + C4JStorage::ETMSStatus eStatus; + // max file size would be 100*256K + unsigned int uiPercentageChunk=100/(pClass->m_uiStorageLength/uiChunkSize); + uiComplete=0; + + if(uiPercentageChunk==0) uiPercentageChunk=1; + + for(int i=0;i<(pClass->m_uiStorageLength/uiChunkSize)+1;i++) + { + sprintf( szFilename, "XboxOne/Slot%.2d%.2d", pClass->m_uiSlotID,i ); + PCHAR pchData=((PCHAR)pClass->m_pvSaveMem)+i*uiChunkSize; + + pClass->m_bWaitingForWrite=true; + if(uiBytesLeft>=uiChunkSize) + { + eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,szFilename,pchData, uiChunkSize, + &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); + uiBytesLeft-=uiChunkSize; + } + else + { + // last bit of the file to upload is less than uiChunkSize + eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,szFilename,pchData, uiBytesLeft, + &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); + } + + // wait until + if(eStatus!=C4JStorage::ETMSStatus_WriteInProgress) + { + // failed + pClass->m_bWaitingForWrite=false; + } + else + { + // loop waiting for the write to complete + while(pClass->m_bWaitingForWrite && (hr == S_OK)) + { + Sleep(50); + } + uiComplete+=uiPercentageChunk; + if(uiComplete>100) uiComplete=100; + + // update the progress + pMinecraft->progressRenderer->progressStagePercentage(uiComplete); + } + } + + + + delete pClass->m_pvSaveMem; + } + return hr; +} + +int CScene_TransferToXboxOne::LoadSaveDataReturned(void *pParam,bool bContinue) +{ + CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne*)pParam; + + if(bContinue==true) + { + unsigned int uiFileSize = StorageManager.GetSaveSize(); + pClass->m_pvSaveMem = new BYTE [uiFileSize]; + pClass->m_uiStorageLength=0; + + StorageManager.GetSaveData( pClass->m_pvSaveMem, &pClass->m_uiStorageLength ); + + pClass->m_bSaveDataReceived=true; + } + + return 0; +} + +HRESULT CScene_TransferToXboxOne::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + if(m_bIgnoreInput) return S_OK; + + // if we're retrieving save info, ignore key presses + if(m_bRetrievingSaveInfo) + { + return S_OK; + } + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr = S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_B: + case VK_ESCAPE: + + app.NavigateBack(XUSER_INDEX_ANY); + rfHandled = TRUE; + break; + case VK_PAD_X: + // wipe the save slots + if(m_pbSlotListFile!=NULL) + { + m_SavesSlotListTimer.SetShow(TRUE); + m_bIgnoreInput=true; + + C4JStorage::ETMSStatus eStatus=StorageManager.TMSPP_DeleteFile(m_iPad,"XboxOne/SlotList",C4JStorage::TMS_FILETYPE_BINARY,&CScene_TransferToXboxOne::TMSPPDeleteReturned,this, 0); + + } + + break; + } + + return hr; +} + +HRESULT CScene_TransferToXboxOne::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) +{ + + //if(m_bReady) + { + CXuiSceneBase::PlayUISFX(eSFX_Focus); + } + + return S_OK; +} + + +HRESULT CScene_TransferToXboxOne::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) +{ + //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; + + if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || + pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) + { + // 4J Stu - We may have had to unload our font renderer in this scene if one of the save files + // uses characters not in our font (eg asian chars) so restore our font renderer + // This will not do anything if our font renderer is already loaded + app.OverrideFontRenderer(true,true); + } + + return S_OK; +} + +HRESULT CScene_TransferToXboxOne::OnFontRendererChange() +{ + // update the tooltips + CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); + + return S_OK; +} + +HRESULT CScene_TransferToXboxOne::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + // update the tooltips + CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); + + return S_OK; +} + +HRESULT CScene_TransferToXboxOne::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) +{ + return S_OK; +} + + diff --git a/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.h b/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.h new file mode 100644 index 00000000..f08de59a --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.h @@ -0,0 +1,88 @@ +#pragma once +using namespace std; +//#include <vector> + +#include "..\Media\xuiscene_TransferToXboxOne.h" + + +class CXuiCtrl4JList; + +class CScene_TransferToXboxOne : public CXuiSceneImpl +{ +protected: + + typedef struct + { + WCHAR wchSaveTitle[XCONTENT_MAX_DISPLAYNAME_LENGTH]; + unsigned int uiImageLength; + } + SLOTDATA; + + CXuiCtrl4JList *m_pSavesSlotList; + CXuiList m_SavesSlotList; + CXuiControl m_SavesSlotListTimer; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_DESTROY(OnDestroy) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_NOTIFY_PRESS_EX(OnNotifyPressEx) + XUI_ON_XM_NOTIFY_SELCHANGED(OnNotifySelChanged) + XUI_ON_XM_NOTIFY_SET_FOCUS(OnNotifySetFocus) + XUI_ON_XM_NOTIFY_KILL_FOCUS(OnNotifyKillFocus) + XUI_ON_XM_TRANSITION_START(OnTransitionStart) + XUI_ON_XM_FONTRENDERERCHANGE_MESSAGE(OnFontRendererChange) + + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_SavesSlotTimer, m_SavesSlotListTimer) + MAP_CONTROL(IDC_SavesSlotsList, m_SavesSlotList) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnDestroy(); + HRESULT OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData,BOOL& rfHandled); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnNavReturn(HXUIOBJ hObj,BOOL& rfHandled); + HRESULT OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled); + HRESULT OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + HRESULT OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ); + HRESULT OnFontRendererChange(); + +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_TransferToXboxOne, L"CScene_TransferToXboxOne", XUI_CLASS_SCENE ) + + static int TMSPPSlotListReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename); + static int TMSPPWriteReturned(LPVOID pParam,int iPad,int iUserData); + static int TMSPPDeleteReturned(LPVOID pParam,int iPad,int iUserData); + static int UploadSaveForXboxOneThreadProc( LPVOID lpParameter ); + static int LoadSaveDataReturned(void *pParam,bool bContinue); +private: + HRESULT BuildSlotFile(int iIndexBeingUpdated,PBYTE pbImageData,DWORD dwImageBytes); + + bool m_bIgnoreInput; + bool m_bRetrievingSaveInfo; + int m_iPad; + int m_MaxSlotC; + int m_iX; // tooltip for clearing all slots if there are saves in them + LoadMenuInitData *m_params; + XCONTENT_DATA m_XContentData; + PBYTE m_pbImageData; + DWORD m_dwImageBytes; + HXUIBRUSH m_hXuiBrush; + PBYTE m_pbSlotListFile; + unsigned int m_uiSlotListFileBytes; + SLOTDATA *m_pSlotDataA; + bool m_bWaitingForWrite; + void *m_pvSaveMem; + unsigned int m_uiStorageLength; + bool m_bSaveDataReceived; + unsigned int m_uiSlotID; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.cpp b/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.cpp new file mode 100644 index 00000000..51121099 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.cpp @@ -0,0 +1,136 @@ +#include "stdafx.h" +#include "XUI_TrialExitUpsell.h" + +// wchImages[TRIAL_EXIT_UPSELL_IMAGE_COUNT] +WCHAR *CScene_TrialExitUpsell::wchImages[]= +{ + L"Graphics/UpsellScreenshots/Screenshot1.png", + L"Graphics/UpsellScreenshots/Screenshot2.png", + L"Graphics/UpsellScreenshots/Screenshot3.png", + L"Graphics/UpsellScreenshots/Screenshot4.png", + L"Graphics/UpsellScreenshots/Screenshot5.png", + L"Graphics/UpsellScreenshots/Screenshot6.png", + L"Graphics/UpsellScreenshots/Screenshot7.png", + L"Graphics/UpsellScreenshots/Screenshot8.png" +}; + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_TrialExitUpsell::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad=*(int *)pInitData->pvInitData; + + MapChildControls(); + + m_bCanExit = true; + m_bFadeStarted = false; + m_bShowingImage1 = true; + m_imagesShown = 0; + + m_image1.SetImagePath( wchImages[m_imagesShown] ); + SetTimer( 0, TRIAL_EXIT_UPSELL_IMAGE_DISPLAY_TIME); + + CXuiSceneBase::ShowBackground(DEFAULT_XUI_MENU_USER , FALSE); + CXuiSceneBase::ShowLogo(DEFAULT_XUI_MENU_USER , FALSE); + + if( m_bCanExit ) + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_EXIT_GAME,IDS_TOOLTIPS_BACK, IDS_UNLOCK_TITLE); + } + else + { + ui.SetTooltips( DEFAULT_XUI_MENU_USER, -1,IDS_TOOLTIPS_BACK, IDS_UNLOCK_TITLE); + } + + return S_OK; +} + +HRESULT CScene_TrialExitUpsell::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + // ignore repeats + if(pInputData->dwFlags&XUI_INPUT_FLAG_REPEAT) return S_OK; + + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + + // Explicitly handle B button presses + switch(pInputData->dwKeyCode) + { + case VK_PAD_A: +#ifdef _XBOX + if( m_bCanExit ) + { + XLaunchNewImage(XLAUNCH_KEYWORD_DASH_ARCADE, 0); + } +#endif + break; + case VK_PAD_B: + case VK_ESCAPE: + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + break; + case VK_PAD_X: + if(ProfileManager.IsSignedIn(pInputData->UserIndex)) + { + TelemetryManager->RecordUpsellPresented(pInputData->UserIndex, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID); + ProfileManager.DisplayFullVersionPurchase(false,pInputData->UserIndex,eSen_UpsellID_Full_Version_Of_Game); + } + break; + } + + return hr; +} + +HRESULT CScene_TrialExitUpsell::OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled) +{ + if(m_bFadeStarted) + { + m_bFadeStarted = false; + m_bShowingImage1 = !m_bShowingImage1; + // We start a timer so we know when this image has been displayed for the required time + return SetTimer( 0, TRIAL_EXIT_UPSELL_IMAGE_DISPLAY_TIME); + } + else + { + return S_OK; + } +} + +HRESULT CScene_TrialExitUpsell::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) +{ + int nStart, nEnd; + + KillTimer(0); + + ++m_imagesShown; + if( m_imagesShown >= TRIAL_EXIT_UPSELL_IMAGE_COUNT ) + { + m_imagesShown = 0; //Loop round to the start + m_bCanExit = true; + + ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_EXIT_GAME,IDS_TOOLTIPS_BACK, IDS_UNLOCK_TITLE); + } + + if( m_bShowingImage1 ) + { + m_image2.SetImagePath( wchImages[m_imagesShown] ); + + FindNamedFrame( L"Fade1to2", &nStart ); + FindNamedFrame( L"EndFade1to2", &nEnd ); + PlayTimeline( nStart, nStart, nEnd, FALSE, TRUE ); + m_bFadeStarted = true; + } + else + { + m_image1.SetImagePath( wchImages[m_imagesShown] ); + + FindNamedFrame( L"Fade2to1", &nStart ); + FindNamedFrame( L"EndFade2to1", &nEnd ); + PlayTimeline( nStart, nStart, nEnd, FALSE, TRUE ); + m_bFadeStarted = true; + } + + return S_OK; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.h b/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.h new file mode 100644 index 00000000..748b36a2 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.h @@ -0,0 +1,46 @@ +#pragma once + +#include "../media/xuiscene_trialexitupsell.h" + +#define TRIAL_EXIT_UPSELL_IMAGE_DISPLAY_TIME 3000 + +#define TRIAL_EXIT_UPSELL_IMAGE_COUNT 8 + +class CScene_TrialExitUpsell : public CXuiSceneImpl +{ +private: + static WCHAR *wchImages[TRIAL_EXIT_UPSELL_IMAGE_COUNT]; + +protected: + CXuiImageElement m_image1, m_image2; + + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_KEYDOWN(OnKeyDown) + XUI_ON_XM_TIMELINE_END(OnTimelineEnd) + XUI_ON_XM_TIMER( OnTimer ) + XUI_END_MSG_MAP() + + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_XuiImage1, m_image1) + MAP_CONTROL(IDC_XuiImage2, m_image2) + END_CONTROL_MAP() + + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled); + HRESULT OnTimelineEnd(HXUIOBJ hObjSource, BOOL& bHandled); + HRESULT OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ); + + int m_iPad; + bool m_bCanExit; + bool m_bFadeStarted; + bool m_bShowingImage1; + unsigned char m_imagesShown; +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_TrialExitUpsell, L"CScene_TrialExitUpsell", XUI_CLASS_SCENE ) + +}; diff --git a/Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp b/Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp new file mode 100644 index 00000000..98951d81 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp @@ -0,0 +1,603 @@ +#include "stdafx.h" +#include "..\..\Common\Tutorial\Tutorial.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Tile.h" +#include "..\..\..\Minecraft.World\Item.h" +#include "XUI_Ctrl_CraftIngredientSlot.h" +#include "XUI_XZP_Icons.h" + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_TutorialPopup::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + HRESULT hr = S_OK; + + tutorial = (Tutorial *)pInitData->pvInitData; + m_iPad = tutorial->getPad(); + + MapChildControls(); + + // splitscreen? + // if we are in splitscreen, then we need to figure out if we want to move this scene + if(app.GetLocalPlayerCount()>1) + { + app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); + } + + m_textFontSize = _fromString<int>( m_fontSizeControl.GetText() ); + m_fontSizeControl.SetShow(false); + + m_interactScene = NULL; + m_lastSceneMovedLeft = false; + m_bAllowFade = false; + + SetShow(false); + XuiSetTimer(m_hObj,TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,TUTORIAL_POPUP_MOVE_SCENE_TIME); + + return hr; +} + +HRESULT CScene_TutorialPopup::OnDestroy() +{ + return S_OK; +} + +HRESULT CScene_TutorialPopup::OnTimer(XUIMessageTimer *pData,BOOL& rfHandled) +{ + if( pData->nId == TUTORIAL_POPUP_FADE_TIMER_ID ) + { + XuiKillTimer(m_hObj,TUTORIAL_POPUP_FADE_TIMER_ID); + SetShow( false ); + XuiSetTimer(m_hObj,TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,TUTORIAL_POPUP_MOVE_SCENE_TIME); + } + else if( pData->nId == TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID ) + { + UpdateInteractScenePosition(IsShown() == TRUE); + XuiKillTimer(m_hObj,TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID); + } + + return S_OK; +} + +void CScene_TutorialPopup::UpdateInteractScenePosition(bool visible) +{ + if( m_interactScene == NULL ) return; + + // 4J-PB - check this players screen section to see if we should allow the animation + bool bAllowAnim=false; + HXUICLASS sceneClass = XuiGetObjectClass( m_interactScene->m_hObj ); + + HXUICLASS inventoryClass = XuiFindClass( L"CXuiSceneInventory" ); + HXUICLASS furnaceClass = XuiFindClass( L"CXuiSceneFurnace" ); + HXUICLASS craftingClass = XuiFindClass( L"CXuiSceneCraftingPanel" ); + HXUICLASS trapClass = XuiFindClass( L"CXuiSceneTrap" ); + HXUICLASS containerClass = XuiFindClass( L"CXuiSceneContainer" ); + HXUICLASS creativeInventoryClass = XuiFindClass( L"CXuiSceneInventoryCreative" ); + HXUICLASS enchantingClass = XuiFindClass( L"CXuiSceneEnchant" ); + HXUICLASS brewingClass = XuiFindClass( L"CXuiSceneBrewingStand" ); + HXUICLASS anvilClass = XuiFindClass( L"CXuiSceneAnvil" ); + HXUICLASS tradingClass = XuiFindClass( L"CXuiSceneTrading" ); + BOOL isCraftingScene = XuiClassDerivesFrom( sceneClass, craftingClass ); + BOOL isCreativeScene = XuiClassDerivesFrom( sceneClass, creativeInventoryClass ); + + switch(Minecraft::GetInstance()->localplayers[m_iPad]->m_iScreenSection) + { + case C4JRender::VIEWPORT_TYPE_FULLSCREEN: + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + bAllowAnim=true; + break; + default: + // anim allowed for everything except the crafting 2x2 and 3x3, and the creative menu + if(!isCraftingScene && !isCreativeScene) + { + bAllowAnim=true; + } + break; + } + + if(bAllowAnim) + { + + XUITimeline *timeline; + XUINamedFrame *startFrame; + XUINamedFrame *endFrame; + bool movingLeft = false; + // Also returns TRUE if they are the same (which is what we want) + if( XuiClassDerivesFrom( sceneClass, inventoryClass ) || + XuiClassDerivesFrom( sceneClass, furnaceClass ) || + XuiClassDerivesFrom( sceneClass, trapClass ) || + XuiClassDerivesFrom( sceneClass, containerClass ) || + XuiClassDerivesFrom( sceneClass, enchantingClass ) || + XuiClassDerivesFrom( sceneClass, brewingClass ) || + XuiClassDerivesFrom( sceneClass, anvilClass ) || + XuiClassDerivesFrom( sceneClass, tradingClass ) || + isCreativeScene || + isCraftingScene == TRUE ) + { + XuiElementGetTimeline( m_interactScene->m_hObj, &timeline); + if(visible) + { + startFrame = timeline->FindNamedFrame( L"MoveLeft" ); + endFrame = timeline->FindNamedFrame( L"EndMoveLeft" ); + movingLeft = true; + } + else + { + startFrame = timeline->FindNamedFrame( L"MoveRight" ); + endFrame = timeline->FindNamedFrame( L"EndMoveRight" ); + } + + if( (m_lastInteractSceneMoved != m_interactScene && movingLeft) || ( m_lastInteractSceneMoved == m_interactScene && m_lastSceneMovedLeft != movingLeft ) ) + { + timeline->Play( startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE ); + + m_lastInteractSceneMoved = m_interactScene; + m_lastSceneMovedLeft = movingLeft; + } + } + } + +} + +HRESULT CScene_TutorialPopup::_SetDescription(CXuiScene *interactScene, LPCWSTR desc, LPCWSTR title, bool allowFade, bool isReminder) +{ + HRESULT hr = S_OK; + m_interactScene = interactScene; + if( interactScene != m_lastInteractSceneMoved ) m_lastInteractSceneMoved = NULL; + if(desc == NULL) + { + SetShow( false ); + XuiSetTimer(m_hObj,TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,TUTORIAL_POPUP_MOVE_SCENE_TIME); + XuiKillTimer(m_hObj,TUTORIAL_POPUP_FADE_TIMER_ID); + } + else + { + SetShow( true ); + XuiSetTimer(m_hObj,TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,TUTORIAL_POPUP_MOVE_SCENE_TIME); + + if( allowFade ) + { + //Initialise a timer to fade us out again + XuiSetTimer(m_hObj,TUTORIAL_POPUP_FADE_TIMER_ID,tutorial->GetTutorialDisplayMessageTime()); + } + else + { + XuiKillTimer(m_hObj,TUTORIAL_POPUP_FADE_TIMER_ID); + } + m_bAllowFade = allowFade; + + if(isReminder) + { + wstring text(app.GetString( IDS_TUTORIAL_REMINDER )); + text.append( desc ); + // set the text colour + wchar_t formatting[40]; + swprintf(formatting, 40, L"<font color=\"#%08x\" size=\"%d\">",app.GetHTMLColour(eHTMLColor_White),m_textFontSize); + text = formatting + text; + + hr = m_description.SetText( text.c_str() ); + } + else + { + wstring text(desc); + // set the text colour + wchar_t formatting[40]; + swprintf(formatting, 40, L"<font color=\"#%08x\" size=\"%d\">",app.GetHTMLColour(eHTMLColor_White),m_textFontSize); + text = formatting + text; + + hr = m_description.SetText( text.c_str() ); + } + + D3DXVECTOR3 titlePos; + hr = XuiElementGetPosition( m_title, &titlePos ); + + BOOL titleShowAtStart = m_title.IsShown(); + if( title != NULL && title[0] != 0 ) + { + m_title.SetText( title ); + m_title.SetShow(TRUE); + } + else + { + m_title.SetText( L"" ); + m_title.SetShow(FALSE); + } + BOOL titleShowAtEnd = m_title.IsShown(); + if(titleShowAtStart != titleShowAtEnd) + { + float fHeight, fWidth, fTitleHeight, fDescHeight, fDescWidth; + m_title.GetBounds(&fWidth,&fTitleHeight); + GetBounds(&fWidth,&fHeight); + + + // 4J Stu - For some reason when we resize the scene it resets the size of the HTML control + // We don't want that to happen, so get it's size before and set it back after + m_description.GetBounds(&fDescWidth,&fDescHeight); + if(titleShowAtEnd) + { + titlePos.y += fTitleHeight; + + SetBounds(fWidth, fHeight + fTitleHeight); + } + else + { + SetBounds(fWidth, fHeight - fTitleHeight); + } + XuiElementSetPosition( m_description, &titlePos ); + m_description.SetBounds(fDescWidth, fDescHeight); + } + + // Check if we need to resize the box + XUIContentDims contentDims; + m_description.GetContentDims(&contentDims); + + int heightDiff = contentDims.nContentHeight - contentDims.nPageHeight; + + float fHeight, fWidth; + GetBounds(&fWidth,&fHeight); + SetBounds(fWidth, fHeight + heightDiff); + + m_description.GetBounds(&fWidth,&fHeight); + m_description.SetBounds(fWidth, (float)(contentDims.nPageHeight + heightDiff)); + } + return hr; +} + +HRESULT CScene_TutorialPopup::SetDescription(int iPad, TutorialPopupInfo *info) +{ + HRESULT hr = S_OK; + +#ifdef _XBOX + HXUIOBJ hObj = app.GetCurrentTutorialScene(iPad); + HXUICLASS thisClass = XuiFindClass( L"CScene_TutorialPopup" ); + HXUICLASS objClass = XuiGetObjectClass( hObj ); + + // Also returns TRUE if they are the same (which is what we want) + if( XuiClassDerivesFrom( objClass, thisClass ) ) + { + + CScene_TutorialPopup *pThis; + hr = XuiObjectFromHandle(hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + wstring parsed = pThis->_SetIcon(info->icon, info->iAuxVal, info->isFoil, info->desc); + parsed = pThis->_SetImage( parsed ); + parsed = CScene_TutorialPopup::ParseDescription(iPad, parsed); + if(parsed.empty()) + { + hr = pThis->_SetDescription( info->interactScene, NULL, NULL, info->allowFade, info->isReminder ); + } + else + { + hr = pThis->_SetDescription( info->interactScene, parsed.c_str(), info->title, info->allowFade, info->isReminder ); + } + } +#endif + return hr; +} + +wstring CScene_TutorialPopup::_SetIcon(int icon, int iAuxVal, bool isFoil, LPCWSTR desc) +{ + wstring temp(desc); + + BOOL iconShowAtStart = m_pCraftingPic->IsShown(); + + if( icon != TUTORIAL_NO_ICON ) + { + bool itemIsFoil = false; + itemIsFoil = (shared_ptr<ItemInstance>(new ItemInstance(icon,1,iAuxVal)))->isFoil(); + if(!itemIsFoil) itemIsFoil = isFoil; + + m_pCraftingPic->SetIcon(m_iPad, icon,iAuxVal,1,10,31,false,itemIsFoil); + } + else + { + wstring openTag(L"{*ICON*}"); + wstring closeTag(L"{*/ICON*}"); + int iconTagStartPos = (int)temp.find(openTag); + int iconStartPos = iconTagStartPos + (int)openTag.length(); + if( iconTagStartPos > 0 && iconStartPos < (int)temp.length() ) + { + int iconEndPos = (int)temp.find( closeTag, iconStartPos ); + + if(iconEndPos > iconStartPos && iconEndPos < (int)temp.length() ) + { + wstring id = temp.substr(iconStartPos, iconEndPos - iconStartPos); + + vector<wstring> idAndAux = stringSplit(id,L':'); + + int iconId = _fromString<int>(idAndAux[0]); + + if(idAndAux.size() > 1) + { + iAuxVal = _fromString<int>(idAndAux[1]); + } + else + { + iAuxVal = 0; + } + + bool itemIsFoil = false; + itemIsFoil = (shared_ptr<ItemInstance>(new ItemInstance(iconId,1,iAuxVal)))->isFoil(); + if(!itemIsFoil) itemIsFoil = isFoil; + + m_pCraftingPic->SetIcon(m_iPad, iconId,iAuxVal,1,10,31,false,itemIsFoil); + + temp.replace(iconTagStartPos, iconEndPos - iconTagStartPos + closeTag.length(), L""); + } + } + + // remove any icon text + else if(temp.find(L"{*CraftingTableIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::workBench->id,0,1,10,31,false); + } + else if(temp.find(L"{*SticksIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::stick->id,0,1,10,31,false); + } + else if(temp.find(L"{*PlanksIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::wood->id,0,1,10,31,false); + } + else if(temp.find(L"{*WoodenShovelIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::shovel_wood->id,0,1,10,31,false); + } + else if(temp.find(L"{*WoodenHatchetIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::hatchet_wood->id,0,1,10,31,false); + } + else if(temp.find(L"{*WoodenPickaxeIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::pickAxe_wood->id,0,1,10,31,false); + } + else if(temp.find(L"{*FurnaceIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::furnace_Id,0,1,10,31,false); + } + else if(temp.find(L"{*WoodenDoorIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::door_wood->id,0,1,10,31,false); + } + else if(temp.find(L"{*TorchIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::torch_Id,0,1,10,31,false); + } + else if(temp.find(L"{*BoatIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::boat_Id,0,1,10,31,false); + } + else if(temp.find(L"{*FishingRodIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::fishingRod_Id,0,1,10,31,false); + } + else if(temp.find(L"{*FishIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::fish_raw_Id,0,1,10,31,false); + } + else if(temp.find(L"{*MinecartIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Item::minecart_Id,0,1,10,31,false); + } + else if(temp.find(L"{*RailIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::rail_Id,0,1,10,31,false); + } + else if(temp.find(L"{*PoweredRailIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::goldenRail_Id,0,1,10,31,false); + } + else if(temp.find(L"{*StructuresIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, XZP_ICON_STRUCTURES,0,1,10,31,false); + } + else if(temp.find(L"{*ToolsIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, XZP_ICON_TOOLS,0,1,10,31,false); + } + else if(temp.find(L"{*StoneIcon*}")!=wstring::npos) + { + m_pCraftingPic->SetIcon(m_iPad, Tile::rock_Id,0,1,10,31,false); + } + else + { + // hide the icon slot + m_pCraftingPic->SetIcon(m_iPad, 0,0,0,0,0,false,false,FALSE); + } + } + + BOOL iconShowAtEnd = m_pCraftingPic->IsShown(); + if(iconShowAtStart != iconShowAtEnd) + { + float fHeight, fWidth, fIconHeight, fDescHeight, fDescWidth; + m_pCraftingPic->GetBounds(&fWidth,&fIconHeight); + GetBounds(&fWidth,&fHeight); + + + // 4J Stu - For some reason when we resize the scene it resets the size of the HTML control + // We don't want that to happen, so get it's size before and set it back after + m_description.GetBounds(&fDescWidth,&fDescHeight); + if(iconShowAtEnd) + { + SetBounds(fWidth, fHeight + fIconHeight); + } + else + { + SetBounds(fWidth, fHeight - fIconHeight); + } + m_description.SetBounds(fDescWidth, fDescHeight); + } + + return temp; +} + +wstring CScene_TutorialPopup::_SetImage(wstring &desc) +{ + + BOOL imageShowAtStart = m_image.IsShown(); + + wstring openTag(L"{*IMAGE*}"); + wstring closeTag(L"{*/IMAGE*}"); + int imageTagStartPos = (int)desc.find(openTag); + int imageStartPos = imageTagStartPos + (int)openTag.length(); + if( imageTagStartPos > 0 && imageStartPos < (int)desc.length() ) + { + int imageEndPos = (int)desc.find( closeTag, imageStartPos ); + + if(imageEndPos > imageStartPos && imageEndPos < (int)desc.length() ) + { + wstring id = desc.substr(imageStartPos, imageEndPos - imageStartPos); + m_image.SetImagePath( id.c_str() ); + m_image.SetShow( TRUE ); + + desc.replace(imageTagStartPos, imageEndPos - imageTagStartPos + closeTag.length(), L""); + } + } + else + { + // hide the icon slot + m_image.SetShow( FALSE ); + } + + BOOL imageShowAtEnd = m_image.IsShown(); + if(imageShowAtStart != imageShowAtEnd) + { + float fHeight, fWidth, fIconHeight, fDescHeight, fDescWidth; + m_image.GetBounds(&fWidth,&fIconHeight); + GetBounds(&fWidth,&fHeight); + + + // 4J Stu - For some reason when we resize the scene it resets the size of the HTML control + // We don't want that to happen, so get it's size before and set it back after + m_description.GetBounds(&fDescWidth,&fDescHeight); + if(imageShowAtEnd) + { + SetBounds(fWidth, fHeight + fIconHeight); + } + else + { + SetBounds(fWidth, fHeight - fIconHeight); + } + m_description.SetBounds(fDescWidth, fDescHeight); + } + + return desc; +} + + +wstring CScene_TutorialPopup::ParseDescription(int iPad, wstring &text) +{ + text = replaceAll(text, L"{*CraftingTableIcon*}", L""); + text = replaceAll(text, L"{*SticksIcon*}", L""); + text = replaceAll(text, L"{*PlanksIcon*}", L""); + text = replaceAll(text, L"{*WoodenShovelIcon*}", L""); + text = replaceAll(text, L"{*WoodenHatchetIcon*}", L""); + text = replaceAll(text, L"{*WoodenPickaxeIcon*}", L""); + text = replaceAll(text, L"{*FurnaceIcon*}", L""); + text = replaceAll(text, L"{*WoodenDoorIcon*}", L""); + text = replaceAll(text, L"{*TorchIcon*}", L""); + text = replaceAll(text, L"{*MinecartIcon*}", L""); + text = replaceAll(text, L"{*BoatIcon*}", L""); + text = replaceAll(text, L"{*FishingRodIcon*}", L""); + text = replaceAll(text, L"{*FishIcon*}", L""); + text = replaceAll(text, L"{*RailIcon*}", L""); + text = replaceAll(text, L"{*PoweredRailIcon*}", L""); + text = replaceAll(text, L"{*StructuresIcon*}", L""); + text = replaceAll(text, L"{*ToolsIcon*}", L""); + text = replaceAll(text, L"{*StoneIcon*}", L""); + + if( app.GetLocalPlayerCount() > 1 ) + { + // TODO TU-1 - This should really be a string as well rather than hardcoded here + text = replaceAll(text, L"{*EXIT_PICTURE*}", L"<div align=\"center\"><img height=\"90\" width=\"160\" src=\"TutorialExitScreenshot.png\"/></div>" ); + + // TODO TU-1 - This should also be separate strings, or move these things out of a localisable file so we can add/change them at will + text = replaceAll(text, L"height=\"30\" width=\"30\"", L"height=\"20\" width=\"20\""); + } + else + { + text = replaceAll(text, L"{*EXIT_PICTURE*}", app.GetString( IDS_TUTORIAL_HTML_EXIT_PICTURE ) ); + } + /* +#define MINECRAFT_ACTION_RENDER_DEBUG ACTION_INGAME_13 +#define MINECRAFT_ACTION_PAUSEMENU ACTION_INGAME_15 +#define MINECRAFT_ACTION_SNEAK_TOGGLE ACTION_INGAME_17 + */ + + return app.FormatHTMLString(iPad,text); +} + +HRESULT CScene_TutorialPopup::_SetVisible(bool show) +{ + HRESULT hr = this->SetShow( show ); + + if( show && m_bAllowFade ) + { + //Initialise a timer to fade us out again + XuiSetTimer(m_hObj,TUTORIAL_POPUP_FADE_TIMER_ID,tutorial->GetTutorialDisplayMessageTime()); + } + + return hr; +} + +bool CScene_TutorialPopup::_IsSceneVisible() +{ + bool isVisible = this->IsShown()==TRUE?true:false; + + return isVisible; +} + +HRESULT CScene_TutorialPopup::SetSceneVisible(int iPad, bool show) +{ + HRESULT hr = S_OK; + + HXUIOBJ hObj = app.GetCurrentTutorialScene(iPad); + HXUICLASS thisClass = XuiFindClass( L"CScene_TutorialPopup" ); + HXUICLASS objClass = XuiGetObjectClass( hObj ); + + // Also returns TRUE if they are the same (which is what we want) + if( XuiClassDerivesFrom( objClass, thisClass ) ) + { + CScene_TutorialPopup *pThis; + hr = XuiObjectFromHandle(hObj, (void **) &pThis); + if (FAILED(hr)) + return hr; + + hr = pThis->_SetVisible( show ); + } + return hr; +} + + +HRESULT CScene_TutorialPopup::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) +{ + bHandled=true; + return app.AdjustSplitscreenScene_PlayerChanged(m_hObj,&m_OriginalPosition,m_iPad,bJoining); +} + +bool CScene_TutorialPopup::IsSceneVisible(int iPad) +{ + bool isVisible = false; + HRESULT hr; + + HXUIOBJ hObj = app.GetCurrentTutorialScene(iPad); + HXUICLASS thisClass = XuiFindClass( L"CScene_TutorialPopup" ); + HXUICLASS objClass = XuiGetObjectClass( hObj ); + + // Also returns TRUE if they are the same (which is what we want) + if( XuiClassDerivesFrom( objClass, thisClass ) ) + { + CScene_TutorialPopup *pThis; + hr = XuiObjectFromHandle(hObj, (void **) &pThis); + if (FAILED(hr)) + return false; + + isVisible = pThis->_IsSceneVisible(); + } + return isVisible; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_TutorialPopup.h b/Minecraft.Client/Common/XUI/XUI_TutorialPopup.h new file mode 100644 index 00000000..65716759 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_TutorialPopup.h @@ -0,0 +1,78 @@ +#pragma once +#include "../media/xuiscene_tutorialpopup.h" +#include "XUI_CustomMessages.h" + +class Tutorial; +class CXuiCtrlCraftIngredientSlot; + +#define TUTORIAL_POPUP_FADE_TIMER_ID 0 +#define TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID 1 +#define TUTORIAL_POPUP_MOVE_SCENE_TIME 500 + +class CScene_TutorialPopup : public CXuiSceneImpl +{ +private: + Tutorial *tutorial; + + // A scene that may be displayed behind the popup that the player is using, that will need shifted so we can see it clearly. + CXuiScene *m_interactScene, *m_lastInteractSceneMoved; + bool m_lastSceneMovedLeft; + bool m_bAllowFade; + + int m_iPad; + + CXuiHtmlControl m_description; + CXuiCtrlCraftIngredientSlot *m_pCraftingPic; + CXuiControl m_title; + CXuiImageElement m_image; + + CXuiControl m_fontSizeControl; + + int m_textFontSize; + D3DXVECTOR3 m_OriginalPosition; + +protected: + // Message map. Here we tie messages to message handlers. + XUI_BEGIN_MSG_MAP() + XUI_ON_XM_INIT( OnInit ) + XUI_ON_XM_TIMER(OnTimer) + XUI_ON_XM_DESTROY( OnDestroy ) + XUI_ON_XM_SPLITSCREENPLAYER_MESSAGE(OnCustomMessage_Splitscreenplayer) + XUI_END_MSG_MAP() + + // Control mapping to objects + BEGIN_CONTROL_MAP() + MAP_CONTROL(IDC_Title, m_title) + MAP_CONTROL(IDC_Description, m_description) + MAP_OVERRIDE(IDC_XuiInventoryPic, m_pCraftingPic) + MAP_CONTROL(IDC_XuiImage, m_image) + MAP_CONTROL(IDC_FontSize, m_fontSizeControl) + + END_CONTROL_MAP() + + HRESULT OnInit( XUIMessageInit* pInitData, BOOL& bHandled ); + HRESULT OnTimer(XUIMessageTimer *pData,BOOL& rfHandled); + HRESULT OnDestroy(); + HRESULT OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled); +public: + + // Define the class. The class name must match the ClassOverride property + // set for the scene in the UI Authoring tool. + XUI_IMPLEMENT_CLASS( CScene_TutorialPopup, L"CScene_TutorialPopup", XUI_CLASS_SCENE ) + +private: + HRESULT _SetDescription(CXuiScene *interactScene, LPCWSTR desc, LPCWSTR title, bool allowFade, bool isReminder); + wstring _SetIcon(int icon, int iAuxVal, bool isFoil, LPCWSTR desc); + wstring _SetImage(wstring &desc); + HRESULT _SetVisible(bool show); + bool _IsSceneVisible(); + void UpdateInteractScenePosition(bool visible); + +public: + static HRESULT SetDescription(int iPad, TutorialPopupInfo *info); + static wstring ParseDescription(int iPad, wstring &text); + + static HRESULT SetSceneVisible(int iPad, bool show); + static bool IsSceneVisible(int iPad); + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_XZP_Icons.h b/Minecraft.Client/Common/XUI/XUI_XZP_Icons.h new file mode 100644 index 00000000..46a1c22d --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_XZP_Icons.h @@ -0,0 +1,20 @@ +#pragma once + +#define XZP_ICON_SKELETON 32000 +#define XZP_ICON_CREEPER 32001 +#define XZP_ICON_SPIDERJOCKEY 32002 +#define XZP_ICON_SPIDER 32003 +#define XZP_ICON_ZOMBIE 32004 +#define XZP_ICON_ZOMBIEPIGMAN 32005 +#define XZP_ICON_SWAM 32006 +#define XZP_ICON_WALKED 32007 +#define XZP_ICON_FALLEN 32008 +#define XZP_ICON_PORTAL 32009 +#define XZP_ICON_CLIMBED 32010 +#define XZP_ICON_GHAST 32011 +#define XZP_ICON_SLIME 32012 +#define XZP_ICON_STRUCTURES 32013 +#define XZP_ICON_TOOLS 32014 + +#define XZP_ICON_SHANK_01 0 +#define XZP_ICON_SHANK_03 1
\ No newline at end of file diff --git a/Minecraft.Client/Common/XUI/XUI_debug.cpp b/Minecraft.Client/Common/XUI/XUI_debug.cpp new file mode 100644 index 00000000..61b818a0 --- /dev/null +++ b/Minecraft.Client/Common/XUI/XUI_debug.cpp @@ -0,0 +1,391 @@ +// Minecraft.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" + +#include <assert.h> +#include "XUI_Debug.h" +#include "..\..\..\Minecraft.Client\StatsCounter.h" + +LPCWSTR CScene_Debug::m_DebugCheckboxTextA[eDebugSetting_Max+1]= +{ + L"Load Saves From Local Folder Mode", + L"Write Saves To Local Folder Mode", + L"Freeze Players", //L"Not Used", + L"Display Safe Area", + L"Mobs don't attack", + L"Freeze Time", + L"Disable Weather", + L"Craft Anything", + L"Use DPad for debug", + L"Mobs don't tick", + L"Instant Mine", + L"Show UI Console", + L"Distributable Save", + L"Debug Leaderboards", + L"Height-Water-Biome Maps", + L"Superflat nether", + //L"Light/Dark background", + L"More lightning when thundering", + L"", +}; + +LPCWSTR CScene_Debug::m_DebugButtonTextA[eDebugButton_Max+1]= +{ + L"Award Theme", + L"Award Avatar Item 1", + L"Award Avatar Item 2", + L"Award Avatar Item 3", + L"Award Gamerpic 1", + L"Award Gamerpic 2", + L"Check Tips", + L"Wipe Leaderboards", + L"", +}; + + + +//---------------------------------------------------------------------------------- +// Performs initialization tasks - retrieves controls. +//---------------------------------------------------------------------------------- +HRESULT CScene_Debug::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) +{ + m_iPad=*(int *)pInitData->pvInitData; + + // set text and enable any debug options required + int iCheckboxIndex=0; + int iButtonIndex=0; + float fWidth=500.0f; + float fX=240.0f; + float fY=200.0f; + float fYInc=5.0f; + float fControlHeight=25.0f; + + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen()) || app.GetLocalPlayerCount()>1) + { + fWidth=250.0f; + fX=30.0f; + fY=30.0f; + fYInc=5.0f; + fControlHeight=15.0f; + } + + CXuiCheckbox *pCheckbox; + CXuiControl *pButton; + m_iTotalCheckboxElements=0; + m_iTotalButtonElements=0; + m_bOnCheckboxes=true; + + // count the items + while((*m_DebugCheckboxTextA[m_iTotalCheckboxElements])!=0) + { + m_iTotalCheckboxElements++; + } + + m_DebugCheckboxDataA= new DEBUGDATA [m_iTotalCheckboxElements]; + + while((*m_DebugCheckboxTextA[iCheckboxIndex])!=0) + { + XuiCreateObject( XUI_CLASS_CHECKBOX, &m_DebugCheckboxDataA[iCheckboxIndex].hXuiObj ); + XuiObjectFromHandle( m_DebugCheckboxDataA[iCheckboxIndex].hXuiObj, &m_DebugCheckboxDataA[iCheckboxIndex].pvData ); + + pCheckbox = (CXuiCheckbox *)m_DebugCheckboxDataA[iCheckboxIndex].pvData; + //m_phXuiObjA[iElementIndex] = pCheckbox->m_hObj; + pCheckbox->SetText(m_DebugCheckboxTextA[iCheckboxIndex]); + pCheckbox->SetShow(TRUE); + + D3DXVECTOR3 vPos; + float tx,ty; + pCheckbox->GetBounds(&tx,&ty); + pCheckbox->SetBounds(fWidth,fControlHeight); + vPos.x=fX; + vPos.y=fY; + vPos.z=0.0f; + pCheckbox->SetPosition(&vPos); + fY+=fControlHeight+fYInc; + + XuiElementAddChild(m_hObj,m_DebugCheckboxDataA[iCheckboxIndex].hXuiObj); + + iCheckboxIndex++; + } + + // and the buttons + if((!RenderManager.IsHiDef() && !RenderManager.IsWidescreen())|| app.GetLocalPlayerCount()>1) + { + fWidth=260.0f; + fX=300.0f; + fY=30.0f; + fControlHeight=40.0f; + } + else + { + fWidth=350.0f; + fX=750.0f; + fY=200.0f; + fControlHeight=40.0f; + } + + + + while((*m_DebugButtonTextA[m_iTotalButtonElements])!=0) + { + m_iTotalButtonElements++; + } + + m_DebugButtonDataA= new DEBUGDATA [m_iTotalButtonElements]; + + while((*m_DebugButtonTextA[iButtonIndex])!=0) + { + XuiCreateObject( XUI_CLASS_BUTTON, &m_DebugButtonDataA[iButtonIndex].hXuiObj ); + XuiObjectFromHandle( m_DebugButtonDataA[iButtonIndex].hXuiObj, &m_DebugButtonDataA[iButtonIndex].pvData ); + + pButton = (CXuiControl *)m_DebugButtonDataA[iButtonIndex].pvData; + //m_phXuiObjA[iElementIndex] = pCheckbox->m_hObj; + pButton->SetText(m_DebugButtonTextA[iButtonIndex]); + pButton->SetShow(TRUE); + + D3DXVECTOR3 vPos; + float tx,ty; + pButton->GetBounds(&tx,&ty); + pButton->SetBounds(fWidth,fControlHeight); + vPos.x=fX; + vPos.y=fY; + vPos.z=0.0f; + pButton->SetPosition(&vPos); + fY+=fControlHeight+fYInc; + + XuiElementAddChild(m_hObj,m_DebugButtonDataA[iButtonIndex].hXuiObj); + + // if you're not the primary player, disable all these - you need a storage device for them + + if(ProfileManager.GetPrimaryPad()!=m_iPad) + { + XuiControlSetEnable(m_DebugButtonDataA[iButtonIndex].hXuiObj,FALSE); + } + iButtonIndex++; + } + + + + unsigned int uiDebugBitmask=app.GetGameSettingsDebugMask(m_iPad); + + for(int i=0;i<iCheckboxIndex;i++) + { + CXuiCheckbox *pCheckbox = (CXuiCheckbox *)m_DebugCheckboxDataA[i].pvData; + pCheckbox->SetCheck( (uiDebugBitmask&(1<<i)) ?TRUE:FALSE); + } + + + if(m_DebugCheckboxDataA[0].hXuiObj) + { + XuiElementSetUserFocus(m_DebugCheckboxDataA[0].hXuiObj,m_iPad); + } + + m_iCurrentCheckboxElement=0; + m_iCurrentButtonElement=0; + +#ifdef _DEBUG + // testing the upload of the player custom skin +// wstring wsTemp; +// +// wsTemp=L"Deadmau5_Skin.png"; +// app.UploadFileToGlobalStorage(m_iPad,C4JStorage::eGlobalStorage_TitleUser,&wsTemp); +// wsTemp=L"Mojang_Cape.png"; +// app.UploadFileToGlobalStorage(m_iPad,C4JStorage::eGlobalStorage_TitleUser,&wsTemp); +// wsTemp=L"4J_Cape.png"; +// app.UploadFileToGlobalStorage(m_iPad,C4JStorage::eGlobalStorage_TitleUser,&wsTemp); +#endif + + return S_OK; +} + +HRESULT CScene_Debug::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) +{ + ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); + + HRESULT hr=S_OK; + int iCurrentBitmaskIndex=0; + unsigned int uiDebugBitmask=0L; + + // Explicitly handle X button presses + if (pInputData->dwKeyCode == VK_PAD_B) + { + // check all the settings + for(int i=0;i<m_iTotalCheckboxElements;i++) + { + CXuiCheckbox *pCheckbox = (CXuiCheckbox *)m_DebugCheckboxDataA[i].pvData; + uiDebugBitmask|=pCheckbox->IsChecked()?(1<<iCurrentBitmaskIndex):0; + iCurrentBitmaskIndex++; + } + + if(uiDebugBitmask!=app.GetGameSettingsDebugMask(pInputData->UserIndex)) + { + app.SetGameSettingsDebugMask(pInputData->UserIndex,uiDebugBitmask); + if(app.DebugSettingsOn()) + { + app.ActionDebugMask(pInputData->UserIndex); + } + else + { + // force debug mask off + app.ActionDebugMask(pInputData->UserIndex,true); + } + + app.CheckGameSettingsChanged(true,pInputData->UserIndex); + } + app.NavigateBack(pInputData->UserIndex); + rfHandled = TRUE; + } + + + return hr; +} + + +HRESULT CScene_Debug::OnControlNavigate(XUIMessageControlNavigate *pControlNavigateData, BOOL& bHandled) +{ + if(m_bOnCheckboxes) + { + // If it's not from the current control, ignore it + if(m_DebugCheckboxDataA[m_iCurrentCheckboxElement].hXuiObj!=pControlNavigateData->hObjSource) return S_OK; + + switch(pControlNavigateData->nControlNavigate) + { + case XUI_CONTROL_NAVIGATE_UP: + if(m_iCurrentCheckboxElement>0) + { + m_iCurrentCheckboxElement--; + XuiElementSetUserFocus(m_DebugCheckboxDataA[m_iCurrentCheckboxElement].hXuiObj, m_iPad); + } + break; + case XUI_CONTROL_NAVIGATE_DOWN: + if((m_iCurrentCheckboxElement+1)<m_iTotalCheckboxElements) + { + m_iCurrentCheckboxElement++; + XuiElementSetUserFocus(m_DebugCheckboxDataA[m_iCurrentCheckboxElement].hXuiObj, m_iPad); + } + break; + case XUI_CONTROL_NAVIGATE_RIGHT: + m_bOnCheckboxes=false; + if(m_iCurrentCheckboxElement<m_iTotalButtonElements) + { + m_iCurrentButtonElement=m_iCurrentCheckboxElement; + } + XuiElementSetUserFocus(m_DebugButtonDataA[m_iCurrentButtonElement].hXuiObj, m_iPad); + break; + } + } + else + { + // If it's not from the current control, ignore it + if(m_DebugButtonDataA[m_iCurrentButtonElement].hXuiObj!=pControlNavigateData->hObjSource) return S_OK; + + switch(pControlNavigateData->nControlNavigate) + { + case XUI_CONTROL_NAVIGATE_UP: + if(m_iCurrentButtonElement>0) + { + m_iCurrentButtonElement--; + XuiElementSetUserFocus(m_DebugButtonDataA[m_iCurrentButtonElement].hXuiObj, m_iPad); + } + break; + case XUI_CONTROL_NAVIGATE_DOWN: + if((m_iCurrentButtonElement+1)<m_iTotalButtonElements) + { + m_iCurrentButtonElement++; + XuiElementSetUserFocus(m_DebugButtonDataA[m_iCurrentButtonElement].hXuiObj, m_iPad); + } + break; + + case XUI_CONTROL_NAVIGATE_LEFT: + m_bOnCheckboxes=true; + if(m_iCurrentButtonElement<m_iTotalCheckboxElements) + { + m_iCurrentCheckboxElement=m_iCurrentButtonElement; + } + XuiElementSetUserFocus(m_DebugCheckboxDataA[m_iCurrentCheckboxElement].hXuiObj, m_iPad); + break; + } + } + + + + return S_OK; +} +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_Debug::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pNotifyValueChanged, BOOL& bHandled ) +{ + + return S_OK; +} +//---------------------------------------------------------------------------------- +// Updates the UI when the list selection changes. +//---------------------------------------------------------------------------------- +HRESULT CScene_Debug::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled ) +{ + + + return S_OK; +} + +//---------------------------------------------------------------------------------- +// Handler for the button press message. +//---------------------------------------------------------------------------------- +HRESULT CScene_Debug::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) +{ + // This assumes all buttons can only be pressed with the A button + ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); + + int iButton=0; + + while((iButton<m_iTotalButtonElements) && m_DebugButtonDataA[iButton].hXuiObj!=hObjPressed) + { + iButton++; + } + + if(iButton==m_iTotalButtonElements) + { + // it's not a button then + return S_OK; + } + + // you need to be the primary player to be able to earn these, since you need a storage device + + switch(iButton) + { + case eDebugButton_Theme: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_socialPost ); + break; + case eDebugButton_Avatar_Item_1: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_eatPorkChop ); + break; + case eDebugButton_Avatar_Item_2: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_play100Days ); + break; + case eDebugButton_Avatar_Item_3: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_arrowKillCreeper ); + break; + case eDebugButton_Gamerpic_1: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_mine100Blocks ); + break; + case eDebugButton_Gamerpic_2: + ProfileManager.Award( pNotifyPressData->UserIndex, eAward_kill10Creepers ); + break; + case eDebugButton_CheckTips: + app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_DebugTips); + break; + + case eDebugButton_WipeLeaderboards: +#ifdef _DEBUG +// commenting out so it doesn't get done by mistake +// Minecraft::GetInstance()->stats[pNotifyPressData->UserIndex]->WipeLeaderboards(); +#endif + break; + + } + + return S_OK; +} + |
