DIFF

TutorialsMenu.c

class TutorialsMenu extends UIScriptedMenu
{
	protected const string PATH_MOUSEKEY 		= "scripts/data/pagedatatutorials.json";
	protected const string PATH_MOUSEKEY_720P 	= "scripts/data/pagedatatutorials_720p.json";
	protected const string PATH_X1_OLD 			= "xbox/pagedatatutorials.json";
	protected const string PATH_X1_OLD_720P 	= "xbox/pagedatatutorials_720p.json";
	protected const string PATH_X1_NEW 			= "xbox/pagedatatutorialsalternate.json";
	protected const string PATH_X1_NEW_720p 	= "xbox/pagedatatutorialsalternate_720p.json";
	protected const string PATH_PS_OLD 			= "ps4/pagedatatutorials.json";
	protected const string PATH_PS_NEW 			= "ps4/pagedatatutorialsalternate.json";
	
	protected const float MIN_LINE_SCALE		= 1.0;
	protected const float MAX_LINE_SCALE		= 1.5;
	protected const float WITDH_SCALE_RES		= 1920.0;
	protected const float HEIGHT_SCALE_RES		= 1080.0;
	protected const float LINE_THICKNESS_BASE 	= 2.0;
	protected const float BRANCH_OFFSET_BASE 	= 50.0;
	
	protected const int EXACT_TEXT_SIZE_LOW_RES = 32;

	protected string 					m_BackButtonTextID;
	
	protected Widget					m_InfoTextLeft;
	protected Widget					m_InfoTextRight;
	protected ButtonWidget				m_Back;
	
	protected ImageWidget 				m_ControlsLayoutImage;
	protected const int 				TABS_COUNT = 4;
	protected ImageWidget 				m_tab_images[TABS_COUNT];
	protected TabberUI					m_TabScript;
	//protected ref TutorialKeybinds		m_KeybindsTab;
	protected int m_CurrentTabIndex = 0;
	protected Input m_Input;
	
	protected bool m_LowResTutorialMode;
	
	void TutorialsMenu()
	{
		m_Input = g_Game.GetInput();
	}
	
	//============================================
	// Init
	//============================================
	override Widget Init()
	{
		m_LowResTutorialMode = IsLowResTutorialMode();
		
		#ifdef PLATFORM_CONSOLE
		if (m_LowResTutorialMode)
			layoutRoot = g_Game.GetWorkspace().CreateWidgets("gui/layouts/new_ui/tutorials/xbox/tutorials_720p.layout");
		else
			layoutRoot = g_Game.GetWorkspace().CreateWidgets("gui/layouts/new_ui/tutorials/xbox/tutorials.layout");
		#else
		if (m_LowResTutorialMode)
			layoutRoot = g_Game.GetWorkspace().CreateWidgets("gui/layouts/new_ui/tutorials/pc/tutorials_720p.layout");
		else
			layoutRoot = g_Game.GetWorkspace().CreateWidgets("gui/layouts/new_ui/tutorials/pc/tutorials.layout");
		#endif
		
		m_InfoTextLeft	= layoutRoot.FindAnyWidget("InfoTextLeft");
		m_InfoTextRight	= layoutRoot.FindAnyWidget("InfoTextRight");
		
		m_Back			= ButtonWidget.Cast(layoutRoot.FindAnyWidget("back"));
		
		layoutRoot.FindAnyWidget("Tabber").GetScript(m_TabScript);
		m_TabScript.m_OnTabSwitch.Insert(DrawConnectingLines);
		
		//! Commented for now as there is no reason to show the tab with mouse and keyboard inputs on console platforms and we don't show the tab on PC or MSS version also
		//! If we ever decide to remap all PlayStation related input keys so we can localize them correctly we can reanable this tab and display the correct bindigs always.
		/*#ifdef PLATFORM_CONSOLE
		if (m_Input.IsEnabledMouseAndKeyboard())
		{
			m_KeybindsTab = new TutorialKeybinds(layoutRoot.FindAnyWidget("Tab_6"), this);
			m_TabScript.EnableTabControl(6, true);
		}
		#endif*/
		
		m_tab_images[0] = ImageWidget.Cast(layoutRoot.FindAnyWidget("MovementTabBackdropImageWidget"));
		m_tab_images[1] = ImageWidget.Cast(layoutRoot.FindAnyWidget("WeaponsAndActionsBackdropImageWidget"));
		m_tab_images[2] = ImageWidget.Cast(layoutRoot.FindAnyWidget("InventoryTabBackdropImageWidget"));
		m_tab_images[3] = ImageWidget.Cast(layoutRoot.FindAnyWidget("MenusTabBackdropImageWidget"));
		
		UpdateControlsElements();
		UpdateControlsElementVisibility();
		
		PPERequesterBank.GetRequester(PPERequester_TutorialMenu).Start(new Param1<float>(0.6));
		DrawConnectingLines(0);
		
		g_Game.GetMission().GetOnInputPresetChanged().Insert(OnInputPresetChanged);
		g_Game.GetMission().GetOnInputDeviceChanged().Insert(OnInputDeviceChanged);
		
		return layoutRoot;
	}
	
