Unstable v0.19.5.0
This commit is contained in:
@@ -1,22 +1,21 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
enum AutoPlayVideo { Yes, No };
|
||||
|
||||
enum TutorialSegmentType { MessageBox, InfoBox };
|
||||
enum TutorialSegmentType { MessageBox, InfoBox, Objective };
|
||||
|
||||
class Tutorial
|
||||
sealed class Tutorial
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string PlayableContentPath = "Content/Tutorials/TutorialVideos/";
|
||||
private const SpawnType SpawnPointType = SpawnType.Human;
|
||||
private const float FadeOutTime = 3f;
|
||||
private const float WaitBeforeFade = 4f;
|
||||
@@ -25,19 +24,11 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
#region Tutorial variables
|
||||
|
||||
public static ImmutableHashSet<Type> Types;
|
||||
|
||||
static Tutorial()
|
||||
{
|
||||
Types = ReflectionUtils.GetDerivedNonAbstract<Tutorial>()
|
||||
.ToImmutableHashSet();
|
||||
}
|
||||
|
||||
public readonly Identifier Identifier;
|
||||
|
||||
public LocalizedString DisplayName { get; }
|
||||
|
||||
public bool ContentRunning { get; protected set; }
|
||||
public bool ContentRunning { get; private set; }
|
||||
|
||||
private GUIComponent infoBox;
|
||||
private Action infoBoxClosedCallback;
|
||||
@@ -51,47 +42,25 @@ namespace Barotrauma.Tutorials
|
||||
private readonly LocalizedString objectiveTextTranslated;
|
||||
|
||||
private readonly List<Segment> ActiveObjectives = new List<Segment>();
|
||||
private const float ObjectiveComponentRemovalTime = 1.5f;
|
||||
private const float ObjectiveComponentAnimationTime = 1.5f;
|
||||
private Segment ActiveContentSegment { get; set; }
|
||||
|
||||
public class Segment
|
||||
{
|
||||
public struct Text
|
||||
public readonly record struct Text(
|
||||
Identifier Tag,
|
||||
int Width = DefaultWidth,
|
||||
int Height = DefaultHeight,
|
||||
Anchor Anchor = Anchor.Center);
|
||||
|
||||
public readonly record struct Video(
|
||||
string FullPath,
|
||||
Identifier TextTag,
|
||||
int Width = DefaultWidth,
|
||||
int Height = DefaultHeight)
|
||||
{
|
||||
private const Anchor DefaultAnchor = Anchor.Center;
|
||||
|
||||
public Identifier Tag;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public Anchor Anchor;
|
||||
|
||||
public Text(Identifier tag, int? width = null, int? height = null, Anchor? anchor = null)
|
||||
{
|
||||
Tag = tag;
|
||||
Width = width ?? DefaultWidth;
|
||||
Height = height ?? DefaultHeight;
|
||||
Anchor = anchor ?? DefaultAnchor;
|
||||
}
|
||||
|
||||
public Text(string tag, int? width = null, int? height = null, Anchor? anchor = null) : this(tag.ToIdentifier(), width, height, anchor) { }
|
||||
}
|
||||
|
||||
public struct Video
|
||||
{
|
||||
public string File;
|
||||
public Identifier TextTag;
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public Video(string file, Identifier textTag, int? width = null, int? height = null)
|
||||
{
|
||||
File = file;
|
||||
TextTag = textTag;
|
||||
Width = width ?? DefaultWidth;
|
||||
Height = height ?? DefaultHeight;
|
||||
}
|
||||
|
||||
public Video(string file, string textTag, int? width = null, int? height = null) : this(file, textTag.ToIdentifier(), width, height) { }
|
||||
public string FileName => Path.GetFileName(FullPath.CleanUpPath());
|
||||
public string ContentPath => Path.GetDirectoryName(FullPath.CleanUpPath());
|
||||
}
|
||||
|
||||
private const int DefaultWidth = 450;
|
||||
@@ -103,15 +72,30 @@ namespace Barotrauma.Tutorials
|
||||
public LocalizedString ObjectiveText;
|
||||
|
||||
public readonly Identifier Id;
|
||||
public readonly Text? TextContent;
|
||||
public readonly Video? VideoContent;
|
||||
public readonly Text TextContent;
|
||||
public readonly Video VideoContent;
|
||||
public readonly AutoPlayVideo AutoPlayVideo;
|
||||
|
||||
public Action OnClickToDisplayMessage;
|
||||
public Action OnClickObjective;
|
||||
|
||||
public readonly TutorialSegmentType SegmentType;
|
||||
|
||||
public Segment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text? textContent = null, Video? videoContent = null)
|
||||
public static Segment CreateInfoBoxSegment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text textContent = default, Video videoContent = default)
|
||||
{
|
||||
return new Segment(id, objectiveTextTag, autoPlayVideo, textContent, videoContent);
|
||||
}
|
||||
|
||||
public static Segment CreateMessageBoxSegment(Identifier id, Identifier objectiveTextTag, Action onClickObjective)
|
||||
{
|
||||
return new Segment(id, objectiveTextTag, onClickObjective);
|
||||
}
|
||||
|
||||
public static Segment CreateObjectiveSegment(Identifier id, Identifier objectiveTextTag)
|
||||
{
|
||||
return new Segment(id, objectiveTextTag);
|
||||
}
|
||||
|
||||
private Segment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text textContent = default, Video videoContent = default)
|
||||
{
|
||||
Id = id;
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
|
||||
@@ -121,15 +105,21 @@ namespace Barotrauma.Tutorials
|
||||
SegmentType = TutorialSegmentType.InfoBox;
|
||||
}
|
||||
|
||||
public Segment(Identifier id, Action onClickToDisplayMessage)
|
||||
private Segment(Identifier id, Identifier objectiveTextTag, Action onClickObjective)
|
||||
{
|
||||
Id = id;
|
||||
var objetiveTextTag = $"{id}.objective".ToIdentifier();
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objetiveTextTag));
|
||||
OnClickToDisplayMessage = onClickToDisplayMessage;
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
|
||||
OnClickObjective = onClickObjective;
|
||||
SegmentType = TutorialSegmentType.MessageBox;
|
||||
}
|
||||
}
|
||||
|
||||
private Segment(Identifier id, Identifier objectiveTextTag)
|
||||
{
|
||||
Id = id;
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
|
||||
SegmentType = TutorialSegmentType.Objective;
|
||||
}
|
||||
}
|
||||
|
||||
private bool completed;
|
||||
public bool Completed
|
||||
@@ -157,60 +147,57 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
private Character character;
|
||||
|
||||
private readonly string submarinePath = "Content/Tutorials/Dugong_Tutorial.sub";
|
||||
private readonly string startOutpostPath = "Content/Tutorials/TutorialOutpost.sub";
|
||||
|
||||
private readonly string levelSeed = "nLoZLLtza";
|
||||
private readonly string levelParams = "ColdCavernsTutorial";
|
||||
private string SubmarinePath => TutorialPrefab.SubmarinePath.Value;
|
||||
private string StartOutpostPath => TutorialPrefab.OutpostPath.Value;
|
||||
private string LevelSeed => TutorialPrefab.LevelSeed;
|
||||
private string LevelParams => TutorialPrefab.LevelParams;
|
||||
|
||||
private SubmarineInfo startOutpost = null;
|
||||
|
||||
public readonly List<(Entity entity, string iconStyle)> Icons = new List<(Entity entity, string iconStyle)>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tutorial Controls
|
||||
|
||||
public Tutorial(TutorialPrefab prefab)
|
||||
{
|
||||
Identifier = $"tutorial.{prefab?.Identifier ?? Identifier.Empty}".ToIdentifier();
|
||||
Identifier = $"tutorial.{prefab.Identifier}".ToIdentifier();
|
||||
DisplayName = TextManager.Get(Identifier);
|
||||
objectiveTextTranslated = TextManager.Get("Tutorial.Objective");
|
||||
|
||||
TutorialPrefab = prefab;
|
||||
submarinePath = prefab.SubmarinePath.Value;
|
||||
startOutpostPath = prefab.OutpostPath.Value;
|
||||
levelSeed = prefab.LevelSeed;
|
||||
levelParams = prefab.LevelParams;
|
||||
eventPrefab = EventSet.GetEventPrefab(prefab.EventIdentifier);
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> Loading()
|
||||
{
|
||||
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
|
||||
SubmarineInfo subInfo = new SubmarineInfo(SubmarinePath);
|
||||
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Identifier == levelParams);
|
||||
LevelGenerationParams.LevelParams.TryGet(LevelParams, out LevelGenerationParams generationParams);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
GameMain.GameSession = new GameSession(subInfo, GameModePreset.Tutorial, missionPrefabs: null);
|
||||
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
|
||||
|
||||
if (generationParams != null)
|
||||
if (generationParams is not null)
|
||||
{
|
||||
Biome biome =
|
||||
Biome.Prefabs.FirstOrDefault(b => generationParams.AllowedBiomeIdentifiers.Contains(b.Identifier)) ??
|
||||
Biome.Prefabs.First();
|
||||
|
||||
if (!string.IsNullOrEmpty(startOutpostPath))
|
||||
if (!string.IsNullOrEmpty(StartOutpostPath))
|
||||
{
|
||||
startOutpost = new SubmarineInfo(startOutpostPath);
|
||||
startOutpost = new SubmarineInfo(StartOutpostPath);
|
||||
}
|
||||
|
||||
LevelData tutorialLevel = new LevelData(levelSeed, 0, 0, generationParams, biome);
|
||||
LevelData tutorialLevel = new LevelData(LevelSeed, 0, 0, generationParams, biome);
|
||||
GameMain.GameSession.StartRound(tutorialLevel, startOutpost: startOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.GameSession.StartRound(levelSeed);
|
||||
GameMain.GameSession.StartRound(LevelSeed);
|
||||
}
|
||||
|
||||
GameMain.GameSession.EventManager.ActiveEvents.Clear();
|
||||
@@ -274,6 +261,7 @@ namespace Barotrauma.Tutorials
|
||||
private void Initialize()
|
||||
{
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = TutorialPrefab.AllowCharacterSwitch;
|
||||
GameMain.GameSession.CrewManager.AutoHideCrewList();
|
||||
|
||||
if (Character.Controlled is Character character)
|
||||
{
|
||||
@@ -450,7 +438,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
public void TriggerTutorialSegment(Segment segment)
|
||||
{
|
||||
if (segment.SegmentType == TutorialSegmentType.MessageBox)
|
||||
if (segment.SegmentType != TutorialSegmentType.InfoBox)
|
||||
{
|
||||
ActiveObjectives.Add(segment);
|
||||
AddToObjectiveList(segment);
|
||||
@@ -462,7 +450,7 @@ namespace Barotrauma.Tutorials
|
||||
ActiveContentSegment = segment;
|
||||
|
||||
var title = TextManager.Get(segment.Id);
|
||||
LocalizedString tutorialText = TextManager.GetFormatted(segment.TextContent.Value.Tag);
|
||||
LocalizedString tutorialText = TextManager.GetFormatted(segment.TextContent.Tag);
|
||||
tutorialText = TextManager.ParseInputTypes(tutorialText);
|
||||
|
||||
switch (segment.AutoPlayVideo)
|
||||
@@ -471,9 +459,9 @@ namespace Barotrauma.Tutorials
|
||||
infoBox = CreateInfoFrame(
|
||||
title,
|
||||
tutorialText,
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor,
|
||||
segment.TextContent.Width,
|
||||
segment.TextContent.Height,
|
||||
segment.TextContent.Anchor,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: LoadActiveContentVideo);
|
||||
break;
|
||||
@@ -481,9 +469,9 @@ namespace Barotrauma.Tutorials
|
||||
infoBox = CreateInfoFrame(
|
||||
title,
|
||||
tutorialText,
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor,
|
||||
segment.TextContent.Width,
|
||||
segment.TextContent.Height,
|
||||
segment.TextContent.Anchor,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: StopCurrentContentSegment,
|
||||
onVideoButtonClicked: LoadActiveContentVideo);
|
||||
@@ -493,7 +481,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
public void CompleteTutorialSegment(Identifier segmentId)
|
||||
{
|
||||
if (!(GetActiveObjective(segmentId) is Segment segment))
|
||||
if (GetActiveObjective(segmentId) is not Segment segment)
|
||||
{
|
||||
DebugConsole.AddWarning($"Warning: tried to complete the tutorial segment \"{segmentId}\" in tutorial \"{Identifier}\" but it isn't active!");
|
||||
return;
|
||||
@@ -501,29 +489,28 @@ namespace Barotrauma.Tutorials
|
||||
if (GUIStyle.GetComponentStyle("ObjectiveIndicatorCompleted") is GUIComponentStyle style)
|
||||
{
|
||||
segment.ObjectiveStateIndicator.ApplyStyle(style);
|
||||
segment.ObjectiveStateIndicator.Flash(color: GUIStyle.Green);
|
||||
}
|
||||
segment.ObjectiveStateIndicator.Parent.Flash(color: GUIStyle.Green, flashDuration: 0.35f, useRectangleFlash: true);
|
||||
segment.ObjectiveButton.OnClicked = null;
|
||||
segment.ObjectiveButton.CanBeFocused = false;
|
||||
}
|
||||
|
||||
public void RemoveTutorialSegment(Identifier segmentId)
|
||||
{
|
||||
if (!(GetActiveObjective(segmentId) is Segment segment))
|
||||
if (GetActiveObjective(segmentId) is not Segment segment)
|
||||
{
|
||||
DebugConsole.AddWarning($"Warning: tried to remove the tutorial segment \"{segmentId}\" in tutorial \"{Identifier}\" but it isn't active!");
|
||||
return;
|
||||
}
|
||||
segment.ObjectiveStateIndicator.FadeOut(ObjectiveComponentRemovalTime, false);
|
||||
segment.LinkedTextBlock.FadeOut(ObjectiveComponentRemovalTime, false);
|
||||
segment.ObjectiveStateIndicator.FadeOut(ObjectiveComponentAnimationTime, false);
|
||||
segment.LinkedTextBlock.FadeOut(ObjectiveComponentAnimationTime, false);
|
||||
var parent = segment.LinkedTextBlock.Parent;
|
||||
parent.FadeOut(ObjectiveComponentRemovalTime, true, onRemove: () =>
|
||||
parent.FadeOut(ObjectiveComponentAnimationTime, true, onRemove: () =>
|
||||
{
|
||||
ActiveObjectives.Remove(segment);
|
||||
objectiveGroup?.Recalculate();
|
||||
});
|
||||
var targetPos = new Point(GameMain.GraphicsWidth - parent.Rect.X, 0);
|
||||
parent.RectTransform.MoveOverTime(targetPos, ObjectiveComponentRemovalTime);
|
||||
parent.RectTransform.MoveOverTime(GetObjectiveHiddenPosition(parent.RectTransform), ObjectiveComponentAnimationTime);
|
||||
segment.ObjectiveButton.OnClicked = null;
|
||||
segment.ObjectiveButton.CanBeFocused = false;
|
||||
}
|
||||
@@ -585,12 +572,14 @@ namespace Barotrauma.Tutorials
|
||||
{
|
||||
var frameRt = new RectTransform(new Vector2(1.0f, 0.1f), objectiveGroup.RectTransform)
|
||||
{
|
||||
AbsoluteOffset = GetObjectiveHiddenPosition(),
|
||||
MinSize = new Point(0, objectiveGroup.AbsoluteSpacing)
|
||||
};
|
||||
var frame = new GUIFrame(frameRt, style: null)
|
||||
{
|
||||
CanBeFocused = true
|
||||
};
|
||||
objectiveGroup.Recalculate();
|
||||
|
||||
segment.LinkedTextBlock = new GUITextBlock(
|
||||
new RectTransform(new Point(frameRt.Rect.Width - objectiveGroup.AbsoluteSpacing, 0), frame.RectTransform, anchor: Anchor.TopRight),
|
||||
@@ -612,6 +601,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
segment.ObjectiveButton = new GUIButton(new RectTransform(Vector2.One, segment.LinkedTextBlock.RectTransform, Anchor.TopLeft, Pivot.TopLeft), style: null)
|
||||
{
|
||||
CanBeFocused = segment.SegmentType != TutorialSegmentType.Objective,
|
||||
ToolTip = objectiveTextTranslated,
|
||||
OnClicked = (GUIButton btn, object userdata) =>
|
||||
{
|
||||
@@ -628,13 +618,15 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
else if (segment.SegmentType == TutorialSegmentType.MessageBox)
|
||||
{
|
||||
segment.OnClickToDisplayMessage?.Invoke();
|
||||
segment.OnClickObjective?.Invoke();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
SetTransparent(segment.ObjectiveButton);
|
||||
|
||||
frameRt.MoveOverTime(new Point(0, frameRt.AbsoluteOffset.Y), ObjectiveComponentAnimationTime, onDoneMoving: () => objectiveGroup?.Recalculate());
|
||||
|
||||
static void SetTransparent(GUIComponent component) => component.Color = component.HoverColor = component.PressedColor = component.SelectedColor = Color.Transparent;
|
||||
}
|
||||
|
||||
@@ -654,15 +646,20 @@ namespace Barotrauma.Tutorials
|
||||
ActiveContentSegment = segment;
|
||||
infoBox = CreateInfoFrame(
|
||||
TextManager.Get(segment.Id),
|
||||
TextManager.Get(segment.TextContent.Value.Tag),
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor,
|
||||
TextManager.Get(segment.TextContent.Tag),
|
||||
segment.TextContent.Width,
|
||||
segment.TextContent.Height,
|
||||
segment.TextContent.Anchor,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: () => ContentRunning = false,
|
||||
onVideoButtonClicked: () => LoadVideo(segment));
|
||||
}
|
||||
|
||||
private Point GetObjectiveHiddenPosition(RectTransform rt = null)
|
||||
{
|
||||
return new Point(GameMain.GraphicsWidth - objectiveGroup.Rect.X, rt?.AbsoluteOffset.Y ?? 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region InfoFrame
|
||||
@@ -772,9 +769,9 @@ namespace Barotrauma.Tutorials
|
||||
if (segment.AutoPlayVideo == AutoPlayVideo.Yes)
|
||||
{
|
||||
videoPlayer.LoadContent(
|
||||
contentPath: PlayableContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.Value.File),
|
||||
textSettings: new VideoPlayer.TextSettings(segment.VideoContent.Value.TextTag, segment.VideoContent.Value.Width),
|
||||
contentPath: segment.VideoContent.ContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.FileName),
|
||||
textSettings: new VideoPlayer.TextSettings(segment.VideoContent.TextTag, segment.VideoContent.Width),
|
||||
contentId: segment.Id,
|
||||
startPlayback: true,
|
||||
objective: segment.ObjectiveText,
|
||||
@@ -783,8 +780,8 @@ namespace Barotrauma.Tutorials
|
||||
else
|
||||
{
|
||||
videoPlayer.LoadContent(
|
||||
contentPath: PlayableContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.Value.File),
|
||||
contentPath: segment.VideoContent.ContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.FileName),
|
||||
textSettings: null,
|
||||
contentId: segment.Id,
|
||||
startPlayback: true,
|
||||
|
||||
Reference in New Issue
Block a user