--[[ * UI LIBRARY * ]]

Using "ClickPoof"
Using "StaminaRestoredFront"
Using "StaminaRestoredBack"
Using "GuidebookCoverToast"
Using "FullscreenFadeIn"
Using "FullscreenFadeInFast"
Using "FullscreenFadeOut"
Using "FullscreenFadeOutFast"
Using "NoticeScreenLoop"
Using "NoticeScreenLoopTransparent"
Using "VictorySmoke"
Using "LocalMPBackdrop"

-- Used in both matches and campaign
Using "LavaFall"

Import "CampaignRecord"
Import "MatchRecord"

OnMenuOpened{ "PauseScreen",
	function( triggerArgs )

		SetSoundCueValue({ Id = GetMixingId({}), Names = { "Pause" }, Value = 1.0 })

		if BootMenu then
			return
		end

		PlaySound({ Name = "/SFX/Menu Sounds/GeneralWhooshMENULoud" })

		-- Pause Speech and Music if player pauses
		if IsMultiplayerMatch() then
			SetSoundCueValue({ Id = GetMixingId({}), Names = { "LowPass" }, Value = 1.0, Duration = 0.0 })
		else
			PauseSound({ Id = MusicId, Duration = 0.3 })
			PauseSound({ Id = BeyonderMusicId, Duration = 0.3 })
			PauseSound({ Id = BardMusicId, Duration = 0.3 })
			PauseSound({ Id = AmbienceId, Duration = 0.3 })
			PauseSound({ Id = AmbienceId2, Duration = 0.3 })
		end
		PauseSpeech({  })
		waitScreenTime(0.01)

		SetMenuOptions({ Name = "PauseScreen", Item = "ArcadeButton", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "PauseScreen", Item = "LocalMPInfo", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "PauseScreen", Item = "CampaignInfo", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "PauseScreen", Item = "ArcadeInfo", Properties = { IsVisible = false } })

		if IsMultiplayerMatch() then
			if ArcadeMode then
				RestoreUserVersusSettings()
				SetMenuOptions({ Name = "PauseScreen", Item = "CampaignButton", Properties = { HelpTextId = "PauseScreen_ExitArcade", ActivateFunction = "MenuExitArcadeConfirm" } })
				SetMenuOptions({ Name = "PauseScreen", Item = "LocalMPButton", Properties = { IsVisible = false } })
			else
				SetMenuOptions({ Name = "PauseScreen", Item = "CampaignButton", Properties = { HelpTextId = "PauseScreen_ExitMP", ActivateFunction = "MenuExitMPConfirm" } })
				SetMenuOptions({ Name = "PauseScreen", Item = "LocalMPButton", Properties = { HelpTextId = "PauseScreen_ResetupMatch" } })
			end
			SetMenuOptions({ Name = "PauseScreen", Item = "ExitCampaignButton", Properties = { IsVisible = false } })
			if TeamA == nil or TeamB == nil or not TeamA.DonePicking or not TeamB.DonePicking then
				SetMenuOptions({ Name = "PauseScreen", Item = "RestartMatchButton", Properties = { TooltipId = "PauseScreen_RestartMatch", HelpTextId = "PauseScreen_RestartMatch", ActivateFunction = "RestartMatch" } })
			else
				SetMenuOptions({ Name = "PauseScreen", Item = "RestartMatchButton", Properties = { TooltipId = "PauseScreen_RestartMatch_Alt", HelpTextId = "PauseScreen_RestartMatch_Alt", ActivateFunction = "RestartMatch" } })
			end
		else
			SetMenuOptions({ Name = "PauseScreen", Item = "LocalMPButton", Properties = { IsVisible = false } })
			SetMenuOptions({ Name = "PauseScreen", Item = "ExitCampaignButton", Properties = { HelpTextId = "PauseScreen_ExitSP", ActivateFunction = "MenuExitSPConfirm" } })
			if HasSaveFile({ }) then
				SetMenuOptions({ Name = "PauseScreen", Item = "CampaignButton", Properties = { HelpTextId = "PauseScreen_LoadLastSave", ActivateFunction = "MenuLoadCheckpointConfirm" } })
			else
				SetMenuOptions({ Name = "PauseScreen", Item = "CampaignButton", Properties = { HelpTextId = "PauseScreen_RestartSP", ActivateFunction = "MenuRestartCampaignConfirm" } })
			end

			if practiceMatch then
				SetMenuOptions({ Name = "PauseScreen", Item = "RestartMatchButton", Properties = { TooltipId = "PauseScreen_RestartMatch_Campaign", HelpTextId = "PauseScreen_RestartMatch_Campaign", ActivateFunction = "MenuRestartMatchConfirm" } })

				if ChallengeData == nil then
					SetMenuOptions({ Name = "PauseScreen", Item = "LeavePracticeButton", Properties = { TooltipId = "PauseScreen_LeavePractice", HelpTextId = "PauseScreen_LeavePractice" } })
				else
					SetMenuOptions({ Name = "PauseScreen", Item = "LeavePracticeButton", Properties = { TooltipId = "PauseScreen_LeaveChallenge", HelpTextId = "PauseScreen_LeaveChallenge" } })
				end

			else

				if introMatch and TitanMode then
					SetMenuOptions({ Name = "PauseScreen", Item = "LeavePracticeButton", Properties = { TooltipId = "PauseScreen_LeaveIntro", HelpTextId = "PauseScreen_LeaveIntro" } })
				end

				SetMenuOptions({ Name = "PauseScreen", Item = "RestartMatchButton", Properties = { TooltipId = "PauseScreen_RestartMatch_Campaign", HelpTextId = "PauseScreen_RestartMatch_Campaign", ActivateFunction = "MenuRestartMatchConfirm" } })
			end
		end

	end
}

OnMenuCloseFinished{ "PauseScreen",
	function( triggerArgs )
		OnPauseScreenClosed()
		if ArcadeMode then
			SetupArcadeMatch()
		end
	end
}

function OnPauseScreenClosed()
	SetSoundCueValue({ Id = GetMixingId({}), Names = { "Pause" }, Value = 0.0 })
	if IsMultiplayerMatch() then
		SetSoundCueValue({ Id = GetMixingId({}), Names = { "LowPass" }, Value = 0.0, Duration = 0.25 })
	else
		if BeyonderMusicId ~= nil then
			ResumeSound({ Id = BeyonderMusicId, Duration = 0.3 })
		elseif BardMusicId ~= nil then
			ResumeSound({ Id = BardMusicId, Duration = 0.3 })
		else
			ResumeSound({ Id = MusicId, Duration = 0.3 })
		end
		ResumeSound({ Id = AmbienceId, Duration = 0.3 })
		ResumeSound({ Id = AmbienceId2, Duration = 0.3 })
	end
	if not SuppressVOResume then
		ResumeSpeech({  })
	else
		SuppressVOResume = false
	end
end

function MenuCampaignMode()
	OpenMenu({ Name = "ProfileScreen" })
end

function MenuResumeProfileCampaign()

	FadeOut({ Color = Color.Black, Duration = 0.25 })
	StopSound({ Id = MusicId, Duration = 0.25 })
	ExitMenu({ Name = "PauseScreen", TransitionOffTime = 0.27 })
	ExitMenu({ Name = "ProfileScreen", TransitionOffTime = 0.27 })
	SetConfigOption({ Name = "AllowPause", Value = true })
	SetConfigOption({ Name = "CampaignReady", Value = true })
	PlaySound({ Name = "/SFX/Menu Sounds/RosterEquip" })

end

function MenuResumeCampaign()
	ExitMenu({ Name = "PauseScreen" })
	ExitMenu({ Name = "ProfileScreen" })
	FireTrigger({ Name = "EndCurrentMusic" })
	SetConfigOption({ Name = "AllowPause", Value = true })
	SetConfigOption({ Name = "CampaignReady", Value = true })
	wait(0.27)
	CampaignStartup()
end

function MenuSetupNewCampaign()
	OpenMenu({ Name = "CampaignSetupScreen" })
	--SetMenuOptions({ Name = "CampaignSetupScreen", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuStartCampaign" } })
end

function MenuStartProfileCampaign()

	FadeOut({ Color = Color.Black, Duration = 0.35 })
	StopSound({ Id = MusicId, Duration = 0.35 })
	ExitMenu({ Name = "PauseScreen", TransitionOffTime = 0.37 })
	ExitMenu({ Name = "ProfileScreen", TransitionOffTime = 0.37 })
	SetConfigOption({ Name = "AllowPause", Value = true })
	SetConfigOption({ Name = "CampaignReady", Value = true })

end

function MenuStartCampaign()
	AddInputBlock({ Name = "StartingCampaign" })
	ExitMenu({ Name = "PauseScreen" })
	ExitMenu({ Name = "ProfileScreen" })
	ExitMenu({ Name = "CampaignSetupScreen" })
	FireTrigger({ Name = "EndCurrentMusic" })
	SetConfigOption({ Name = "AllowPause", Value = true })
	SetConfigOption({ Name = "CampaignReady", Value = true })
	wait(0.27)
	RemoveInputBlock({ Name = "StartingCampaign" })
	CampaignStartup()
end

function MenuExitSPConfirm()
	OpenMenu({ Name = "ExitConfirmDialog" })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { DisplayNameId = "PauseScreen_ExitSP_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_ExitSP_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuExitSP" } })
end

function MenuExitSP()
	AddInputBlock({ Name = "MenuExitSP" })
	FadeOut({ Color = Color.Black })
	ExitMenu({ Names = { "PauseScreen", "ExitConfirmDialog", "LocationMenuScreen", "DialogueScreen", "RosterScreen", "InventoryScreen", "CharacterSkillsScreen", "CharacterBioScreen" } })
	waitScreenTime(0.17)
	-- Keep the filter going until load
	SetSoundCueValue({ Id = GetMixingId({}), Names = { "Pause" }, Value = 0.0 })
	SetMultiplayerMatchOff()
	SetConfigOption({ Name = "CampaignReady", Value = false })
	RemoveInputBlock({ Name = "MenuExitSP" })
	if HasSaveFile({ }) then
		LoadCheckpoint({ })
	else
		LoadMap({ Name = "Campaign", ResetApp = true })
	end
end

function MenuExitMPConfirm()
	OpenMenu({ Name = "ExitConfirmDialog" })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { DisplayNameId = "PauseScreen_ExitMP_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_ExitMP_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuExitMP" } })
end

function MenuExitArcadeConfirm()
	OpenMenu({ Name = "ExitConfirmDialog" })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { DisplayNameId = "PauseScreen_ExitArcade_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_ExitArcade_ExitConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuExitMP" } })
end

function MenuExitMP()

	AddInputBlock({ Name = "MenuExitMP" })
	FadeOut({ Color = Color.Black })
	ExitMenu({ Name = "PauseScreen" })
	ExitMenu({ Name = "ExitConfirmDialog" })
	waitScreenTime(0.17)
	-- Keep the filter going until load
	SetSoundCueValue({ Id = GetMixingId({}), Names = { "Pause" }, Value = 0.0 })
	SetMultiplayerMatchOff()
	SetConfigOption({ Name = "CampaignReady", Value = false })
	RestoreUserVersusSettings()
	RemoveInputBlock({ Name = "MenuExitMP" })
	if HasSaveFile({ }) then
		LoadCheckpoint({ })
	else
		LoadMap({ Name = "Campaign", ResetApp = true })
	end
end

function MenuLoadCheckpointConfirm()
	OpenMenu({ Name = "ExitConfirmDialog" })
	if matchStarted and ( IsCampaignSeasonMatch() or ascensionMatch ) then
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { HelpTextId = "PauseScreen_LoadLastSave_Match_01" } })
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_LoadLastSave_Match_01" } })
	else
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { HelpTextId = "PauseScreen_LoadLastSave_Confirm" } })
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_LoadLastSave_Confirm" } })
	end
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuLoadCheckpoint" } })
end

function MenuRestartCampaignConfirm()
	OpenMenu({ Name = "ExitConfirmDialog" })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { HelpTextId = "PauseScreen_RestartConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_RestartConfirm" } })
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "MenuRestartSP" } })
end

function MenuLoadCheckpoint()
	FadeOut({ Color = Color.Black, Duration = 0.0 })
	waitScreenTime(0.01)
	ExitMenu({ Name = "PauseScreen" })
	SetConfigOption({ Name = "CampaignReady", Value = true })
	LoadCheckpoint({ })
end

function MenuRestartSP()
	FadeOut({ Color = Color.Black, Duration = 0.0 })
	waitScreenTime(0.01)
	ExitMenu({ Name = "PauseScreen" })
	SetConfigOption({ Name = "CampaignReady", Value = true })
	LoadMap({ Name = "Campaign", ResetApp = true })
end

ViewedTooltips = ViewedTooltips or {}

function FadeOutComponents( components )
	for k, component in ipairs( components ) do
		SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 0.0 } })
	end
end

function HideComponents( components )
	for k, component in ipairs( components ) do
		SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { IsVisible = false } })
	end
end

function ShowComponents( components )
	for k, component in ipairs( components ) do
		SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { IsVisible = true } })
	end
end

function FadeInComponents( components )
	for k, component in ipairs( components ) do
		SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 1.0 } })
	end
end

function hideEntireUI()
	HideMatchUI()
	FadeOutOvermapComponents()
	HideObjectiveLog()
end

function ShowMatchUI()

	if TeamA ~= nil then
		SetMenuOptions({ Name = "InGameUI", Item = "TeamAGoalHealthIcon", Properties = { Graphic = TeamA.PyreIcon } })
		SetMenuOptions({ Name = "InGameUI", Item = "TeamAGoalHealthText", Properties = { SetText = TeamA.PyreHealth } })
	end
	if TeamB ~= nil then
		SetMenuOptions({ Name = "InGameUI", Item = "TeamBGoalHealthIcon", Properties = { Graphic = TeamB.PyreIcon } })
		SetMenuOptions({ Name = "InGameUI", Item = "TeamBGoalHealthText", Properties = { SetText = TeamB.PyreHealth } })
	end

	SetMenuOptions({ Name = "InGameUI", Properties = { Run = "ShowMatchUI" } })
	SetConfigOption({ Name = "ShowOffscreenIndicators", Value = true })

	if noEnemies or forfeitMatch then
		-- introMatch exception
		SetMenuOptions({ Name = "InGameUI", Item = "TeamBGoalHealthBacking", Properties = { FadeTarget = 0.0 } })
		SetMenuOptions({ Name = "InGameUI", Item = "TeamBGoalHealthIcon", Properties = { FadeTarget = 0.0 } })
		SetMenuOptions({ Name = "InGameUI", Item = "TeamBGoalHealthText", Properties = { FadeTarget = 0.0 } })
	end

end

function HideMatchUI()
	SetMenuOptions({ Name = "InGameUI", Properties = { Run = "HideMatchUI" } })
	SetConfigOption({ Name = "ShowOffscreenIndicators", Value = false })

	if CurrentTutorialBox == "Info_ControlsUI" then
		HideTutorialBox()
	end
end

function ShowControlUI()
	SetMenuOptions({ Name = "InGameUI", Properties = { Run = "ShowControlUI" } })
end

function ShowOvermapUI()
	if demoPan then
		return
	end

	SetupCaravanControls()
	UpdateMovesAvailable()

	if caravanFlying then
		SetConfigOption({ Name = "ShowOffscreenIndicators", Value = true })
	end
	FadeInOvermapComponents()
	AdjustBrightness({ Fraction = fullFraction, Duration = fadeDuration })

end

function HideObjectiveLog()

	if IsEmpty( ActiveObjectives ) then
		return
	end

	objectiveLogVisible = false

	for k, activeObjective in pairs( ActiveObjectives ) do
		UpdateWorldText({ Id = activeObjective.AnchorId, FadeTarget = 0.0 })
		StopAnimation({ DestinationId = activeObjective.AnchorId })
	end
end

function ShowObjectiveLog()

	if IsEmpty( ActiveObjectives ) then
		return
	end

	if objectiveLogVisible then
		return
	end

	objectiveLogVisible = true

	for k, activeObjective in pairs( ActiveObjectives ) do
		UpdateWorldText({ Id = activeObjective.AnchorId, FadeTarget = 1.0 })
		DisplayObjectiveBacking( activeObjective.AnchorId )
	end

	if ProppedObjectiveQueue ~= nil then
		for objectiveName, v in pairs( ProppedObjectiveQueue ) do
			wait(0.3)
			DisplayObjective( objectiveName )
			wait(0.3)
		end
	end
	ProppedObjectiveQueue = { }

	if CompletedObjectiveQueue ~= nil then
		for objectiveName, v in pairs( CompletedObjectiveQueue ) do
			wait(0.3)
			MarkObjectiveComplete( objectiveName )
			wait(0.3)
		end
	end
	CompletedObjectiveQueue = { }
end

function FadeInOvermapComponents()
	for k, component in ipairs( OvermapComponents ) do
		if component == "CaravanEnterButton" then
			if CanOpenCaravan() then
				SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { DoFadeInAnimation = true } })
				SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 1.0 } })
			end
		else
			SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 1.0 } })
		end
	end
end

function FadeOutOvermapComponents()
	for k, component in ipairs( OvermapComponents ) do
		if component == "CaravanEnterButton" then
			SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { DoFadeOutAnimation = true } })
			SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 0.0 } })
		else
			SetMenuOptions({ Name = "InGameUI", Item = component, Properties = { FadeTarget = 0.0 } })
		end
	end
end

function HideOvermapUI()

	FadeOutOvermapComponents()
	HideOvermapUINonButtons()

end

function HideOvermapUINonButtons()
	SetConfigOption({ Name = "ShowOffscreenIndicators", Value = false })
end

function UpdateLocationText( args )
	if GetMapName({ }) ~= "Campaign" then
		return
	end

	if not GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
		return
	end

	-- only show location text for goal locations or new swaths
	if ( currentNodeId ~= goalNodeId ) or ( previouslyOccupiedSwath == currentlyOccupiedSwath ) then
		return
	end

	local text = NodeData[currentNodeId].Location
	if args == "swath" then
		text = SwathData[currentlyOccupiedSwath].SwathName
	end

	if not displayingLocationText then
		if not NodeData[currentNodeId].Unpack and args ~= "swath" then
			return
		end

		local color = Color.White

		-- don't show this in Trailer Mode (normally this option is true)
		if GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
			DisplayWorldText({ Id = locationTextConstant, Group = "Overlay", Text = text, Justification = "LEFT", ShadowBlur = 3,
					ShadowColor = {0.1,0.09,0.08,1.0}, ShadowOffset = {3, 3}, OutlineThickness = 1.0, OutlineColor = {0.3, 0.29, 0.28, 1.0},
					Color = {0.91, 0.9, 0.89}, Font = "KellsSDRegular", FontSize = "72", LerpTime = 0.16, Interval = 0.05, OffsetX = 40 })
		end

		PlaySound({ Name = "/SFX/World Sounds/MapText", Id = locationTextConstant })

		SetConfigOption({ Name = "ShowOffscreenIndicators", Value = false })
		displayingLocationText = true
	end

	if args == "swath" and displayingLocationText then
		RemoveWorldText({ DestinationId = locationTextConstant, Delay = 3, Duration = 0.65 })
		RemoveWorldText({ DestinationId = singleUseTextConstant, Delay = 3, Duration = 0.65 })
		displayingLocationText = false
	end

end

function HideLocationText()

	if not displayingLocationText then
		return
	end
	RemoveWorldText({ DestinationId = locationTextConstant, Duration = 0.65 })
	RemoveWorldText({ DestinationId = singleUseTextConstant, Duration = 0.65 })
	displayingLocationText = false

end

function ShowSwathNameText( textDelay )

	if not GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
		return
	end

	if textDelay ~= nil and textDelay > 0 then
		wait( textDelay )
	end
	swathNameTextAnchor = SpawnObstacle({ Name = "InvisibleTarget", Group = "Scripting", DestinationName = "Player" })
	DrawScreenRelative({ Id = swathNameTextAnchor })
	Teleport({ Id = swathNameTextAnchor, OffsetX = 50, OffsetY = 100 })

	local text = nil
	if currentlyOccupiedSwath ~= nil then
		text = SwathData[currentlyOccupiedSwath]["SwathName"]
	else
		text = SwathData[1]["SwathName"]
	end

	DisplayWorldText({ Id = swathNameTextAnchor, Group = "Overlay", Text = text, Justification = "LEFT", ShadowBlur = 3,
					ShadowColor = {0.1,0.09,0.08,1.0}, ShadowOffset = {3, 3}, OutlineThickness = 1.0, OutlineColor = {0.3, 0.29, 0.28, 1.0},
					Color = {0.91, 0.9, 0.89}, Font = "KellsSDRegular", FontSize = "72", LerpTime = 0.16, Interval = 0.05, OffsetX = 40 })

	PlaySound({ Name = "/SFX/World Sounds/MapText", Id = swathNameTextAnchor })

end

function HideSwathNameText( textDelay )
	if textDelay ~= nil and textDelay > 0 then
		wait( textDelay )
	end
	RemoveWorldText({ DestinationId = swathNameTextAnchor, Duration = 0.65 })
end

function ShowUnpackText()

	if displayingUnpackText then
		return
	end
	displayingUnpackText = true

	local color = {0.86, 0.82, 0.78, 1.0}
	local text = "Info_SingleUse_Travel"

	local currentNode = NodeData[currentNodeId]
	if currentNode ~= nil then
		if currentNode.Category == "Hometown" then
			text = "Info_SingleUse_Hometown"
		elseif currentNode.Category == "Arena" then
			if currentNodeId == goalNodeId then
				text = "Info_SingleUse_MatchSite"
			else
				text = "Info_SingleUse_Arena"
			end
		elseif currentNode.Category == "Shop" then
			text = "Info_SingleUse_Shop"
		end
	end

	SetInteractProperty({ DestinationId = currentNodeId, Name = "InstructionId", Value = text })

end

function HideUnpackText()
	RemoveWorldText({ DestinationId = singleUseTextConstant, Duration = 0.35 })
	displayingUnpackText = false
end