	void ~TutorialsMenu()
	{
		m_TabScript.m_OnTabSwitch.Remove(DrawConnectingLines);
		PPERequesterBank.GetRequester(PPERequester_TutorialMenu).Stop();
	}
	
	protected bool IsLowResTutorialMode()
	{
		int screenW, screenH;
		GetScreenSize(screenW, screenH);
		return screenW <= 1280 || screenH <= 720;
	}
	
	protected float GetTutorialLineScale()
	{
		int screenW, screenH;
		GetScreenSize(screenW, screenH);
	
		if (screenW <= 0 || screenH <= 0)
			return MIN_LINE_SCALE;
	
		float widthScale = WITDH_SCALE_RES / screenW;
		float heightScale = HEIGHT_SCALE_RES / screenH;
		float scale = Math.Max(widthScale, heightScale);
		scale = Math.Clamp(scale, MIN_LINE_SCALE, MAX_LINE_SCALE);
		
		return scale;
	}
	
	protected float GetTutorialLineThickness()
	{
		return LINE_THICKNESS_BASE * GetTutorialLineScale();
	}
	
	protected float GetTutorialBranchOffset()
	{
		return BRANCH_OFFSET_BASE * GetTutorialLineScale();
	}
	
	protected void OnInputPresetChanged()
	{
		#ifdef PLATFORM_CONSOLE
		RefreshControlMappings();
		/*if (m_KeybindsTab)
		{
			m_KeybindsTab.Rebuild();
		}*/
		#endif
	}
	
	protected void RefreshControlMappings()
	{
		UpdateControlsElements();
		UpdateControlsElementVisibility();
		DrawConnectingLines(m_CurrentTabIndex);
	}
	
	protected void OnInputDeviceChanged(EInputDeviceType pInputDeviceType)
	{
		bool mk = m_Input.IsEnabledMouseAndKeyboard();
		bool mkServer = m_Input.IsEnabledMouseAndKeyboardEvenOnServer();

		switch (pInputDeviceType)
		{
		case EInputDeviceType.CONTROLLER:
			if (mk && mkServer)
			{
				g_Game.GetUIManager().ShowUICursor(false);
			}
		break;

		default:
			if (mk && mkServer)
			{
				g_Game.GetUIManager().ShowUICursor(true);
			}
		break;
		}
		
		RefreshControlMappings();
		/*if (m_KeybindsTab)
		{
			m_KeybindsTab.Rebuild();
		}*/
	}
	
	override void OnShow()
	{
		super.OnShow();
		
		SetFocus(null);
		OnInputDeviceChanged(m_Input.GetCurrentInputDevice());
	}
	
	void Back()
	{
		g_Game.GetUIManager().Back();
	}
	
