4jcraft/Minecraft.Client/Platform/Common/UI/UIComponent_TutorialPopup.cpp
MatthewBeshay dfb0e3b03e refactor: replace NULL with nullptr across C++ codebase
Excludes vendored C libs (zlib, Miles, DirectXMath, boost, Iggy).
2026-03-30 16:25:52 +11:00

506 lines
20 KiB
C++

#include "../../Minecraft.World/Platform/stdafx.h"
#include "UI.h"
#include "UIComponent_TutorialPopup.h"
#include "../Tutorial/Tutorial.h"
#include "../../Minecraft.World/Util/StringHelpers.h"
#include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h"
#include "../../Minecraft.Client/Minecraft.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.h"
UIComponent_TutorialPopup::UIComponent_TutorialPopup(int iPad, void* initData,
UILayer* parentLayer)
: UIScene(iPad, parentLayer) {
// Setup all the Iggy references we need for this scene
initialiseMovie();
m_interactScene = nullptr;
m_lastInteractSceneMoved = nullptr;
m_lastSceneMovedLeft = false;
m_bAllowFade = false;
m_iconItem = nullptr;
m_iconIsFoil = false;
m_bContainerMenuVisible = false;
m_bSplitscreenGamertagVisible = false;
m_iconType = e_ICON_TYPE_IGGY;
m_labelDescription.init(L"");
// 4jcraft added
m_tutorial = nullptr;
}
std::wstring UIComponent_TutorialPopup::getMoviePath() {
switch (m_parentLayer->getViewport()) {
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
return L"TutorialPopupSplit";
break;
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
default:
return L"TutorialPopup";
break;
}
}
void UIComponent_TutorialPopup::UpdateTutorialPopup() {
// has the Splitscreen Gamertag visibility been changed? Re-Adjust Layout to
// prevent overlaps!
if (m_bSplitscreenGamertagVisible !=
(bool)(app.GetGameSettings(ProfileManager.GetPrimaryPad(),
eGameSetting_DisplaySplitscreenGamertags) !=
0)) {
m_bSplitscreenGamertagVisible =
(bool)(app.GetGameSettings(
ProfileManager.GetPrimaryPad(),
eGameSetting_DisplaySplitscreenGamertags) != 0);
handleReload();
}
}
void UIComponent_TutorialPopup::handleReload() {
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_boolean;
value[0].boolval =
(bool)((app.GetGameSettings(ProfileManager.GetPrimaryPad(),
eGameSetting_DisplaySplitscreenGamertags) !=
0) &&
!m_bContainerMenuVisible); // 4J - TomK - Offset for splitscreen
// gamertag?
IggyResult out = IggyPlayerCallMethodRS(getMovie(), &result,
IggyPlayerRootPath(getMovie()),
m_funcAdjustLayout, 1, value);
setupIconHolder(m_iconType);
}
void UIComponent_TutorialPopup::SetTutorialDescription(
TutorialPopupInfo* info) {
m_interactScene = info->interactScene;
// 4jcraft added
m_tutorial = info->tutorial;
std::wstring parsed =
_SetIcon(info->icon, info->iAuxVal, info->isFoil, info->desc);
parsed = _SetImage(parsed);
parsed = ParseDescription(m_iPad, parsed);
if (parsed.empty()) {
_SetDescription(info->interactScene, L"", L"", info->allowFade,
info->isReminder);
} else {
_SetDescription(info->interactScene, parsed, info->title,
info->allowFade, info->isReminder);
}
}
void UIComponent_TutorialPopup::RemoveInteractSceneReference(UIScene* scene) {
if (m_interactScene == scene) {
m_interactScene = nullptr;
}
}
void UIComponent_TutorialPopup::SetVisible(bool visible) {
m_parentLayer->showComponent(0, eUIComponent_TutorialPopup, visible);
if (visible && m_bAllowFade) {
// Initialise a timer to fade us out again
app.DebugPrintf(
"UIComponent_TutorialPopup::SetVisible: setting "
"TUTORIAL_POPUP_FADE_TIMER_ID to %d\n",
m_tutorial->GetTutorialDisplayMessageTime());
addTimer(TUTORIAL_POPUP_FADE_TIMER_ID,
m_tutorial->GetTutorialDisplayMessageTime());
}
}
bool UIComponent_TutorialPopup::IsVisible() {
return m_parentLayer->isComponentVisible(eUIComponent_TutorialPopup);
}
void UIComponent_TutorialPopup::handleTimerComplete(int id) {
switch (id) {
case TUTORIAL_POPUP_FADE_TIMER_ID:
SetVisible(false);
killTimer(id);
app.DebugPrintf(
"handleTimerComplete: setting "
"TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID\n");
addTimer(TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,
TUTORIAL_POPUP_MOVE_SCENE_TIME);
break;
case TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID:
UpdateInteractScenePosition(IsVisible());
killTimer(id);
break;
}
}
void UIComponent_TutorialPopup::_SetDescription(UIScene* interactScene,
const std::wstring& desc,
const std::wstring& title,
bool allowFade,
bool isReminder) {
m_interactScene = interactScene;
app.DebugPrintf("Setting m_interactScene to %08x\n", m_interactScene);
if (interactScene != m_lastInteractSceneMoved)
m_lastInteractSceneMoved = nullptr;
if (desc.empty()) {
SetVisible(false);
app.DebugPrintf(
"_SetDescription1: setting TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID\n");
addTimer(TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,
TUTORIAL_POPUP_MOVE_SCENE_TIME);
killTimer(TUTORIAL_POPUP_FADE_TIMER_ID);
} else {
SetVisible(true);
app.DebugPrintf(
"_SetDescription2: setting TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID\n");
addTimer(TUTORIAL_POPUP_MOVE_SCENE_TIMER_ID,
TUTORIAL_POPUP_MOVE_SCENE_TIME);
if (allowFade) {
// Initialise a timer to fade us out again
app.DebugPrintf(
"_SetDescription: setting TUTORIAL_POPUP_FADE_TIMER_ID\n");
addTimer(TUTORIAL_POPUP_FADE_TIMER_ID,
m_tutorial->GetTutorialDisplayMessageTime());
} else {
app.DebugPrintf(
"_SetDescription: killing TUTORIAL_POPUP_FADE_TIMER_ID\n");
killTimer(TUTORIAL_POPUP_FADE_TIMER_ID);
}
m_bAllowFade = allowFade;
if (isReminder) {
std::wstring text(app.GetString(IDS_TUTORIAL_REMINDER));
text.append(desc);
stripWhitespaceForHtml(text);
// set the text colour
wchar_t formatting[40];
// 4J Stu - Don't set HTML font size, that's set at design time in
// flash
// swprintf(formatting, 40, L"<font color=\"#%08x\"
// size=\"%d\">",app.GetHTMLColour(eHTMLColor_White),m_textFontSize);
swprintf(formatting, 40, L"<font color=\"#%08x\">",
app.GetHTMLColour(eHTMLColor_White));
text = formatting + text;
m_labelDescription.setLabel(text, true);
} else {
std::wstring text(desc);
stripWhitespaceForHtml(text);
// set the text colour
wchar_t formatting[40];
// 4J Stu - Don't set HTML font size, that's set at design time in
// flash
// swprintf(formatting, 40, L"<font color=\"#%08x\"
// size=\"%d\">",app.GetHTMLColour(eHTMLColor_White),m_textFontSize);
swprintf(formatting, 40, L"<font color=\"#%08x\">",
app.GetHTMLColour(eHTMLColor_White));
text = formatting + text;
m_labelDescription.setLabel(text, true);
}
m_labelTitle.setLabel(title, true);
m_labelTitle.setVisible(!title.empty());
// read host setting if gamertag is visible or not and pass on to Adjust
// Layout function (so we can offset it to stay clear of the gamertag)
m_bSplitscreenGamertagVisible =
(bool)(app.GetGameSettings(
ProfileManager.GetPrimaryPad(),
eGameSetting_DisplaySplitscreenGamertags) != 0);
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_boolean;
value[0].boolval =
(m_bSplitscreenGamertagVisible &&
!m_bContainerMenuVisible); // 4J - TomK - Offset for splitscreen
// gamertag?
IggyResult out = IggyPlayerCallMethodRS(getMovie(), &result,
IggyPlayerRootPath(getMovie()),
m_funcAdjustLayout, 1, value);
}
}
std::wstring UIComponent_TutorialPopup::_SetIcon(int icon, int iAuxVal,
bool isFoil,
const wchar_t* desc) {
std::wstring temp(desc);
bool isFixedIcon = false;
m_iconIsFoil = isFoil;
if (icon != TUTORIAL_NO_ICON) {
m_iconIsFoil = false;
m_iconItem =
std::shared_ptr<ItemInstance>(new ItemInstance(icon, 1, iAuxVal));
} else {
m_iconItem = nullptr;
std::wstring openTag(L"{*ICON*}");
std::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()) {
std::wstring id =
temp.substr(iconStartPos, iconEndPos - iconStartPos);
std::vector<std::wstring> idAndAux = stringSplit(id, L':');
int iconId = _fromString<int>(idAndAux[0]);
if (idAndAux.size() > 1) {
iAuxVal = _fromString<int>(idAndAux[1]);
} else {
iAuxVal = 0;
}
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(iconId, 1, iAuxVal));
temp.replace(iconTagStartPos,
iconEndPos - iconTagStartPos + closeTag.length(),
L"");
}
}
// remove any icon text
else if (temp.find(L"{*CraftingTableIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::workBench_Id, 1, 0));
} else if (temp.find(L"{*SticksIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::stick_Id, 1, 0));
} else if (temp.find(L"{*PlanksIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::wood_Id, 1, 0));
} else if (temp.find(L"{*WoodenShovelIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::shovel_wood_Id, 1, 0));
} else if (temp.find(L"{*WoodenHatchetIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::hatchet_wood_Id, 1, 0));
} else if (temp.find(L"{*WoodenPickaxeIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::pickAxe_wood_Id, 1, 0));
} else if (temp.find(L"{*FurnaceIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::furnace_Id, 1, 0));
} else if (temp.find(L"{*WoodenDoorIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::door_wood, 1, 0));
} else if (temp.find(L"{*TorchIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::torch_Id, 1, 0));
} else if (temp.find(L"{*BoatIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::boat_Id, 1, 0));
} else if (temp.find(L"{*FishingRodIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::fishingRod_Id, 1, 0));
} else if (temp.find(L"{*FishIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::fish_raw_Id, 1, 0));
} else if (temp.find(L"{*MinecartIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Item::minecart_Id, 1, 0));
} else if (temp.find(L"{*RailIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::rail_Id, 1, 0));
} else if (temp.find(L"{*PoweredRailIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::goldenRail_Id, 1, 0));
} else if (temp.find(L"{*StructuresIcon*}") != std::wstring::npos) {
isFixedIcon = true;
setupIconHolder(e_ICON_TYPE_STRUCTURES);
} else if (temp.find(L"{*ToolsIcon*}") != std::wstring::npos) {
isFixedIcon = true;
setupIconHolder(e_ICON_TYPE_TOOLS);
} else if (temp.find(L"{*StoneIcon*}") != std::wstring::npos) {
m_iconItem = std::shared_ptr<ItemInstance>(
new ItemInstance(Tile::stone_Id, 1, 0));
} else {
m_iconItem = nullptr;
}
}
if (!isFixedIcon && m_iconItem != nullptr) setupIconHolder(e_ICON_TYPE_IGGY);
m_controlIconHolder.setVisible(isFixedIcon || m_iconItem != nullptr);
return temp;
}
std::wstring UIComponent_TutorialPopup::_SetImage(std::wstring& desc) {
// 4J Stu - Unused
return desc;
}
std::wstring UIComponent_TutorialPopup::ParseDescription(int iPad,
std::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"");
bool exitScreenshot = false;
size_t pos = text.find(L"{*EXIT_PICTURE*}");
if (pos != std::wstring::npos) exitScreenshot = true;
text = replaceAll(text, L"{*EXIT_PICTURE*}", L"");
m_controlExitScreenshot.setVisible(exitScreenshot);
/*
#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);
}
void UIComponent_TutorialPopup::UpdateInteractScenePosition(bool visible) {
if (m_interactScene == nullptr) return;
// 4J-PB - check this players screen section to see if we should allow the
// animation
bool bAllowAnim = false;
bool isCraftingScene =
(m_interactScene->getSceneType() == eUIScene_Crafting2x2Menu) ||
(m_interactScene->getSceneType() == eUIScene_Crafting3x3Menu);
bool isCreativeScene =
(m_interactScene->getSceneType() == eUIScene_CreativeMenu);
bool isTradingScene =
(m_interactScene->getSceneType() == eUIScene_TradingMenu);
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 && !isTradingScene) {
bAllowAnim = true;
}
break;
}
if (bAllowAnim) {
bool movingLeft = visible;
if ((m_lastInteractSceneMoved != m_interactScene && movingLeft) ||
(m_lastInteractSceneMoved == m_interactScene &&
m_lastSceneMovedLeft != movingLeft)) {
if (movingLeft) {
m_interactScene->slideLeft();
} else {
m_interactScene->slideRight();
}
m_lastInteractSceneMoved = m_interactScene;
m_lastSceneMovedLeft = movingLeft;
}
}
}
void UIComponent_TutorialPopup::render(S32 width, S32 height,
C4JRender::eViewportType viewport) {
if (viewport != C4JRender::VIEWPORT_TYPE_FULLSCREEN) {
S32 xPos = 0;
S32 yPos = 0;
switch (viewport) {
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
xPos = (S32)(ui.getScreenWidth() / 2);
yPos = (S32)(ui.getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
yPos = (S32)(ui.getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
xPos = (S32)(ui.getScreenWidth() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
xPos = (S32)(ui.getScreenWidth() / 2);
yPos = (S32)(ui.getScreenHeight() / 2);
break;
default:
break;
}
// Adjust for safezone
switch (viewport) {
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
yPos += getSafeZoneHalfHeight();
break;
default:
break;
}
switch (viewport) {
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
xPos -= getSafeZoneHalfWidth();
break;
default:
break;
}
ui.setupRenderPosition(xPos, yPos);
IggyPlayerSetDisplaySize(getMovie(), width, height);
IggyPlayerDraw(getMovie());
} else {
UIScene::render(width, height, viewport);
}
}
void UIComponent_TutorialPopup::customDraw(
IggyCustomDrawCallbackRegion* region) {
if (m_iconItem != nullptr)
customDrawSlotControl(region, m_iPad, m_iconItem, 1.0f,
m_iconItem->isFoil() || m_iconIsFoil, false);
}
void UIComponent_TutorialPopup::setupIconHolder(EIcons icon) {
app.DebugPrintf("Setting icon holder to %d\n", icon);
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_number;
value[0].number = (F64)icon;
IggyResult out = IggyPlayerCallMethodRS(getMovie(), &result,
IggyPlayerRootPath(getMovie()),
m_funcSetupIconHolder, 1, value);
m_iconType = icon;
}