ControlComponents =
{
	"ControlsShadow",
	"ButtonA", "ButtonB", "ButtonX", "ButtonY", "ButtonLT", "ButtonRT",
	"ButtonAText", "ButtonBText", "ButtonXText", "ButtonYText", "ButtonLTText", "ButtonRTText",
	"PassControl", "CastControl", "JumpControl", "ThrowControl", "AutoLockControl", "SprintControl",
}

PortraitComponents =
{
	"TeamABacking", "TeamBBacking",
	"TeamASelectedPortrait", "TeamBSelectedPortrait",
	"PortraitA", "FrameA", "RespawnAnimA", "RespawnTimeA",
	"PortraitB", "FrameB", "RespawnAnimB", "RespawnTimeB",
	"PortraitC", "FrameC", "RespawnAnimC", "RespawnTimeC",
	"PortraitD", "FrameD", "RespawnAnimD", "RespawnTimeD",
	"PortraitE", "FrameE", "RespawnAnimE", "RespawnTimeE",
	"PortraitF", "FrameF", "RespawnAnimF", "RespawnTimeF",
	"TeamAFullWipeFeedback", "TeamBFullWipeFeedback",
}

StaminaComponents =
{
	"StaminaMeterA", "StaminaMeterBackA",
	"StaminaMeterB", "StaminaMeterBackB",
	"StaminaMeterC", "StaminaMeterBackC",
	"StaminaMeterD", "StaminaMeterBackD",
	"StaminaMeterE", "StaminaMeterBackE",
	"StaminaMeterF", "StaminaMeterBackF",
}

OvermapComponents =
{
	"CaravanEnterButton",
}

-- Hints & Hotkeys

OnControlPressed{ "OpenWagon",
	function( triggerArgs )
		if openedCaravan then
			return
		end

		if not IsInputAllowed({ }) then
			return
		end

		local topScreen = GetTopScreenName({ })
		if topScreen ~= "LocationMenuScreen" and topScreen ~= nil then
			return
		end

		if not LocationMenuIn then
			return
		end

		OpenCaravan()
	end
}

OnMenuButtonPressed{ "CaravanEnterButton",
	function( triggerArgs )
		if openedCaravan then
			return
		end

		if not IsInputAllowed({ }) then
			return
		end

		local topScreen = GetTopScreenName({ })
		if topScreen ~= "LocationMenuScreen" and topScreen ~= nil then
			return
		end

		if not LocationMenuIn then
			return
		end

		OpenCaravan()
	end
}

-- RosterScreen: restore camera follow in wagon, etc.
OnMenuClosed{ "RosterScreen",
	function( triggerArgs )
		if choosingChallengeCharacter then
			for k, character in pairs( PlayerTeam.TeamBench ) do
				character.Undraftable = character.SeasonUndraftable
			end
			choosingChallengeCharacter = false
			PickNarrationEvent( "PickBeyonderExit" )
		end
		if openedCaravan then
			EnableCaravanCursor()
			FocusCamera({ Fraction = CARAVAN_DEFAULT_ZOOM, Duration = 1, ZoomType = "Ease" })
			SetGroupVisibility({ Names = AllWagonGroups, Visible = true })
		end
	end
}

-- RosterScreen: alt tooltips
OnMenuOpened{ "CharacterBioScreen",
	function( triggerArgs )
		SelectedCharacter.UnviewedBio = false
		if IsScreenOpen({ Name = "RosterScreen" }) then
			SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { TooltipId = "Roster_OpenBio_Alt" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { TopAnimation = "null" } })
		end
	end
}

OnMenuClosed{ "CharacterBioScreen",
	function( triggerArgs )
		if IsScreenOpen({ Name = "RosterScreen" }) then
			SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { TooltipId = "Roster_OpenBio" } })
		end
	end
}

OnMenuOpened{ "CharacterSkillsScreen",
	function( triggerArgs )
		if IsScreenOpen({ Name = "RosterScreen" }) and not postMatchScreen then
			SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { TooltipId = "Roster_OpenSkills_Alt" } })
		end
		wait(0.01)
		SetMenuOptions({ Name = "CharacterSkillsScreen", Item = "SkillTreeIconA", Properties = { Graphic = ArchetypeData[SelectedCharacter.Archetype].SkillTreeBackgroundLeft } })
		SetMenuOptions({ Name = "CharacterSkillsScreen", Item = "SkillTreeIconB", Properties = { Graphic = ArchetypeData[SelectedCharacter.Archetype].SkillTreeBackgroundRight } })
	end
}

OnMenuClosed{ "CharacterSkillsScreen",
	function( triggerArgs )
		if IsScreenOpen({ Name = "RosterScreen" }) and not postMatchScreen then
			SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { TooltipId = "Roster_OpenSkills" } })
		end
	end
}

OnMenuClosed{ "InventoryScreen",
	function( triggerArgs )
		if IsScreenOpen({ Name = "RosterScreen" }) then
			SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { TooltipId = "Roster_OpenInventory" } })
		end
	end
}

-- Infopanel: Caravan
OnTriggerFired{ "ShowOvermap",
  function( triggerArgs )
	if openedCaravanScreenOnce or not campaign then
		return
	end

	if matchesPlayed >= 1 and movesAvailable <= 4 and not menuHintPlayedRecently and not allowQuestGoalPan then
		menuHintPlayedRecently = true
		wait(1.25)
		if overmapScreen then
			-- DisplayInfoPanelOnce({ Text = "Hint_ViewCaravan" })
		end
	end
  end
}

OnMenuClosed{ "ItemPurchaseScreen",
  function( triggerArgs )
	wait(1.25)
	if allowPurchasedWeaponHint then
		allowPurchasedWeaponHint = false
		--DisplayInfoPanelText({ Text = "Hint_ViewCaravan" })
	end
  end
}

-- Infopanel: GuideBook
OnTriggerFired{ "ShowOvermap",
  function( triggerArgs )
	if openedGuideBookOnce or not campaign then
		return
	end

	if matchesPlayed >= 1 and movesAvailable <= 5 and not menuHintPlayedRecently and not allowQuestGoalPan then
		menuHintPlayedRecently = true
		wait(1.25)
		if overmapScreen then
			-- DisplayInfoPanelText({ Text = "Hint_ViewGuideBook" })
		end
	end
  end
}

OnAnyLoad{ function( triggerArgs )

	PersistVariable({ Name = "ViewedTooltips" })

	if CaravanScreenOpeners == nil then
		CaravanScreenOpeners = {
			-- Bard
			{
				DisplayOffsetX = 0, DisplayOffsetY = 0,
				Menu = "None", Id = 210105,
				NarrativeDisplayName = "Wagon_Prologue_Bard", CaravanObjectDisabled = true,
				NoHighlight = true,
				ShowNameAnyway = true,
			},
			-- Dialogue
			{
				DisplayOffsetX = 0, DisplayOffsetY = -40,
				Menu = "Character",
				NarrativeDisplayName = "None", CaravanObjectDisabled = true,
			},
			{
				DisplayOffsetX = 0, DisplayOffsetY = -40,
				Menu = "Partner",
				NarrativeDisplayName = "None", CaravanObjectDisabled = true,
			},
			-- Robes
			{
				DisplayOffsetX = -10, DisplayOffsetY = -100,
				Id = 190003, CaravanObjectDisabled = true,
				NarrativeDisplayName = "Wagon_Prologue_Robes",
				EditorScale = 0.96,
				NoHighlight = true,
				ShowNameAnyway = true,
			},
			-- Roster / Common Room
			{
				DisplayName = "Lobby_OpenRoster", DisplayOffsetX = -10, DisplayOffsetY = -100,
				Menu = "RosterScreen", Id = 210085, CaravanObjectDisabled = true,
				NarrativeDisplayName = "Wagon_Bunks_Intro",
				AltNarrativeDisplayName = "Wagon_Bunks_Closed",
				NoHighlight = true,
				EditorScale = 1.0,
				ShowNameAnyway = true,
			},
			-- Books / GuideBook
			{
				DisplayName = "Lobby_OpenGuideBook", DisplayOffsetX = 10, DisplayOffsetY = 80,
				Menu = "GuideBookScreen", Id = 190015,
				NarrativeDisplayName = "Wagon_Prologue_GuideBook",
				NoHighlight = true,
				EditorScale = 0.41,
			},
			-- Chest / Stash / WagonScreen
			{
				DisplayName = "Lobby_OpenStash", DisplayOffsetX = 45, DisplayOffsetY = -180,
				Menu = "CentrifugeScreen", Id = 190009, CaravanObjectDisabled = true,
				NarrativeDisplayName = "Wagon_Prologue_Imps",
				NoHighlight = true,
				ShowNameAnyway = true,
			},
			-- Exit
			{
				DisplayName = "Lobby_Back", DisplayOffsetX = 0, DisplayOffsetY = -50,
				Menu = "Exit", Id = 190019,
				NarrativeDisplayName = "Lobby_Intro_Exit",
			},
		}
		PersistVariable({ Name = "CaravanScreenOpeners" })
	end
	-- wagonNarrativeSequence = true
end
}

function IsWagonActionAllowed()

	if caravanClosing or not openedCaravan then
		return false
	end

	if doForageEvent or doLootDropEvent or chooseGrantXP or CurrentMapName ~= "Campaign" then
		return false
	end

	if IsScreenOpen({ Name = "DialogueScreen" }) or IsScreenOpen({ Name = "InventoryScreen" }) then
		return false
	end

	return true

end

function EnterSideMatch( matchMode )
	if not IsWagonActionAllowed() then
		DisplayInfoPanelOnce({ Text = "Hint_CannotPracticeHere", Duration = 2.5 })
		return
	end

	if IsScreenOpen({ Name = "RosterScreen" }) then
		ExitMenu({ Name = "RosterScreen" })
	end

	DisableInput({  })

	if matchMode == "Practice" then
		practiceMatch = true
		PersistVariable({ Name = "practiceMatch" })
		blockMatchVO = true
		PersistVariable({ Name = "blockMatchVO" })
	end

	if IsScreenOpen({ Name = "LocationMenuScreen" }) then
		locationMenuSuspended = true
		PersistVariable({ Name = "locationMenuSuspended" })
		ExitMenu({ Name = "LocationMenuScreen" })
	end

	DreamSequenceFade( "Challenge" )
	LoadMap({ Name = "MatchSiteA" })
end

function RestartPracticeMatch()
	FireTrigger({ Name = "EndCurrentMusic" })
	DreamSequenceFade( "Challenge" )
	wait(1.0)
	LoadMap({ Name = "MatchSiteA" })
end

function SetupMapRotation()
	mapRotation = mapRotation or GetMapRotation({ }) or { "MatchSiteB", "MatchSiteC", "MatchSiteE", "MatchSiteG" }
	PersistVariable({ Name = "mapRotation" })
end

-- Enable Bard/Minstrel
function AwakenBard()
	if not bardAwakened then
		-- remove the sleeping bard from the wagon
		SetOpacity({ Ids = { 210105 }, Fraction = 0.0 })
		UseableOff({ Ids = { 210105 } })

		for k, caravanScreenButton in pairs( CaravanScreenOpeners ) do
			if caravanScreenButton.NarrativeDisplayName == "Wagon_Prologue_Bard" then
				caravanScreenButton.CaravanObjectDisabled = true
				caravanScreenButton.HideScreenOpener = true
				break
			end
		end

		Clickables["wagon2interactbard01"].DisableClickable = true

		bardAwakened = true
		PersistVariable({ Name = "bardAwakened" })
	end
end

BardId = 10074

function BardJoined( args )

	-- don't do the following checks until the bard joins
	if not bardJoined and args == "status" then
		return
	end

	-- do not show bard in wagon immediately after matches
	if not JustCameFromMatch() then

		bardJoined = true
		PersistVariable({ Name = "bardJoined" })

	else

		SetOpacity({ Id = BardId, Fraction = 0.0 })
		UseableOff({ Id = BardId })

	end

end

OnTriggerFired{ "UnlockWagonScreenRoster",
	function( triggerArgs )
		EnableRosterDoor()
	end
}

function EnableRosterDoor()

	for k, caravanScreenButton in pairs( CaravanScreenOpeners ) do
		if caravanScreenButton.DisplayName == "Lobby_OpenRoster" then
			caravanScreenButton.CaravanObjectDisabled = false
			caravanScreenButton.HideScreenOpener = true
			caravanScreenButton.Id = 10047
			break
		end
	end

	-- Setup Roster Door in WagonScreen
	if Clickables ~= nil then
		Clickables["wagon2interactdoor01"]["TooltipId"] = "Lobby_OpenRoster"
		Clickables["wagon2interactdoor01"]["MouseOverSpecialAction"] = "RisingHold"
		Clickables["wagon2interactdoor01"]["InteractMaxUsesLifetime"] = nil
		Clickables["wagon2interactdoor01"]["InteractSound"] = nil
		Clickables["wagon2interactdoor01"]["DisableClickable"] = true
		Clickables["wagon2interactdoor01open"]["DisableClickable"] = nil
	end

	OpenRosterDoor()

	rosterUnlocked = true
	PersistVariable({ Name = "rosterUnlocked" })

end

function OpenRosterDoor()

	-- switch to open door art
	local closedDoor = GetIdsByType({ Name = "wagon2interactdoor01" })
	SetOpacity({ Id = closedDoor, Fraction = 0.0 })
	local openDoor = GetIdsByType({ Name = "wagon2interactdoor01open" })
	SetOpacity({ Id = openDoor, Fraction = 1.0 })

	UseableOff({ Id = closedDoor })
	UseableOn({ Id = openDoor })

	SetInteractProperty({ DestinationId = openDoor, Name = "ChangeCursor", Value = true })

	PlayAmbientSound({ Id = openDoor })

end

function CloseRosterDoor()

	-- switch to open door art
	local closedDoor = GetIdsByType({ Name = "wagon2interactdoor01" })
	SetOpacity({ Id = closedDoor, Fraction = 1.0 })
	local openDoor = GetIdsByType({ Name = "wagon2interactdoor01open" })
	SetOpacity({ Id = openDoor, Fraction = 0.0 })

	UseableOn({ Id = closedDoor })
	UseableOff({ Id = openDoor })
	SetInteractProperty({ DestinationId = openDoor, Name = "ChangeCursor", Value = false })

	StopAmbientSound({ Id = openDoor })

end

function QueueRosterInfoPanel()
	waitUntil("RemovedBasicChoices")
	waitUntil("LocationMenuPresentationComplete")
	wait(0.75)
	if GetTopScreenName({ }) == "LocationMenuScreen" then
		DisplayInfoPanelOnce({ Text = "Info_NewWagonCompartment_Roster", Duration = 3.0 })
	end
end

function QueueStashInfoPanel()
	waitUntil("RemovedBasicChoices")
	waitUntil("LocationMenuPresentationComplete")
	wait(0.75)
	if GetTopScreenName({ }) == "LocationMenuScreen" then
		DisplayInfoPanelOnce({ Text = "Info_NewWagonCompartment_Stash" })
	end
end

-- used to unlock various systems and content after week 1
OnTriggerFired{ "UnlockWagonScreenCompartments",
	function( triggerArgs )
		if ActiveNarrationName == "S1W2_Start" or ActiveNarrationName == "Intro_Week2_Onward" then
			EnableRosterDoor()

			-- change behavior of week 1 clickables where needed
			if Clickables ~= nil then
				Clickables["wagon2interactladder01"]["InteractRemovesTooltip"] = nil
			end
			EnableBasicChoices()
		end
	end
}

CARAVAN_CAMERA_FOLLOW_CURSOR_SPEED = 150

-- WagonScreen Setup
OnAnyLoad
{
	function( triggerArgs )

		-- Bard
		if bardAwakened then
			SetOpacity({ Ids = { 210105 }, Fraction = 0.0 })
			UseableOff({ Ids = { 210105 } })
		else
			SetOpacity({ Ids = { 210105 }, Fraction = 1.0 })
			UseableOn({ Ids = { 210105 } })
		end
		-- Scoped Campaign: minstrel removed from wagon interior for now [GK 12/26/16]
		if bardJoined then
			-- SetOpacity({ Ids = { 10074 }, Fraction = 1.0 })
			-- UseableOn({ Ids = { 10074 } })
		else
			SetOpacity({ Ids = { 10074 }, Fraction = 0.0 })
			UseableOff({ Ids = { 10074 } })
		end
		-- Roster Door
		if rosterUnlocked then
			EnableRosterDoor()
		end
	end
}

function OpenCaravanPresentation()

	if caravanPresentationOn then
		EnableInput({ })
		return
	end

	AddInputBlock({ Name = "OpenCaravanPresentation" })

	ClearCaravanText()
	caravanPresentationOn = true

	for k, v in pairs( CaravanScreenOpeners ) do

		-- narrative sequence scripting
		if wagonNarrativeSequence and ( v.NarrativeDisplayName == "None" or v["NarrativeObjectUsed"] ) then
			UseableOff({ Id = v.Id })
			SetInteractProperty({ DestinationId = v.Id, Name = "ChangeCursor", Value = false })

		elseif wagonNarrativeSequence and v.NarrativeDisplayName ~= "None" and not v["NarrativeObjectUsed"] then
			SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.NarrativeDisplayName })

		-- standard wagonscreen scripting
		elseif v.ShowNameAnyway or ( not wagonNarrativeSequence and v.Menu ~= "None" and v.Menu ~= "Character" and v.Menu ~= "Partner" and not v["CaravanObjectDisabled"] ) then

			local text = v.DisplayName
			if v.ShowNameAnyway then
				text = v.NarrativeDisplayName
			end

			if v.Id == 210105 and not v.NarrativeObjectUsed and not bardAwakened then
				UseableOn({ Id = v.Id })
				SetInteractProperty({ DestinationId = v.Id, Name = "ChangeCursor", Value = true })
			end

			if text ~= nil then
				SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.NarrativeDisplayName })
				-- Roster exception
				if v.DisplayName == "Lobby_OpenRoster" then
					if introComplete then
						SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.DisplayName })
					else
						SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.AltNarrativeDisplayName })
					end
				-- Books exception
				elseif v.DisplayName == "Lobby_OpenGuideBook" then
					SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.DisplayName })
				-- StandingsScreen exception
				elseif v.DisplayName == "Lobby_OpenStandings" then
					SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.DisplayName })
				-- Exit Door exception
				elseif v.DisplayName == "Lobby_Back" then
					if not nightwingWagonScare then
						SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = v.DisplayName })
					else
						-- Oralech in Wagon
						SetInteractProperty({ DestinationId = v.Id, Name = "TooltipId", Value = "Lobby_Nightwing_Exit" })
					end
				end
			end
		end

	end

	EnableInput({ })
	RemoveInputBlock({ Name = "OpenCaravanPresentation" })
	openedCaravanToday = true

end

function ClearCaravanText()

	if not openedCaravan then
		return
	end

	for k, v in pairs( CaravanScreenOpeners ) do

		if v.Menu ~= "Character" and v.Menu ~= "Partner" and not v.HideScreenOpener then -- Character tooltips are handled separately
			SetColor({ Id = v.Id, Color = Color.White, Duration = 0 })
			RemoveWorldText({ DestinationId = v.Id })
		end

	end

	caravanPresentationOn = false

end

function CloseCaravanPresentation()

	if not openedCaravan or caravanClosing then
		return
	end

	if nightwingWagonScare then
		return
	end

	caravanClosing = true
	AddInputBlock({ Name = "CaravanClosing" })

	PlaySound({ Name = "/SFX/Leftovers/DoorClose" })

	if introComplete and not openedCaravanScreenOnce then
		-- used for infopanel, faster presentation
		openedCaravanScreenOnce = true
		PersistVariable({ Name = "openedCaravanScreenOnce" })
	end

	DisableCaravanCursor()
	LockCamera({ Id = wagonCameraLockPoint, Speed = 40 })

	Stop({ Id = 210321 }) -- floating rock

	FadeOut({ Color = Color.Black, Duration = 0.3 })

	thread( WagonAmbienceOff )

	-- Bard Music Player
	if BardMusicId ~= nil then
		StopSound({ Id = BardMusicId, Duration = 2.0 })
		BardMusicId = nil
		BardTrackName = nil
	end
	ResumeSound({ Id = OvermapMusicId, Duration = 3.0 })

	wait(0.325)

	-- Under black now

	SetGroupVisibility({ Names = AllWagonGroups, Visible = false })

	ClearCaravanText()
	StopFloatingRock()

	if IsScreenOpen({ Name = "LocationMenuScreen" }) then
		SetOvermapMusic( "mapzoomed" )
	else
		SetOvermapMusic( "mapidle" )
	end

	SetAudioEffectState({ Name = "Reverb", Value = 0.0 })

	ClearCameraClamp({ Duration = 0, LerpTime = 0 })

	SetupOvermapLockPoint()

	if fakeSwathZeroNight then
		LockCamera({ Id = 10019 })
	elseif locMenuCameraLockPoint ~= nil then
		LockCamera({ Id = locMenuCameraLockPoint })
	else
		LockCamera({ Id = baseCaravan, OffsetY = OVERMAP_LOCATION_MENU_OFFSET_Y_DEFAULT })
	end

	SetupOvermapClamps()

	if locationChoicesFramed then
		AdjustZoom({ Fraction = 1, LerpTime = 0.00001, Duration = 999999 })
	else
		AdjustZoom({ Fraction = OVERMAP_ZOOM_DEFAULT * 4, LerpTime = 0.00001, Duration = 999999 })
	end

	PlaySound({ Name = "/SFX/World Sounds/MapZoomOut" })
	if SpecialOvermapBloom then
		AdjustFullscreenBloom({ Name = SpecialOvermapBloom, Duration = 0.05 })
	else
		AdjustFullscreenBloom({ Name = SwathData[currentlyOccupiedSwath]["Bloom"], Duration = 0.05 })
	end

	if SpecialOvermapColorGrade then
		AdjustColorGrading({ Name = SpecialOvermapColorGrade, Duration = 0 })
	elseif timeofday == "night" then
		AdjustColorGrading({ Name = SwathData[currentlyOccupiedSwath]["ColorGradeNight"], Duration = 0 })
	else
		AdjustColorGrading({ Name = SwathData[currentlyOccupiedSwath]["ColorGradeDay"], Duration = 0 })
	end

	if timeofday == "night" then
		SetOpacity({ Id = nightBackground, Fraction = 0.5, Duration = 0 })
		--SetAmbientLightColor({ Color = Color.White, Intensity = 0.01, Duration = 0 })
	else
		--SetAmbientLightColor({ Color = preCaravanAmbientLightColor, Duration = 0 })
	end

	wait(0.05)

	if singleUse then
		UpdateLocationText()
		ShowUnpackText()
	end

	FadeIn({ Duration = 0.3 })

	-- condition to zoom based on whether you're at OVERMAP_ZOOM_DEFAULT or 1.0
	local doSave = false
	if IsScreenOpen({ Name = "LocationMenuScreen" }) then
		LocationMenuZoom( nil, "fromCaravan" ) -- has a wait in it
		if wasLocationMenuIn then
			SlideIn( false )
		end
		doSave = true
	else
		if demoPan then
			local caravanMarker = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = realOvermapUnit })
			PanCamera({ Id = caravanMarker, OffsetY = -150, Duration = 0.3, Delay = 0 })
			FocusCamera({ Fraction = OVERMAP_ZOOM_DEFAULT, Duration = 0.35, ZoomType = "Ease" })
		else
			FocusCamera({ Fraction = OVERMAP_ZOOM_LOCATION_MENU_DEFAULT, Duration = 0.35, ZoomType = "Ease" })
		end
		if locationChoicesFramed then
			FrameOvermapLocationChoices()
		end
	end

	justSawSandra = false

	if bellRings ~= nil then
		bellRings = 0
		if NarrationRecord["SideCon_BellRinger_01"] then
			closedWagonSinceRinging = true
			PersistVariable({ Name = "closedWagonSinceRinging" })
		end
	end

	if moonShineSwigs ~= nil then
		moonShineSwigs = 0
	end

	wait(0.3)

	caravanClosing = false
	openedCaravan = false
	if introComplete and not demoPan then
		-- Oralech in Wagon -- scene when you exit the wagon
		if NarrationRecord["SideCon_Nightwing_01"] then
			NarrationSequenceOnce( "LeftWagon_NightwingWagonScare" )
		end
		ShowOvermapUI()
	end

	-- for Sandra Sendoff
	CheckSandraSendoff()

	if doSave then
		DoLocationMenuSave()
	end

	numBigSpeechLines = nil

	RemoveInputBlock({ Name = "CaravanClosing" })

	notifyExistingWaiters( "CloseCaravanPresentationComplete" )