	void DrawConnectingLines(int index)
	{
		m_CurrentTabIndex = index;
		
		if (index == 6)
		{
			m_InfoTextLeft.Show(false);
			m_InfoTextRight.Show(false);
		}
		else
		{
			m_InfoTextLeft.Show(true);
			m_InfoTextRight.Show(true);
			array<ref JsonControlMappingInfo> controlMappingInfo = new array<ref JsonControlMappingInfo>;
			array<ref array <ref JsonControlMappingInfo>> tabArray = new array<ref array <ref JsonControlMappingInfo>>;
			
			map<string, ref array<int>> buttonMarkerGroupsUnfiltered = new map<string, ref array<int>>;
			map<string, ref array<int>> buttonMarkerGroups = new map<string, ref array<int>>;
			
			float textWidgetPosX, textWidgetPosY;
			float textWidgetWidth, textWidgetHeight;
			float dotPosX, dotPosY;
			float dotWidth, dotHeight;
			float drawPosX, drawPosY;
			float lineThickness;
			float branchOffset;
			
			CanvasWidget canvasWidget = CanvasWidget.Cast(layoutRoot.FindAnyWidget("CanvasWidget_" + index));
			canvasWidget.Clear();
			lineThickness = GetTutorialLineThickness();
			branchOffset = GetTutorialBranchOffset();
			controlMappingInfo = GetControlMappingInfo();
			
			for (int i = 0; i < m_TabScript.GetTabCount(); i++)
			{
				tabArray.Insert(new array<ref JsonControlMappingInfo>);
				for (int j = 0; j < 30; j++)
				{
					tabArray[i].Insert(NULL);
				}
			}
			
			// insert json info to array by index, so it is sorted
			int controlMappingInfoCount = controlMappingInfo.Count();
			for (i = 0; i < controlMappingInfoCount; i++)
			{
				JsonControlMappingInfo info = controlMappingInfo.Get(i);
				tabArray[info.m_TabID][info.m_TextWidgetID] = info;
			}
			
			// create group of buttons which are connected together with line
			for (int l = 0; l < controlMappingInfoCount; l++)
			{
				JsonControlMappingInfo info1 = controlMappingInfo[l];
				string buttonName = info1.m_ButtonName;
				int textWidgetID = info1.m_TextWidgetID;
				if (info1.m_TabID != index)
				{
					continue;
				}
				if (!buttonMarkerGroupsUnfiltered.Contains(buttonName))
				{
					buttonMarkerGroupsUnfiltered.Insert(buttonName, new array<int>);
					buttonMarkerGroupsUnfiltered.Get(buttonName).Insert(textWidgetID);
				}
				else
				{
					buttonMarkerGroupsUnfiltered.Get(buttonName).Insert(textWidgetID);
				}
			}
			
			// we want groups which are bigger than 1
			for (l = 0; l < buttonMarkerGroupsUnfiltered.Count(); l++)
			{
				if (buttonMarkerGroupsUnfiltered.GetElement(l).Count() > 1)
				{
					string key = buttonMarkerGroupsUnfiltered.GetKey(l);
					buttonMarkerGroups.Insert(buttonMarkerGroupsUnfiltered.GetKey(l), buttonMarkerGroupsUnfiltered.Get(key));
				}
			}
			
			// hide all button markers
			Widget xboxControlsImage = layoutRoot.FindAnyWidget("Markers_" + index);
			
			Widget panelWidget;
			Widget buttonMarkerWidget;
			
			for (l = 0; l < tabArray[index].Count(); l++)
			{
				panelWidget = layoutRoot.FindAnyWidget("PanelWidget" + l);
				if (tabArray[index][l] != NULL)
				{
					RichTextWidget textWidget = RichTextWidget.Cast(panelWidget.FindAnyWidget("TextWidget" + l));
					buttonMarkerWidget = layoutRoot.FindAnyWidget("button_marker_" + tabArray[index][l].m_ButtonName);
						
					if (m_LowResTutorialMode)
						textWidget.SetTextExactSize(EXACT_TEXT_SIZE_LOW_RES);
					
					textWidget.SetText(tabArray[index][l].m_InfoText);
					
					panelWidget.Show(true);
					panelWidget.Update();
					
					if (!buttonMarkerGroups.Contains(tabArray[index][l].m_ButtonName))
					{
						panelWidget.GetScreenPos(textWidgetPosX, textWidgetPosY);
						panelWidget.GetScreenSize(textWidgetWidth,textWidgetHeight);
						
						buttonMarkerWidget.GetScreenPos(dotPosX, dotPosY);
						buttonMarkerWidget.GetScreenSize(dotWidth, dotHeight);
						
						drawPosY = textWidgetPosY + textWidgetHeight / 2;
						
						if (l < 15)
						{
							drawPosX = textWidgetPosX + textWidgetWidth - 1;
						}
						else
						{
							drawPosX = textWidgetPosX;
						}
						
						canvasWidget.DrawLine(drawPosX, drawPosY, dotPosX + dotWidth / 2, drawPosY, lineThickness, ARGBF(0.6, 1, 1, 1));
						canvasWidget.DrawLine(dotPosX + dotWidth / 2, drawPosY, dotPosX + dotWidth / 2, dotPosY + dotHeight / 2, lineThickness, ARGBF(0.6, 1, 1, 1));
					}
				}
				else
				{
					panelWidget.Show(false);
				}
				panelWidget.Update();
			}
			
			// draw connecting lines 
			for (l = 0; l <  buttonMarkerGroups.Count(); l++)
			{
				textWidgetPosX = 0;
				textWidgetPosY = 0;
				textWidgetWidth = 0;
				textWidgetHeight = 0;
				float groupPointX = 0, groupPointY = 0;
				float firstX = 0, firstY = 0;
				
				array<int> element = buttonMarkerGroups.GetElement(l);
				string keyName = buttonMarkerGroups.GetKey(l);
				buttonMarkerWidget = layoutRoot.FindAnyWidget("button_marker_" + keyName);
				
				int elementsCount = element.Count();
				for (int g = 0; g < elementsCount; g++)
				{
					panelWidget = layoutRoot.FindAnyWidget("PanelWidget" + element[g]);
					
					panelWidget.GetScreenPos(textWidgetPosX, textWidgetPosY);
					panelWidget.GetScreenSize(textWidgetWidth, textWidgetHeight);
					
					if (g == 0)
					{
						if (element[0] < 15)
						{
							firstX = textWidgetPosX + textWidgetWidth + branchOffset;
						}
						else
						{
							firstX = textWidgetPosX - branchOffset;
						}
						firstY = textWidgetPosY + textWidgetHeight/2;
						
					}
					
					groupPointX += textWidgetPosX;
					groupPointY += textWidgetPosY;
					
					if (element[0] < 15)
					{
						canvasWidget.DrawLine(textWidgetPosX + textWidgetWidth - 1, textWidgetPosY + textWidgetHeight / 2, textWidgetPosX + textWidgetWidth + branchOffset, textWidgetPosY + textWidgetHeight / 2, lineThickness, ARGBF(0.6, 1, 1, 1));
					}
					else
					{
						canvasWidget.DrawLine(textWidgetPosX, textWidgetPosY + textWidgetHeight / 2, textWidgetPosX - branchOffset, textWidgetPosY + textWidgetHeight / 2, lineThickness, ARGBF(0.6, 1, 1, 1));
					}
				}
				
				if (element[0] < 15)
				{
					groupPointX = groupPointX / elementsCount + textWidgetWidth + branchOffset;
				}
				else
				{
					groupPointX = groupPointX / elementsCount - branchOffset;
				}
				
				groupPointY = groupPointY/elementsCount + textWidgetHeight/2;
				
				buttonMarkerWidget.GetScreenPos(dotPosX, dotPosY);
				buttonMarkerWidget.GetScreenSize(dotWidth, dotHeight);
				
				canvasWidget.DrawLine(groupPointX, groupPointY, dotPosX + dotWidth / 2, groupPointY, lineThickness, ARGBF(0.6, 1, 1, 1));
				canvasWidget.DrawLine(dotPosX + dotWidth / 2, groupPointY, dotPosX + dotWidth / 2, dotPosY, lineThickness, ARGBF(0.6, 1, 1, 1));
				
				if (element[0] < 15)
				{
					canvasWidget.DrawLine(firstX, firstY, textWidgetPosX + textWidgetWidth + branchOffset, textWidgetPosY + textWidgetHeight / 2, lineThickness, ARGBF(0.6, 1, 1, 1));
				}
				else
				{
					canvasWidget.DrawLine(firstX, firstY, textWidgetPosX - branchOffset, textWidgetPosY + textWidgetHeight / 2, lineThickness, ARGBF(0.6, 1, 1, 1));
				}
			}
		}
	}
	
