From b691c43c44ff180d10e7d4a9afc83b98551ff586 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sun, 1 Mar 2026 12:16:08 +0800 Subject: Initial commit --- Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp | 603 ++++++++++++++++++++++ 1 file changed, 603 insertions(+) create mode 100644 Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp (limited to 'Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp') 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( 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"",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"",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(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 idAndAux = stringSplit(id,L':'); + + int iconId = _fromString(idAndAux[0]); + + if(idAndAux.size() > 1) + { + iAuxVal = _fromString(idAndAux[1]); + } + else + { + iAuxVal = 0; + } + + bool itemIsFoil = false; + itemIsFoil = (shared_ptr(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"
" ); + + // 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 -- cgit v1.2.3