end

function DoLocationMenuSave()
	locationMenuSuspended = true
	PersistVariable({ Name = "locationMenuSuspended" })
	SaveCheckpoint({ SuspendNonPersisted = true, DevSaveName = CreateLocationMenuDevSaveName() })
	locationMenuSuspended = false
end

OnControlPressed{ "Cancel",
	function( triggerArgs )

		if not IsInputAllowed({ }) then
			return
		end

		if openedCaravan and not clickSequence and introComplete then
			local topScreenName = GetTopScreenName({ })
			if topScreenName == "LocationMenuScreen" or topScreenName == "InGameUI" or topScreenName == nil then
				CloseCaravanPresentation()
			end
		end
	end
}

function CanOpenCaravan()

	if caravanCheat then
		return true
	end

	if ActiveNarrationName == "Week5_Seaworthy" then
		return true
	end

	if openedCaravan or caravanClosing or caravanMoving or swathTransitioning or singleUse then
		return false
	end

	if showStarMap or constellationPick or caravanFlying then
		return false
	end

	-- intro special cases
	if matchesPlayed == 0 then

		if not continuedFromIntroduction and not madeFirstMove then
			return false
		end

		if introComplete and not madeFirstMove then
			return false
		end

		if introComplete then
			if not madeFirstMove then
				return false
			end
		else
			if not wagonNarrativeSequence then
				return false
			end
		end

		if not introComplete then
			return true
		end

	end

	if blockWagonScreen then
		return false
	end

	if takeoffQueued and not JustCameFromAnyMatch() and not IsScreenOpen({ Name = "LocationMenuScreen" }) then
		if NarrationRecord["FirstTakeOff"] then
			return false
		end
	end

	if IsScreenOpen({ Name = "InventoryScreen" }) then
		return false
	end

	if CurrentMapName ~= "Campaign" then
		return false
	end

	if introComplete and singleUse then
		return false
	end

	if not caravanUnpacked and ActiveNarrationName ~= "PrepareForFirstTakeOff" then
		return false
	end

	return true

end

function OpenCaravan( addCharacters )

	if not CanOpenCaravan() then
		return
	end

	if addCharacters == nil then
		addCharacters = true
	end

	AddInputBlock({ Name = "OpenCaravan" })

	openedCaravan = true

	-- used for Caravan Button Availability
	openedCaravanSinceLastLocation = true

	caravanCenter = 50023
	CARAVAN_DEFAULT_ZOOM = 0.65

	if wagonNarrativeSequence and not introComplete then
		if not continuedFromIntroduction then
			baseCaravan = 40074
		else
			baseCaravan = realOvermapUnit
		end

		wagonCameraLockPoint = SpawnObstacle({ Name = "InvisibleTarget", OffsetY = -90, DestinationId = baseCaravan, OffsetX = 20 })
		LockCamera({ Id = wagonCameraLockPoint, Duration = 0.3 })
	else
		baseCaravan = realOvermapUnit
	end

	HideOvermapUI()
	HideUnpackText()
	wasLocationMenuIn = LocationMenuIn
	if IsScreenOpen({ Name = "LocationMenuScreen" }) and wasLocationMenuIn then
		SlideOut( false )
	end

	-- don't play this sound returning from matches
	if JustCameFromAnyMatch() or JustCameFromEncounter() then
	--
	else
		if not openedCaravanToday then
			--
		else
			PlaySound({ Name = "/SFX/World Sounds/MapZoomInTight" })
		end
	end

	if not cameFromIntroMatch then
		if cameFromFreePlayMatch or cameFromChallengeMatch then
			PlaySound({ Name = "/SFX/World Sounds/MapZoomIn" })
		else
			PlaySound({ Name = "/SFX/World Sounds/CaravanDoorOpen" })
		end
	end

	wait(0.01)
	-- caravan zoom
	if locationChoicesFramed then
		AdjustZoom({ Fraction = 3, LerpTime = 0.35 })
	else
		AdjustZoom({ Fraction = 6, LerpTime = 0.35 })
	end

	wait(0.14)
	FadeOut({ Color = Color.Black, Duration = 0.15 })
	wait(0.17)

	-- Save heavy setup until under full black
	SetGroupVisibility({ Names = AllWagonGroups, Visible = true })

	-- hide location UI if it's showing
	HideLocationText()

	-- nightstate
	CheckCaravanNightState()

	-- imp state
	CheckCaravanImpState()

	-- clickables
	CheckClickableConditions()

	-- practice stone
	CheckUnviewedChallenges()

	-- GuideBook
	CheckUnreadPages()

	-- Roster Door
	CheckRosterDoorVisuals()

	-- character rich presence
	CheckCharacterRichPresence()

	-- floating rock
	StartFloatingRock()

	if nightwingWagonScare or not introComplete then
		CloseRosterDoor()
	else
		OpenRosterDoor()
	end

	-- challenge match status
	if CountChallengeMatchesAvailable() == 0 then
		challengeMatchesString = "ChallengeString_NoMatchesAvailable"
	else
		challengeMatchesString = "ChallengeString_MatchesAvailable"
	end

	-- roster bio updates
	CheckRosterBioUpdates()

	MovingHoldCamera({ Enabled = false })
	AdjustColorGrading({ Name = "Off", Duration = 0 })

	if addCharacters then
		BardJoined( "status" )
		SetupConversationOpener()
	end

	wait(0.3)

	if timeofday == "night" then
		SetOpacity({ Id = nightBackground, Fraction = 0, Duration = 0 })
	end

	preCaravanAmbientLightColor = GetAmbientLightColor({ })

	SetOvermapMusicInsideWagon()

	SetAudioEffectState({ Name = "Reverb", Value = -1.0 })
	OvermapMusicId = MusicId

	EnableCaravanCursor()

	thread( WagonAmbienceOn )

	LockCamera({ Id = caravanCenter	})
	AdjustZoom({ Fraction = CARAVAN_DEFAULT_ZOOM, LerpTime = 0.0001, Duration = 99999 })

	SetCameraClamp({ Ids = { 50024, 50025 }, LerpTime = 0 })

	wait(0.05)
	wagonCameraLockPoint = SpawnObstacle({ Name = "InvisibleTarget", OffsetX = 15, OffsetY = -70, DestinationId = caravanCenter })

	if matchesPlayed == 8 then
		LockCamera({ Id = 50064, Duration = 4 })
	else
		LockCamera({ Id = wagonCameraLockPoint, Duration = 3.5 })
	end
	FadeIn({ Duration = 0.3 })

	if not wagonNarrativeSequence then
		AdjustFullscreenBloom({ Name = "Off", Duration = 0.5 })
	end

	-- WagonScreen Intro
	if matchesPlayed == 0 and not openedCaravanScreenOnce and introComplete and not madeFirstMove then
		DisableInput({  })
		NarrationSequenceOnce( "EnteredWagon_Intro" )
		wait(0.35)
		EnableInput({  })
	-- Oralech in Wagon
	elseif nightwingWagonScare then
		AddInputBlock({ Name = "OralechInWagon" })
		wait(0.35)
		PlaySound({ Name = "/SFX/Leftovers/TextReveal" })
		RemoveInputBlock({ Name = "OralechInWagon" })
		NarrationSequenceOnce( "EnteredWagon_NightwingWagonScare" )
	end

	if not openedCaravanScreenOnce then
		wait(0.6)
	else
		-- interact points highlight faster after first use
		wait(0.3)
	end

	if not wagonNarrativeSequence then
		OpenCaravanPresentation()
	end

	RemoveInputBlock({ Name = "OpenCaravan" })

	SetRichPresence({ Name = "RP_InWagon" })
end

function EnableCaravanCursor()
	if GetConfigOptionValue({ Name = "UseMouse" }) then
		SetConfigOption({ Name = "CameraEdgePanSpeed", Value = 470 })
		SetConfigOption({ Name = "CameraEdgePanThreshold", Value = 75 })

		SetConfigOption({ Name = "CameraFollowCursor", Value = 0 })
	else
		SetConfigOption({ Name = "CameraFollowCursor", Value = CARAVAN_CAMERA_FOLLOW_CURSOR_SPEED })

		SetConfigOption({ Name = "CameraEdgePanSpeed", Value = 0 })
		SetConfigOption({ Name = "CameraEdgePanThreshold", Value = 0 })
	end
end

function DisableCaravanCursor( cursorDelay )
	if cursorDelay ~= nil and cursorDelay > 0 then
		wait(cursorDelay)
	end
	SetConfigOption({ Name = "CameraFollowCursor", Value = 0.0 })
	SetConfigOption({ Name = "CameraEdgePanSpeed", Value = 0 })
	SetConfigOption({ Name = "CameraEdgePanThreshold", Value = 0 })
end

local CaravanTimeOfDayIds = { 310544 }
local CaravanTimeOfDayOpacityIds = { 212407, 212342 }

function CheckCaravanNightState()
	if timeofday == "night" or fakeSwathZeroNight then
		SetColor({ Ids = CaravanTimeOfDayIds, Color = { 135, 205, 255, 122 }, Override = true, Duration = 0.05 })
		SetOpacity({ Ids = CaravanTimeOfDayOpacityIds, Fraction = 1, Duration = 0.05 })
		if not fakeSwathZeroNight then -- don't use color grading for Swath 0 fake night
			AdjustColorGrading({ Name = SwathData[currentlyOccupiedSwath]["ColorGradeCaravanNight"], Duration = 0, Delay = 0 })
		end
	else
		SetColor({ Ids = CaravanTimeOfDayIds, Color = { 255, 203, 135, 122 }, Override = true, Duration = 0.05 })
		SetOpacity({ Ids = CaravanTimeOfDayOpacityIds, Fraction = 0, Duration = 0.05 })
		AdjustColorGrading({ Name = SwathData[currentlyOccupiedSwath]["ColorGradeCaravanDay"], Duration = 0, Delay = 0 })
	end
end

local impGroupA = { 311106, 211331, 190021, 212044, 310118, 310342, 10059, 310543}
local impGroupB = { 311131, 311141, 311142, 311090, 311114, 311143 }

function CheckCaravanImpState()
	if not introComplete then
		-- turn on group A
		SetOpacity({ Ids = impGroupA, Fraction = 1.0 })
		UseableOn({ Ids = impGroupA })
		-- turn off group B
		SetOpacity({ Ids = impGroupB, Fraction = 0.0 })
		UseableOff({ Ids = impGroupB })
	else
		-- turn on group B
		SetOpacity({ Ids = impGroupB, Fraction = 1.0 })
		UseableOn({ Ids = impGroupB })
		-- turn off group A
		SetOpacity({ Ids = impGroupA, Fraction = 0.0 })
		UseableOff({ Ids = impGroupA })
	end
end

function SetupConversationOpener()

	if QueuedConversation == nil then
		return
	end

	if not CanHaveSideConversation() then
		TurnOffSpeechBubble()
		for k, opener in pairs( CaravanScreenOpeners ) do
			if opener.Menu == "Character" and opener.Id ~= nil then
				Delete({ Id = opener.Id })
				opener.Id = nil
			end
		end
		return
	end

	-- For Character Dialogue
	for k, opener in pairs( CaravanScreenOpeners ) do
		if opener.Menu == "Character" then

			local character = GetFirstEventCharacter( QueuedConversation )
			if character ~= nil then

				local obstacleName = character.Portrait.."_Interactable"

				-- Delete the old one first
				if opener.Id ~= nil then
					Delete({ Id = opener.Id })
					opener.Id = nil
				end

				local startingPortrait = GetFirstCharacterPortrait( QueuedConversation )

				local charSpawnTarget = 130000
				local offsetX = character.CaravanOffsetX or 0
				local offsetY = character.CaravanOffsetY or 0
				if startingPortrait ~= nil and string.find( startingPortrait, "Robe" ) then
					offsetX = character.CaravanRobedOffsetX or offsetX
					offsetY = character.CaravanRobedOffsetY or offsetY
				end

				opener.Id = SpawnObstacle({ Name = obstacleName, DestinationId = charSpawnTarget, Group = "Wagon_Character01", OffsetX = offsetX, OffsetY = offsetY })
				opener.DisplayName = character.FirstName
				opener.CaravanObjectDisabled = false
				wagonCharacterVoice = character.VoicePrefix


				if startingPortrait ~= nil then
					SetThingProperty({ DestinationId = opener.Id, Name = "Graphic", Value = startingPortrait })
				end
				SetMaskColors( opener.Id, League[character.TeamIndex] )
				SetOpacity({ Id = opener.Id, Fraction = 1.0 })

				if not opener.NarrativeObjectUsed then
					UseableOn({ Id = opener.Id })
					SetInteractProperty({ DestinationId = opener.Id, Name = "ChangeCursor", Value = true })
				end

				SetInteractProperty({ DestinationId = opener.Id, Name = "TooltipId", Value = "Wagon_Character" })
				AttachLua({ Id = opener.Id, Table = character })

				-- AttractQuip
				if not IsScreenOpen({ Name = "DialogueScreen" }) then
					local eventData = NarrationData[QueuedConversation]
					if eventData.AttractQuip ~= nil then
						PlaySound({ Name = eventData.AttractQuip, Id = opener.Id, Delay = 0.5 })
					elseif character.AttractQuip ~= nil then
						PlaySound({ Name = character.AttractQuip, Id = opener.Id, Delay = 0.5 })
					end
				end

			end
		end
	end

end

OnUsed{ "Wagon_LeftFront02 Wagon_LeftFront01 Wagon_RightFront03 Wagon_RightFront02 Wagon_RightFront01 Wagon_Mid05 Wagon_Mid04 Wagon_Mid03 Wagon_Mid02 Wagon_Mid01 Wagon_Back02 Wagon_Back01 Wagon_09 Wagon_Character01",
	function( triggerArgs )

		if clickSequence then
			return
		end

		local wagonScreenClickedObject = triggerArgs.triggeredById
		EndRisingHold( wagonScreenClickedObject )

		-- Wagon Exit
		if GetName({ Id = wagonScreenClickedObject }) == "wagon2interactdoor02" then
			if wagonNarrativeSequence then
				PlaySound({ Name = "/SFX/Leftovers/DoorClose" })
			else
				CloseCaravanPresentation()
				return
			end
		end

		local clickable = wagonScreenClickedObject
		local clickableType = GetName({ Id = clickable })
		local caravanClackyObjects = { "wagonlobbyfloorFront01", "wagonlobbyback01", "wagonlobbyfloorMid01", "wagonlobbyshelfWall01", "wagonlobbyshelfWall02", "wagonlobbyceiling01" }

		-- reactive object types
		if clickableType == "wagonlobbywheel01" then
			PlaySound({ Name = "/SFX/Menu Sounds/WoodKnockInteract", Id = clickable })
		elseif Contains(caravanClackyObjects, clickableType) then
			PlaySound({ Name = "/SFX/Menu Sounds/WaxUp", Id = clickable })
		end

		local clickedScreenOpener = nil
		for k, screenOpener in pairs( CaravanScreenOpeners ) do
			if screenOpener.Id == wagonScreenClickedObject then
				clickedScreenOpener = screenOpener
				break
			end
		end

		if clickedScreenOpener == nil then
			return
		end

		clickSequence = true
		if introComplete or clickedScreenOpener.Menu == "GuideBookScreen" then
			AddInputBlock({ Name = "ClickSequence" })
		end

		CARAVAN_MOUSECLICK_LERP_SPEED = 500

		-- wagon interact presentation
		if k ~= 190020 and not wagonNarrativeSequence and not clickedScreenOpener.CaravanObjectDisabled and clickedScreenOpener.Menu ~= "Exit" and clickedScreenOpener.Menu ~= "Character" and clickedScreenOpener.Menu ~= "Partner" then

			FocusCamera({ Fraction = CARAVAN_DEFAULT_ZOOM * 1.035, Duration = 0.5, ZoomType = "Ease" })

		-- Intro WagonScreen Content
		elseif clickedScreenOpener.NarrativeDisplayName == "Wagon_Prologue_Robes" then
			if introComplete then
				NarrationSequenceOnce( "Intro_Week1_WagonInterior_Robes" )
			end
		elseif clickedScreenOpener.NarrativeDisplayName == "Wagon_Prologue_Imps" then
			if introComplete and matchesPlayed < 3 then
				NarrationSequenceOnce( "Intro_Week1_WagonInterior_Stash" )
			end
		elseif clickedScreenOpener.NarrativeDisplayName == "Wagon_Prologue_Bard" then
			if introComplete and not bardAwakened then
				NarrationSequenceOnce( "Intro_Week1_WagonInterior_Bard" )
			end
		elseif clickedScreenOpener.DisplayName == "Lobby_OpenRoster" then
			if introComplete and matchesPlayed == 0 and movesAvailable >= 2 then
				if Clickables ~= nil then
					Clickables["wagon2interactdoor01"]["TooltipId"] = nil
				end
				SetInteractProperty({ DestinationId = clickedScreenOpener.Id, Name = "TooltipId", Value = nil })
				NarrationSequenceOnce( "Intro_Week1_WagonInterior_Roster" )
			end
		elseif clickedScreenOpener.Menu == "Character" then
			PlaySound({ Name = "/SFX/Match SFX/RobeFlutter" })
		end

		wait(0.2)

		if introComplete then
			-- don't remove RosterScreen tooltip after week 1 day 2
			if clickedScreenOpener.DisplayName == "Lobby_OpenRoster" and ( movesAvailable <= 1 or matchesPlayed > 0 ) then
			-- don't remove GuideBook tooltip in week 1
			elseif clickedScreenOpener.DisplayName == "Lobby_OpenGuideBook" then
			-- any other tooltip exceptions
			end
		else
			-- remove tooltip after interacting
			SetInteractProperty({ DestinationId = clickedScreenOpener.Id, Name = "TooltipId", Value = nil })
		end
		clickedScreenOpener.ShowNameAnyway = false

		if CanUseCaravanScreenOpener( clickedScreenOpener ) then
			-- custom scripts for Side Conversation character
			if clickedScreenOpener.Menu == "Character" or clickedScreenOpener.Menu == "Partner" then
				RemoveConversationOpeners()
				LobbyDialogueButtonPressed()
			-- custom scripts for RosterScreen
			elseif clickedScreenOpener.Menu == "RosterScreen" then
				AddInputBlock({ Name = "WagonRosterOpen" })
				if rosterUnlocked then
					if NarrationSequenceOnce( "Intro_RosterUnlocked" ) then
						wait(0.1)
					end
				end
				OpenMenu({ Name = clickedScreenOpener.Menu, StyleXML = clickedScreenOpener.Menu })
				SetMenuOptions({ Name = "RosterScreen", Item = "CancelButton", Properties = { IsVisible = false, FadeTarget = 0.0, Enabled = false } })
				-- Can't open tabs manually until the auto-open happens
				SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { Enabled = false } })
				SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { Enabled = false } })
				SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { Enabled = false } })
				local bioTabAutoOpenDelay = 0.27
				DisableCaravanCursor( bioTabAutoOpenDelay )
				SetMenuOptions({ Name = "RosterScreen", Properties = { Run = "PressBioTab" } })
				LockCamera({ Id = wagonCameraLockPoint, Speed = 40 })
				wait( bioTabAutoOpenDelay )
				SetGroupVisibility({ Names = AllWagonGroups, Visible = false })
				SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { Enabled = true } })
				SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { Enabled = true } })
				SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { Enabled = true } })
				RosterDoorContentViewed()
				CheckBioTutorialBox()
				SetMenuOptions({ Name = "RosterScreen", Item = "CancelButton", Properties = { IsVisible = true, FadeTarget = 1.0, Enabled = true } })
				RemoveInputBlock({ Name = "WagonRosterOpen" })

			elseif clickedScreenOpener.Menu == "GuideBookScreen" then
				if introComplete then
					if nightwingWagonScare then
						NarrationSequence( "GuideBook_Disabled_01" )
					else
						OpenGuidebook()
					end
				end
			elseif clickedScreenOpener.Menu ~= "Exit" and clickedScreenOpener.Menu ~= "None" then
				OpenMenu({ Name = clickedScreenOpener.Menu })
			end
		end

		if wagonNarrativeSequence then
			if clickedScreenOpener.NarrativeDisplayName ~= "None" then
				clickedScreenOpener.NarrativeObjectUsed = true
				clickedScreenOpener.ShowNameAnyway = false
				HandleNarrativeWagonClick( clickedScreenOpener.Id )
			end
		end

		clickSequence = false
		RemoveInputBlock({ Name = "ClickSequence" })

	end
}