	protected array<ref JsonControlMappingInfo> GetControlMappingInfo()
	{
		array<ref JsonControlMappingInfo> controlMappingInfo = new array<ref JsonControlMappingInfo>;
		string filePath;
		
		//! PC variant (also used for MSS build when mouse and keyboard are then active input device).
		if (!m_LowResTutorialMode)
			filePath = PATH_MOUSEKEY;
		else
			filePath = PATH_MOUSEKEY_720P;
		
		string profileName = "";
		m_Input.GetProfileName(m_Input.GetCurrentProfile(), profileName);
		
	#ifdef PLATFORM_CONSOLE
		bool controllerActive = m_Input.GetCurrentInputDevice() == EInputDeviceType.CONTROLLER;
		if (controllerActive)
		{
			if (profileName == "#STR_UAPRESET_0" || profileName == "#STR_USER")
			{
				#ifdef PLATFORM_MSSTORE
				if (!m_LowResTutorialMode)
					filePath =	PATH_X1_OLD;
				else
					filePath =	PATH_X1_OLD_720P;
				#endif
				#ifdef PLATFORM_XBOX
				if (!m_LowResTutorialMode)
					filePath =	PATH_X1_OLD;
				else
					filePath =	PATH_X1_OLD_720P;
				#endif
				#ifdef PLATFORM_PS4
					filePath =	PATH_PS_OLD;
				#endif
			}
			else if (profileName == "#STR_UAPRESET_1")
			{
				#ifdef PLATFORM_MSSTORE
				if (!m_LowResTutorialMode)
					filePath =	PATH_X1_NEW;
				else
					filePath =	PATH_X1_NEW_720p;
				#endif
				#ifdef PLATFORM_XBOX
				if (!m_LowResTutorialMode)
					filePath =	PATH_X1_NEW;
				else
					filePath =	PATH_X1_NEW_720p;
				#endif
				#ifdef PLATFORM_PS4
					filePath =	PATH_PS_NEW;
				#endif
			}
			else
			{
				ErrorEx("Invalid file path!");
				filePath =	"";
			}
		}
	#endif
		FileHandle file_handle = OpenFile(filePath, FileMode.READ);
		JsonSerializer js = new JsonSerializer();
		
		string js_error = "";
		string line_content = "";
		string content = "";
		if (file_handle)
		{
			while (FGets(file_handle,  line_content) >= 0)
			{
				content += line_content;
			}
			CloseFile(file_handle);
			
			if (js.ReadFromString(controlMappingInfo, content, js_error))
			{
				return controlMappingInfo;
			}
			else
			{
				ErrorEx("JSON ERROR => [TutorialsMenu]: " + js_error);
			}
		}
		else
		{
			ErrorEx("FILEHANDLE ERROR => [TutorialsMenu]: " + js_error);
		}
		
		return controlMappingInfo;
	}
	