function RemoveConversationOpeners()

	for k, screenOpener in pairs( CaravanScreenOpeners ) do
		if screenOpener.Menu == "Character" or screenOpener.Menu == "Partner" then
			RemoveWorldText({ DestinationId = screenOpener.Id, Duration = 0.2 })
			SetColor({ Id = screenOpener.Id, Color = Color.DarkGray, Duration = 0.2 })
			SetOpacity({ Id = screenOpener.Id, Fraction = 0.0, Duration = 0.2 })
			Delete({ Id = screenOpener.Id, Delay = 0.3 })
			screenOpener.Id = nil
			screenOpener.CaravanObjectDisabled = true
		end
	end

end

function CanUseCaravanScreenOpener( caravanScreenOpener )

	if caravanClosing or not openedCaravan then
		return false
	end

	if caravanScreenOpener.CaravanObjectDisabled then
		return false
	end

	if caravanScreenOpener.ShowNameAnyway then
		return true
	end

	if caravanScreenOpener.Menu == nil or caravanScreenOpener.Menu == "None" then
		return false
	end

	if wagonNarrativeSequence and caravanScreenOpener.NarrativeObjectUsed then
		return false
	end

	if not IsWagonActionAllowed() then
		return false
	end

	return true

end

OnMouseOver{
	"Wagon_LeftFront02 Wagon_LeftFront01 Wagon_RightFront03 Wagon_RightFront02 Wagon_RightFront01 Wagon_Mid05 Wagon_Mid04 Wagon_Mid03 Wagon_Mid02 Wagon_Mid01 Wagon_Back02 Wagon_Back01 Wagon_09",
	function(triggerArgs)
		--StopObjectAttract()

		local clickable = triggerArgs.triggeredById
		CheckReactiveObject( clickable, "mouseover")
	end
}

OnMouseOff{ "Wagon_LeftFront02 Wagon_LeftFront01 Wagon_RightFront03 Wagon_RightFront02 Wagon_RightFront01 Wagon_Mid05 Wagon_Mid04 Wagon_Mid03 Wagon_Mid02 Wagon_Mid01 Wagon_Back02 Wagon_Back01 Wagon_09",
	function(triggerArgs)
		local clickable = triggerArgs.triggeredById
		EndRisingHold( clickable )
	end
}

function EndRisingHold( clickable )

	if not RisingHoldObjects[clickable] then
		return
	end

	StopSound({ Name = "/SFX/World Sounds/Caravan Interior/ObjectHover", Duration = 0 })
	Rumble({ Duration = 0 })
	Shake({ Id = clickable, Duration = 0.15, Speed = 80, Distance = 1 })
	RisingHoldObjects[clickable] = nil

end

function StartObjectAttract()
	endWagonObjectFlash = false

	if Clickables == nil then
		return
	end

	if objectFlashCooldown then
		return
	end

	objectFlashCooldown = true

	for k, v in pairs(Clickables) do

		-- if v.MouseOverSpecialAction == "RisingHold" and k ~= "wagon2interactdoor02" then
		if v.MouseOverSpecialAction == "RisingHold" then
			local flashVariance = RandomFloat(0.6, 0.8)
			local allClickablesOfType = GetIdsByType({ Name = k })

			for k, v in pairs(allClickablesOfType) do
				if IsUseable({ Id = v }) then
					Flash({ Id= v, Speed = 1, MinFraction = 0, MaxFraction = 0.15, Color = Color.Orange, Delay = 0 })
					wait(flashVariance)
					Flash({ Id = v, Speed = 1, MinFraction = 0, MaxFraction = 0.0, Color = Color.White, Delay = 0 })
				end
			end
		end
	end

	wait(3)
	objectFlashCooldown = false
end

function StopObjectAttract()
	endWagonObjectFlash = true
	for k, v in pairs(Clickables) do
		if v.MouseOverSpecialAction == "RisingHold" then
			local allClickablesOfType = GetIdsByType({ Name = k })
			Flash({ Ids = allClickablesOfType, Speed = 1, MinFraction = 0, MaxFraction = 0.0, Color = Color.White, Delay = 0 })
		end
	end
end

function HandleNarrativeWagonClick( wagonObject, wagonNarrativeSequence )
	RemoveWorldText({ DestinationId = wagonObject, Duration = 0.2 })
	-- UseableOff({ Id = wagonObject })
	SetInteractProperty({ DestinationId = wagonObject, Name = "ChangeCursor", Value = false })

	if wagonObject ~= 190019 and wagonObject ~= 210105 then
		SetScale({ Id = risingFlare, Fraction = 2.5, Duration = 0.3 })
	end

	wait(0.1)

	if wagonObject == 190015 and not NarrationRecord["Intro_WagonInterior_Books"] then
		NarrationSequence( "Intro_WagonInterior_Books" )
	end

	wait(0.1)

	if wagonObject ~= 210105 then
		SetScale({ Id = risingFlare, Fraction = 0, Duration = 0.2 })
	end

	FocusCamera({ Fraction = CARAVAN_DEFAULT_ZOOM, Duration = 1, ZoomType = "Ease" })
end

OnKeyPressed{ "Shift Y",  Name = "OpenCaravan",
	function(triggerArgs)
		SetOpacity({ Id = 40074, Fraction = 1 })
		SetColor({ Id = 40074, Color = Color.Black })
		LockCamera({ Id = 40074, OffsetY = -50, Duration = 0 })
		wagonNarrativeSequence = true
		caravanCheat = true

		wait(1)
		OpenCaravan()
	end
}

function OpenGuidebook()

	preGuideBookBloom = GetBloomSettingName({ })
	AdjustFullscreenBloom({ Name = "Blurry", Duration = 0.35, UseWorldTime = false })

	OpenMenu({ Name = "GuideBookScreen" })
	-- don't show the Back button in Trailer Mode (normally this option is true)
	if not GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
		SetMenuOptions({ Name = "GuideBookScreen", Item = "CancelButton", Properties = { Enabled = true, FadeTarget = 0.0, FadeSpeed = 0.0 } })
	end

	-- intro-specific
	if not introComplete then
		RemoveInputBlock({ Name = "ClickSequence" })
		SetMenuOptions({ Name = "GuideBookScreen", Properties = { Run = "Reveal" } })
		GuideBook[1].Entries[1].Viewed = true

		SetSoundCueValue({ Names = { "Bass", "Drums" }, Id = GetMusicId(), Value = 0, Duration = 1.0 })
		SetSoundCueValue({ Names = { "Mandolins", "Misc" }, Id = GetMusicId(), Value = 1, Duration = 1.0 })

		if GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
			SetMenuOptions({ Name = "GuideBookScreen", Item = "CancelButton", Properties = { IsVisible = false, Enabled = false, FadeTarget = 0.0, FadeSpeed = 0.0 } })
		else
			SetMenuOptions({ Name = "GuideBookScreen", Item = "CancelButton", Properties = { Enabled = true, FadeTarget = 0.0, FadeSpeed = 0.0 } })
		end
		-- Disable Exit button until you turn the page
		waitScreenTime(3.8)
		-- don't show the Back button in Trailer Mode (normally this option is true)
		if GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
			SetMenuOptions({ Name = "GuideBookScreen", Item = "CancelButton", Properties = { IsVisible = true, Enabled = true, FadeTarget = 1.0, FadeSpeed = 4.0 } })
		end

		waitUntil( "GuideBookScreenClosed" )
		NarrationSequence( "Intro_WagonInterior_SetupIntroMatch" )
	end

end

OnMenuOpened{ "GuideBookScreen",
	function( triggerArgs )
		if not openedGuideBookOnce then
			-- used for infopanel
			openedGuideBookOnce = true
			PersistVariable({ Name = "openedGuideBookOnce" })
		end
		-- thread( GuideBookOpenedAudio )
		guideBookScreenOpened = true
	end
}

function OpenShop()
	NarrationSequence( "ItemShop" )
end

function SetupCaravanControls()

	if not caravanControlsSetup then
		singleUseTextConstant = SpawnObstacle({ Name = "InvisibleTarget", Group = "Scripting", DestinationName = "Player" })
		locationTextConstant = SpawnObstacle({ Name = "InvisibleTarget", Group = "Scripting", DestinationName = "Player" })
		swathNameTextConstant = SpawnObstacle({ Name = "InvisibleTarget", Group = "Scripting", DestinationName = "Player" })
		DrawScreenRelative({ Id = locationTextConstant })
		Teleport({ Id = locationTextConstant, OffsetX = 50, OffsetY = 100 })
		DrawScreenRelative({ Id = swathNameTextConstant })
		Teleport({ Id = swathNameTextConstant, OffsetX = 50, OffsetY = 200 })
	end

	caravanControlsSetup = true

end

-- **Misc. Campaign Hints**

function ShowDeferredHint( args )
	if ranShowDeferredHint then
		return
	end
	if args == "mapmovement" then
		ranShowDeferredHint = true
		wait(35)
		if not madeFirstMove and not openedCaravan and not caravanMoving then
			DisplayInfoPanelOnce({ Text = "Hint_MapMovement", Duration = 2.5 })
		end
	end
end


OnMenuOpened{ "InventoryScreen",
  function( triggerArgs )

	if IsScreenOpen({ Name = "RosterScreen" }) then
		SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { TooltipId = "Roster_OpenInventory_Alt" } })
	end

	wait(0.01)
	UpdateMoney()

	for k, item in pairs( PlayerTeam.TeamQuestStash ) do
		CalcSellValue( item )
	end

	if IsMultiplayerMatch() then
		SetMenuOptions({ Name = "InventoryScreen", Item = "MoneyHeader", Properties = { IsVisible = false } })
	end

	if IsScreenOpen({ Name = "RosterScreen" }) then
		SetMenuOptions({ Name = "InventoryScreen", Item = "Back", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "InventoryScreen", Item = "Background", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "InventoryScreen", Item = "BackgroundObject2", Properties = { IsVisible = false } })
		SetMenuOptions({ Name = "InventoryScreen", Item = "AnimatedBackground", Properties = { IsVisible = false } })
		if not trading then
			SetMenuOptions({ Name = "InventoryScreen", Item = "CancelButton", Properties = { IsVisible = false } })
		end
	elseif openedCaravan then
		SetMenuOptions({ Name = "InventoryScreen", Item = "Background", Properties = { IsVisible = false } })
	end

	for itemKey, item in pairs( PlayerTeam.TeamQuestStash ) do
		if item.ItemName == "Consumable_Fuel_01" then
			waitScreenTime(0.75)
			if IsScreenOpen({ Name = "InventoryScreen" }) and matchesPlayed == 0 and not IsScreenOpen({ Name = "ItemPurchaseScreen" }) and not IsScreenOpen({ Name = "RosterScreen" }) then
				DisplayInfoPanelOnce({ Text = "Info_UsingImpGrub", Duration = 3.0 })
			end
		end
	end

	if CurrentTutorialBox == "Info_EquipLatestTalisman" then
		HideTutorialBox( "RosterScreen" )
		SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { FlashExpireAfterCycle = true } })
		TutorialItem = nil
	end

	if NarrationRecord["Shopping_UpgradeItemBought"] and not TutorialBoxRecord["Info_StardustTutorial"] and SelectedCharacter ~= nil and SelectedCharacter.UpgradeItem ~= nil and not IsScreenOpen({ Name = "ItemPurchaseScreen" }) and not doForageEvent then
		local skillPowerItem = GetSkillPowerItem( PlayerTeam )
		if skillPowerItem ~= nil then
			local belowMaxUpgradeItem = GetBelowMaxUpgradeItem( PlayerTeam )
			if belowMaxUpgradeItem ~= nil then
				-- stardust tutorial
				DisplayTutorialBox({ HelpTextId = "Info_StardustTutorial", X = skillPowerItem.LocationX + 0, Y = skillPowerItem.LocationY + 210, Animation = "TutorialBoxSmallIn", Arrow = "Up" })
			end
		end
	end

  end
}

EquipLatestTutorial = "Info_EquipLatestTalisman"

OnMenuOpened{ "RosterScreen",
	function( triggerArgs )
		if SelectedTeam == nil then
			SelectedTeam = PlayerTeam
		end
		if CurrentTutorialBox == "Info_QuietRon" then
			HideTutorialBox()
		end

		wait(0.01)

		if IsMultiplayerMatch() then
			if not GetConfigOptionValue({ Name = "LocalMPUseItems" }) then
				SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { Enabled = false, Graphic = "GUI\\Screens\\DetailsButton_Talisman_Unavailable", TooltipId = "Roster_OpenInventory_Disabled" } })
				SetMenuOptions({ Name = "RosterScreen", Item = "UpgradeIconBack", Properties = { Enabled = false, TooltipId = "RosterScreen_EmptyEquipSlot_LocalMP" } })
			end
			if GetConfigOptionValue({ Name = "LocalMPCharacterLevel" }) <= 1 then
				SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { Enabled = false, Graphic = "GUI\\Screens\\DetailsButton_Skills_Unavailable", TooltipId = "Roster_OpenSkills_Disabled" } })
			end
			-- Local MP / Versus Mode: custom RosterScreen Strings
			SetMenuOptions({ Name = "RosterScreen", Item = "XpLabel", Properties = { TooltipId = "Skills_Header_XP_Tooltip_LocalMP" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "XpBar", Properties = { TooltipId = "Skills_Header_XP_Tooltip_LocalMP" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "XpBarBack", Properties = { TooltipId = "Skills_Header_XP_Tooltip_LocalMP" } })

			SetMenuOptions({ Name = "RosterScreen", Item = "Skill1", Properties = { Enabled = false, TooltipId = "null" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "Skill2", Properties = { Enabled = false, TooltipId = "null" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "Skill3", Properties = { Enabled = false, TooltipId = "null" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "Skill4", Properties = { Enabled = false, TooltipId = "null" } })

			if not rosterViewOpponentOnly then
				SetMenuOptions({ Name = "RosterScreen", Item = "ConfirmButton", Properties = { TooltipId = "Roster_Draft_LocalMP_Tooltip" } })
			end
		else
			if not inMatch and not choosingChallengeCharacter and not chooseGrantXP then
				SetMenuOptions({ Name = "RosterScreen", Item = "ConfirmButton", Properties = { TooltipId = "null" } })
			end
		end

		-- Shopping Tutorial / Equipping Tutorial: in the RosterScren, prompt player to equip Talisman
		if shoppingTutorial and not shoppingTutorialRosterScreen then
			BlockItemSelling = false
			HideTutorialBox()
			shoppingTutorialRosterScreen = true
			NarrationSequenceOnce( "Week2_ShoppingTalismanEquippable" )
			SetMenuOptions({ Name = "RosterScreen", Item = "CancelButton", Properties = { Enabled = false, IsVisible = false, FadeTarget = 0.0 } })
			SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { Graphic = "GUI\\Screens\\DetailsButton_Bio_Unavailable", Enabled = false, TooltipId = "Roster_OpenBio_Disabled_PostMatch" } })
			SetMenuOptions({ Name = "RosterScreen", Item = "SkillsTab", Properties = { Graphic = "GUI\\Screens\\DetailsButton_Skills_Unavailable", Enabled = false, TooltipId = "Roster_OpenSkills_Disabled_PostMatch" } })
			FlashItemName = "QuickRespawnItem"
			SetMenuOptions({ Name = "InventoryScreen", Properties = { Run = "FlashItemName" } })
			waitScreenTime(0.35)
			DisplayTutorialBox({ HelpTextId = "Info_ItemEquipTutorial", X = 542, Y = 406, Animation = "TutorialBoxSmallIn", Arrow = "Right" })
		end

		if drafting and matchesPlayed >= 2 and not ascensionMatch and SelectedCharacter.UpgradeItem == nil and SelectedTeam == PlayerTeam then
			if not TutorialBoxRecord[EquipLatestTutorial] then
				TutorialItem = GetNeverEquippedUpgradeItem( PlayerTeam )
				if TutorialItem ~= nil and TutorialItem.RequiredArchetype == nil then
					DisplayTutorialBox({ HelpTextId = EquipLatestTutorial, X = 542, Y = 406, Animation = "TutorialBoxSmallIn", Arrow = "Right" })
					SetMenuOptions({ Name = "RosterScreen", Item = "InventoryTab", Properties = { StartFlashing = true } })
				end
			end
		end

	end
}

function UpdateMovesAvailable()

	if not firstDate then
		UpdateCurrentDate(3)
		firstDate = true
		PersistVariable({ Name = "firstDate" })
	end

end

function UpdateMoney()

	if not caravanControlsSetup then
		return
	end

	if IsScreenOpen({ Name = "InventoryScreen" }) then
		SetMenuOptions({ Name = "InventoryScreen", Item = "MoneyHeader", Properties = { ClearText = true, DisplayNameId = "Inventory_MoneyHeader" } })
	end

end

function IncompleteDemo()
	if campaignRecord ~= nil then
		CampaignRecordEnd( campaignRecord, true )
	elseif matchRecord ~= nil then
		MatchRecordEnd( matchRecord, true )
	end
end

-- Kiosk Mode Restart Features
function RestartKioskMode()
	LoadMap({ Name = "Campaign", ResetApp = true, LoadBackgroundColor = { 0, 0, 0, 1 } })
end

function KioskModeAutoRestart()
	if true then
		return
	end

	if not GetConfigOptionValue({ Name = "KioskMode" }) then
		return
	end

	if not checkingForIdlePlayer then
		checkingForIdlePlayer = true
		SetFlagTrue({ Name = "CheckingForIdlePlayer" })
		StartTimer({ Name = "KioskModeAutoRestartWarningTimer" })
		SetTimer({ Name = "KioskModeAutoRestartWarningTimer", Id = 0 })
		SetTimer({ Name = "KioskModeAutoRestartIminentTimer", Id = 0 })
	end

end

OnTimer{ "KioskModeAutoRestartWarningTimer >= 180",
	RequiredFlag = "CheckingForIdlePlayer",
	function( triggerArgs )
		SetFlagTrue({ Name = "AutoRestartIminent" })
		StopTimer({ Name = "KioskModeAutoRestartWarningTimer" })
		SetTimer({ Name = "KioskModeAutoRestartWarningTimer", Id = 0 })
		DisplayInfoPanelText({ Text = "KioskMode_AutoRestart_Warning", Duration = 3.0 })
		StartTimer({ Name = "KioskModeAutoRestartIminentTimer" })
		SetTimer({ Name = "KioskModeAutoRestartIminentTimer", Id = 0 })
	end
}

OnTimer{ "KioskModeAutoRestartIminentTimer >= 10",
	RequiredFlag = "AutoRestartIminent",
	function( triggerArgs )
		SetFlagFalse({ Name = "AutoRestartIminent" })
		StopTimer({ Name = "KioskModeAutoRestartIminentTimer" })
		DisplayInfoPanelText({ Text = "KioskMode_AutoRestart_Confirm", Duration = 3.0 })
		FadeMusicOut({ Duration = 3.0 })
		wait(1.0)
		FadeOut({ Color = Color.Black, Duration = 1.5 })
		wait(3.0)
		IncompleteDemo()
		RestartKioskMode()
	end
}

OnPlayerInput{
	RequiredFlag = "CheckingForIdlePlayer",
	function( triggerArgs )
		SetFlagFalse({ Name = "CheckingForIdlePlayer" })
		SetFlagFalse({ Name = "AutoRestartIminent" })
		StopTimer({ Name = "KioskModeAutoRestartWarningTimer" })
		SetTimer({ Name = "KioskModeAutoRestartWarningTimer", Id = 0 })
		StopTimer({ Name = "KioskModeAutoRestartIminentTimer" })
		SetTimer({ Name = "KioskModeAutoRestartIminentTimer", Id = 0 })
		checkingForIdlePlayer = false
		KioskModeAutoRestart()
	end
}

blackBarEntranceSpeed = 350
function ShowInputDisabledPresentation( type )
	if not GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
		return
	end

	if showBlackBars then
		return
	end

	local blackBarDestination = ballId
	if blackBarDestination == nil then
		blackBarDestination = realOvermapUnit
	end

	showBlackBars = true

	local barSpeed = blackBarEntranceSpeed
	local barDelay = 0.5

	-- hide this in Trailer Mode (normally this option is true)
	if GetConfigOptionValue({ Name = "ShowUIAnimations" }) then

		blackBarTop = SpawnObstacle({ Name = "Letterbox01", DestinationId = blackBarDestination, Group = "Overlay" })
		blackBarBottom = SpawnObstacle({ Name = "Letterbox01", DestinationId = blackBarDestination, Group = "Overlay" })
		blackBars = { blackBarTop, blackBarBottom }
		SetScale({ Ids = blackBarTop, Fraction = -1 })
		SetScale({ Ids = blackBarBottom, Fraction = 1 })
		local barStartOffsetY = 0
		Teleport({ Id = blackBarTop, OffsetX = 1920/2, OffsetY = -130 })
		Teleport({ Id = blackBarBottom, OffsetX = 1920/2, OffsetY = 1216 })
		DrawScreenRelative({ Ids = blackBars })

		local blackBarDistance = 170
		local blackBarDistance2 = 635
		local blackBarDuration = 0.5

		blackBarTopDestinationPoint = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })
		blackBarBottomDestinationPoint = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })

		blackBarTopArrivalPoint = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })
		blackBarBottomArrivalPoint = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })

		blackBarTopArrivalPoint2 = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })
		blackBarBottomArrivalPoint2 = SpawnObstacle({ Name = "InvisibleTarget", DestinationId = blackBarDestination, Group = "Overlay" })

		blackBarHelpers = { blackBarTopArrivalPoint, blackBarBottomArrivalPoint, blackBarTopDestinationPoint, blackBarBottomDestinationPoint, blackBarTopArrivalPoint2, blackBarBottomArrivalPoint2 }

		Teleport({ Id = blackBarTopDestinationPoint, OffsetX = 1920/2, OffsetY = -130 })
		Teleport({ Id = blackBarBottomDestinationPoint, OffsetX = 1920/2, OffsetY = 1216 })

		Teleport({ Id = blackBarTopArrivalPoint, OffsetX = 1920/2, OffsetY = -130 + blackBarDistance })
		Teleport({ Id = blackBarBottomArrivalPoint, OffsetX = 1920/2, OffsetY = 1216 - blackBarDistance })

		Teleport({ Id = blackBarTopArrivalPoint2, OffsetX = 1920/2, OffsetY = -130 + blackBarDistance2 })
		Teleport({ Id = blackBarBottomArrivalPoint2, OffsetX = 1920/2, OffsetY = 1216 - blackBarDistance2 })

		DrawScreenRelative({ Ids = blackBarHelpers })

		if type == "StartBlindsClosed" then
			thread( CloseBlinds, nil, 0.01 )
		else
			Move({ Id = blackBarTop, DestinationId = blackBarTopArrivalPoint, Duration = blackBarDuration, SmoothStep = true })
			Move({ Id = blackBarBottom, DestinationId = blackBarBottomArrivalPoint, Duration = blackBarDuration, SmoothStep = true })
		end
	end

	-- PlaySound({ Name = "/SFX/Leftovers/InfoPanelLeave" })

	if initialUIShown and GetMapName({ }) ~= "Campaign" then
		thread(HideMatchUI)
	end

end

function CloseBlinds( startDelay, blackBarDuration )
	if startDelay ~= nil and startDelay > 0 then
		wait(startDelay)
	end

	if blackBarDuration == nil then
		blackBarDuration = 3.0
	end
	Move({ Id = blackBarTop, DestinationId = blackBarTopArrivalPoint2, Duration = blackBarDuration, SmoothStep = true })
	Move({ Id = blackBarBottom, DestinationId = blackBarBottomArrivalPoint2, Duration = blackBarDuration, SmoothStep = true })

	PlaySound({ Name = "/SFX/World Sounds/MapText" })
end

OnKeyPressed{"Alt G",
	function(triggerArgs)
		thread(HideInputDisabledPresentation)
		wait(3.1)
		ShowInputDisabledPresentation()
		--ShowInputDisabledPresentation( "StartBlindsClosed" )
		wait(3.1)
		CloseBlinds()
		wait(5.1)
		OpenBlinds()
		wait(3.1)
		HideInputDisabledPresentation()
	end
}

function OpenBlinds( startDelay )
	if startDelay ~= nil and startDelay > 0 then
		wait(startDelay)
	end

	local blackBarDuration = 2.0
	Move({ Id = blackBarTop, DestinationId = blackBarTopArrivalPoint, Duration = blackBarDuration, SmoothStep = true })
	Move({ Id = blackBarBottom, DestinationId = blackBarBottomArrivalPoint, Duration = blackBarDuration, SmoothStep = true })

	PlaySound({ Name = "/SFX/Menu Sounds/BlindsCloseOpen" })
end

function HideInputDisabledPresentation( type )
	showBlackBars = false

	local blackBarDuration = 0.5
	Move({ Id = blackBarTop, DestinationId = blackBarTopDestinationPoint, Duration = blackBarDuration, SmoothStep = true })
	Move({ Id = blackBarBottom, DestinationId = blackBarBottomDestinationPoint, Duration = blackBarDuration, SmoothStep = true })
	-- PlaySound({ Name = "/SFX/Leftovers/InfoPanelLeave" })

	wait(blackBarDuration + 0.05)
	Destroy({ Ids = blackBars })
	Destroy({ Ids = blackBarHelpers })

	if initialUIShown and GetMapName({ }) ~= "Campaign" then
		thread(ShowMatchUI)
	end

end

function PickMoonPhase()
	if currentNodeData ~= nil and currentNodeData.BlockSunMoon then
		return
	end
	if inMatch then
		local CameraStart = GetIds({ Name = "CameraStart" })
		SetupConstellationVisuals( CameraStart[1] )
		local moonSigils = { 215480 }
		SetOpacity({ Ids = moonSigils, Fraction = 1.00 })
	else
		if StarAlignmentLocations[currentNodeId] ~= nil and currentNodeId == goalNodeId and not JustCameFromMatch() then
			SetupConstellationVisuals( StarAlignmentLocations[currentNodeId] )
		end
	end
end

local SpecialStarLocations =
{
	[1] = { X = -100, Y = 270, StarId = nil },
	[2] = { X = -100, Y = 85, StarId = nil },
	[3] = { X = -100, Y = -150, StarId = nil },
	[4] = { X = 110, Y = 210, StarId = nil },
	[5] = { X = -250, Y = 0, StarId = nil },
	[6] = { X = 200, Y = 0, StarId = nil },
	[7] = { X = 50, Y = 85, StarId = nil },
	[8] = { X = 50, Y = -200, StarId = nil },
}

MoonStars =
{
	[1] = 215431,
	[2] = 215441,
	[3] = 215442,
	[4] = 215478,
	[5] = 215463,
	[6] = 215477,
	[7] = 215476,
	[8] = 215475,
}

MoonSigils = { 215480 }

function StarSkyPresentation()
	local starWait = 0.4
	if not starsAlignedOnce then
		starsAlignedOnce = true
		PersistVariable({ Name = "starsAlignedOnce" })
		if not inMatch then
			--thread(CloseBlinds, 3.85 )
			thread(CloseBlinds, 3.15 )
		end
	else
		starWait = 0.2
		if not inMatch and IsAscensionWeek() then
			starWait = 0.4
			thread(CloseBlinds, 3.850 )
		elseif not inMatch then
			--thread(CloseBlinds, 1.275 )
			thread(CloseBlinds, 2.275 )
		end
	end

	if GetMapName({ }) ~= "Campaign" then
		starWait = 0.05
	end

	for k, v in ipairs(MoonStars) do
		if lastStar == nil then
			lastStar = v
		end
		if starWait > 0.1 then
			if playStarWaitSound then
				PlaySound({ Name = "/SFX/Menu Sounds/ConstellationFormAMinorALT" })
			end
			playStarWaitSound = true
			Rumble({ LeftFraction = 0.15, Duration = 0.2 })
		end
		DrawLine({ Id = lastStar, DestinationId = v, Animation = "StarConnector", Stretch = true, Delay = 0 })
		wait(starWait)
		lastStar = v
	end

	StopUnattachedAnimations({ Animation = "StarConnector", Delay = 0.2 })
	StopUnattachedAnimations({ Animation = "StarConnectorLoop", Delay = 0.3 })

	SetOpacity({ Ids = MoonSigils, Fraction = 1.0, Duration = 0.1, Delay = 0.05 })
	RemoveSpecialOvermapState()
	AscensionSkyPresentation( )
	FadeAllConstellations( 1.0 )

	PlaySound({ Name = "/SFX/Menu Sounds/BlindsCloseOpen", Delay = 0.1 })
	Rumble({ RightFraction = 0.5, Duration = 0.7, Delay = 0.1 })

	wait(1.25)
	if not inMatch then
		--wait(0.6)
		if not starsAlignedOnce then
			wait(2.7)
		else
			wait(2.35)
		end
	end
end

function AscensionSkyPresentation()
	if not IsAscensionWeek() then
		return
	end
	SetGroupVisibility({ Name = "AscensionSkyTop", Visible = true })
	SetGroupVisibility({ Name = "AscensionSkyBot", Visible = true })
	SetOpacity({ Names = {"AscensionSkyTop", "AscensionSkyBot"}, Fraction = 0 })
	SetOpacity({ Names = {"AscensionSkyTop", "AscensionSkyBot"}, Fraction = 1.0, Duration = 0.1 })
	SetColor({ Id = 215479, Color = { 255, 255, 255, 255 }, Duration = 0.1 })
	AdjustColorGrading({ Name = "MeteorStrike", Duration = 0 })
	AdjustColorGrading({ Name = "Off", Duration = 1.0, Delay = 0.2 })
	if not inMatch then
		PlaySound({ Name = "/SFX/World Sounds/MapZoomSlow" })
	end
end

function StarSkyPresentationInstant()
	if IsMultiplayerMatch() then
		return
	end

	--[[
	for k, v in ipairs(MoonStars) do
		if lastStar == nil then
			lastStar = v
		end
		DrawLine({ Id = lastStar, DestinationId = v, Animation = "StarConnector", Stretch = true, Delay = 0 })
		lastStar = v
	end
	]]

	SetOpacity({ Ids = MoonSigils, Fraction = 1.0, Duration = 0, Delay = 0.05 })
	AscensionSkyPresentation()
end

function PreMapLoad()
	--AdjustFullscreenBloom({ Name = "NewType10", Duration = 0.3 })
	--FadeOut({ Color = { 254, 254, 254, 255 }, Duration = 0.3 })
	if IsAscensionWeek() then
		--wait(1.8)
		--FadeOut({ Color = Color.White, Duration = 0.4 })
		FadeOut({ Color = Color.Black, Duration = 0.3 })
		wait(0.4)
	else
		FadeOut({ Color = Color.Black, Duration = 0.3 })
	end
end

OnAnyLoad
{
	function( triggerArgs )
		SetConfigOption({ Name = "ClickAnimation", Value = nil })
	end
}

-- Guidebook Rumbles
OnMenuOpened{ "GuideBookScreen",
	function( triggerArgs )

		if openedCaravan then
			DisableCaravanCursor()
			--LockCamera({ Id = wagonCameraLockPoint, Speed = 50 })
			HaltCamera({ })
		end

		-- Menu Rumble
		waitScreenTime(0.3)
		Rumble({ RightFraction = 0.18, Duration = 0.85 })
		waitScreenTime(0.75)
		Rumble({ LeftFraction = 0.3, Duration = 0.6 })

		SetRichPresence({ Name = "RP_InGuideBook" })

	end
}

-- StandingsScreen Scripting
OnControlPressed{ "Taunt",
	function(triggerArgs)
		if not showStarMap then
			return
		end
		if allowStandingScreenAtStarmap and not IsScreenOpen({ Name = "StandingsScreen" }) then
			OpenStandingsScreen()
		end
	end
}

function OpenStandingsScreen()
	UpdateStandings()
	OpenMenu({ Name = "StandingsScreen" })
	LastWeekStandingsViewed = PlayerTeam.MatchesPlayed
end

OnMenuOpened{ "StandingsScreen",
	function( triggerArgs )
		if openedCaravan then
			LockCamera({ Id = wagonCameraLockPoint, Speed = 50 })
			DisableCaravanCursor()
		end
		if showStarMap then
			DefaultTeamTooltipPortraits()
			StopZoomOutMapCursor()
		end
		if openedCaravan or showStarMap then
			preStandingsScreenBloom = GetBloomSettingName({ })
			AdjustFullscreenBloom({ Name = "Blurry", Duration = 0.35, UseWorldTime = false })
		end
		if PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 1 then
			for k, team in pairs( League ) do
				if team.LeagueIndex ~= 1 then
					team.Eliminated = true
				end
			end
		end
		wait(0.01)
		SetupStandingsScreen()
	end
}

OnMenuCloseFinished{ "StandingsScreen",
	function( triggerArgs )

		for k, team in pairs( League ) do
			team.TooltipIds.TeamName = team.PrevTeamNameTooltipId
		end

		if openedCaravan then
			EnableCaravanCursor()
		elseif showStarMap then
			StarPickTeamTooltipPortraits()
			SetupZoomOutMapCursor()
		end
		if preStandingsScreenBloom ~= nil then
			AdjustFullscreenBloom({ Name = preStandingsScreenBloom, Duration = 0.25 })
			preStandingsScreenBloom = nil
		end
	end
}

OnMenuButtonPressed
{
	function( triggerArgs )

		if triggerArgs.name == nil then
			return
		end

		if triggerArgs.ScreenName ~= "GuideBookScreen" then
			return
		end

		if triggerArgs.name ~= "Cancel" then
			return
		end

		waitScreenTime(0.1)
		Rumble({ RightFraction = 0.35, Duration = 0.38 })
	end
}

OnMenuComponentClicked{ "DialogueBoxDecoration",
	function( triggerArgs )
		local trackerId = SpawnObstacleOnScreen({ Name = "InvisibleTarget", Screen = "DialogueScreen", Component = "DialogueBoxDecoration" })
		PlayOverheadAnimation({ DestinationId = trackerId, Name = "ClickPoofOverlay", Scale = 0.45, UseCursorLocation = true, IgnoreOverheadOffset = true })
		PlaySound({ Name = "/SFX/World Sounds/Caravan Interior/SmallGlassTap", Id = trackerId })
	end
}

function ShowMPNameVersusString()
	local playerOneName = GetPlayerName({ PlayerIndex = 1 })
	local playerTwoName = GetPlayerName({ PlayerIndex = 2 })
	local vsString = playerOneName.." vs. "..playerTwoName

	local mpNameAnchor =  SpawnObstacle({ Name = "InvisibleTarget", DestinationId = ballId })
	Teleport({ Id = mpNameAnchor, OffsetX = 1920/2, OffsetY = 300 })
	DrawScreenRelative({ Id = mpNameAnchor })

	DisplayWorldText({ Id = mpNameAnchor, Text = vsString, Justification = "CENTER", OffsetX = 0, OffsetY = 0,
				ShadowBlur = 1, ShadowColor = {0,0,0,1}, ShadowOffset = {3, 3}, OutlineThickness = 1.0, OutlineColor = {0.0, 0.0, 0.0,1}, Color = {1.0, 1.0, 1.0, 1.0}, Font="AlegreyaSCRegular40", Scale = 4.0 })

	local mapLocation = GetMapName({ })
	DisplayWorldText({ Id = mpNameAnchor, Text = mapLocation, Justification = "CENTER", OffsetX = 0, OffsetY = 200,
				ShadowBlur = 1, ShadowColor = {0,0,0,1}, ShadowOffset = {3, 3}, OutlineThickness = 1.0, OutlineColor = {0.0, 0.0, 0.0,1}, Color = {1.0, 1.0, 1.0, 1.0}, Font="AlegreyaSCRegular40", Scale = 4.0 })

	wait(4.0)
	RemoveWorldText({ DestinationId = mpNameAnchor, Duration = 0.3 })

end

TutorialBoxRecord = TutorialBoxRecord or {}
PersistVariable({ Name = "TutorialBoxRecord" })

function DisplayTutorialBox( params )

	if IsMultiplayerMatch() then
		return
	end

	if TitanMode then
		return
	end

	TutorialBoxInAnimation = params.Animation or "TutorialBoxSmallIn"
	TutorialBoxBackAnimation = "TutorialBoxBG"

	if params.Arrow == nil then
		params.Arrow = "Left"
	end

	local useWorldLocation = false
	local scaleWithZoom = false
	if params.AttachToId ~= nil then
		useWorldLocation = true
		scaleWithZoom = true
	end
	local arrowFlip = false
	local arrowAngle = 0
	local arrowOffsetX = params.OffsetX or 0
	local arrowOffsetY = params.OffsetY or 0
	if params.Arrow == "Left" then
		arrowFlip = true
		arrowOffsetX = arrowOffsetX - 205
	elseif params.Arrow == "Right" then
		arrowFlip = false
		arrowOffsetX = arrowOffsetX + 205
	elseif params.Arrow == "Up" then
		arrowAngle = 90
		arrowOffsetY = arrowOffsetY - 115
	elseif params.Arrow == "Down" then
		arrowAngle = 270
		arrowOffsetY = arrowOffsetY + 115
	end
	arrowAngle = math.rad( arrowAngle )


	if TutorialBoxInAnimation == "TutorialBoxSmallIn" then
		TutorialBoxBackAnimation = "TutorialBoxBGSmall"
	elseif TutorialBoxInAnimation == "TutorialBoxLargeIn" then
		if params.Arrow == "Up" then
			arrowOffsetY = arrowOffsetY - 35
		end

		if params.Arrow == "Down" then
			arrowOffsetY = arrowOffsetY + 35
		end
	end

	if params.OffsetX == nil then
		params.OffsetX = 0
	end
	if params.OffsetY == nil then
		params.OffsetY = 0
	end

	local topScreenName = params.Screen or GetTopScreenName({ })
	SetMenuOptions({ Name = topScreenName, Item = "TutorialBoxBackGlow",
		Properties = { X = params.X, Y = params.Y, Graphic = TutorialBoxBackAnimation, FadeTarget = 1.0, AttachToId = params.AttachToId, UseWorldLocation = useWorldLocation, OffsetX = params.OffsetX, OffsetY = params.OffsetY, ScaleWithZoom = scaleWithZoom } })
	SetMenuOptions({ Name = topScreenName, Item = "TutorialBoxBack",
		Properties = { X = params.X, Y = params.Y, Graphic = TutorialBoxInAnimation, FadeTarget = 1.0, AttachToId = params.AttachToId, UseWorldLocation = useWorldLocation, OffsetX = params.OffsetX, OffsetY = params.OffsetY, ScaleWithZoom = scaleWithZoom } })
	SetMenuOptions({ Name = topScreenName, Item = "TutorialBoxArrow",
		Properties = { X = params.X, Y = params.Y, Graphic = "TutorialArrowIn", FadeTarget = 1.0, AttachToId = params.AttachToId, UseWorldLocation = useWorldLocation, OffsetX = arrowOffsetX, OffsetY = arrowOffsetY, FlipHorizontal = arrowFlip, Angle = arrowAngle, ScaleWithZoom = scaleWithZoom } })
	if useWorldLocation then
		SetMenuOptions({ Name = topScreenName, Item = "TutorialBoxText",
			Properties = { FadeTarget = 1.0, HelpTextId = params.HelpTextId, AttachToId = params.AttachToId, UseWorldLocation = useWorldLocation, OffsetX = -85, OffsetY = -100 } })
	else
		SetMenuOptions({ Name = topScreenName, Item = "TutorialBoxText",
			Properties = { FadeTarget = 1.0, HelpTextId = params.HelpTextId, AttachTo = "TutorialBoxBack", UseWorldLocation = useWorldLocation } })
	end
	PlaySound({ Name = "/SFX/Menu Sounds/InfoPanelInURSA" })

	CurrentTutorialBox = params.HelpTextId
	TutorialBoxRecord[params.HelpTextId] = true

end

function HideTutorialBox( screenName )

	if CurrentTutorialBox == nil or TutorialBoxInAnimation == nil then
		return
	end

	if screenName == nil then
		screenName = GetTopScreenName({ })
	end

	local len = string.len( TutorialBoxInAnimation )
	local outAnimation = string.sub( TutorialBoxInAnimation, 1, len - 2 )
	outAnimation = outAnimation.."Out"

	SetMenuOptions({ Name = screenName, Item = "TutorialBoxBackGlow", Properties = { FadeTarget = 0.0 } })
	SetMenuOptions({ Name = screenName, Item = "TutorialBoxBack", Properties = { Graphic = outAnimation } })
	SetMenuOptions({ Name = screenName, Item = "TutorialBoxArrow", Properties = { Graphic = "TutorialArrowOut" } })
	SetMenuOptions({ Name = screenName, Item = "TutorialBoxText", Properties = { FadeTarget = 0.0 } })
	PlaySound({ Name = "/SFX/Menu Sounds/InfoPanelOutURSA" })

	CurrentTutorialBox = nil

end

function IsStoreOpen()

	if matchesPlayed == nil then
		return false
	end

	if matchesPlayed == 0 then
		return false
	end

	if matchesPlayed == 1 then
		if currentlyOccupiedSwath == 1 then
			return false
		else
			return true
		end
	end

	if matchesPlayed == 16 and NarrationRecord["Junction_ShopKeeper_01_LeaveHim"] then
		return false
	end

	if JustCameFromMatch() then
		return false
	end

	if not movedSinceLastMatch then
		return false
	end

	return true

end

local guidebookId = 190015
newEntryFlare = nil

function GuidebookEntriesAvailable()

	if wagonNarrativeSequence then
		return
	end

	local guidebookVFX = Clickables.wagon2interactbook01.RecurringVFX
	SetOpacity({ Ids = guidebookVFX, Fraction = 1.0, Duration = 0.1 })
end

function GuidebookEntriesRead()

	local guidebookVFX = Clickables.wagon2interactbook01.RecurringVFX
	SetOpacity({ Ids = guidebookVFX, Fraction = 0.0, Duration = 0.2 })

end


function ChallengeMatchUnlockPresentation( character )
	thread( Toast, "ChallengeMatch", character )
end

ArenaUnlockRequirements = {
	["MatchSiteC"] = 2,
	["MatchSiteD"] = 3,
	["MatchSiteE"] = 4,
	["MatchSiteF"] = 5,
	["MatchSiteG"] = 6,
	["MatchSiteH"] = 7,
	["MatchSiteI"] = 8,
	["MatchSiteJ"] = 15,
}

CharacterUnlockRequirements = {
	["LendelMP"] = { Match = 1, Tag = "Story_Accuser" },
	["DalbertMP"] = { Match = 2, Tag = "Story_FateDad" },
	["AlmerMP"] = { Match = 2, Tag = "Store_FateSon" },
	["BarkerMP"] = { Match = 3, Tag = "Story_Dissident" },
	["UdmildheMP"] = { Match = 4, Tag = "Story_Withdrawn" },
	["DelugeMP"] = { Match = 5, Tag = "Story_Pyreheart" },
	["TamithaMP"] = { Match = 6, Tag = "Story_Essence" },
	["ManleyMP"] = { Match = 7, Tag = "Story_Chastity" },
	["IgnariusMP"] = { Match = 8, Tag = "Story_Temper" },
	["OralechMP"] = { Match = 16, Tag = "Story_Nightwing" },
	["SandraMP"] = { Match = 18, Tag = "Story_Beyonder" },
}

function LocalMPCharacterUnlockPresentation( character )
	LatestUnlockedCharacter = character.FirstName
	Toast("LocalMPCharacterUnlock", character)
end