	override void Update(float timeslice)
	{
		if (GetUApi().GetInputByID(UAUITabLeft).LocalPress())
		{
			m_TabScript.PreviousTab();
		}
		
		//RIGHT BUMPER - TAB RIGHT
		if (GetUApi().GetInputByID(UAUITabRight).LocalPress())
		{
			m_TabScript.NextTab();
		}
		
		if (GetUApi().GetInputByID(UAUIBack).LocalPress())
		{
			Back();
		}
	}
	
		/// Initial texts load for the footer buttons
	protected void LoadFooterButtonTexts()
	{
		TextWidget uiBackText 	= TextWidget.Cast(layoutRoot.FindAnyWidget("BackText"));		
		
		if (uiBackText)
		{
			uiBackText.SetText(m_BackButtonTextID);
		}
	}
	/// Set correct bottom button texts based on platform (ps4 vs xbox texts)
	protected void LoadTextStrings()
	{
		#ifdef PLATFORM_PS4
			m_BackButtonTextID = "ps4_ingame_menu_back";
		#else 
			m_BackButtonTextID = "STR_rootFrame_toolbar_bg_ConsoleToolbar_Back_BackText0";	
		#endif
	}
	
	override bool OnClick(Widget w, int x, int y, int button)
	{
		if (button == MouseState.LEFT)
		{
			if (w == m_Back)
			{
				Back();
				return true;
			}
		}
		return false;
	}
	
	override bool OnMouseEnter(Widget w, int x, int y)
	{
		if (IsFocusable(w))
		{
			ColorHighlight(w);
			return true;
		}
		return false;
	}
	
	override bool OnMouseLeave(Widget w, Widget enterW, int x, int y)
	{
		if (IsFocusable(w))
		{
			ColorNormal(w);
			return true;
		}
		return false;
	}
	