function CheckLocalMPArenaUnlock()
	for k, v in pairs(ArenaUnlockRequirements) do
		if matchesPlayed >= v then
			LatestUnlockedArena = k,
			thread(Toast, "LocalMPArenaUnlock", k)
		end
	end
end

function CheckLocalMPCharacterUnlock()
	for k, v in pairs(CharacterUnlockRequirements) do
		if matchesPlayed > v.Match then
			LatestUnlockedCharacter = GetCharacterDataByStoryTag( v.Tag )
			thread(Toast, "LocalMPCharacterUnlock", LatestUnlockedCharacter)
		end
	end
end

ActiveToasts = { }
function Toast( toastType, character )

	if not GetConfigOptionValue({ Name = "ShowUIAnimations" }) then
		return
	end

	if debugSkipToast then
		return
	end

	table.insert( ActiveToasts, toastType )

	local toastYOffset = 70
	local chunkSize = 4

	local numActiveToasts = TableLength( ActiveToasts )
	local chunkNumber = math.ceil(numActiveToasts / chunkSize)
	local chunkIndex = (numActiveToasts - 1) % chunkSize
	local toastAdditionalYOffset = chunkIndex * toastYOffset

	local toastData = nil
	if toastType == "GuideBook" then
		toastData = LatestUnlockedEntry
	end

	local toastWait = (numActiveToasts * 0.45) + ( (chunkNumber - 1) * 4.0 )
	if toastWait ~= nil and toastWait > 0 then
		wait(toastWait)
	end

	local toastMessage = "Toast"
	local toastSpeed = 500
	local toastDuration = 3.2
	local toastScalar = 0.8
	local toastGroupName = "ScreenOverlay"
	local startSound = "/SFX/Menu Sounds/ChoirShorter"
	local endSound = "/SFX/Menu Sounds/StarSelectConfirmReverseShort"

	if toastType == "GuideBook" then
		unreadPages = true
		startSound = "SFX/Menu Sounds/GuideBookChapterUnlockQuieter"
		endSound = "/SFX/Menu Sounds/StarSelectConfirmReverseShort"
		if skippingMultiToast then
			RemoveValueAndCollapse( ActiveToasts, toastType )
			return
		end
		if unlockedGuideBookEntriesRecently then
			toastMessage = "GuideBookUnlock_2_1"
		elseif skipMultiToast and not skippingMultiToast then
			-- toastMessage = "GuideBookUnlock_FullChapter"
			if PlayerTeam.AscensionMatchesPlayed == 2 then
				toastMessage = "GuideBookUnlock_FullChapter"
			elseif PlayerTeam.AscensionMatchesPlayed == 3 then
				toastMessage = "GuideBookUnlock_FullChapter"
			else
				toastMessage = "GuideBookUnlock_Burst"
			end
			toastData = LatestUnlockedChapter
			skippingMultiToast = true
		else
			toastMessage = "GuideBookUnlock_2_1"
			-- toastMessage = "GuideBookUnlock_Alt"
		end
	elseif toastType == "ChallengeMatch" then
		if character == nil then
			RemoveValueAndCollapse( ActiveToasts, toastType )
			return
		end
		unplayedChallenges = true
		startSound = "/SFX/Menu Sounds/ChoirShort"
		endSound = "/SFX/Menu Sounds/GetBallMenu"
		toastMessage = "PracticeStone_ChallengeUnlocked"
	-- for Sandra Sendoff
	elseif toastType == "SandraSendoff" then
		startSound = "/SFX/Menu Sounds/ChoirShort"
		endSound = "/SFX/Menu Sounds/GetBallMenu"
		toastMessage = "PracticeStone_SandraSendoff"
	elseif toastType == "LocalMPCharacterUnlock" then
		if character == nil then
			RemoveValueAndCollapse( ActiveToasts, toastType )
			return
		end
		startSound = "/SFX/Menu Sounds/ChoirShort"
		endSound = "/SFX/Menu Sounds/GetBallMenu"
		toastMessage = "LocalMP_CharacterUnlocked"
	elseif toastType == "LocalMPArenaUnlock" then
		startSound = "/SFX/Menu Sounds/ChoirShort"
		endSound = "/SFX/Menu Sounds/GetBallMenu"
		toastMessage = "LocalMP_ArenaUnlocked"
	elseif toastType == "RosterBio" then
		if character == nil then
			RemoveValueAndCollapse( ActiveToasts, toastType )
			return
		end
		toastData = character
		unreadBioChanges = true
		startSound = "SFX/Menu Sounds/GuideBookChapterUnlockQuieter"
		endSound = "/SFX/Menu Sounds/StarSelectConfirmReverseShort"
		toastMessage = "RosterScreen_BioUpdated"
	elseif toastType == "BanishmentSickness" then
		if character == nil then
			RemoveValueAndCollapse( ActiveToasts, toastType )
			return
		end
		toastData = character
		startSound = "/SFX/Menu Sounds/TitanToggleBanishmentSickness"
		endSound = "/SFX/Menu Sounds/GetBallMenu"
		toastMessage = "Toast_BanishSicknessCharacter"
	end

	wait(1.0)

	local toastAnchor = SpawnObstacle({ Name = "InvisibleTarget", Group = "ScreenOverlay", DestinationName = "Player" })
	Teleport({ Id = toastAnchor, OffsetX = -120, OffsetY = 500 + toastAdditionalYOffset })
	DrawScreenRelative({ Id = toastAnchor })

	PlayOverheadAnimation({ Name = "MatchObjectiveBGIn",
			DestinationId = toastAnchor,
			IgnoreOverheadOffset = true,
			OffsetX = -42 * toastScalar,
			OffsetY = -19 * toastScalar,
			Scale = 2.0 * toastScalar,
			Group = toastGroupName,
	})

	if toastType == "GuideBook" then
		PlayOverheadAnimation({ Name = "GuidebookCoverToast", DestinationId = toastAnchor,
				IgnoreOverheadOffset = true,
				OffsetX = 0 * toastScalar,
				OffsetY = 21 * toastScalar,
				Scale = 0.08 * toastScalar,
				Group = toastGroupName,
		})
	elseif toastType == "ChallengeMatch" then
		PlayOverheadAnimation({ Name = character.TooltipPortrait, DestinationId = toastAnchor,
				IgnoreOverheadOffset = true,
				OffsetX = 0 * toastScalar,
				OffsetY = 21 * toastScalar,
				Scale = 0.5 * toastScalar,
				Group = toastGroupName,
		})
	elseif toastType == "SandraSendoff" then
		PlayOverheadAnimation({ Name = RivalBeyonder.TooltipPortrait, DestinationId = toastAnchor,
				IgnoreOverheadOffset = true,
				OffsetX = 0 * toastScalar,
				OffsetY = 21 * toastScalar,
				Scale = 0.5 * toastScalar,
				Group = toastGroupName,
		})
	elseif toastType == "RosterBio" or toastType == "BanishmentSickness" then
		PlayOverheadAnimation({ Name = character.TooltipPortrait, DestinationId = toastAnchor,
				IgnoreOverheadOffset = true,
				OffsetX = 0 * toastScalar,
				OffsetY = 21 * toastScalar,
				Scale = 0.5 * toastScalar,
				Group = toastGroupName,
		})
	end

	DisplayWorldText({ Id = toastAnchor, Group = toastGroupName, Text = toastMessage, Justification = "Left",
			TooltipKey = tooltipKey,
			LuaKey = "ToastData",
			LuaData = toastData,
			ShadowBlur = 1,
			ShadowColor = {0.113, 0.113, 0.113, 1},
			ShadowOffset = {0, 1},
			OutlineThickness = 2,
			OutlineColor = {0.113, 0.113, 0.113, 1},
			Color = textColor,
			Font="AlegreyaSCBold40",
			Scale = 1 * toastScalar,
			CharFadeTime = .02,
			CharFadeInterval = .02,
			CharFadeColor = Color.Gold,
			CharFadeColorLag = .25,
			OffsetX = 34 * toastScalar,
			OffsetY = 20 * toastScalar,
	})

	Move({ Id = toastAnchor, Angle = 0, Speed = toastSpeed })
	Stop({ Id = toastAnchor, Delay = 0.5 })

	if not IsScreenOpen({ Name = "DialogueScreen" }) or toastType == "BanishmentSickness" or skipMultiToast then
		PlaySound({ Name = startSound })
	end

	wait(toastDuration)

	RemoveValueAndCollapse(ActiveToasts, toastType)

	if not IsScreenOpen({ Name = "DialogueScreen" }) or toastType == "BanishmentSickness" or skipMultiToast then
		PlaySound({ Name = endSound })
	end
	Move({ Id = toastAnchor, Speed = toastSpeed * 5, Angle = 180 })

	if toastType == "ChallengeMatch" or toastType == "SandraSendoff" then
		thread( PracticeStoneNewContentPresentation )
	end
end

challengeStoneId = 10056

function CheckChallengeMatchUnlocks()

	if not NarrationRecord["Week4_PracticeStoneIntro_Inside"] then
		return
	end
	if matchesPlayed == 3 then
		-- rukey's challenge unlocked
	elseif matchesPlayed == 6 then
		-- jodi's challenge unlocked
	elseif matchesPlayed == 7 and currentNodeId == 10077 then
		-- highest XP character's challenge unlocked
		local highestXPChar = nil
		for k, character in pairs( PlayerTeam.TeamBench ) do
			if character.ChallengeStatus ~= "Revealed" and character.ChallengeStatus ~= "Completed" then
				if highestXPChar == nil or character.TotalXP > highestXPChar.TotalXP then
					highestXPChar = character
				end
			end
		end
		if highestXPChar ~= nil then
			highestXPChar.ThirdChallengeCharacter = true
		end
	elseif matchesPlayed >= 8 then
		-- everyone else's challenges unlocked based on their level
	else
		CheckChallengeOption()
		return
	end

	local eligibleCharacters = { }
	for k, character in pairs( PlayerTeam.TeamBench ) do
		if IsChallengeEligible( character ) then
			if character.ChallengeStatus ~= "Revealed" then
				table.insert( eligibleCharacters, character )
			end
		end
	end

	if not IsEmpty( eligibleCharacters ) then
		ChallengeCharacter = RemoveFirstValue( eligibleCharacters )
		ChallengeCharacter.ChallengeStatus = "Revealed"

		UnviewedChallenges = true
		PersistVariable({ Name = "UnviewedChallenges" })

		if not IsEmpty( LockedBeyonderChatEvents ) then
			local nextChatEvent = RemoveFirstIndexValue( LockedBeyonderChatEvents )
			table.insert( BeyonderChatEvents, nextChatEvent )
		end

		thread( ChallengeMatchUnlockPresentation, ChallengeCharacter )
	end

	CheckChallengeOption()

end

-- for Sandra Sendoff
function CountChallengeMatchesComplete()

	local challengesComplete = 0
	for k, character in pairs( PlayerTeam.TeamBench ) do
		if character.ChallengeStatus == "Completed" then
			challengesComplete = challengesComplete + 1
		end
	end
	return challengesComplete

end

function CountChallengeMatchesAvailable()

	local challengesAvailableCount = 0
	for k, character in pairs( PlayerTeam.TeamBench ) do
		if IsChallengeEligible( character ) and character.ChallengeStatus == "Revealed" then
			challengesAvailableCount = challengesAvailableCount + 1
		end
	end
	challengeMatchesAvailable = challengesAvailableCount
	return challengeMatchesAvailable

end

-- for Sandra Sendoff
function CheckSandraSendoff()
	-- must be at MatchSiteI before Final Liberation
	if PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 1 and currentNodeId == 10049 then
		-- min 5 challenges completed and 0 challenges available
		if CountChallengeMatchesComplete() > 4 and CountChallengeMatchesAvailable() == 0 then
			-- must have done some Beyonder Chat events
			if NarrationRecord["PracticeStone_BeyonderChat_04"] then
				if not NarrationRecord["PracticeStone_SandraSendoff_01"] then
					sandraSendoff = true
					PersistVariable({ Name = "sandraSendoff" })
					thread( Toast, "SandraSendoff" )
				end
			end
		end
	end
end

OnKeyPressed{ "ControlAlt H",
	function(triggerArgs)
		-- unlock everyone cheat
		for k, v in pairs( PlayerTeam.TeamBench ) do
			v.ChallengeStatus = "Revealed"
		end
	end
}

function CheckUnviewedChallenges()

	if NarrationRecord["PracticeStone_SandraSendoff_01_TakeIt"] then
		PracticeStoneUsed()
		return
	end

	if ( UnviewedChallenges and GetNumEligibleChallengeCharacters() > 0 ) or sandraSendoff then
		PracticeStoneNewContentPresentation()
	else
		PracticeStoneUsed()
	end
end

function FirstChallengeUnlockPresentation()
	CheckChallengeMatchUnlocks()
	PlayOverheadAnimation({ Name = "ClickPoofOverlay", DestinationId = challengeStoneId, Delay = 1.0, IgnoreOverheadOffset = true, Scale = 1.85, OffsetY = -80 })
end

challengeFlare = nil

function PracticeStoneNewContentPresentation()

	if wagonNarrativeSequence then
		return
	end

	local practiceStoneVFX = Clickables.wagon2crystal01.RecurringVFX
	SetOpacity({ Ids = practiceStoneVFX, Fraction = 1.0, Duration = 0.1 })

end

function PracticeStoneUsed()
	UnviewedChallenges = false
	local practiceStoneVFX = Clickables.wagon2crystal01.RecurringVFX
	SetOpacity({ Ids = practiceStoneVFX, Fraction = 0.0, Duration = 0.4 })
end

function CheckRosterBioUpdates()
	for k, character in pairs(PlayerTeam.TeamBench) do
		if character.UnviewedBio and not character.BioPresentation then
			character.BioPresentation = true
			NewRosterDoorContentPresentation()
		end
	end
end

function NewRosterDoorContentPresentation()
	local bioTabVFX = Clickables.wagon2interactdoor01open.RecurringVFX
	SetOpacity({ Ids = bioTabVFX, Fraction = 1.0, Duration = 0.1 })
end

function RosterDoorContentViewed()
	local bioTabVFX = Clickables.wagon2interactdoor01open.RecurringVFX
	SetOpacity({ Ids = bioTabVFX, Fraction = 0.0, Duration = 0.4 })
end

function CheckRosterDoorVisuals()
	local bioTabVFX = Clickables.wagon2interactdoor01open.RecurringVFX
	if CheckBioTabUpdates() then
		SetOpacity({ Ids = bioTabVFX, Fraction = 1.0, Duration = 0.1 })
	else
		SetOpacity({ Ids = bioTabVFX, Fraction = 0.0, Duration = 0.0 })
	end
end

function CheckBioTabUpdates()
	for k, character in pairs(PlayerTeam.TeamBench) do
		if character.UnviewedBio and character.RosterStatus == "Active" then
			return true
		end
	end
	return false
end

function CheckBioTutorialBox()
	for k, character in pairs( PlayerTeam.TeamBench ) do
		if character.UnviewedBio and character.RosterStatus == "Active" then
			UnviewedCharacter = character
			if UnviewedCharacter.FirstName == SelectedCharacter.FirstName then
				HideTutorialBox()
			else
				wait(0.1)
				local xOffset = GetBioBoxHintXOffset()
				DisplayTutorialBox({ HelpTextId = "Info_NightwingsBioTabUpdated", Screen = "RosterScreen", X = xOffset, Y = 952, Animation = "TutorialBoxSmallIn", Arrow = "Left" })
				wait(0.3)
			end
			return true
		end
	end
	return false
end

function GetBioBoxHintXOffset()
	local xOffset = 695
	for k, character in pairs(PlayerTeam.TeamBench) do
		if character.RosterStatus == "Active" then
			xOffset = xOffset + 60
		end
	end
	DebugPrint({ Text = tostring(xOffset) })
	return xOffset
end


function HighlightRosterAdversaryButton()
	flashingAdversaryButton = true
	SetMenuOptions({ Name = "RosterScreen", Item = "YButton", Properties = { StartFlashing = true } })
end

-- Versus Mode / LocalMP
OnMenuButtonPressed{ "ConfirmButton",
	function( triggerArgs )

		if triggerArgs.ScreenName ~= "LocalMPScreen" then
			return
		end

		ArcadeMode = false
		LocalMPConfirmPressed()
	end
}


function LocalMPConfirmPressed()

	SetMultiplayerMatchOn()
	AddInputBlock({ Name = "LocalMPConfirm" })
	CleanupMatchSounds( 0.5 )
	StopSound({ Id = BeyonderMusicId, Duration = 0.5 })
	StopSound({ Id = BardMusicId, Duration = 0.5 })
	SetVolume({ Id = LocalMPMusicId, Value = 1.0, Duration = 0.5 })
	SetSoundCueValue({ Names = { "Misc", }, Id = LocalMPMusicId, Value = 1, Duration = 0.5 })
	SetSoundCueValue({ Names = { "Drums", }, Id = LocalMPMusicId, Value = 0, Duration = 0.3 })
	FadeOut({ Color = Color.Black, Duration = 0.0 })
	PlaySound({ Name = "/SFX/Menu Sounds/RosterEquip" })
	waitScreenTime(0.5) -- Need time to save profile
	OnPauseScreenClosed()
	RemoveInputBlock({ Name = "LocalMPConfirm" })

	SetConfigOption({ Name = "AllowPause", Value = true })
	SetConfigOption({ Name = "CampaignReady", Value = false })
	RequestStartLocalMP()

end

-- Versus Mode
OnMenuOpened{ "LocalMPScreen",
	function( triggerArgs )
		if PlayerTeam == nil then
			CreateLeague()
		end
		waitScreenTime(0.4)
		if not IsScreenOpen({ Name = "LocalMPScreen" }) then
			-- Screen was closed immediately
			return
		end
		if ConsecutiveLocalMPMatches == nil or ConsecutiveLocalMPMatches == 0 then
			-- Pyre.
			-- PlaySpeech({ Name = "/VO/Match_1196", Delay = 1.25 })
		end
		if MusicName == BootMenuTrackName then
			PauseSound({ Id = MusicId, Duration = 0.25 })
		end
		-- thread( VersusModeAttractAudio )
		if LocalMPMusicId == nil then
			LocalMPTrackName = "/Music/OvermapMusic3_MC"
			LocalMPMusicId = PlaySound({ Name = LocalMPTrackName })
			SetDefaultMusicParams( LocalMPTrackName, LocalMPMusicId )
			PersistVariable({ Name = "LocalMPMusicName" })
			PersistVariable({ Name = "LocalMPMusicId" })
			if matchStarted and LocalMP then
				SetVolume({ Id = LocalMPMusicId, Value = 0.0, Duration = 0.0 })
			end
		else
			SetVolume({ Id = LocalMPMusicId, Value = 1.0, Duration = 0.5 })
		end
	end
}

OnMenuButtonPressed{ "CancelButton",
	function( triggerArgs )

		if triggerArgs.ScreenName ~= "LocalMPScreen" then
			return
		end
		if not LocalMP or matchStarted then
			StopSound({ Id = LocalMPMusicId, Value = 1.0, Duration = 0.5 })
			LocalMPMusicId = nil
		end
		if MusicName == BootMenuTrackName then
			ResumeSound({ Id = MusicId, Duration = 0.25 })
		end
	end
}