	override bool OnFocus(Widget w, int x, int y)
	{
		if (IsFocusable(w))
		{
			ColorHighlight(w);
			return true;
		}
		return false;
	}
	
	override bool OnFocusLost(Widget w, int x, int y)
	{
		if (IsFocusable(w))
		{
			ColorNormal(w);
			return true;
		}
		return false;
	}
	
	bool IsFocusable(Widget w)
	{
		return (w && w == m_Back);
	}
	
	//Coloring functions (Until WidgetStyles are useful)
	void ColorHighlight(Widget w)
	{
		if (!w)
			return;
		
		int color_pnl = ARGB(255, 0, 0, 0);
		int color_lbl = ARGB(255, 255, 0, 0);
		int color_img = ARGB(255, 200, 0, 0);
		
		#ifdef PLATFORM_CONSOLE
			color_pnl = ARGB(255, 200, 0, 0);
			color_lbl = ARGB(255, 255, 255, 255);
		#endif
		
		ButtonSetColor(w, color_pnl);
		ButtonSetTextColor(w, color_lbl);
		ImagenSetColor(w, color_img);
	}
	
	void ColorNormal(Widget w)
	{
		if (!w)
			return;
		
		int color_pnl = ARGB(0, 0, 0, 0);
		int color_lbl = ARGB(255, 255, 255, 255);
		int color_img = ARGB(255, 255, 255, 255);
		
		ButtonSetColor(w, color_pnl);
		ButtonSetTextColor(w, color_lbl);
		ImagenSetColor(w, color_img);
	}
	
	void ButtonSetText(Widget w, string text)
	{
		if (!w)
			return;
				
		TextWidget label = TextWidget.Cast(w.FindWidget(w.GetName() + "_label"));
		
		if (label)
		{
			label.SetText(text);
		}
		
	}
	
	void ButtonSetColor(Widget w, int color)
	{
		if (!w)
			return;
		
		Widget panel = w.FindWidget(w.GetName() + "_panel");
		
		if (panel)
		{
			panel.SetColor(color);
		}
	}
	
	void ImagenSetColor(Widget w, int color)
	{
		if (!w)
			return;
		
		Widget panel = w.FindWidget(w.GetName() + "_image");
		
		if (panel)
		{
			panel.SetColor(color);
		}
	}
	
	void ButtonSetTextColor(Widget w, int color)
	{
		if (!w)
			return;

		TextWidget label	= TextWidget.Cast(w.FindAnyWidget(w.GetName() + "_label"));
		TextWidget text		= TextWidget.Cast(w.FindAnyWidget(w.GetName() + "_text"));
		TextWidget text2	= TextWidget.Cast(w.FindAnyWidget(w.GetName() + "_text_1"));
				
		if (label)
		{
			label.SetColor(color);
		}
		
		if (text)
		{
			text.SetColor(color);
		}
		
		if (text2)
		{
			text2.SetColor(color);
		}
	}
	
	protected void UpdateControlsElements()
	{
		#ifdef PLATFORM_CONSOLE
		RichTextWidget toolbar_text = RichTextWidget.Cast(layoutRoot.FindAnyWidget("ContextToolbarText"));
		if (toolbar_text)
		{
			string text = string.Format(" %1",InputUtils.GetRichtextButtonIconFromInputAction("UAUIBack", "#STR_settings_menu_root_toolbar_bg_ConsoleToolbar_Back_BackText0", EUAINPUT_DEVICE_CONTROLLER, InputUtils.ICON_SCALE_TOOLBAR));
			toolbar_text.SetText(text);
		}
		#endif
	}
	
	protected void UpdateControlsElementVisibility()
	{
		bool toolbarShow = false;
		#ifdef PLATFORM_CONSOLE
		toolbarShow = !m_Input.IsEnabledMouseAndKeyboardEvenOnServer() || m_Input.GetCurrentInputDevice() == EInputDeviceType.CONTROLLER;
		#endif
		
		#ifdef PLATFORM_CONSOLE
		layoutRoot.FindAnyWidget("toolbar_bg").Show(toolbarShow);
		#endif
		layoutRoot.FindAnyWidget("play_panel_root").Show(!toolbarShow);
	}
}