OnTriggerFired{ "LocalMPOptionsChanged",
	function( triggerArgs )
		waitScreenTime(0.01)

		local humanGraphic = "GUI\\Screens\\Versus\\Icon_HumanPlayer"
		local humanSelectedGraphic = "GUI\\Screens\\Versus\\Icon_HumanPlayer_Highlight"
		if GetConfigOptionValue({ Name = "PS4Gamepad" }) then
			humanGraphic = "GUI\\Screens\\Versus\\Icon_PS4Controller"
			humanSelectedGraphic = "GUI\\Screens\\Versus\\Icon_PS4Controller_Highlight"
		elseif GetConfigOptionValue({ Name = "SteamGamepadCount" }) >= 1 then
			humanGraphic = "GUI\\Screens\\Versus\\Icon_SteamController"
			humanSelectedGraphic = "GUI\\Screens\\Versus\\Icon_SteamController_Highlight"
		end
		local mouseGraphic = "GUI\\Screens\\Versus\\Icon_Mouse"
		local mouseSelectedGraphic = "GUI\\Screens\\Versus\\Icon_Mouse_Highlight"

		local mouseIndex = GetConfigOptionValue({ Name = "LocalMPMouseIndex" })

		if GetConfigOptionValue({ Name = "LocalMPHumanTeamA" }) then
			if mouseIndex == 0 and not IsPS4({ }) and GetConfigOptionValue({ Name = "LocalMPHumanTeamB" }) and GetNumConnectedControllers({ }) <= 1 then
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamAControllerButton", Properties =
					{ Graphic = mouseGraphic, SelectedGraphic = mouseSelectedGraphic, DisplayNameId = "LocalMP_HumanPlayer", TooltipId = "LocalMP_HumanPlayer_Tooltip" } })
			else
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamAControllerButton", Properties =
					{ Graphic = humanGraphic, SelectedGraphic = humanSelectedGraphic, DisplayNameId = "LocalMP_HumanPlayer", TooltipId = "LocalMP_HumanPlayer_Tooltip" } })
			end
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamAControllerButton", Properties =
				{ Graphic = "GUI\\Screens\\Versus\\Icon_CPUPlayer", SelectedGraphic = "GUI\\Screens\\Versus\\Icon_CPUPlayer_Highlight", DisplayNameId = "LocalMP_AIPlayer", TooltipId = "LocalMP_AIPlayer_Tooltip" } })
			local difficulty = GetConfigOptionValue({ Name = "LocalMPTeamADifficulty" })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamADifficultyButton", Properties = { TooltipId = difficulty.."_Tooltip" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamADifficultyLabel", Properties = { TooltipId = difficulty.."_Tooltip" } })
		end

		if GetConfigOptionValue({ Name = "LocalMPHumanTeamB" }) then

			if mouseIndex == 1 and not IsPS4({ }) and GetConfigOptionValue({ Name = "LocalMPHumanTeamA" }) and GetNumConnectedControllers({ }) <= 1 then
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBControllerButton", Properties =
					{ Graphic = mouseGraphic, SelectedGraphic = mouseSelectedGraphic, DisplayNameId = "LocalMP_HumanOpponent", TooltipId = "LocalMP_HumanOpponent_Tooltip" } })
			else
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBControllerButton", Properties =
					{ Graphic = humanGraphic, SelectedGraphic = humanSelectedGraphic, DisplayNameId = "LocalMP_HumanOpponent", TooltipId = "LocalMP_HumanOpponent_Tooltip" } })
			end

			if GetConfigOptionValue({ Name = "LocalMPTeamBDraft" }) then
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBDraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_DraftOn_Human" } })
			else
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBDraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_DraftOff_Human" } })
			end
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBControllerButton", Properties =
				{ Graphic = "GUI\\Screens\\Versus\\Icon_CPUPlayer", SelectedGraphic = "GUI\\Screens\\Versus\\Icon_CPUPlayer_Highlight", DisplayNameId = "LocalMP_AIOpponent", TooltipId = "LocalMP_AIOpponent_Tooltip" } })
			if GetConfigOptionValue({ Name = "LocalMPTeamBDraft" }) then
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBDraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_DraftOn_CPU" } })
			else
				SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamBDraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_DraftOff_CPU" } })
			end
			local difficulty = GetConfigOptionValue({ Name = "LocalMPDifficulty" })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "DifficultyButton", Properties = { TooltipId = difficulty.."_Tooltip" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "DifficultyLabel", Properties = { TooltipId = difficulty.."_Tooltip" } })
		end

		if GetConfigOptionValue({ Name = "LocalMPUseItems" }) then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "ItemsButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_ItemsOn" } })
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "ItemsButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_ItemsOff" } })
		end

		local characterLevel = GetConfigOptionValue({ Name = "LocalMPCharacterLevel" })
		if characterLevel == 0 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Star", TooltipId = "LocalMP_CharacterLevelPreset" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = "" } })
		elseif characterLevel == 1 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_CharacterLevel1Set" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = characterLevel - 1, TooltipId = "LocalMP_CharacterLevel1Set" } })
		elseif characterLevel == 2 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_CharacterLevel2Set" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = characterLevel - 1, TooltipId = "LocalMP_CharacterLevel2Set" } })
		elseif characterLevel == 3 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_CharacterLevel3Set" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = characterLevel - 1, TooltipId = "LocalMP_CharacterLevel3Set" } })
		elseif characterLevel == 4 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_CharacterLevel4Set" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = characterLevel - 1, TooltipId = "LocalMP_CharacterLevel4Set" } })
		elseif characterLevel == 5 then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_CharacterLevel5Set" } })
			SetMenuOptions({ Name = "LocalMPScreen", Item = "CharacterLevelValue", Properties = { RawText = characterLevel - 1, TooltipId = "LocalMP_CharacterLevel5Set" } })
		end

		local matchSite = GetConfigOptionValue({ Name = "LocalMPMap" })
		SetMenuOptions({ Name = "LocalMPScreen", Item = "MapButton", Properties = { Graphic = "GUI\\Screens\\Versus\\LocalePreview_"..matchSite, TooltipId = matchSite.."_Tooltip" } })
		SetMenuOptions({ Name = "LocalMPScreen", Item = "MapLabel", Properties = { DisplayNameId = matchSite, TooltipId = matchSite.."_Tooltip" } })

		if GetConfigOptionValue({ Name = "LocalMPTeamADraft" }) then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamADraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_DraftOn" } })
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "TeamADraftButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_DraftOff" } })
		end

		if GetConfigOptionValue({ Name = "LocalMPIntroPresentation" }) == "LocalMP_Intro_Long" then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "IntroButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_Intro_Long_Tooltip" } })
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "IntroButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_Intro_Short_Tooltip" } })
		end

		local teamAIndex = GetConfigOptionValue({ Name = "LocalMPTeamAIndex" })
		LocalMPTeamAName = League[teamAIndex].TeamName
		LocalMPTeamAPyreHealth = GetConfigOptionValue({ Name = "LocalMPTeamAPyreHealth" })

		local teamBIndex = GetConfigOptionValue({ Name = "LocalMPTeamBIndex" })
		LocalMPTeamBName = League[teamBIndex].TeamName
		LocalMPTeamBPyreHealth = GetConfigOptionValue({ Name = "LocalMPTeamBPyreHealth" })

		if GetConfigOptionValue({ Name = "LocalMPUseConstellations" }) then
			SetMenuOptions({ Name = "LocalMPScreen", Item = "ConstellationsButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Checked", TooltipId = "LocalMP_ConstellationsOn" } })
		else
			SetMenuOptions({ Name = "LocalMPScreen", Item = "ConstellationsButton", Properties = { Graphic = "GUI\\Screens\\Versus\\CheckBox_Unchecked", TooltipId = "LocalMP_ConstellationsOff" } })
		end

		SetMenuOptions({ Name = "LocalMPScreen", Properties = { Run = "MarkTooltipDirty" } })

	end
}

function MenuRestartMatchConfirm()

	OpenMenu({ Name = "ExitConfirmDialog" })
	if matchOpeningSequence or not matchStarted then
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { DisplayNameId = "PauseScreen_RestartMatch_Campaign_Confirm" } })
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_RestartMatch_Campaign_Confirm" } })
	else
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "TitleText", Properties = { DisplayNameId = "PauseScreen_RestartMatch_Campaign_Confirm_Alt" } })
		SetMenuOptions({ Name = "ExitConfirmDialog", Item = "PromptText", Properties = { DescriptionId = "PauseScreen_RestartMatch_Campaign_Confirm_Alt" } })
	end
	SetMenuOptions({ Name = "ExitConfirmDialog", Item = "ConfirmButton", Properties = { ActivateFunction = "RestartMatch" } })

end

function RestartMatch()

	FadeOut({ Color = Color.Black, Duration = 0.0 })
	ExitMenu({ Name = "ExitConfirmDialog", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "PauseScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "InventoryScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "CharacterSkillsScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "CharacterBioScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "RosterScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "PostMatchScreen", TransitionOffTime = 0.0 })
	ExitMenu({ Name = "DialogueScreen", TransitionOffTime = 0.0 })

	local currentMap = GetMapName({ })

	if practiceMatch then
		CleanupMatchSounds()
		LoadMap({ Name = currentMap })
		return
	end

	if IsMultiplayerMatch() then
		SetConfigOption({ Name = "LocalMPReady", Value = true })
		ForceShortIntro = true
		SuppressVOResume = true
		PersistVariable({ Name = "ForceShortIntro" })
		if TeamA.DonePicking and TeamB.DonePicking then
			TeamALastDraftPicks = {}
			PersistVariable({ Name = "TeamALastDraftPicks" })
			for k, character in pairs( TeamA.TeamBench ) do
				if character.ActiveStatus == "Assigned" or character.ActiveStatus == "PlayedLastMatch" then
					TeamALastDraftPicks[character.DraftOrder] = k
				end
			end
			TeamBLastDraftPicks = {}
			for k, character in pairs( TeamB.TeamBench ) do
				if character.ActiveStatus == "Assigned" or character.ActiveStatus == "PlayedLastMatch" then
					TeamBLastDraftPicks[character.DraftOrder] = k
				end
			end
			PersistVariable({ Name = "TeamBLastDraftPicks" })
		end
		RequestLocalMPRematch = false
		CleanupMatchSounds()

		local mapToLoad = currentMap
		if GetConfigOptionValue({ Name = "LocalMPMap" }) == "LocalMP_MapRandom" then
			SetupMapRotation()
			mapToLoad = RemoveRandomValue( mapRotation )
			if IsEmpty( mapRotation ) then
				mapRotation = nil
			end
		end

		LoadMap({ Name = mapToLoad })
		return
	end

	if matchOpeningSequence then
		local fadeOutTime = 0.25
		FadeOutAllAmbience( fadeOutTime )
		StopSound({ Id = goalAFireAmbientLoopId, Duration = fadeOutTime })
		StopSound({ Id = goalBFireAmbientLoopId, Duration = fadeOutTime })
		StopSound({ Id = PausedMusicId })
		PauseMusicId = nil
		PausedMusicName = nil
		ResumeMusic({ Id = MusicId })
		LoadMap({ Name = currentMap })
		return
	end

	SetConfigOption({ Name = "UseCampaignShortMatchIntro", Value = true })
	LoadCheckpoint({ SaveName = "_StartRite" })

end

function RequestStartLocalMP()

	local mapRequest = GetConfigOptionValue({ Name = "LocalMPMap" })
	if mapRequest == "LocalMP_MapRandom" then
		SetupMapRotation()
		mapRequest = RemoveRandomValue( mapRotation )
		if IsEmpty( mapRotation ) then
			mapRotation = nil
		end
	end
	ForceShortIntro = false
	CleanupMatchSounds( 1.0 )
	if ArcadeMode and HasSaveFile({ Name = "_ArcadeMode" }) then
		LoadCheckpoint({ SaveName = "_ArcadeMode" })
	else
		LoadMap({ Name = mapRequest })
	end

end

function CleanupMatchSounds( fadeOutTime )
	if fadeOutTime == nil then
		fadeOutTime = 0.25
	end
	FadeOutAllAmbience( fadeOutTime )
	StopSound({ Id = goalAFireAmbientLoopId, Duration = fadeOutTime })
	StopSound({ Id = goalBFireAmbientLoopId, Duration = fadeOutTime })
	FadeMusicOut({ Duration = fadeOutTime })
	StopSound({ Id = PausedMusicId })
	PauseMusicId = nil
	PausedMusicName = nil
end

OnTriggerFired{ "RosterCharacterSelected",
	function( triggerArgs )
		if characterSelecting then
			return
		end
		characterSelecting = true
		wait(0.01)
		characterSelecting = false

		SetMenuOptions({ Name = "CharacterSkillsScreen", Item = "SkillTreeIconA", Properties = { Graphic = ArchetypeData[SelectedCharacter.Archetype].SkillTreeBackgroundLeft } })
		SetMenuOptions({ Name = "CharacterSkillsScreen", Item = "SkillTreeIconB", Properties = { Graphic = ArchetypeData[SelectedCharacter.Archetype].SkillTreeBackgroundRight } })

		if IsScreenOpen({ Name = "CharacterBioScreen" }) then
			SelectedCharacter.UnviewedBio = false
		end
		if SelectedCharacter.UnviewedBio and not postMatchScreen then
			SetMenuOptions({ Name = "RosterScreen", Item = "BioTab", Properties = { TopAnimation = "DetailsButtonBioUpdated" } })
		end
		if rosterViewOpponentOnly then
			PanCamera({ Id = SelectedCharacter.ObjectId, Duration = 1.5, OffsetX = -800, OffsetY = -210, Retarget = false })
			return
		end
		if DraftPlayerModelViewer ~= nil then
			DraftPlayerModelViewer( draftFocusObjectId )
		end

		if UnviewedCharacter ~= nil and openedCaravan and IsScreenOpen({ Name = "CharacterBioScreen" }) and CurrentTutorialBox == "Info_NightwingsBioTabUpdated" then
			SelectedCharacter.UnviewedBio = false
			if SelectedCharacter == UnviewedCharacter then
				HideTutorialBox( "RosterScreen" ) -- for wagon roster screen
			end
		end
	end
}

-- Fades
function FullscreenFadeOut( speed, layer )
	if layer == nil then
		layer = "ScreenOverlay"
	end
	if fadePlaying then
		DebugPrint({ Text = "Fade Playing" })
		return
	end

	fadePlaying = true
	local fadeAnchor = SpawnObstacle({ Name = "InvisibleTarget", DestinationName = "Player", Group = layer })
	Teleport({ Id = fadeAnchor, OffsetX = 1920/2, OffsetY = 1080/2 })
	DrawScreenRelative({ Id = fadeAnchor })

	local fadeAnimation = nil
	if speed == nil or speed == "Normal" then
		fadeAnimation = "FullscreenFadeIn"
		fadeDuration = 2.0
		fadeOutDelay = 1.8
		fadeOutDuration = 0.2
	else
		fadeAnimation = "FullscreenFadeInFast"
		fadeDuration = 1.0
		fadeOutDelay = 0.9
		fadeOutDuration = 0.1
	end
	PlayOverheadAnimation({ Name = fadeAnimation, DestinationId = fadeAnchor, IgnoreOverheadOffset = true, Scale = 1.03 })
	PlaySound({ Name = "/SFX/World Sounds/MapZoomSlow" })
	wait(fadeOutDelay)
	FadeOut({ Color = Color.Black, Duration = fadeOutDuration })
	wait(fadeDuration - fadeOutDelay)
	fadePlaying = false
	if queuedFadeInSpeed ~= nil then
		FullscreenFadeIn( queuedFadeInSpeed, layer )
		queuedFadeInSpeed = nil
	end
end

function FullscreenFadeIn( speed, layer )
	if layer == nil then
		layer = "ScreenOverlay"
	end
	if fadePlaying then
		DebugPrint({ Text = "Fade Playing" })
		queuedFadeInSpeed = speed
		return
	end

	fadePlaying = true
	local fadeAnchor = SpawnObstacle({ Name = "InvisibleTarget", DestinationName = "Player", Group = layer })
	Teleport({ Id = fadeAnchor, OffsetX = 1920/2, OffsetY = 1080/2 })
	DrawScreenRelative({ Id = fadeAnchor })

	local fadeAnimation = nil
	if speed == nil or speed == "Normal" then
		fadeAnimation = "FullscreenFadeOut"
		fadeDuration = 2.0
		fadeInDuration = 0.1
	else
		fadeAnimation = "FullscreenFadeOutFast"
		fadeDuration = 1.0
		fadeInDuration = 0.1
	end
	FadeIn({ Duration = fadeInDuration })
	PlayOverheadAnimation({ Name = fadeAnimation, DestinationId = fadeAnchor, IgnoreOverheadOffset = true, Scale = 1.03 })
	PlaySound({ Name = "/SFX/World Sounds/MapText" })
	wait(fadeDuration)
	fadePlaying = false
end

OnKeyPressed{ "ControlAlt J",
	function(triggerArgs)
		thread( FullscreenFadeOut, "Normal", nil )
		wait(0.1)
		thread( FullscreenFadeIn, "Normal", nil )
	end
}

function AscensionBackground()
	AdjustColorGrading({ Name = "Team11", Duration = 0.1 })
	AdjustColorGrading({ Name = "Sunrise", Duration = 3, Delay = 0.3 })
end

function PickNextMapLoadHint( mapToLoad )

	local hints = {}
	SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = true })

	-- special maps
	if mapToLoad == "ScenarioDefense" then
		table.insert( hints, "Loading_Misc_Hint_AimAssist" )

	elseif mapToLoad == "ScenarioRetrieval" then
		table.insert( hints, "Loading_Campaign_ScenarioRetrieval_01" )

	elseif mapToLoad == "Epilogue" then
		table.insert( hints, "Loading_Campaign_Epilogue_01" )

	elseif string.find( mapToLoad, "MatchSite" ) then

		if IsMultiplayerMatch() then
			GatherLocalMPHints( hints )
		else
			GatherCampaignEnterMatchHints( hints )
			GatherEnterMatchMiscHints( hints )
		end

	elseif mapToLoad == "Campaign" then
		GatherCampaignPostMatchHints( hints )
	end

	-- catch-all for safety
	if IsMultiplayerMatch() then
		GatherEnterMatchMiscHints( hints )
	else
		if allowCaravanFly then
			GatherOpenStructureMiscHints( hints )
			GatherLinearStructureMiscHints( hints )
		else
			GatherLinearStructureMiscHints( hints )
		end
	end

	local hintCarousel = ""
	for k, hint in ipairs( hints ) do
		if k == 1 then
			hintCarousel = hint
		else
			hintCarousel = hintCarousel.." "..hint
		end
	end
	SetConfigOption({ Name = "LoadScreenHints", Value = hintCarousel })

end

function GatherCampaignEnterMatchHints( hints )

	if not introComplete then
		table.insert( hints, "Loading_Campaign_Story_Blank" )
		return
	end

	if practiceMatch then
		local ChallengeCharacter = GetCharByRef( ChallengeMatchCharRef )
		if ChallengeCharacter ~= nil then
			-- for challenge matches
			if CurrentMapName == "Campaign" then
				-- Entering a Challenge from Campaign, show the Archetype hint
				if ChallengeCharacter == CharFriend then
					table.insert( hints, "Loading_Campaign_Archetype_Nomads" )
				elseif ChallengeCharacter == CharBadass then
					table.insert( hints, "Loading_Campaign_Archetype_Demons" )
				elseif ChallengeCharacter == CharJoker then
					table.insert( hints, "Loading_Campaign_Archetype_Curs" )
				elseif ChallengeCharacter == CharPsycho then
					table.insert( hints, "Loading_Campaign_Archetype_Savages" )
				elseif ChallengeCharacter == CharMascot then
					table.insert( hints, "Loading_Campaign_Archetype_Imps" )
				elseif ChallengeCharacter == CharKnight then
					table.insert( hints, "Loading_Campaign_Archetype_Wyrms" )
				elseif ChallengeCharacter == CharVamp then
					table.insert( hints, "Loading_Campaign_Archetype_Harps" )
				elseif ChallengeCharacter == CharDoc then
					table.insert( hints, "Loading_Campaign_Archetype_Saps" )
				elseif ChallengeCharacter == CharDiva then
					table.insert( hints, "Loading_Campaign_Archetype_Crones" )
				end
			else
				-- Restarting a Challenge, show a different hint
				local restartHints = { "Loading_Campaign_Challenge_ComeBackLater_01", "Loading_Campaign_Challenge_ComeBackLater_02", "Loading_Campaign_Challenge_Hint_01" }
				local restartHint = RemoveRandomValue( restartHints )
				table.insert( hints, restartHint )
			end
		else
			-- for freeplay matches
			SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
		end

		return
	end

	-- standard matches
	if matchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_MainObject" )
	elseif matchesPlayed == 1 then
		table.insert( hints, "Loading_Misc_Hint_LosingAura" )
	elseif matchesPlayed == 2 then
		table.insert( hints, "Loading_Misc_Hint_StaminaUse" )
	elseif matchesPlayed == 3 then
		table.insert( hints, "Loading_Campaign_Hint_Enlightenment" )
	elseif matchesPlayed == 4 then
		table.insert( hints, "Loading_Misc_Hint_Glory" )
	elseif matchesPlayed == 5 then
		table.insert( hints, "Loading_Misc_Hint_Races" )
	elseif matchesPlayed == 6 then
		table.insert( hints, "Loading_Campaign_Hint_Masteries" )
	elseif matchesPlayed == 7 then
		table.insert( hints, "Loading_Campaign_Hint_KeepGoing" )
	-- S2
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 0 then
		table.insert( hints, "Loading_Misc_Hint_Landmarks" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_CheckAdversaries" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 2 then
		table.insert( hints, "Loading_Campaign_Hint_TitanStars" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 3 then
		table.insert( hints, "Loading_Campaign_Hint_LiberatedExiles" )
	-- S3
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 0 then
		table.insert( hints, "Loading_Campaign_Archetype_Bertrude" )
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_ChallengeMatches" )
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 2 then
		table.insert( hints, "Loading_Campaign_Hint_GoodLuck" )
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 3 then
		table.insert( hints, "Loading_Campaign_Hint_PartingTalismans" )
	-- S4
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 0 then
		table.insert( hints, "Loading_Campaign_Archetype_Volfred" )
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_Stardust" )
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 2 then
		table.insert( hints, "Loading_Boot_22" )
	-- S5
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 0 then
		table.insert( hints, "Loading_Misc_Hint_OrbTrick" )
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 2 then
		table.insert( hints, "Loading_Campaign_Hint_OnPressure" )
	-- S6
	elseif PlayerTeam.AscensionMatchesPlayed == 5 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 5 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_PlanProgress" )
	-- S7
	elseif PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_FinalLiberation" )
	end

end

function GatherLocalMPHints( hints )
	table.insert( hints, "Loading_Misc_Hint_MainObject" )

	table.insert( hints, "Loading_Misc_MatchSiteB" )
	table.insert( hints, "Loading_Misc_MatchSiteC" )
	table.insert( hints, "Loading_Misc_MatchSiteD" )
	table.insert( hints, "Loading_Misc_MatchSiteE" )
	table.insert( hints, "Loading_Misc_MatchSiteF" )
	table.insert( hints, "Loading_Misc_MatchSiteG" )
	table.insert( hints, "Loading_Misc_MatchSiteH" )
	table.insert( hints, "Loading_Misc_MatchSiteI" )
	table.insert( hints, "Loading_Misc_MatchSiteJ" )

	table.insert( hints, "Loading_Misc_Triumvirate_01" )
	table.insert( hints, "Loading_Misc_Triumvirate_02" )
	table.insert( hints, "Loading_Misc_Triumvirate_03" )
	table.insert( hints, "Loading_Misc_Triumvirate_04" )
	table.insert( hints, "Loading_Misc_Triumvirate_05" )
	table.insert( hints, "Loading_Misc_Triumvirate_06" )
	table.insert( hints, "Loading_Misc_Triumvirate_07" )
	table.insert( hints, "Loading_Misc_Triumvirate_08" )
	table.insert( hints, "Loading_Misc_Triumvirate_09" )
	table.insert( hints, "Loading_Misc_Triumvirate_10" )
	table.insert( hints, "Loading_Misc_Triumvirate_11" )

	table.insert( hints, "Loading_Campaign_Archetype_Nomads" )
	table.insert( hints, "Loading_Campaign_Archetype_Demons" )
	table.insert( hints, "Loading_Campaign_Archetype_Curs" )
	table.insert( hints, "Loading_Campaign_Archetype_Savages" )
	table.insert( hints, "Loading_Campaign_Archetype_Imps" )
	table.insert( hints, "Loading_Campaign_Archetype_Wyrms" )
	table.insert( hints, "Loading_Campaign_Archetype_Harps" )
	table.insert( hints, "Loading_Campaign_Archetype_Saps" )
	table.insert( hints, "Loading_Campaign_Archetype_Crones" )

	table.insert( hints, "Loading_Misc_Hint_ThreeAsOne" )
	table.insert( hints, "Loading_Misc_Hint_LosingAura" )
	table.insert( hints, "Loading_Misc_Hint_AuraCast" )
	table.insert( hints, "Loading_Misc_Hint_PassAiming" )
	table.insert( hints, "Loading_Misc_Hint_Passing" )
	table.insert( hints, "Loading_Misc_Hint_OrbFling" )
	table.insert( hints, "Loading_Misc_Hint_OrbTrick" )
	table.insert( hints, "Loading_Misc_Hint_AuraLinking" )
	table.insert( hints, "Loading_Misc_Hint_SacrificeScoring" )
	table.insert( hints, "Loading_Misc_Hint_Glory" )
	table.insert( hints, "Loading_Misc_Hint_Hope" )
	table.insert( hints, "Loading_Misc_Hint_Quickness" )
	table.insert( hints, "Loading_Misc_Hint_Aura" )
	table.insert( hints, "Loading_Misc_Hint_Talismans" )
	table.insert( hints, "Loading_Misc_Hint_Landmarks" )
	table.insert( hints, "Loading_Misc_Hint_Races" )
	table.insert( hints, "Loading_Misc_Hint_BanishmentEvasion" )
	table.insert( hints, "Loading_Misc_Hint_StaminaUse" )
	table.insert( hints, "Loading_Misc_Hint_JumpBlocking" )
	table.insert( hints, "Loading_Misc_Hint_TeamWipe" )
	table.insert( hints, "Loading_Misc_Hint_PowerShot" )
	table.insert( hints, "Loading_Misc_Hint_SprintCancel" )
	table.insert( hints, "Loading_Misc_Hint_AimAssist" )
	table.insert( hints, "Loading_Misc_Hint_AuraSize_01" )
	table.insert( hints, "Loading_Misc_Hint_AuraSize_02" )
	table.insert( hints, "Loading_Misc_Hint_TeamComp" )
	table.insert( hints, "Loading_Misc_Hint_Taunting" )

	table.insert( hints, "Loading_Backstory_Downside" )
	table.insert( hints, "Loading_Backstory_Scribes" )
	table.insert( hints, "Loading_Backstory_Rites" )
	table.insert( hints, "Loading_Backstory_Commonwealth" )
	table.insert( hints, "Loading_Backstory_Exile" )
	table.insert( hints, "Loading_Backstory_LiteracyBan" )
	table.insert( hints, "Loading_Backstory_TwoSides" )

	table.insert( hints, "Loading_Boot_01" )
	table.insert( hints, "Loading_Boot_02" )
	table.insert( hints, "Loading_Boot_03" )
	table.insert( hints, "Loading_Boot_04" )
	table.insert( hints, "Loading_Boot_05" )
	table.insert( hints, "Loading_Boot_06" )
	table.insert( hints, "Loading_Boot_07" )
	table.insert( hints, "Loading_Boot_08" )
	table.insert( hints, "Loading_Boot_09" )
	table.insert( hints, "Loading_Boot_10" )
	table.insert( hints, "Loading_Boot_11" )
	table.insert( hints, "Loading_Boot_12" )
	table.insert( hints, "Loading_Boot_13" )
	table.insert( hints, "Loading_Boot_14" )
	table.insert( hints, "Loading_Boot_15" )
	table.insert( hints, "Loading_Boot_16" )
	table.insert( hints, "Loading_Boot_17" )
	table.insert( hints, "Loading_Boot_18" )
	table.insert( hints, "Loading_Boot_19" )
	table.insert( hints, "Loading_Boot_20" )
	table.insert( hints, "Loading_Boot_21" )
	table.insert( hints, "Loading_Boot_22" )
	table.insert( hints, "Loading_Boot_23" )

end

function GatherEnterMatchMiscHints( hints )

	table.insert( hints, "Loading_Misc_Hint_TeamComp" )
	table.insert( hints, "Loading_Misc_Hint_Taunting" )
	table.insert( hints, "Loading_Misc_Hint_ThreeAsOne" )
	table.insert( hints, "Loading_Misc_Hint_LosingAura" )
	table.insert( hints, "Loading_Misc_Hint_AuraCast" )
	table.insert( hints, "Loading_Misc_Hint_PassAiming" )
	table.insert( hints, "Loading_Misc_Hint_Passing" )
	table.insert( hints, "Loading_Misc_Hint_OrbFling" )
	table.insert( hints, "Loading_Misc_Hint_OrbTrick" )
	table.insert( hints, "Loading_Misc_Hint_AuraLinking" )
	table.insert( hints, "Loading_Misc_Hint_SacrificeScoring" )
	table.insert( hints, "Loading_Misc_Hint_Glory" )
	table.insert( hints, "Loading_Misc_Hint_Hope" )
	table.insert( hints, "Loading_Misc_Hint_Quickness" )
	table.insert( hints, "Loading_Misc_Hint_Aura" )
	table.insert( hints, "Loading_Misc_Hint_Talismans" )
	table.insert( hints, "Loading_Misc_Hint_Landmarks" )
	table.insert( hints, "Loading_Misc_Hint_Races" )
	table.insert( hints, "Loading_Misc_Hint_AimAssist" )
	table.insert( hints, "Loading_Campaign_Hint_Enlightenment" )
	table.insert( hints, "Loading_Campaign_Hint_Inspiration" )
	table.insert( hints, "Loading_Misc_Hint_BanishmentEvasion" )
	table.insert( hints, "Loading_Misc_Hint_StaminaUse" )
	table.insert( hints, "Loading_Misc_Hint_AuraSize_01" )
	table.insert( hints, "Loading_Misc_Hint_AuraSize_02" )

end

function GatherCampaignPostMatchHints( hints )

	if CurrentMapName == "MatchSiteA" then
		if not introComplete then
			table.insert( hints, "Loading_Misc_Hint_ThreeAsOne" )
		elseif cameFromFreePlayMatch or cameFromFreePlayMatch then
			if currentlyOccupiedSwath == 3 and PlayerTeam.AscensionMatchesPlayed == 0 then
				table.insert( hints, "Loading_Misc_Hint_PassAiming" )
			else
				SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
			end
		end
	elseif CurrentMapName == "MatchSiteB" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_OrbFling" )
	elseif CurrentMapName == "MatchSiteC" and PlayerTeam.AscensionMatchesPlayed == 0 then
		if TitanMode then
			table.insert( hints, "Loading_Campaign_Hint_DifficultySetting_TitanMode" )
		else
			table.insert( hints, "Loading_Campaign_Hint_DifficultySetting" )
		end
	elseif CurrentMapName == "ScenarioDefense" then
		table.insert( hints, "Loading_Misc_Hint_PowerShot" )
	elseif CurrentMapName == "MatchSiteD" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_BanishmentEvasion" )
	elseif CurrentMapName == "MatchSiteE" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_AuraLinking" )
	elseif CurrentMapName == "MatchSiteF" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_Talismans" )
	elseif CurrentMapName == "ScenarioRetrieval" then
		table.insert( hints, "Loading_Campaign_ScenarioRetrieval_02" )
	elseif CurrentMapName == "MatchSiteG" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_JumpBlocking" )
	elseif CurrentMapName == "MatchSiteH" and PlayerTeam.AscensionMatchesPlayed == 0 then
		table.insert( hints, "Loading_Misc_Hint_Passing" )
	elseif CurrentMapName == "MatchSiteI" then
		if PlayerTeam.AscensionMatchesPlayed == 1 then
			table.insert( hints, "Loading_Campaign_Hint_AscensionFrequency" )
		elseif PlayerTeam.AscensionMatchesPlayed == 2 then
			table.insert( hints, "Loading_Campaign_Hint_Inspiration" )
		elseif PlayerTeam.AscensionMatchesPlayed == 3 then
			table.insert( hints, "Loading_Boot_07" )
		elseif PlayerTeam.AscensionMatchesPlayed == 4 then
			table.insert( hints, "Loading_Campaign_Hint_FinalChances" )
		elseif PlayerTeam.AscensionMatchesPlayed == 5 then
			table.insert( hints, "Loading_Boot_17" )
		elseif PlayerTeam.AscensionMatchesPlayed == 6 then
			table.insert( hints, "Loading_Boot_23" )
		end
	-- S2
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 0 then
		table.insert( hints, "Loading_Campaign_Hint_Triumvirates" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 1 then
		table.insert( hints, "Loading_Campaign_Hint_Souvenirs" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 2 then
		table.insert( hints, "Loading_Campaign_Hint_Planner" )
	elseif PlayerTeam.AscensionMatchesPlayed == 1 and MatchesPlayedThisSeason == 3 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- S3
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 2 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 2 and MatchesPlayedThisSeason == 3 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- S4
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 3 and MatchesPlayedThisSeason == 2 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- S5
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 4 and MatchesPlayedThisSeason == 2 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- S6
	elseif PlayerTeam.AscensionMatchesPlayed == 5 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 5 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- S7
	elseif PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 0 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	elseif PlayerTeam.AscensionMatchesPlayed == 6 and MatchesPlayedThisSeason == 1 then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	-- random campaign hints
	else
		table.insert( hints, "Loading_Boot_03" )
		table.insert( hints, "Loading_Campaign_Hint_Market" )
	end

end

function GatherOpenStructureMiscHints( hints )

	if IsEmpty( hints ) then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	end

	table.insert( hints, "Loading_Campaign_Swath_01" )
	table.insert( hints, "Loading_Campaign_Swath_02" )
	table.insert( hints, "Loading_Campaign_Swath_03" )
	table.insert( hints, "Loading_Campaign_Swath_04" )
	table.insert( hints, "Loading_Campaign_Swath_05" )
	table.insert( hints, "Loading_Campaign_Swath_06" )
	table.insert( hints, "Loading_Campaign_Swath_07" )
	table.insert( hints, "Loading_Campaign_Swath_07Alt" )
	table.insert( hints, "Loading_Campaign_Swath_08" )
	table.insert( hints, "Loading_Campaign_Swath_09" )

	table.insert( hints, "Loading_Misc_Triumvirate_01" )
	table.insert( hints, "Loading_Misc_Triumvirate_02" )
	table.insert( hints, "Loading_Misc_Triumvirate_03" )
	table.insert( hints, "Loading_Misc_Triumvirate_04" )
	table.insert( hints, "Loading_Misc_Triumvirate_05" )
	table.insert( hints, "Loading_Misc_Triumvirate_06" )
	table.insert( hints, "Loading_Misc_Triumvirate_07" )
	table.insert( hints, "Loading_Misc_Triumvirate_08" )
	table.insert( hints, "Loading_Misc_Triumvirate_09" )
	table.insert( hints, "Loading_Misc_Triumvirate_10" )

	table.insert( hints, "Loading_Misc_MatchSiteB" )
	table.insert( hints, "Loading_Misc_MatchSiteC" )
	table.insert( hints, "Loading_Misc_MatchSiteD" )
	table.insert( hints, "Loading_Misc_MatchSiteE" )
	table.insert( hints, "Loading_Misc_MatchSiteF" )
	table.insert( hints, "Loading_Misc_MatchSiteG" )
	table.insert( hints, "Loading_Misc_MatchSiteH" )
	table.insert( hints, "Loading_Misc_MatchSiteI" )

	table.insert( hints, "Loading_Campaign_Hint_HurryText" )
	if TitanMode then
		table.insert( hints, "Loading_Campaign_Hint_DifficultySetting_TitanMode" )
	else
		table.insert( hints, "Loading_Campaign_Hint_DifficultySetting" )
	end

	table.insert( hints, "Loading_Misc_Hint_JumpBlocking" )

	table.insert( hints, "Loading_Backstory_HarpFaction" )
	table.insert( hints, "Loading_Backstory_WyrmFaction" )

end

function GatherLinearStructureMiscHints( hints )

	if IsEmpty( hints ) then
		SetConfigOption({ Name = "LoadScreenStartWithFirstHint", Value = false })
	end

	table.insert( hints, "Loading_Backstory_Downside" )
	table.insert( hints, "Loading_Backstory_Scribes" )
	table.insert( hints, "Loading_Backstory_Rites" )
	table.insert( hints, "Loading_Backstory_Commonwealth" )
	table.insert( hints, "Loading_Backstory_Exile" )
	table.insert( hints, "Loading_Backstory_LiteracyBan" )
	table.insert( hints, "Loading_Backstory_TwoSides" )

	table.insert( hints, "Loading_Misc_Hint_TeamComp" )
	table.insert( hints, "Loading_Misc_Hint_Taunting" )
	table.insert( hints, "Loading_Misc_Hint_TeamWipe" )
	table.insert( hints, "Loading_Misc_Hint_PowerShot" )
	table.insert( hints, "Loading_Misc_Hint_SprintCancel" )

	table.insert( hints, "Loading_Campaign_Archetype_DemonHistory" )
	table.insert( hints, "Loading_Campaign_Hint_SideConversations" )
	table.insert( hints, "Loading_Campaign_Hint_SaveSystem" )

	table.insert( hints, "Loading_Boot_01" )
	table.insert( hints, "Loading_Boot_02" )
	table.insert( hints, "Loading_Boot_03" )
	table.insert( hints, "Loading_Boot_04" )
	table.insert( hints, "Loading_Boot_05" )
	table.insert( hints, "Loading_Boot_06" )
	table.insert( hints, "Loading_Boot_07" )
	table.insert( hints, "Loading_Boot_08" )
	table.insert( hints, "Loading_Boot_09" )
	table.insert( hints, "Loading_Boot_10" )
	table.insert( hints, "Loading_Boot_11" )
	table.insert( hints, "Loading_Boot_12" )
	table.insert( hints, "Loading_Boot_13" )
	table.insert( hints, "Loading_Boot_14" )
	table.insert( hints, "Loading_Boot_15" )
	table.insert( hints, "Loading_Boot_16" )
	table.insert( hints, "Loading_Boot_17" )
	table.insert( hints, "Loading_Boot_18" )
	table.insert( hints, "Loading_Boot_19" )
	table.insert( hints, "Loading_Boot_20" )
	table.insert( hints, "Loading_Boot_21" )

end

OnControlHotSwap
{
	function( triggerArgs )
		HandleHotSwap()
	end
}

function HandleHotSwap()

	if IsScreenOpen({ Name = "StandingsScreen" }) or IsScreenOpen({ Name = "RosterScreen" }) or IsScreenOpen({ Name = "DialogueScreen" })  then
		if not GetConfigOptionValue({ Name = "UseMouse" }) then
			TeleportCursor({ OffsetX = 960, OffsetY = 540, PlayerIndex = 1 })
		end
		return
	end

	if showStarMap and IsInputAllowed({ })  then
		SetupZoomOutMapCursor()
		return
	end

	if openedCaravan and not caravanClosing then
		EnableCaravanCursor()
		return
	end

	if CurrentMapName == "Epilogue" then
		ToggleEpilogueCursorControlOn()
		return
	end

	if not GetConfigOptionValue({ Name = "UseMouse" }) then
		TeleportCursor({ OffsetX = 960, OffsetY = 540, PlayerIndex = 1 })
	end

end

ArcadeModeTeams =
{
	[2] = "MatchSiteB",
	[3] = "MatchSiteC",
	[4] = "MatchSiteD",
	[5] = "MatchSiteE",
	[6] = "MatchSiteF",
	[7] = "MatchSiteG",
	[8] = "MatchSiteH",
	[9] = "MatchSiteJ",
	[10] = "MatchSiteA",
	[11] = "MatchSiteI",
}

SaveVersusSettings =
{
	"LocalMPMap",
	"LocalMPIntroPresentation",
	"LocalMPUseItems",
	"LocalMPHumanTeamA",
	"LocalMPTeamADraft",
	"LocalMPHumanTeamB",
	"LocalMPTeamBDraft",
	"LocalMPUseConstellations",
	"LocalMPDifficulty",
	"LocalMPTeamAIndex",
	"LocalMPTeamBIndex",
	"LocalMPMap",
	"LocalMPTeamAPyreHealth",
	"LocalMPTeamBPyreHealth",
}

function StartArcadeMode()

	ArcadeMode = true
	PersistVariable({ Name = "ArcadeMode" })

	if ArcadeModeMaxStars == nil then
		ArcadeModeMaxStars = 0
		PersistVariable({ Name = "ArcadeModeMaxStars" })
	end

	CurrentArcadeTeamIndex = 10
	PersistVariable({ Name = "CurrentArcadeTeamIndex" })

	ArcadeTeamsRemaining = ShallowCopyTable( ArcadeModeTeams )
	ArcadeTeamsRemaining[CurrentArcadeTeamIndex] = nil
	PersistVariable({ Name = "ArcadeTeamsRemaining" })

	SetConfigOption({ Name = "LocalMPMap", Value = "MatchSiteA" })
	SetupArcadeMatch()

	LocalMPConfirmPressed()

end

function RequestStartNextArcadeMatch()

	if IsEmpty( ArcadeTeamsRemaining ) then
		-- Run Victory
		ArcadeModeMaxStars = CountConstellationsActive()
		ArcadeModeRunFinished()
		return
	end

	TeamALastDraftPicks = {}
	PersistVariable({ Name = "TeamALastDraftPicks" })
	for k, character in pairs( TeamA.TeamBench ) do
		if character.ActiveStatus == "Assigned" or character.ActiveStatus == "PlayedLastMatch" then
			TeamALastDraftPicks[character.DraftOrder] = k
		end
	end

	local eligibleTeams = ShallowCopyTable( ArcadeTeamsRemaining )
	local teamsRemaining = TableLength( eligibleTeams )
	if teamsRemaining >= 2 then
		-- Save True Nightwings for the end
		eligibleTeams[11] = nil
	end
	CurrentArcadeTeamIndex = GetRandomKey( eligibleTeams )
	ArcadeTeamsRemaining[CurrentArcadeTeamIndex] = nil

	local mapRequest = ArcadeModeTeams[CurrentArcadeTeamIndex]
	SetConfigOption({ Name = "LocalMPReady", Value = true })
	ForceShortIntro = true
	SuppressVOResume = true
	PersistVariable({ Name = "ForceShortIntro" })
	CleanupMatchSounds( 1.0 )
	SaveCheckpoint({ SaveName = "_ArcadeMode", StartNextMap = mapRequest, DevSaveName = CreateArcadeDevSaveName() })
	LoadMap({ Name = mapRequest })

end

function ArcadeModeRunFinished()

	AddInputBlock({ Name = "MenuExitMP" })
	FadeOut({ Color = Color.Black })
	ExitMenu({ Name = "PauseScreen" })
	ExitMenu({ Name = "ExitConfirmDialog" })
	waitScreenTime(0.17)
	-- Keep the filter going until load
	SetSoundCueValue({ Id = GetMixingId({}), Names = { "Pause" }, Value = 0.0 })
	SetMultiplayerMatchOff()
	SetConfigOption({ Name = "CampaignReady", Value = false })

	CurrentArcadeTeamIndex = 10
	ArcadeTeamsRemaining = ShallowCopyTable( ArcadeModeTeams )
	ArcadeTeamsRemaining[CurrentArcadeTeamIndex] = nil

	RemoveInputBlock({ Name = "MenuExitMP" })

	SaveCheckpoint({ SaveName = "_ArcadeMode", LoadOnlyStartNextMap = "MatchSiteA", SuspendNonPersisted = true, DevSaveName = CreateArcadeDevSaveName() })

	RestoreUserVersusSettings()

	if HasSaveFile({ }) then
		LoadCheckpoint({ })
	else
		LoadMap({ Name = "Campaign", ResetApp = true })
	end
end

function RecordUserVersusSettings()

	if PrevVersusSettings ~= nil then
		-- Already have the user set recorded - don't want to overwrite it with the ArcadeMode set
		return
	end

	PrevVersusSettings = {}
	for k, setting in pairs( SaveVersusSettings ) do
		PrevVersusSettings[setting] = GetConfigOptionValue({ Name = setting })
	end
	PersistVariable({ Name = "PrevVersusSettings" })

end

function RestoreUserVersusSettings()

	if PrevVersusSettings == nil then
		-- Nothing recorded
		return
	end

	for setting, value in pairs( PrevVersusSettings ) do
		SetConfigOption({ Name = setting, Value = value })
	end
	PrevVersusSettings = nil

end

function SetupArcadeMatch()

	RecordUserVersusSettings()

	-- All matches
	SetConfigOption({ Name = "LocalMPUseItems", Value = true })
	SetConfigOption({ Name = "LocalMPCharacterLevel", Value = 0 })
	SetConfigOption({ Name = "LocalMPHumanTeamA", Value = true })
	SetConfigOption({ Name = "LocalMPHumanTeamB", Value = false })
	SetConfigOption({ Name = "LocalMPTeamBDraft", Value = false })
	SetConfigOption({ Name = "LocalMPTeamAIndex", Value = 1 })
	SetConfigOption({ Name = "LocalMPTeamAPyreHealth", Value = 100 })
	SetConfigOption({ Name = "LocalMPTeamBPyreHealth", Value = 100 })
	SetConfigOption({ Name = "LocalMPTeamBIndex", Value = CurrentArcadeTeamIndex })

	if CurrentArcadeTeamIndex == 10 then

		-- First match

		SetConfigOption({ Name = "LocalMPIntroPresentation", Value = "LocalMP_Intro_Long" })
		SetConfigOption({ Name = "LocalMPUseConstellations", Value = true })
		SetConfigOption({ Name = "LocalMPDifficulty", Value = "LocalMP_Easy" })
		SetConfigOption({ Name = "LocalMPTeamADraft", Value = true })

	else

		-- Subsequent matches

		local teamsRemaining = TableLength( ArcadeTeamsRemaining ) + 1
		if teamsRemaining >= 9 then
			SetConfigOption({ Name = "LocalMPDifficulty", Value = "LocalMP_Easy" })
		elseif teamsRemaining >= 7 then
			SetConfigOption({ Name = "LocalMPDifficulty", Value = "LocalMP_Medium" })
		elseif teamsRemaining >= 4 then
			SetConfigOption({ Name = "LocalMPDifficulty", Value = "LocalMP_Hard" })
		elseif teamsRemaining >= 2 then
			SetConfigOption({ Name = "LocalMPDifficulty", Value = "LocalMP_VeryHard" })
		end

		SetConfigOption({ Name = "LocalMPUseConstellations", Value = false })
		SetConfigOption({ Name = "LocalMPTeamADraft", Value = false })

	end

end