Unstable v0.19.3.0
This commit is contained in:
@@ -1,346 +0,0 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
class CaptainTutorial : ScenarioTutorial
|
||||
{
|
||||
// Room 1
|
||||
private float shakeTimer = 1f;
|
||||
private float shakeAmount = 20f;
|
||||
|
||||
// Room 2
|
||||
private Door captain_firstDoor;
|
||||
private LightComponent captain_firstDoorLight;
|
||||
|
||||
// Room 3
|
||||
private Character captain_medic;
|
||||
private MotionSensor captain_medicObjectiveSensor;
|
||||
private Vector2 captain_medicSpawnPos;
|
||||
private Door tutorial_submarineDoor;
|
||||
private LightComponent tutorial_submarineDoorLight;
|
||||
|
||||
// Submarine
|
||||
private MotionSensor captain_enteredSubmarineSensor;
|
||||
private Steering captain_navConsole;
|
||||
private Sonar captain_sonar;
|
||||
private Item captain_statusMonitor;
|
||||
private Character captain_security;
|
||||
private Character captain_mechanic;
|
||||
private Character captain_engineer;
|
||||
private Reactor tutorial_submarineReactor;
|
||||
private Door tutorial_lockedDoor_1;
|
||||
private Door tutorial_lockedDoor_2;
|
||||
|
||||
// Variables
|
||||
private Character captain;
|
||||
private LocalizedString radioSpeakerName;
|
||||
private Sprite captain_steerIcon;
|
||||
private Color captain_steerIconColor;
|
||||
|
||||
public CaptainTutorial() : base("tutorial.captaintraining".ToIdentifier(),
|
||||
new Segment(
|
||||
"Captain.CommandMedic".ToIdentifier(),
|
||||
"Captain.CommandMedicObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Captain.CommandMedicText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_command.webm", TextTag = "Captain.CommandMedicText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Captain.CommandMechanic".ToIdentifier(),
|
||||
"Captain.CommandMechanicObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Captain.CommandMechanicText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Captain.CommandSecurity".ToIdentifier(),
|
||||
"Captain.CommandSecurityObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Captain.CommandSecurityText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Captain.CommandEngineer".ToIdentifier(),
|
||||
"Captain.CommandEngineerObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Captain.CommandEngineerText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Captain.Undock".ToIdentifier(),
|
||||
"Captain.UndockObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Captain.UndockText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_undock.webm", TextTag = "Captain.UndockText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Captain.Navigate".ToIdentifier(),
|
||||
"Captain.NavigateObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Captain.NavigateText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_navigation.webm", TextTag = "Captain.NavigateText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Captain.Dock".ToIdentifier(),
|
||||
"Captain.DockObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Captain.DockText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_docking.webm", TextTag = "Captain.DockText".ToIdentifier(), Width = 450, Height = 80 }))
|
||||
{ }
|
||||
|
||||
protected override CharacterInfo GetCharacterInfo()
|
||||
{
|
||||
return new CharacterInfo(
|
||||
CharacterPrefab.HumanSpeciesName,
|
||||
jobOrJobPrefab: new Job(
|
||||
JobPrefab.Prefabs["captain"], Rand.RandSync.Unsynced, 0,
|
||||
new Skill("medical".ToIdentifier(), 20),
|
||||
new Skill("weapons".ToIdentifier(), 20),
|
||||
new Skill("mechanical".ToIdentifier(), 20),
|
||||
new Skill("electrical".ToIdentifier(), 20),
|
||||
new Skill("helm".ToIdentifier(), 70)));
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
captain = Character.Controlled;
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman");
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
|
||||
|
||||
foreach (Item item in captain.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(captain);
|
||||
captain.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var steerOrder = OrderPrefab.Prefabs["steer"];
|
||||
captain_steerIcon = steerOrder.SymbolSprite;
|
||||
captain_steerIconColor = steerOrder.Color;
|
||||
|
||||
// Room 2
|
||||
captain_firstDoor = Item.ItemList.Find(i => i.HasTag("captain_firstdoor")).GetComponent<Door>();
|
||||
captain_firstDoorLight = Item.ItemList.Find(i => i.HasTag("captain_firstdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(captain_firstDoor, captain_firstDoorLight, true);
|
||||
|
||||
// Room 3
|
||||
captain_medicObjectiveSensor = Item.ItemList.Find(i => i.HasTag("captain_medicobjectivesensor")).GetComponent<MotionSensor>();
|
||||
captain_medicSpawnPos = Item.ItemList.Find(i => i.HasTag("captain_medicspawnpos")).WorldPosition;
|
||||
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
|
||||
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
|
||||
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("medicaldoctor".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
captain_medic = Character.Create(medicInfo, captain_medicSpawnPos, "medicaldoctor");
|
||||
captain_medic.GiveJobItems(null);
|
||||
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
|
||||
// Submarine
|
||||
captain_enteredSubmarineSensor = Item.ItemList.Find(i => i.HasTag("captain_enteredsubmarinesensor")).GetComponent<MotionSensor>();
|
||||
tutorial_submarineReactor = Item.ItemList.Find(i => i.HasTag("engineer_submarinereactor")).GetComponent<Reactor>();
|
||||
captain_navConsole = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
|
||||
captain_sonar = captain_navConsole.Item.GetComponent<Sonar>();
|
||||
captain_statusMonitor = Item.ItemList.Find(i => i.HasTag("captain_statusmonitor"));
|
||||
|
||||
tutorial_submarineReactor.CanBeSelected = false;
|
||||
tutorial_submarineReactor.IsActive = tutorial_submarineReactor.AutoTemp = false;
|
||||
|
||||
tutorial_lockedDoor_1 = Item.ItemList.Find(i => i.HasTag("tutorial_lockeddoor_1")).GetComponent<Door>();
|
||||
tutorial_lockedDoor_2 = Item.ItemList.Find(i => i.HasTag("tutorial_lockeddoor_2")).GetComponent<Door>();
|
||||
SetDoorAccess(tutorial_lockedDoor_1, null, false);
|
||||
SetDoorAccess(tutorial_lockedDoor_2, null, false);
|
||||
|
||||
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("mechanic".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "mechanic");
|
||||
captain_mechanic.GiveJobItems();
|
||||
|
||||
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "securityofficer");
|
||||
captain_security.GiveJobItems();
|
||||
|
||||
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "engineer");
|
||||
captain_engineer.GiveJobItems();
|
||||
|
||||
captain_mechanic.CanSpeak = captain_security.CanSpeak = captain_engineer.CanSpeak = false;
|
||||
captain_mechanic.AIController.Enabled = captain_security.AIController.Enabled = captain_engineer.AIController.Enabled = false;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Started");
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Started");
|
||||
}
|
||||
|
||||
public override IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen) yield return null;
|
||||
|
||||
// Room 1
|
||||
while (shakeTimer > 0.0f) // Wake up, shake
|
||||
{
|
||||
shakeTimer -= 0.1f;
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
}
|
||||
|
||||
// Room 2
|
||||
do { yield return null; } while (!captain_firstDoor.IsOpen);
|
||||
captain_medic.AIController.Enabled = true;
|
||||
|
||||
// Room 3
|
||||
do { yield return null; } while (!captain_medicObjectiveSensor.MotionDetected);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(captain_medic.Info.DisplayName, TextManager.Get("Captain.Radio.Medic"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
GameMain.GameSession.CrewManager.AutoShowCrewList();
|
||||
GameMain.GameSession.CrewManager.AddCharacter(captain_medic);
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command));
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_medic, "follow", highlightColor, new Vector2(5, 5));
|
||||
}
|
||||
while (!HasOrder(captain_medic, "follow"));
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
|
||||
RemoveCompletedObjective(0);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective0");
|
||||
|
||||
// Submarine
|
||||
do { yield return null; } while (!captain_enteredSubmarineSensor.MotionDetected);
|
||||
yield return new WaitForSeconds(3f, false);
|
||||
captain_mechanic.AIController.Enabled = captain_security.AIController.Enabled = captain_engineer.AIController.Enabled = true;
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command));
|
||||
GameMain.GameSession.CrewManager.AddCharacter(captain_mechanic);
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
|
||||
//HighlightOrderOption("jobspecific");
|
||||
} while (!HasOrder(captain_mechanic, "repairsystems") && !HasOrder(captain_mechanic, "repairmechanical") && !HasOrder(captain_mechanic, "repairelectrical"));
|
||||
RemoveCompletedObjective(1);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective1");
|
||||
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command));
|
||||
GameMain.GameSession.CrewManager.AddCharacter(captain_security);
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_security, "operateweapons", highlightColor, new Vector2(5, 5));
|
||||
HighlightOrderOption("fireatwill");
|
||||
}
|
||||
while (!HasOrder(captain_security, "operateweapons"));
|
||||
RemoveCompletedObjective(2);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective2");
|
||||
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
TriggerTutorialSegment(3, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command));
|
||||
GameMain.GameSession.CrewManager.AddCharacter(captain_engineer);
|
||||
tutorial_submarineReactor.CanBeSelected = true;
|
||||
//recreate autonomous objectives to make sure the engineer didn't abandon the operate reactor objective because it was not selectable
|
||||
(captain_engineer.AIController as HumanAIController).ObjectiveManager.CreateAutonomousObjectives();
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_engineer, "operatereactor", highlightColor, new Vector2(5, 5));
|
||||
HighlightOrderOption("powerup");
|
||||
}
|
||||
while (!HasOrder(captain_engineer, "operatereactor", "powerup"));
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective3");
|
||||
|
||||
do { yield return null; } while (!tutorial_submarineReactor.IsActive); // Wait until reactor on
|
||||
TriggerTutorialSegment(4);
|
||||
while (ContentRunning) yield return null;
|
||||
captain.AddActiveObjectiveEntity(captain_navConsole.Item, captain_steerIcon, captain_steerIconColor);
|
||||
SetHighlight(captain_navConsole.Item, true);
|
||||
SetHighlight(captain_sonar.Item, true);
|
||||
SetHighlight(captain_statusMonitor, true);
|
||||
do
|
||||
{
|
||||
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
} while (Submarine.MainSub.DockedTo.Any());
|
||||
captain_navConsole.UseAutoDocking = false;
|
||||
RemoveCompletedObjective(4);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective4");
|
||||
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(5); // Navigate to destination
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(captain_navConsole.Item))
|
||||
{
|
||||
if (captain_sonar.SonarModeSwitch.Frame.FlashTimer <= 0)
|
||||
{
|
||||
captain_sonar.SonarModeSwitch.Frame.Flash(highlightColor, 1.5f, false, false, new Vector2(2.5f, 2.5f));
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (captain_sonar.CurrentMode != Sonar.Mode.Active);
|
||||
do { yield return null; } while (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 4000f);
|
||||
RemoveCompletedObjective(5);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective5");
|
||||
|
||||
captain_navConsole.UseAutoDocking = true;
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
TriggerTutorialSegment(6); // Docking
|
||||
do
|
||||
{
|
||||
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
} while (!Submarine.MainSub.AtEndExit || !Submarine.MainSub.DockedTo.Any());
|
||||
RemoveCompletedObjective(6);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Objective6");
|
||||
|
||||
yield return new WaitForSeconds(3f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.GetWithVariable("Captain.Radio.Complete", "[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);
|
||||
SetHighlight(captain_navConsole.Item, false);
|
||||
SetHighlight(captain_sonar.Item, false);
|
||||
SetHighlight(captain_statusMonitor, false);
|
||||
captain.RemoveActiveObjectiveEntity(captain_navConsole.Item);
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:CaptainTutorial:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
private void HighlightOrderOption(string option)
|
||||
{
|
||||
if (GameMain.GameSession.CrewManager.OrderOptionButtons.Count == 0) return;
|
||||
var order = GameMain.GameSession.CrewManager.OrderOptionButtons[0].UserData as Order;
|
||||
|
||||
int orderIndex = 0;
|
||||
for (int i = 0; i < GameMain.GameSession.CrewManager.OrderOptionButtons.Count; i++)
|
||||
{
|
||||
if (orderIndex >= order.Options.Length)
|
||||
{
|
||||
orderIndex = 0;
|
||||
}
|
||||
if (order.Options[orderIndex] == option)
|
||||
{
|
||||
if (GameMain.GameSession.CrewManager.OrderOptionButtons[i].FlashTimer <= 0)
|
||||
{
|
||||
GameMain.GameSession.CrewManager.OrderOptionButtons[i].Flash(highlightColor);
|
||||
}
|
||||
}
|
||||
|
||||
orderIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSelectedItem(Item item)
|
||||
{
|
||||
return
|
||||
captain?.SelectedItem == item ||
|
||||
(captain?.SelectedItem?.linkedTo?.Contains(item) ?? false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,521 +0,0 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
class DoctorTutorial : ScenarioTutorial
|
||||
{
|
||||
// Room 1
|
||||
private float shakeTimer = 1f;
|
||||
private float shakeAmount = 20f;
|
||||
|
||||
private LocalizedString radioSpeakerName;
|
||||
private Character doctor;
|
||||
|
||||
private ItemContainer doctor_suppliesCabinet;
|
||||
private ItemContainer doctor_medBayCabinet;
|
||||
private Character patient1, patient2;
|
||||
private List<Character> subPatients;
|
||||
private Hull medBay;
|
||||
|
||||
private Door doctor_firstDoor;
|
||||
private Door doctor_secondDoor;
|
||||
private Door doctor_thirdDoor;
|
||||
private Door tutorial_upperFinalDoor;
|
||||
private Door tutorial_lockedDoor_2;
|
||||
|
||||
private LightComponent doctor_firstDoorLight;
|
||||
private LightComponent doctor_secondDoorLight;
|
||||
private LightComponent doctor_thirdDoorLight;
|
||||
private Door tutorial_submarineDoor;
|
||||
private LightComponent tutorial_submarineDoorLight;
|
||||
|
||||
// Variables
|
||||
private Sprite doctor_firstAidIcon;
|
||||
private Color doctor_firstAidIconColor;
|
||||
|
||||
|
||||
public DoctorTutorial() : base("tutorial.medicaldoctortraining".ToIdentifier(),
|
||||
new Segment(
|
||||
"Doctor.Supplies".ToIdentifier(),
|
||||
"Doctor.SuppliesObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Doctor.SuppliesText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Doctor.OpenMedicalInterface".ToIdentifier(),
|
||||
"Doctor.OpenMedicalInterfaceObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Doctor.OpenMedicalInterfaceText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_medinterface1.webm", TextTag = "Doctor.OpenMedicalInterfaceText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Doctor.FirstAidSelf".ToIdentifier(),
|
||||
"Doctor.FirstAidSelfObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Doctor.FirstAidSelfText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_medinterface1.webm", TextTag = "Doctor.FirstAidSelfText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Doctor.Medbay".ToIdentifier(),
|
||||
"Doctor.MedbayObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Doctor.MedbayText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_command.webm", TextTag = "Doctor.MedbayText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Doctor.TreatBurns".ToIdentifier(),
|
||||
"Doctor.TreatBurnsObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Doctor.TreatBurnsText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_medinterface2.webm", TextTag = "Doctor.TreatBurnsText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Doctor.CPR".ToIdentifier(),
|
||||
"Doctor.CPRObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Doctor.CPRText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_cpr.webm", TextTag = "Doctor.CPRText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Doctor.Submarine".ToIdentifier(),
|
||||
"Doctor.SubmarineObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Doctor.SubmarineText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }))
|
||||
{ }
|
||||
|
||||
protected override CharacterInfo GetCharacterInfo()
|
||||
{
|
||||
return new CharacterInfo(
|
||||
CharacterPrefab.HumanSpeciesName,
|
||||
jobOrJobPrefab: new Job(
|
||||
JobPrefab.Prefabs["medicaldoctor"], Rand.RandSync.Unsynced, 0,
|
||||
new Skill("medical".ToIdentifier(), 70),
|
||||
new Skill("weapons".ToIdentifier(), 20),
|
||||
new Skill("mechanical".ToIdentifier(), 20),
|
||||
new Skill("electrical".ToIdentifier(), 20),
|
||||
new Skill("helm".ToIdentifier(), 20)));
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
var firstAidOrder = OrderPrefab.Prefabs["requestfirstaid"];
|
||||
doctor_firstAidIcon = firstAidOrder.SymbolSprite;
|
||||
doctor_firstAidIconColor = firstAidOrder.Color;
|
||||
|
||||
subPatients = new List<Character>();
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
doctor = Character.Controlled;
|
||||
|
||||
foreach (Item item in doctor.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>();
|
||||
doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>();
|
||||
|
||||
var patientHull1 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "waitingroom").CurrentHull;
|
||||
var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
|
||||
medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
|
||||
|
||||
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
|
||||
patient1.GiveJobItems(null);
|
||||
patient1.CanSpeak = false;
|
||||
patient1.Params.Health.BurnReduction = 0;
|
||||
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 15.0f) }, stun: 0, playSound: false);
|
||||
patient1.AIController.Enabled = false;
|
||||
|
||||
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
|
||||
patient2.GiveJobItems(null);
|
||||
patient2.CanSpeak = false;
|
||||
patient2.AIController.Enabled = false;
|
||||
|
||||
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient1.Params.Health.BurnReduction = 0;
|
||||
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient1);
|
||||
|
||||
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer".ToIdentifier()));
|
||||
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient2.TeamID = CharacterTeamType.Team1;
|
||||
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient2);
|
||||
|
||||
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
|
||||
{
|
||||
TeamID = CharacterTeamType.Team1
|
||||
};
|
||||
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient3.Params.Health.BurnReduction = 0;
|
||||
subPatient3.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient3);
|
||||
|
||||
doctor_firstDoor = Item.ItemList.Find(i => i.HasTag("doctor_firstdoor")).GetComponent<Door>();
|
||||
doctor_secondDoor = Item.ItemList.Find(i => i.HasTag("doctor_seconddoor")).GetComponent<Door>();
|
||||
doctor_thirdDoor = Item.ItemList.Find(i => i.HasTag("doctor_thirddoor")).GetComponent<Door>();
|
||||
tutorial_upperFinalDoor = Item.ItemList.Find(i => i.HasTag("tutorial_upperfinaldoor")).GetComponent<Door>();
|
||||
doctor_firstDoorLight = Item.ItemList.Find(i => i.HasTag("doctor_firstdoorlight")).GetComponent<LightComponent>();
|
||||
doctor_secondDoorLight = Item.ItemList.Find(i => i.HasTag("doctor_seconddoorlight")).GetComponent<LightComponent>();
|
||||
doctor_thirdDoorLight = Item.ItemList.Find(i => i.HasTag("doctor_thirddoorlight")).GetComponent<LightComponent>();
|
||||
SetDoorAccess(doctor_firstDoor, doctor_firstDoorLight, false);
|
||||
SetDoorAccess(doctor_secondDoor, doctor_secondDoorLight, false);
|
||||
SetDoorAccess(doctor_thirdDoor, doctor_thirdDoorLight, false);
|
||||
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
|
||||
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
tutorial_lockedDoor_2 = Item.ItemList.Find(i => i.HasTag("tutorial_lockeddoor_2")).GetComponent<Door>();
|
||||
SetDoorAccess(tutorial_lockedDoor_2, null, true);
|
||||
|
||||
|
||||
foreach (var patient in subPatients)
|
||||
{
|
||||
patient.CanSpeak = false;
|
||||
patient.AIController.Enabled = false;
|
||||
patient.GiveJobItems();
|
||||
}
|
||||
|
||||
Item reactorItem = Item.ItemList.Find(i => i.Submarine == Submarine.MainSub && i.GetComponent<Reactor>() != null);
|
||||
reactorItem.GetComponent<Reactor>().AutoTemp = true;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Started");
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Started");
|
||||
}
|
||||
|
||||
public override IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen) yield return null;
|
||||
|
||||
// explosions and radio messages ------------------------------------------------------
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
|
||||
//SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
|
||||
//// Room 1
|
||||
//while (shakeTimer > 0.0f) // Wake up, shake
|
||||
//{
|
||||
// shakeTimer -= 0.1f;
|
||||
// GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
// yield return new WaitForSeconds(0.1f);
|
||||
//}
|
||||
//yield return new WaitForSeconds(2.5f);
|
||||
//GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.WakeUp"), ChatMessageType.Radio, null);
|
||||
|
||||
//yield return new WaitForSeconds(2.5f);
|
||||
|
||||
doctor.SetStun(1.5f);
|
||||
var explosion = new Explosion(range: 100, force: 10, damage: 0, structureDamage: 0, itemDamage: 0);
|
||||
explosion.DisableParticles();
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
explosion.Explode(Character.Controlled.WorldPosition - Vector2.UnitX * 25, null);
|
||||
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition - Vector2.UnitX * 25);
|
||||
|
||||
yield return new WaitForSeconds(0.5f, false);
|
||||
|
||||
doctor.DamageLimb(
|
||||
Character.Controlled.WorldPosition,
|
||||
doctor.AnimController.GetLimb(LimbType.Torso),
|
||||
new List<Affliction> { new Affliction(AfflictionPrefab.InternalDamage, 10.0f) },
|
||||
stun: 3.0f, playSound: true, attackImpulse: 0.0f);
|
||||
|
||||
shakeTimer = 0.5f;
|
||||
while (shakeTimer > 0.0f) // Wake up, shake
|
||||
{
|
||||
shakeTimer -= 0.1f;
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.KnockedDown"), ChatMessageType.Radio, null);
|
||||
|
||||
// first tutorial segment, get medical supplies ------------------------------------------------------
|
||||
|
||||
yield return new WaitForSeconds(1.5f, false);
|
||||
SetHighlight(doctor_suppliesCabinet.Item, true);
|
||||
|
||||
/*while (doctor.CurrentHull != doctor_suppliesCabinet.Item.CurrentHull)
|
||||
{
|
||||
yield return new WaitForSeconds(2.0f);
|
||||
}*/
|
||||
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), "None"); // Medical supplies objective
|
||||
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < doctor_suppliesCabinet.Inventory.Capacity; i++)
|
||||
{
|
||||
if (doctor_suppliesCabinet.Inventory.GetItemAt(i) != null)
|
||||
{
|
||||
HighlightInventorySlot(doctor_suppliesCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
if (doctor.SelectedItem == doctor_suppliesCabinet.Item)
|
||||
{
|
||||
for (int i = 0; i < doctor.Inventory.Capacity; i++)
|
||||
{
|
||||
if (doctor.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (doctor.Inventory.FindItemByIdentifier("antidama1".ToIdentifier()) == null); // Wait until looted
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
|
||||
SetHighlight(doctor_suppliesCabinet.Item, false);
|
||||
RemoveCompletedObjective(0);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective0");
|
||||
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
|
||||
// 2nd tutorial segment, treat self -------------------------------------------------------------------------
|
||||
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Health)); // Open health interface
|
||||
while (CharacterHealth.OpenHealthWindow == null)
|
||||
{
|
||||
doctor.CharacterHealth.HealthBarPulsateTimer = 1.0f;
|
||||
yield return null;
|
||||
}
|
||||
yield return null;
|
||||
RemoveCompletedObjective(1);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective1");
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
TriggerTutorialSegment(2); //Treat self
|
||||
while (doctor.CharacterHealth.GetAfflictionStrength("damage") > 0.01f)
|
||||
{
|
||||
if (CharacterHealth.OpenHealthWindow == null)
|
||||
{
|
||||
doctor.CharacterHealth.HealthBarPulsateTimer = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
HighlightInventorySlot(doctor.Inventory, "antidama1".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
RemoveCompletedObjective(2);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective2");
|
||||
SetDoorAccess(doctor_firstDoor, doctor_firstDoorLight, true);
|
||||
|
||||
while (CharacterHealth.OpenHealthWindow != null)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
}
|
||||
|
||||
// treat patient --------------------------------------------------------------------------------------------
|
||||
|
||||
//patient 1 requests first aid
|
||||
var newOrder = new Order(OrderPrefab.Prefabs["requestfirstaid"], patient1.CurrentHull, null, orderGiver: patient1);
|
||||
doctor.AddActiveObjectiveEntity(patient1, doctor_firstAidIcon, doctor_firstAidIconColor);
|
||||
//GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(patient1.Name, newOrder.GetChatMessage("", patient1.CurrentHull?.DisplayName?.Value, givingOrderToSelf: false), ChatMessageType.Order, null);
|
||||
|
||||
while (doctor.CurrentHull != patient1.CurrentHull)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
}
|
||||
yield return new WaitForSeconds(0.0f, false);
|
||||
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.AssistantBurns"), ChatMessageType.Radio, null);
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
|
||||
GameMain.GameSession.CrewManager.AddCharacter(doctor);
|
||||
GameMain.GameSession.CrewManager.AddCharacter(patient1);
|
||||
GameMain.GameSession.CrewManager.AutoShowCrewList();
|
||||
patient1.CharacterHealth.UseHealthWindow = false;
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
patient1.AIController.Enabled = true;
|
||||
doctor.RemoveActiveObjectiveEntity(patient1);
|
||||
TriggerTutorialSegment(3, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command)); // Get the patient to medbay
|
||||
|
||||
while (patient1.GetCurrentOrderWithTopPriority()?.Identifier != "follow")
|
||||
{
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(patient1, "follow", highlightColor, new Vector2(5, 5));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SetDoorAccess(doctor_secondDoor, doctor_secondDoorLight, true);
|
||||
|
||||
while (patient1.CurrentHull != medBay)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
}
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective3");
|
||||
SetHighlight(doctor_medBayCabinet.Item, true);
|
||||
SetDoorAccess(doctor_thirdDoor, doctor_thirdDoorLight, true);
|
||||
patient1.CharacterHealth.UseHealthWindow = true;
|
||||
|
||||
yield return new WaitForSeconds(2.0f, false);
|
||||
|
||||
TriggerTutorialSegment(4, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Health)); // treat burns
|
||||
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (doctor_medBayCabinet.Inventory.GetItemAt(i) != null)
|
||||
{
|
||||
HighlightInventorySlot(doctor_medBayCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
if (doctor.SelectedItem == doctor_medBayCabinet.Item)
|
||||
{
|
||||
for (int i = 0; i < doctor.Inventory.Capacity; i++)
|
||||
{
|
||||
if (doctor.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (doctor.Inventory.FindItemByIdentifier("antibleeding1".ToIdentifier()) == null); // Wait until looted
|
||||
SetHighlight(doctor_medBayCabinet.Item, false);
|
||||
SetHighlight(patient1, true);
|
||||
|
||||
while (patient1.CharacterHealth.GetAfflictionStrength("burn") > 0.01f)
|
||||
{
|
||||
if (CharacterHealth.OpenHealthWindow == null)
|
||||
{
|
||||
doctor.CharacterHealth.HealthBarPulsateTimer = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
HighlightInventorySlot(doctor.Inventory, "antibleeding1".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
|
||||
}
|
||||
RemoveCompletedObjective(4);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective4");
|
||||
SetHighlight(patient1, false);
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.AssistantBurnsHealed"), ChatMessageType.Radio, null);
|
||||
|
||||
// treat unconscious patient ------------------------------------------------------
|
||||
|
||||
//patient calls for help
|
||||
//patient2.CanSpeak = true;
|
||||
yield return new WaitForSeconds(2.0f, false);
|
||||
newOrder = new Order(OrderPrefab.Prefabs["requestfirstaid"], patient2.CurrentHull, null, orderGiver: patient2);
|
||||
doctor.AddActiveObjectiveEntity(patient2, doctor_firstAidIcon, doctor_firstAidIconColor);
|
||||
//GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(patient2.Name, newOrder.GetChatMessage("", patient1.CurrentHull?.DisplayName?.Value, givingOrderToSelf: false), ChatMessageType.Order, null);
|
||||
patient2.AIController.Enabled = true;
|
||||
patient2.Oxygen = -50;
|
||||
CoroutineManager.StartCoroutine(KeepPatientAlive(patient2), "KeepPatient2Alive");
|
||||
|
||||
/*while (doctor.CurrentHull != patient2.CurrentHull)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
}*/
|
||||
do { yield return null; } while (!tutorial_upperFinalDoor.IsOpen);
|
||||
yield return new WaitForSeconds(2.0f, false);
|
||||
|
||||
TriggerTutorialSegment(5, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Health)); // perform CPR
|
||||
SetHighlight(patient2, true);
|
||||
while (patient2.IsUnconscious)
|
||||
{
|
||||
if (CharacterHealth.OpenHealthWindow != null && doctor.AnimController.Anim != AnimController.Animation.CPR)
|
||||
{
|
||||
//Disabled pulse until it's replaced by a better effect
|
||||
//CharacterHealth.OpenHealthWindow.CPRButton.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f);
|
||||
if (CharacterHealth.OpenHealthWindow.CPRButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
CharacterHealth.OpenHealthWindow.CPRButton.Flash(highlightColor);
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
RemoveCompletedObjective(5);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective5");
|
||||
SetHighlight(patient2, false);
|
||||
doctor.RemoveActiveObjectiveEntity(patient2);
|
||||
CoroutineManager.StopCoroutines("KeepPatient2Alive");
|
||||
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
|
||||
|
||||
while (doctor.Submarine != Submarine.MainSub)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
}
|
||||
|
||||
subPatients[2].Oxygen = -50;
|
||||
CoroutineManager.StartCoroutine(KeepPatientAlive(subPatients[2]), "KeepPatient3Alive");
|
||||
|
||||
yield return new WaitForSeconds(5.0f, false);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.EnteredSub"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
TriggerTutorialSegment(6, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Health)); // give treatment to anyone in need
|
||||
|
||||
foreach (var patient in subPatients)
|
||||
{
|
||||
//patient.CanSpeak = true;
|
||||
patient.AIController.Enabled = true;
|
||||
SetHighlight(patient, true);
|
||||
}
|
||||
|
||||
double subEnterTime = Timing.TotalTime;
|
||||
|
||||
bool[] patientCalledHelp = new bool[] { false, false, false };
|
||||
|
||||
while (subPatients.Any(p => p.Vitality < p.MaxVitality * 0.9f && !p.IsDead))
|
||||
{
|
||||
for (int i = 0; i < subPatients.Count; i++)
|
||||
{
|
||||
//make patients call for help to make sure the player finds them
|
||||
//(within 1 minute intervals of entering the sub)
|
||||
if (!patientCalledHelp[i] && Timing.TotalTime > subEnterTime + 60 * (i + 1))
|
||||
{
|
||||
doctor.AddActiveObjectiveEntity(subPatients[i], doctor_firstAidIcon, doctor_firstAidIconColor);
|
||||
newOrder = new Order(OrderPrefab.Prefabs["requestfirstaid"], subPatients[i].CurrentHull, null, orderGiver: subPatients[i]);
|
||||
string message = newOrder.GetChatMessage("", subPatients[i].CurrentHull?.DisplayName?.Value, givingOrderToSelf: false);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(subPatients[i].Name, message, ChatMessageType.Order, null);
|
||||
patientCalledHelp[i] = true;
|
||||
}
|
||||
|
||||
if (subPatients[i].ExternalHighlight && subPatients[i].Vitality >= subPatients[i].MaxVitality * 0.9f)
|
||||
{
|
||||
doctor.RemoveActiveObjectiveEntity(subPatients[i]);
|
||||
SetHighlight(subPatients[i], false);
|
||||
}
|
||||
}
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
}
|
||||
RemoveCompletedObjective(6);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Objective6");
|
||||
foreach (var patient in subPatients)
|
||||
{
|
||||
SetHighlight(patient, false);
|
||||
doctor.RemoveActiveObjectiveEntity(patient);
|
||||
}
|
||||
|
||||
// END TUTORIAL
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:DoctorTutorial:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
public IEnumerable<CoroutineStatus> KeepPatientAlive(Character patient)
|
||||
{
|
||||
while (patient != null && !patient.Removed)
|
||||
{
|
||||
patient.Oxygen = Math.Max(patient.Oxygen, -50);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,664 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
class EngineerTutorial : ScenarioTutorial
|
||||
{
|
||||
// Other tutorial items
|
||||
private LightComponent tutorial_securityFinalDoorLight;
|
||||
private LightComponent tutorial_mechanicFinalDoorLight;
|
||||
private Steering tutorial_submarineSteering;
|
||||
|
||||
// Room 1
|
||||
private float shakeTimer = 1f;
|
||||
private float shakeAmount = 20f;
|
||||
|
||||
// Room 2
|
||||
private MotionSensor engineer_equipmentObjectiveSensor;
|
||||
private ItemContainer engineer_equipmentCabinet;
|
||||
private Door engineer_firstDoor;
|
||||
private LightComponent engineer_firstDoorLight;
|
||||
|
||||
// Room 3
|
||||
private Powered tutorial_oxygenGenerator;
|
||||
private Reactor engineer_reactor;
|
||||
private Door engineer_secondDoor;
|
||||
private LightComponent engineer_secondDoorLight;
|
||||
|
||||
// Room 4
|
||||
private Item engineer_brokenJunctionBox;
|
||||
private Door engineer_thirdDoor;
|
||||
private LightComponent engineer_thirdDoorLight;
|
||||
|
||||
// Room 5
|
||||
private PowerTransfer[] engineer_disconnectedJunctionBoxes;
|
||||
private ConnectionPanel[] engineer_disconnectedConnectionPanels;
|
||||
private Item engineer_wire_1;
|
||||
private Powered engineer_lamp_1;
|
||||
private Item engineer_wire_2;
|
||||
private Powered engineer_lamp_2;
|
||||
private Door engineer_fourthDoor;
|
||||
private LightComponent engineer_fourthDoorLight;
|
||||
|
||||
// Room 6
|
||||
private Pump engineer_workingPump;
|
||||
private Door tutorial_lockedDoor_1;
|
||||
|
||||
// Submarine
|
||||
private Door tutorial_submarineDoor;
|
||||
private LightComponent tutorial_submarineDoorLight;
|
||||
private MotionSensor tutorial_enteredSubmarineSensor;
|
||||
private Item engineer_submarineJunctionBox_1;
|
||||
private Item engineer_submarineJunctionBox_2;
|
||||
private Item engineer_submarineJunctionBox_3;
|
||||
private Reactor engineer_submarineReactor;
|
||||
|
||||
// Variables
|
||||
private LocalizedString radioSpeakerName;
|
||||
private Character engineer;
|
||||
private int[] reactorLoads = new int[5] { 1500, 3000, 2000, 5000, 3500 };
|
||||
private float reactorLoadChangeTime = 2f;
|
||||
private float reactorLoadError = 200f;
|
||||
private bool reactorOperatedProperly;
|
||||
private const float waterVolumeBeforeOpening = 15f;
|
||||
private Sprite engineer_repairIcon;
|
||||
private Color engineer_repairIconColor;
|
||||
private Sprite engineer_reactorIcon;
|
||||
private Color engineer_reactorIconColor;
|
||||
private bool wiringActive = false;
|
||||
|
||||
public EngineerTutorial() : base("tutorial.engineertraining".ToIdentifier(),
|
||||
new Segment(
|
||||
"Mechanic.Equipment".ToIdentifier(),
|
||||
"Mechanic.EquipmentObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.EquipmentText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Engineer.Reactor".ToIdentifier(),
|
||||
"Engineer.ReactorObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Engineer.ReactorText".ToIdentifier(), Width = 700, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_reactor.webm", TextTag = "Engineer.ReactorText".ToIdentifier(), Width = 700, Height = 80 }),
|
||||
new Segment(
|
||||
"Engineer.OperateReactor".ToIdentifier(),
|
||||
"Engineer.OperateReactorObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Engineer.OperateReactorText".ToIdentifier(), Width = 700, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_reactor.webm", TextTag = "Engineer.ReactorText".ToIdentifier(), Width = 700, Height = 80 }),
|
||||
new Segment(
|
||||
"Engineer.RepairJunctionBox".ToIdentifier(),
|
||||
"Engineer.RepairJunctionBoxObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Engineer.RepairJunctionBoxText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Engineer.WireJunctionBoxes".ToIdentifier(),
|
||||
"Engineer.WireJunctionBoxesObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Engineer.WireJunctionBoxesText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_wiring.webm", TextTag = "Engineer.WireJunctionBoxesText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Engineer.RepairElectricalRoom".ToIdentifier(),
|
||||
"Engineer.RepairElectricalRoomObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Engineer.RepairElectricalRoomText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Engineer.PowerUpReactor".ToIdentifier(),
|
||||
"Engineer.PowerUpReactorObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Engineer.PowerUpReactorText".ToIdentifier(), Width = 700, Height = 80, Anchor = Anchor.Center }))
|
||||
{ }
|
||||
|
||||
protected override CharacterInfo GetCharacterInfo()
|
||||
{
|
||||
return new CharacterInfo(
|
||||
CharacterPrefab.HumanSpeciesName,
|
||||
jobOrJobPrefab: new Job(
|
||||
JobPrefab.Prefabs["engineer"], Rand.RandSync.Unsynced, 0,
|
||||
new Skill("medical".ToIdentifier(), 0),
|
||||
new Skill("weapons".ToIdentifier(), 0),
|
||||
new Skill("mechanical".ToIdentifier(), 20),
|
||||
new Skill("electrical".ToIdentifier(), 60),
|
||||
new Skill("helm".ToIdentifier(), 0)));
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
engineer = Character.Controlled;
|
||||
|
||||
foreach (Item item in engineer.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(engineer);
|
||||
engineer.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
|
||||
engineer_repairIcon = repairOrder.SymbolSprite;
|
||||
engineer_repairIconColor = repairOrder.Color;
|
||||
|
||||
var reactorOrder = OrderPrefab.Prefabs["operatereactor"];
|
||||
engineer_reactorIcon = reactorOrder.SymbolSprite;
|
||||
engineer_reactorIconColor = reactorOrder.Color;
|
||||
|
||||
// Other tutorial items
|
||||
tutorial_securityFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoorlight")).GetComponent<LightComponent>();
|
||||
tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent<LightComponent>();
|
||||
tutorial_submarineSteering = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
|
||||
|
||||
tutorial_submarineSteering.CanBeSelected = false;
|
||||
foreach (ItemComponent ic in tutorial_submarineSteering.Item.Components)
|
||||
{
|
||||
ic.CanBeSelected = false;
|
||||
}
|
||||
|
||||
SetDoorAccess(null, tutorial_securityFinalDoorLight, false);
|
||||
SetDoorAccess(null, tutorial_mechanicFinalDoorLight, false);
|
||||
|
||||
// Room 2
|
||||
engineer_equipmentObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_equipmentobjectivesensor")).GetComponent<MotionSensor>();
|
||||
engineer_equipmentCabinet = Item.ItemList.Find(i => i.HasTag("engineer_equipmentcabinet")).GetComponent<ItemContainer>();
|
||||
engineer_firstDoor = Item.ItemList.Find(i => i.HasTag("engineer_firstdoor")).GetComponent<Door>();
|
||||
engineer_firstDoorLight = Item.ItemList.Find(i => i.HasTag("engineer_firstdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(engineer_firstDoor, engineer_firstDoorLight, false);
|
||||
|
||||
// Room 3
|
||||
tutorial_oxygenGenerator = Item.ItemList.Find(i => i.HasTag("tutorial_oxygengenerator")).GetComponent<OxygenGenerator>();
|
||||
engineer_reactor = Item.ItemList.Find(i => i.HasTag("engineer_reactor")).GetComponent<Reactor>();
|
||||
engineer_reactor.FireDelay = engineer_reactor.MeltdownDelay = float.PositiveInfinity;
|
||||
engineer_reactor.FuelConsumptionRate = 0.0f;
|
||||
engineer_reactor.PowerOn = true;
|
||||
reactorOperatedProperly = false;
|
||||
|
||||
engineer_secondDoor = Item.ItemList.Find(i => i.HasTag("engineer_seconddoor")).GetComponent<Door>(); ;
|
||||
engineer_secondDoorLight = Item.ItemList.Find(i => i.HasTag("engineer_seconddoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(engineer_secondDoor, engineer_secondDoorLight, false);
|
||||
|
||||
// Room 4
|
||||
engineer_brokenJunctionBox = Item.ItemList.Find(i => i.HasTag("engineer_brokenjunctionbox"));
|
||||
engineer_thirdDoor = Item.ItemList.Find(i => i.HasTag("engineer_thirddoor")).GetComponent<Door>();
|
||||
engineer_thirdDoorLight = Item.ItemList.Find(i => i.HasTag("engineer_thirddoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
engineer_brokenJunctionBox.Indestructible = false;
|
||||
engineer_brokenJunctionBox.Condition = 0f;
|
||||
|
||||
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, false);
|
||||
|
||||
// Room 5
|
||||
engineer_disconnectedJunctionBoxes = new PowerTransfer[4];
|
||||
engineer_disconnectedConnectionPanels = new ConnectionPanel[4];
|
||||
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
engineer_disconnectedJunctionBoxes[i] = Item.ItemList.Find(item => item.HasTag($"engineer_disconnectedjunctionbox_{i + 1}")).GetComponent<PowerTransfer>();
|
||||
engineer_disconnectedConnectionPanels[i] = engineer_disconnectedJunctionBoxes[i].Item.GetComponent<ConnectionPanel>();
|
||||
engineer_disconnectedConnectionPanels[i].Locked = false;
|
||||
|
||||
for (int j = 0; j < engineer_disconnectedJunctionBoxes[i].PowerConnections.Count; j++)
|
||||
{
|
||||
foreach (Wire wire in engineer_disconnectedJunctionBoxes[i].PowerConnections[j].Wires)
|
||||
{
|
||||
if (wire == null) continue;
|
||||
wire.Locked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engineer_wire_1 = Item.ItemList.Find(i => i.HasTag("engineer_wire_1"));
|
||||
engineer_wire_1.SpriteColor = Color.Transparent;
|
||||
engineer_wire_2 = Item.ItemList.Find(i => i.HasTag("engineer_wire_2"));
|
||||
engineer_wire_2.SpriteColor = Color.Transparent;
|
||||
engineer_lamp_1 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_1")).GetComponent<Powered>();
|
||||
engineer_lamp_2 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_2")).GetComponent<Powered>();
|
||||
engineer_fourthDoor = Item.ItemList.Find(i => i.HasTag("engineer_fourthdoor")).GetComponent<Door>();
|
||||
engineer_fourthDoorLight = Item.ItemList.Find(i => i.HasTag("engineer_fourthdoorlight")).GetComponent<LightComponent>();
|
||||
SetDoorAccess(engineer_fourthDoor, engineer_fourthDoorLight, false);
|
||||
|
||||
// Room 6
|
||||
engineer_workingPump = Item.ItemList.Find(i => i.HasTag("engineer_workingpump")).GetComponent<Pump>();
|
||||
engineer_workingPump.Item.CurrentHull.WaterVolume += engineer_workingPump.Item.CurrentHull.Volume;
|
||||
engineer_workingPump.IsActive = true;
|
||||
tutorial_lockedDoor_1 = Item.ItemList.Find(i => i.HasTag("tutorial_lockeddoor_1")).GetComponent<Door>();
|
||||
SetDoorAccess(tutorial_lockedDoor_1, null, true);
|
||||
|
||||
// Submarine
|
||||
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
|
||||
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
|
||||
|
||||
tutorial_enteredSubmarineSensor = Item.ItemList.Find(i => i.HasTag("tutorial_enteredsubmarinesensor")).GetComponent<MotionSensor>();
|
||||
engineer_submarineJunctionBox_1 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_1"));
|
||||
engineer_submarineJunctionBox_2 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_2"));
|
||||
engineer_submarineJunctionBox_3 = Item.ItemList.Find(i => i.HasTag("engineer_submarinejunctionbox_3"));
|
||||
engineer_submarineReactor = Item.ItemList.Find(i => i.HasTag("engineer_submarinereactor")).GetComponent<Reactor>();
|
||||
engineer_submarineReactor.PowerOn = true;
|
||||
engineer_submarineReactor.IsActive = engineer_submarineReactor.AutoTemp = false;
|
||||
|
||||
engineer_submarineJunctionBox_1.Indestructible = false;
|
||||
engineer_submarineJunctionBox_1.Condition = 0f;
|
||||
engineer_submarineJunctionBox_2.Indestructible = false;
|
||||
engineer_submarineJunctionBox_2.Condition = 0f;
|
||||
engineer_submarineJunctionBox_3.Indestructible = false;
|
||||
engineer_submarineJunctionBox_3.Condition = 0f;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Started");
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Started");
|
||||
}
|
||||
|
||||
public override IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen) { yield return null; }
|
||||
|
||||
// Room 1
|
||||
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
|
||||
while (shakeTimer > 0.0f) // Wake up, shake
|
||||
{
|
||||
shakeTimer -= 0.1f;
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
}
|
||||
|
||||
//// Remove
|
||||
//for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
//{
|
||||
// SetHighlight(engineer_disconnectedJunctionBoxes[i].Item, true);
|
||||
//}
|
||||
//do { CheckGhostWires(); HandleJunctionBoxWiringHighlights(); yield return null; } while (engineer_workingPump.Voltage < engineer_workingPump.MinVoltage); // Wait until connected all the way to the pump
|
||||
//CheckGhostWires();
|
||||
//// Remove
|
||||
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.WakeUp"), ChatMessageType.Radio, null);
|
||||
SetHighlight(engineer_equipmentCabinet.Item, true);
|
||||
|
||||
// Room 2
|
||||
do { yield return null; } while (!engineer_equipmentObjectiveSensor.MotionDetected);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(0.5f, false);
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Retrieve equipment
|
||||
bool firstSlotRemoved = false;
|
||||
bool secondSlotRemoved = false;
|
||||
bool thirdSlotRemoved = false;
|
||||
bool fourthSlotRemoved = false;
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(engineer_equipmentCabinet.Item))
|
||||
{
|
||||
if (!firstSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
if (engineer_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!secondSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
|
||||
if (engineer_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!thirdSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
|
||||
if (engineer_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!fourthSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 3, highlightColor, .5f, .5f, 0f);
|
||||
if (engineer_equipmentCabinet.Inventory.GetItemAt(2) == null) { fourthSlotRemoved = true; }
|
||||
}
|
||||
|
||||
for (int i = 0; i < engineer.Inventory.visualSlots.Length; i++)
|
||||
{
|
||||
if (engineer.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(engineer.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
|
||||
yield return null;
|
||||
} while (!engineer_equipmentCabinet.Inventory.IsEmpty()); // Wait until looted
|
||||
RemoveCompletedObjective(0);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective0");
|
||||
SetHighlight(engineer_equipmentCabinet.Item, false);
|
||||
SetHighlight(engineer_reactor.Item, true);
|
||||
SetDoorAccess(engineer_firstDoor, engineer_firstDoorLight, true);
|
||||
|
||||
// Room 3
|
||||
do { yield return null; } while (!IsSelectedItem(engineer_reactor.Item));
|
||||
yield return new WaitForSeconds(0.5f, false);
|
||||
TriggerTutorialSegment(1);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(engineer_reactor.Item))
|
||||
{
|
||||
engineer_reactor.AutoTemp = false;
|
||||
if (engineer_reactor.PowerButton.FlashTimer <= 0)
|
||||
{
|
||||
engineer_reactor.PowerButton.Flash(highlightColor, 1.5f, false);
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!engineer_reactor.PowerOn);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(engineer_reactor.Item) && engineer_reactor.Item.OwnInventory.visualSlots != null)
|
||||
{
|
||||
engineer_reactor.AutoTemp = false;
|
||||
HighlightInventorySlot(engineer.Inventory, "fuelrod".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
|
||||
for (int i = 0; i < engineer_reactor.Item.OwnInventory.visualSlots.Length; i++)
|
||||
{
|
||||
HighlightInventorySlot(engineer_reactor.Item.OwnInventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (engineer_reactor.AvailableFuel == 0);
|
||||
RemoveCompletedObjective(1);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective1");
|
||||
TriggerTutorialSegment(2);
|
||||
CoroutineManager.StartCoroutine(ReactorOperatedProperly());
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(engineer_reactor.Item))
|
||||
{
|
||||
engineer_reactor.AutoTemp = false;
|
||||
if (engineer_reactor.FissionRateScrollBar.FlashTimer <= 0)
|
||||
{
|
||||
engineer_reactor.FissionRateScrollBar.Flash(highlightColor, 1.5f);
|
||||
}
|
||||
|
||||
if (engineer_reactor.TurbineOutputScrollBar.FlashTimer <= 0)
|
||||
{
|
||||
engineer_reactor.TurbineOutputScrollBar.Flash(highlightColor, 1.5f);
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!reactorOperatedProperly);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.ReactorStable"), ChatMessageType.Radio, null);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(engineer_reactor.Item))
|
||||
{
|
||||
if (engineer_reactor.AutoTempSwitch.FlashTimer <= 0)
|
||||
{
|
||||
engineer_reactor.AutoTempSwitch.Flash(highlightColor, 1.5f, false, false, new Vector2(10, 10));
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!engineer_reactor.AutoTemp);
|
||||
|
||||
float wait = 1.5f;
|
||||
do
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
wait -= 0.1f;
|
||||
engineer_reactor.AutoTemp = true;
|
||||
} while (wait > 0.0f);
|
||||
engineer.SelectedItem = null;
|
||||
engineer_reactor.CanBeSelected = false;
|
||||
RemoveCompletedObjective(2);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective2");
|
||||
SetHighlight(engineer_reactor.Item, false);
|
||||
SetHighlight(engineer_brokenJunctionBox, true);
|
||||
SetDoorAccess(engineer_secondDoor, engineer_secondDoorLight, true);
|
||||
|
||||
// Room 4
|
||||
do { yield return null; } while (!engineer_secondDoor.IsOpen);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
Repairable repairableJunctionBoxComponent = engineer_brokenJunctionBox.GetComponent<Repairable>();
|
||||
TriggerTutorialSegment(3, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select)); // Repair the junction box
|
||||
do
|
||||
{
|
||||
if (!engineer.HasEquippedItem("screwdriver".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(engineer.Inventory, "screwdriver".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
else if (IsSelectedItem(engineer_brokenJunctionBox) && repairableJunctionBoxComponent.CurrentFixer == null)
|
||||
{
|
||||
if (repairableJunctionBoxComponent.RepairButton.FlashTimer <= 0)
|
||||
{
|
||||
repairableJunctionBoxComponent.RepairButton.Flash();
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (repairableJunctionBoxComponent.IsBelowRepairThreshold); // Wait until repaired
|
||||
SetHighlight(engineer_brokenJunctionBox, false);
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective3");
|
||||
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, true);
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
SetHighlight(engineer_disconnectedJunctionBoxes[i].Item, true);
|
||||
}
|
||||
|
||||
// Room 5
|
||||
do { yield return null; } while (!engineer_thirdDoor.IsOpen);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.FaultyWiring"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(4, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Use), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Connect the junction boxes
|
||||
do { CheckGhostWires(); HandleJunctionBoxWiringHighlights(); yield return null; } while (engineer_workingPump.Voltage < engineer_workingPump.MinVoltage); // Wait until connected all the way to the pump
|
||||
CheckGhostWires();
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
SetHighlight(engineer_disconnectedJunctionBoxes[i].Item, false);
|
||||
}
|
||||
RemoveCompletedObjective(4);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective4");
|
||||
do { yield return null; } while (engineer_workingPump.Item.CurrentHull.WaterPercentage > waterVolumeBeforeOpening); // Wait until drained
|
||||
wiringActive = false;
|
||||
SetDoorAccess(engineer_fourthDoor, engineer_fourthDoorLight, true);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.ChangeOfPlans"), ChatMessageType.Radio, null);
|
||||
|
||||
// Submarine
|
||||
do { yield return null; } while (!tutorial_enteredSubmarineSensor.MotionDetected);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Submarine"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(5); // Repair junction box
|
||||
while (ContentRunning) yield return null;
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_1, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_2, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_3, engineer_repairIcon, engineer_repairIconColor);
|
||||
SetHighlight(engineer_submarineJunctionBox_1, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_2, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_3, true);
|
||||
|
||||
Repairable repairableJunctionBoxComponent1 = engineer_submarineJunctionBox_1.GetComponent<Repairable>();
|
||||
Repairable repairableJunctionBoxComponent2 = engineer_submarineJunctionBox_2.GetComponent<Repairable>();
|
||||
Repairable repairableJunctionBoxComponent3 = engineer_submarineJunctionBox_3.GetComponent<Repairable>();
|
||||
|
||||
// Remove highlights when each individual machine is repaired
|
||||
do { CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3); yield return null; } while (repairableJunctionBoxComponent1.IsBelowRepairThreshold || repairableJunctionBoxComponent2.IsBelowRepairThreshold || repairableJunctionBoxComponent3.IsBelowRepairThreshold);
|
||||
CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3);
|
||||
RemoveCompletedObjective(5);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective5");
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(6); // Powerup reactor
|
||||
SetHighlight(engineer_submarineReactor.Item, true);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineReactor.Item, engineer_reactorIcon, engineer_reactorIconColor);
|
||||
do { yield return null; } while (!IsReactorPoweredUp(engineer_submarineReactor)); // Wait until ~matches load
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineReactor.Item);
|
||||
SetHighlight(engineer_submarineReactor.Item, false);
|
||||
RemoveCompletedObjective(6);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective6");
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (wiringActive)
|
||||
{
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < engineer_disconnectedJunctionBoxes[i].PowerConnections.Count; j++)
|
||||
{
|
||||
engineer_disconnectedJunctionBoxes[i].PowerConnections[j].UpdateFlashTimer(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSelectedItem(Item item)
|
||||
{
|
||||
return engineer?.SelectedItem == item;
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> ReactorOperatedProperly()
|
||||
{
|
||||
float timer;
|
||||
|
||||
for (int i = 0; i < reactorLoads.Length; i++)
|
||||
{
|
||||
timer = reactorLoadChangeTime;
|
||||
tutorial_oxygenGenerator.PowerConsumption = reactorLoads[i];
|
||||
while (timer > 0)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
if (CoroutineManager.DeltaTime > 0.0f && IsReactorPoweredUp(engineer_reactor))
|
||||
{
|
||||
timer -= CoroutineManager.DeltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reactorOperatedProperly = true;
|
||||
}
|
||||
|
||||
private void CheckGhostWires()
|
||||
{
|
||||
Color wireColor =
|
||||
Color.Orange *
|
||||
MathHelper.Lerp(0.25f, 0.75f, (float)(Math.Sin((Timing.TotalTime * 4.0f)) + 1.0f) / 2.0f);
|
||||
|
||||
if (engineer_wire_1 != null)
|
||||
{
|
||||
engineer_wire_1.SpriteColor = wireColor;
|
||||
if (engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
|
||||
{
|
||||
engineer_wire_1.Remove();
|
||||
engineer_wire_1 = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (engineer_wire_2 != null)
|
||||
{
|
||||
engineer_wire_2.SpriteColor = wireColor;
|
||||
if (engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
|
||||
{
|
||||
engineer_wire_2.Remove();
|
||||
engineer_wire_2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void HandleJunctionBoxWiringHighlights()
|
||||
{
|
||||
Item selected = engineer.SelectedItem;
|
||||
|
||||
if (!engineer.HasEquippedItem("screwdriver".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(engineer.Inventory, "screwdriver".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
|
||||
int selectedIndex = -1;
|
||||
|
||||
if (selected != null)
|
||||
{
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
if (selected == engineer_disconnectedJunctionBoxes[i].Item)
|
||||
{
|
||||
selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wiringActive = selectedIndex != -1;
|
||||
|
||||
if (!engineer.HasEquippedItem("wire".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlotWithTag(engineer.Inventory, "wire".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wiringActive) return;
|
||||
for (int i = 0; i < engineer_disconnectedConnectionPanels[selectedIndex].Connections.Count; i++)
|
||||
{
|
||||
var connection = engineer_disconnectedConnectionPanels[selectedIndex].Connections[i];
|
||||
if (connection.IsPower && connection.FlashTimer <= 0)
|
||||
{
|
||||
foreach (Wire wire in engineer_disconnectedConnectionPanels[selectedIndex].Connections[i].Wires)
|
||||
{
|
||||
if (wire == null) continue;
|
||||
if (!wire.Locked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
connection.Flash(highlightColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckJunctionBoxHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
|
||||
{
|
||||
if (!comp1.IsBelowRepairThreshold && engineer_submarineJunctionBox_1.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_1, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_1);
|
||||
}
|
||||
if (!comp2.IsBelowRepairThreshold && engineer_submarineJunctionBox_2.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_2, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_2);
|
||||
}
|
||||
if (!comp3.IsBelowRepairThreshold && engineer_submarineJunctionBox_3.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_3, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_3);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsReactorPoweredUp(Reactor reactor)
|
||||
{
|
||||
float load = 0.0f;
|
||||
List<Connection> connections = reactor.Item.Connections;
|
||||
if (connections != null && connections.Count > 0)
|
||||
{
|
||||
foreach (Connection connection in connections)
|
||||
{
|
||||
if (!connection.IsPower) continue;
|
||||
foreach (Connection recipient in connection.Recipients)
|
||||
{
|
||||
if (!(recipient.Item is Item it)) continue;
|
||||
|
||||
PowerTransfer pt = it.GetComponent<PowerTransfer>();
|
||||
if (pt == null) continue;
|
||||
|
||||
load = Math.Max(load, pt.PowerLoad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Abs(load + reactor.CurrPowerConsumption) < reactorLoadError;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,737 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
class MechanicTutorial : ScenarioTutorial
|
||||
{
|
||||
// Other tutorial items
|
||||
private LightComponent tutorial_securityFinalDoorLight;
|
||||
private Door tutorial_upperFinalDoor;
|
||||
private Steering tutorial_submarineSteering;
|
||||
|
||||
// Room 1
|
||||
private float shakeTimer = 1f;
|
||||
private float shakeAmount = 20f;
|
||||
private Door mechanic_firstDoor;
|
||||
private LightComponent mechanic_firstDoorLight;
|
||||
|
||||
// Room 2
|
||||
private MotionSensor mechanic_equipmentObjectiveSensor;
|
||||
private ItemContainer mechanic_equipmentCabinet;
|
||||
private Door mechanic_secondDoor;
|
||||
private LightComponent mechanic_secondDoorLight;
|
||||
|
||||
// Room 3
|
||||
private MotionSensor mechanic_weldingObjectiveSensor;
|
||||
private Pump mechanic_workingPump;
|
||||
private Door mechanic_thirdDoor;
|
||||
private LightComponent mechanic_thirdDoorLight;
|
||||
private Structure mechanic_brokenWall_1;
|
||||
private Hull mechanic_brokenhull_1;
|
||||
|
||||
// Room 4
|
||||
private MotionSensor mechanic_craftingObjectiveSensor;
|
||||
private Deconstructor mechanic_deconstructor;
|
||||
private Fabricator mechanic_fabricator;
|
||||
private ItemContainer mechanic_craftingCabinet;
|
||||
private Door mechanic_fourthDoor;
|
||||
private LightComponent mechanic_fourthDoorLight;
|
||||
|
||||
// Room 5
|
||||
private MotionSensor mechanic_fireSensor;
|
||||
private DummyFireSource mechanic_fire;
|
||||
private Door mechanic_fifthDoor;
|
||||
private LightComponent mechanic_fifthDoorLight;
|
||||
|
||||
// Room 6
|
||||
private MotionSensor mechanic_divingSuitObjectiveSensor;
|
||||
private ItemContainer mechanic_divingSuitContainer;
|
||||
private ItemContainer mechanic_oxygenContainer;
|
||||
private Door tutorial_mechanicFinalDoor;
|
||||
private LightComponent tutorial_mechanicFinalDoorLight;
|
||||
|
||||
// Room 7
|
||||
private Pump mechanic_brokenPump;
|
||||
private Structure mechanic_brokenWall_2;
|
||||
private Hull mechanic_brokenhull_2;
|
||||
private Door tutorial_submarineDoor;
|
||||
private LightComponent tutorial_submarineDoorLight;
|
||||
|
||||
// Submarine
|
||||
private MotionSensor tutorial_enteredSubmarineSensor;
|
||||
private Engine mechanic_submarineEngine;
|
||||
private Pump mechanic_ballastPump_1;
|
||||
private Pump mechanic_ballastPump_2;
|
||||
|
||||
// Variables
|
||||
private const float waterVolumeBeforeOpening = 15f;
|
||||
private LocalizedString radioSpeakerName;
|
||||
private Character mechanic;
|
||||
private Sprite mechanic_repairIcon;
|
||||
private Color mechanic_repairIconColor;
|
||||
private Sprite mechanic_weldIcon;
|
||||
|
||||
public MechanicTutorial() : base("tutorial.mechanictraining".ToIdentifier(),
|
||||
new Segment(
|
||||
"Mechanic.OpenDoor".ToIdentifier(),
|
||||
"Mechanic.OpenDoorObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.OpenDoorText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.Equipment".ToIdentifier(),
|
||||
"Mechanic.EquipmentObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.EquipmentText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_inventory.webm", TextTag = "Mechanic.EquipmentText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Mechanic.Welding".ToIdentifier(),
|
||||
"Mechanic.WeldingObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.WeldingText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_equip.webm", TextTag = "Mechanic.WeldingText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Mechanic.Drain".ToIdentifier(),
|
||||
"Mechanic.DrainObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.DrainText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.Deconstruct".ToIdentifier(),
|
||||
"Mechanic.DeconstructObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.DeconstructText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_deconstruct.webm", TextTag = "Mechanic.DeconstructText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Mechanic.Fabricate".ToIdentifier(),
|
||||
"Mechanic.FabricateObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.FabricateText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_fabricate.webm", TextTag = "Mechanic.FabricateText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Mechanic.Extinguisher".ToIdentifier(),
|
||||
"Mechanic.ExtinguisherObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.ExtinguisherText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.DropExtinguisher".ToIdentifier(),
|
||||
"Mechanic.DropExtinguisherObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.DropExtinguisherText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.Diving".ToIdentifier(),
|
||||
"Mechanic.DivingObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.DivingText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.RepairPump".ToIdentifier(),
|
||||
"Mechanic.RepairPumpObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.RepairPumpText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Mechanic.RepairSubmarine".ToIdentifier(),
|
||||
"Mechanic.RepairSubmarineObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.RepairSubmarineText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"tutorial.laddertitle".ToIdentifier(),
|
||||
"tutorial.laddertitle".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "tutorial.ladderdescription".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }))
|
||||
{ }
|
||||
|
||||
protected override CharacterInfo GetCharacterInfo()
|
||||
{
|
||||
return new CharacterInfo(
|
||||
CharacterPrefab.HumanSpeciesName,
|
||||
jobOrJobPrefab: new Job(
|
||||
JobPrefab.Prefabs["mechanic"], Rand.RandSync.Unsynced, 0,
|
||||
new Skill("medical".ToIdentifier(), 0),
|
||||
new Skill("weapons".ToIdentifier(), 0),
|
||||
new Skill("mechanical".ToIdentifier(), 50),
|
||||
new Skill("electrical".ToIdentifier(), 20),
|
||||
new Skill("helm".ToIdentifier(), 0)));
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
mechanic = Character.Controlled;
|
||||
|
||||
foreach (Item item in mechanic.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
|
||||
mechanic_repairIcon = repairOrder.SymbolSprite;
|
||||
mechanic_repairIconColor = repairOrder.Color;
|
||||
mechanic_weldIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(1, 256, 127, 127), new Vector2(0.5f, 0.5f));
|
||||
|
||||
// Other tutorial items
|
||||
tutorial_securityFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoorlight")).GetComponent<LightComponent>();
|
||||
tutorial_upperFinalDoor = Item.ItemList.Find(i => i.HasTag("tutorial_upperfinaldoor")).GetComponent<Door>();
|
||||
tutorial_submarineSteering = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
|
||||
|
||||
tutorial_submarineSteering.CanBeSelected = false;
|
||||
foreach (ItemComponent ic in tutorial_submarineSteering.Item.Components)
|
||||
{
|
||||
ic.CanBeSelected = false;
|
||||
}
|
||||
|
||||
SetDoorAccess(null, tutorial_securityFinalDoorLight, false);
|
||||
SetDoorAccess(tutorial_upperFinalDoor, null, false);
|
||||
|
||||
// Room 1
|
||||
mechanic_firstDoor = Item.ItemList.Find(i => i.HasTag("mechanic_firstdoor")).GetComponent<Door>();
|
||||
mechanic_firstDoorLight = Item.ItemList.Find(i => i.HasTag("mechanic_firstdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(mechanic_firstDoor, mechanic_firstDoorLight, false);
|
||||
|
||||
// Room 2
|
||||
mechanic_equipmentObjectiveSensor = Item.ItemList.Find(i => i.HasTag("mechanic_equipmentobjectivesensor")).GetComponent<MotionSensor>();
|
||||
mechanic_equipmentCabinet = Item.ItemList.Find(i => i.HasTag("mechanic_equipmentcabinet")).GetComponent<ItemContainer>();
|
||||
mechanic_secondDoor = Item.ItemList.Find(i => i.HasTag("mechanic_seconddoor")).GetComponent<Door>();
|
||||
mechanic_secondDoorLight = Item.ItemList.Find(i => i.HasTag("mechanic_seconddoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(mechanic_secondDoor, mechanic_secondDoorLight, false);
|
||||
|
||||
// Room 3
|
||||
mechanic_weldingObjectiveSensor = Item.ItemList.Find(i => i.HasTag("mechanic_weldingobjectivesensor")).GetComponent<MotionSensor>();
|
||||
mechanic_workingPump = Item.ItemList.Find(i => i.HasTag("mechanic_workingpump")).GetComponent<Pump>();
|
||||
mechanic_thirdDoor = Item.ItemList.Find(i => i.HasTag("mechanic_thirddoor")).GetComponent<Door>();
|
||||
mechanic_thirdDoorLight = Item.ItemList.Find(i => i.HasTag("mechanic_thirddoorlight")).GetComponent<LightComponent>();
|
||||
mechanic_brokenWall_1 = Structure.WallList.Find(i => i.SpecialTag == "mechanic_brokenwall_1");
|
||||
//mechanic_ladderSensor = Item.ItemList.Find(i => i.HasTag("mechanic_laddersensor")).GetComponent<MotionSensor>();
|
||||
|
||||
SetDoorAccess(mechanic_thirdDoor, mechanic_thirdDoorLight, false);
|
||||
mechanic_brokenWall_1.Indestructible = false;
|
||||
mechanic_brokenWall_1.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_1.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_1.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_1 = mechanic_brokenWall_1.Sections[0].gap.FlowTargetHull;
|
||||
|
||||
// Room 4
|
||||
mechanic_craftingObjectiveSensor = Item.ItemList.Find(i => i.HasTag("mechanic_craftingobjectivesensor")).GetComponent<MotionSensor>();
|
||||
mechanic_deconstructor = Item.ItemList.Find(i => i.HasTag("mechanic_deconstructor")).GetComponent<Deconstructor>();
|
||||
mechanic_fabricator = Item.ItemList.Find(i => i.HasTag("mechanic_fabricator")).GetComponent<Fabricator>();
|
||||
mechanic_craftingCabinet = Item.ItemList.Find(i => i.HasTag("mechanic_craftingcabinet")).GetComponent<ItemContainer>();
|
||||
mechanic_fourthDoor = Item.ItemList.Find(i => i.HasTag("mechanic_fourthdoor")).GetComponent<Door>();
|
||||
mechanic_fourthDoorLight = Item.ItemList.Find(i => i.HasTag("mechanic_fourthdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(mechanic_fourthDoor, mechanic_fourthDoorLight, false);
|
||||
|
||||
// Room 5
|
||||
mechanic_fifthDoor = Item.ItemList.Find(i => i.HasTag("mechanic_fifthdoor")).GetComponent<Door>();
|
||||
mechanic_fifthDoorLight = Item.ItemList.Find(i => i.HasTag("mechanic_fifthdoorlight")).GetComponent<LightComponent>();
|
||||
mechanic_fireSensor = Item.ItemList.Find(i => i.HasTag("mechanic_firesensor")).GetComponent<MotionSensor>();
|
||||
|
||||
SetDoorAccess(mechanic_fifthDoor, mechanic_fifthDoorLight, false);
|
||||
|
||||
// Room 6
|
||||
mechanic_divingSuitObjectiveSensor = Item.ItemList.Find(i => i.HasTag("mechanic_divingsuitobjectivesensor")).GetComponent<MotionSensor>();
|
||||
mechanic_divingSuitContainer = Item.ItemList.Find(i => i.HasTag("mechanic_divingsuitcontainer")).GetComponent<ItemContainer>();
|
||||
foreach (Item item in mechanic_divingSuitContainer.Inventory.AllItems)
|
||||
{
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
ic.CanBePicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
mechanic_oxygenContainer = Item.ItemList.Find(i => i.HasTag("mechanic_oxygencontainer")).GetComponent<ItemContainer>();
|
||||
foreach (Item item in mechanic_oxygenContainer.Inventory.AllItems)
|
||||
{
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
ic.CanBePicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
tutorial_mechanicFinalDoor = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoor")).GetComponent<Door>();
|
||||
tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, false);
|
||||
|
||||
// Room 7
|
||||
mechanic_brokenPump = Item.ItemList.Find(i => i.HasTag("mechanic_brokenpump")).GetComponent<Pump>();
|
||||
mechanic_brokenPump.Item.Indestructible = false;
|
||||
mechanic_brokenPump.Item.Condition = 0;
|
||||
mechanic_brokenPump.CanBeSelected = false;
|
||||
mechanic_brokenPump.Item.GetComponent<Repairable>().CanBeSelected = false;
|
||||
mechanic_brokenWall_2 = Structure.WallList.Find(i => i.SpecialTag == "mechanic_brokenwall_2");
|
||||
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
|
||||
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
mechanic_brokenWall_2.Indestructible = false;
|
||||
mechanic_brokenWall_2.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_2.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_2.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_2 = mechanic_brokenWall_2.Sections[0].gap.FlowTargetHull;
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
|
||||
// Submarine
|
||||
tutorial_enteredSubmarineSensor = Item.ItemList.Find(i => i.HasTag("tutorial_enteredsubmarinesensor")).GetComponent<MotionSensor>();
|
||||
mechanic_submarineEngine = Item.ItemList.Find(i => i.HasTag("mechanic_submarineengine")).GetComponent<Engine>();
|
||||
mechanic_submarineEngine.Item.Indestructible = false;
|
||||
mechanic_submarineEngine.Item.Condition = 0f;
|
||||
mechanic_ballastPump_1 = Item.ItemList.Find(i => i.HasTag("mechanic_ballastpump_1")).GetComponent<Pump>();
|
||||
mechanic_ballastPump_1.Item.Indestructible = false;
|
||||
mechanic_ballastPump_1.Item.Condition = 0f;
|
||||
mechanic_ballastPump_2 = Item.ItemList.Find(i => i.HasTag("mechanic_ballastpump_2")).GetComponent<Pump>();
|
||||
mechanic_ballastPump_2.Item.Indestructible = false;
|
||||
mechanic_ballastPump_2.Item.Condition = 0f;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Started");
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Started");
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (mechanic_brokenhull_1 != null)
|
||||
{
|
||||
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
|
||||
}
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
public override IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen) yield return null;
|
||||
|
||||
// Room 1
|
||||
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
|
||||
while (shakeTimer > 0.0f) // Wake up, shake
|
||||
{
|
||||
shakeTimer -= 0.1f;
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
}
|
||||
yield return new WaitForSeconds(2.5f, false);
|
||||
|
||||
mechanic_fabricator.RemoveFabricationRecipes(allowedIdentifiers:
|
||||
new[] { "extinguisher", "wrench", "weldingtool", "weldingfuel", "divingmask", "railgunshell", "nuclearshell", "uex", "harpoongun" }.ToIdentifiers());
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.WakeUp"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(2.5f, false);
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Up), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Left), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Down), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Right), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select)); // Open door objective
|
||||
yield return new WaitForSeconds(0.0f, false);
|
||||
SetDoorAccess(mechanic_firstDoor, mechanic_firstDoorLight, true);
|
||||
SetHighlight(mechanic_firstDoor.Item, true);
|
||||
do { yield return null; } while (!mechanic_firstDoor.IsOpen);
|
||||
SetHighlight(mechanic_firstDoor.Item, false);
|
||||
yield return new WaitForSeconds(1.5f, false);
|
||||
RemoveCompletedObjective(0);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective0");
|
||||
|
||||
// Room 2
|
||||
yield return new WaitForSeconds(0.0f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Equipment & inventory objective
|
||||
SetHighlight(mechanic_equipmentCabinet.Item, true);
|
||||
bool firstSlotRemoved = false;
|
||||
bool secondSlotRemoved = false;
|
||||
bool thirdSlotRemoved = false;
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(mechanic_equipmentCabinet.Item))
|
||||
{
|
||||
if (!firstSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
if (mechanic_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!secondSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
|
||||
if (mechanic_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!thirdSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
|
||||
if (mechanic_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
|
||||
}
|
||||
|
||||
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
|
||||
{
|
||||
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
|
||||
yield return null;
|
||||
} while (mechanic.Inventory.FindItemByIdentifier("divingmask".ToIdentifier()) == null || mechanic.Inventory.FindItemByIdentifier("weldingtool".ToIdentifier()) == null || mechanic.Inventory.FindItemByIdentifier("wrench".ToIdentifier()) == null); // Wait until looted
|
||||
SetHighlight(mechanic_equipmentCabinet.Item, false);
|
||||
yield return new WaitForSeconds(1.5f, false);
|
||||
RemoveCompletedObjective(1);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective1");
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Breach"), ChatMessageType.Radio, null);
|
||||
|
||||
// Room 3
|
||||
do { yield return null; } while (!mechanic_weldingObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Welding objective
|
||||
do
|
||||
{
|
||||
if (!mechanic.HasEquippedItem("divingmask".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "divingmask".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
|
||||
if (!mechanic.HasEquippedItem("weldingtool".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "weldingtool".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (!mechanic.HasEquippedItem("divingmask".ToIdentifier()) || !mechanic.HasEquippedItem("weldingtool".ToIdentifier())); // Wait until equipped
|
||||
SetDoorAccess(mechanic_secondDoor, mechanic_secondDoorLight, true);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_1, mechanic_weldIcon, mechanic_repairIconColor);
|
||||
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_1)); // Highlight until repaired
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_1);
|
||||
RemoveCompletedObjective(2);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective2");
|
||||
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
TriggerTutorialSegment(3, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select)); // Pump objective
|
||||
SetHighlight(mechanic_workingPump.Item, true);
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
if (IsSelectedItem(mechanic_workingPump.Item))
|
||||
{
|
||||
if (mechanic_workingPump.PowerButton.FlashTimer <= 0)
|
||||
{
|
||||
mechanic_workingPump.PowerButton.Flash(uiHighlightColor, 1.5f, true);
|
||||
}
|
||||
}
|
||||
} while (mechanic_workingPump.FlowPercentage >= 0 || !mechanic_workingPump.IsActive); // Highlight until draining
|
||||
SetHighlight(mechanic_workingPump.Item, false);
|
||||
do { yield return null; } while (mechanic_brokenhull_1 != null && mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective3");
|
||||
|
||||
SetDoorAccess(mechanic_thirdDoor, mechanic_thirdDoorLight, true);
|
||||
//TriggerTutorialSegment(11, GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Select], GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Up], GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Down], GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Select]); // Ladder objective
|
||||
//do { yield return null; } while (!mechanic_ladderSensor.MotionDetected);
|
||||
//RemoveCompletedObjective(segments[11]);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.News"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Fire"), ChatMessageType.Radio, null);
|
||||
|
||||
// Room 4
|
||||
do { yield return null; } while (!mechanic_thirdDoor.IsOpen);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
mechanic_fire = new DummyFireSource(new Vector2(20f, 2f), Item.ItemList.Find(i => i.HasTag("mechanic_fire")).WorldPosition);
|
||||
//do { yield return null; } while (!mechanic_craftingObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(4); // Deconstruct
|
||||
|
||||
SetHighlight(mechanic_craftingCabinet.Item, true);
|
||||
|
||||
bool gotOxygenTank = false;
|
||||
bool gotSodium = false;
|
||||
do
|
||||
{
|
||||
if (mechanic.SelectedItem == mechanic_craftingCabinet.Item)
|
||||
{
|
||||
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
|
||||
{
|
||||
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
|
||||
if (mechanic.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) == null && mechanic.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) == null)
|
||||
{
|
||||
for (int i = 0; i < mechanic_craftingCabinet.Capacity; i++)
|
||||
{
|
||||
Item item = mechanic_craftingCabinet.Inventory.GetItemAt(i);
|
||||
if (item != null && item.Prefab.Identifier == "oxygentank")
|
||||
{
|
||||
HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mechanic.Inventory.FindItemByIdentifier("sodium".ToIdentifier()) == null)
|
||||
{
|
||||
for (int i = 0; i < mechanic_craftingCabinet.Inventory.Capacity; i++)
|
||||
{
|
||||
Item item = mechanic_craftingCabinet.Inventory.GetItemAt(i);
|
||||
if (item != null && item.Prefab.Identifier == "sodium")
|
||||
{
|
||||
HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotOxygenTank && (mechanic.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) != null ||
|
||||
mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) != null))
|
||||
{
|
||||
gotOxygenTank = true;
|
||||
}
|
||||
if (!gotSodium && mechanic.Inventory.FindItemByIdentifier("sodium".ToIdentifier()) != null)
|
||||
{
|
||||
gotSodium = true;
|
||||
}
|
||||
yield return null;
|
||||
} while (!gotOxygenTank || !gotSodium); // Wait until looted
|
||||
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
SetHighlight(mechanic_craftingCabinet.Item, false);
|
||||
SetHighlight(mechanic_deconstructor.Item, true);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(mechanic_deconstructor.Item))
|
||||
{
|
||||
if (mechanic_deconstructor.OutputContainer.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) != null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_deconstructor.OutputContainer.Inventory, "aluminium".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
|
||||
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
|
||||
{
|
||||
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mechanic.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) != null && mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) == null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "oxygentank".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.Capacity; i++)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank".ToIdentifier()) != null && !mechanic_deconstructor.IsActive)
|
||||
{
|
||||
if (mechanic_deconstructor.ActivateButton.FlashTimer <= 0)
|
||||
{
|
||||
mechanic_deconstructor.ActivateButton.Flash(highlightColor, 1.5f, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (
|
||||
mechanic.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) == null &&
|
||||
mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) == null); // Wait until aluminium obtained
|
||||
|
||||
SetHighlight(mechanic_deconstructor.Item, false);
|
||||
RemoveCompletedObjective(4);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective4");
|
||||
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
TriggerTutorialSegment(5); // Fabricate
|
||||
SetHighlight(mechanic_fabricator.Item, true);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(mechanic_fabricator.Item))
|
||||
{
|
||||
if (mechanic_fabricator.SelectedItem?.TargetItem.Identifier != "extinguisher")
|
||||
{
|
||||
mechanic_fabricator.HighlightRecipe("extinguisher", highlightColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mechanic_fabricator.OutputContainer.Inventory.FindItemByIdentifier("extinguisher".ToIdentifier()) != null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_fabricator.OutputContainer.Inventory, "extinguisher".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
|
||||
/*for (int i = 0; i < mechanic.Inventory.Capacity; i++)
|
||||
{
|
||||
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}*/
|
||||
}
|
||||
else if (mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) != null && mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("sodium".ToIdentifier()) != null && !mechanic_fabricator.IsActive)
|
||||
{
|
||||
if (mechanic_fabricator.ActivateButton.FlashTimer <= 0)
|
||||
{
|
||||
mechanic_fabricator.ActivateButton.Flash(highlightColor, 1.5f, false);
|
||||
}
|
||||
}
|
||||
else if (mechanic.Inventory.FindItemByIdentifier("aluminium".ToIdentifier()) != null || mechanic.Inventory.FindItemByIdentifier("sodium".ToIdentifier()) != null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "aluminium".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
HighlightInventorySlot(mechanic.Inventory, "sodium".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
|
||||
if (mechanic_fabricator.InputContainer.Inventory.GetItemAt(0) == null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
|
||||
if (mechanic_fabricator.InputContainer.Inventory.GetItemAt(1) == null)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 1, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (mechanic.Inventory.FindItemByIdentifier("extinguisher".ToIdentifier()) == null); // Wait until extinguisher is created
|
||||
RemoveCompletedObjective(5);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective5");
|
||||
SetHighlight(mechanic_fabricator.Item, false);
|
||||
SetDoorAccess(mechanic_fourthDoor, mechanic_fourthDoorLight, true);
|
||||
|
||||
// Room 5
|
||||
do { yield return null; } while (!mechanic_fireSensor.MotionDetected);
|
||||
TriggerTutorialSegment(6, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Using the extinguisher
|
||||
do { yield return null; } while (!mechanic_fire.Removed); // Wait until extinguished
|
||||
yield return new WaitForSeconds(3f, false);
|
||||
RemoveCompletedObjective(6);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective6");
|
||||
|
||||
if (mechanic.HasEquippedItem("extinguisher".ToIdentifier())) // do not trigger if dropped already
|
||||
{
|
||||
TriggerTutorialSegment(7);
|
||||
do
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "extinguisher".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
yield return null;
|
||||
} while (mechanic.HasEquippedItem("extinguisher".ToIdentifier()));
|
||||
RemoveCompletedObjective(7);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective7");
|
||||
}
|
||||
SetDoorAccess(mechanic_fifthDoor, mechanic_fifthDoorLight, true);
|
||||
|
||||
// Room 6
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Diving"), ChatMessageType.Radio, null);
|
||||
do { yield return null; } while (!mechanic_divingSuitObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(8); // Dangers of pressure, equip diving suit objective
|
||||
SetHighlight(mechanic_divingSuitContainer.Item, true);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(mechanic_divingSuitContainer.Item))
|
||||
{
|
||||
if (mechanic_divingSuitContainer.Inventory.visualSlots != null)
|
||||
{
|
||||
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.Capacity; i++)
|
||||
{
|
||||
HighlightInventorySlot(mechanic_divingSuitContainer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!mechanic.HasEquippedItem("divingsuit".ToIdentifier(), slotType: InvSlotType.OuterClothes));
|
||||
SetHighlight(mechanic_divingSuitContainer.Item, false);
|
||||
RemoveCompletedObjective(8);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective8");
|
||||
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, true);
|
||||
|
||||
// Room 7
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_weldIcon, mechanic_repairIconColor);
|
||||
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2));
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(9, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Use)); // Repairing machinery (pump)
|
||||
SetHighlight(mechanic_brokenPump.Item, true);
|
||||
mechanic_brokenPump.CanBeSelected = true;
|
||||
Repairable repairablePumpComponent = mechanic_brokenPump.Item.GetComponent<Repairable>();
|
||||
repairablePumpComponent.CanBeSelected = true;
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
if (repairablePumpComponent.IsBelowRepairThreshold)
|
||||
{
|
||||
if (!mechanic.HasEquippedItem("wrench".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(mechanic.Inventory, "wrench".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
else if (IsSelectedItem(mechanic_brokenPump.Item) && repairablePumpComponent.CurrentFixer == null)
|
||||
{
|
||||
if (repairablePumpComponent.RepairButton.FlashTimer <= 0)
|
||||
{
|
||||
repairablePumpComponent.RepairButton.Flash();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsSelectedItem(mechanic_brokenPump.Item))
|
||||
{
|
||||
if (mechanic_brokenPump.PowerButton.FlashTimer <= 0)
|
||||
{
|
||||
mechanic_brokenPump.PowerButton.Flash(uiHighlightColor, 1.5f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (repairablePumpComponent.IsBelowRepairThreshold || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
|
||||
RemoveCompletedObjective(9);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective9");
|
||||
SetHighlight(mechanic_brokenPump.Item, false);
|
||||
do { yield return null; } while (mechanic_brokenhull_2.WaterPercentage > waterVolumeBeforeOpening);
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
|
||||
|
||||
// Submarine
|
||||
do { yield return null; } while (!tutorial_enteredSubmarineSensor.MotionDetected);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Submarine"), ChatMessageType.Radio, null);
|
||||
TriggerTutorialSegment(10); // Repairing ballast pumps, engine
|
||||
while (ContentRunning) yield return null;
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_ballastPump_1.Item, mechanic_repairIcon, mechanic_repairIconColor);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_ballastPump_2.Item, mechanic_repairIcon, mechanic_repairIconColor);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_submarineEngine.Item, mechanic_repairIcon, mechanic_repairIconColor);
|
||||
SetHighlight(mechanic_ballastPump_1.Item, true);
|
||||
SetHighlight(mechanic_ballastPump_2.Item, true);
|
||||
SetHighlight(mechanic_submarineEngine.Item, true);
|
||||
|
||||
Repairable repairablePumpComponent1 = mechanic_ballastPump_1.Item.GetComponent<Repairable>();
|
||||
Repairable repairablePumpComponent2 = mechanic_ballastPump_2.Item.GetComponent<Repairable>();
|
||||
Repairable repairableEngineComponent = mechanic_submarineEngine.Item.GetComponent<Repairable>();
|
||||
|
||||
// Remove highlights when each individual machine is repaired
|
||||
do { CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent); yield return null; } while (repairablePumpComponent1.IsBelowRepairThreshold || repairablePumpComponent2.IsBelowRepairThreshold || repairableEngineComponent.IsBelowRepairThreshold);
|
||||
CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent);
|
||||
RemoveCompletedObjective(10);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective10");
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
// END TUTORIAL
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
private bool IsSelectedItem(Item item)
|
||||
{
|
||||
return mechanic?.SelectedItem == item;
|
||||
}
|
||||
|
||||
private bool WallHasDamagedSections(Structure wall)
|
||||
{
|
||||
for (int i = 0; i < wall.SectionCount; i++)
|
||||
{
|
||||
if (wall.Sections[i].damage > 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CheckHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
|
||||
{
|
||||
if (!comp1.IsBelowRepairThreshold && mechanic_ballastPump_1.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_ballastPump_1.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_1.Item);
|
||||
}
|
||||
if (!comp2.IsBelowRepairThreshold && mechanic_ballastPump_2.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_ballastPump_2.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_2.Item);
|
||||
}
|
||||
if (!comp3.IsBelowRepairThreshold && mechanic_submarineEngine.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_submarineEngine.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_submarineEngine.Item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,526 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
class OfficerTutorial : ScenarioTutorial
|
||||
{
|
||||
// Other tutorial items
|
||||
private LightComponent tutorial_mechanicFinalDoorLight;
|
||||
private Steering tutorial_submarineSteering;
|
||||
|
||||
// Room 1
|
||||
private float shakeTimer = 1f;
|
||||
private float shakeAmount = 20f;
|
||||
|
||||
// Room 2
|
||||
private MotionSensor officer_equipmentObjectiveSensor;
|
||||
private ItemContainer officer_equipmentCabinet;
|
||||
private Door officer_firstDoor;
|
||||
private LightComponent officer_firstDoorLight;
|
||||
|
||||
// Room 3
|
||||
private MotionSensor officer_crawlerSensor;
|
||||
private Character officer_crawler;
|
||||
private Vector2 officer_crawlerSpawnPos;
|
||||
private Door officer_secondDoor;
|
||||
private LightComponent officer_secondDoorLight;
|
||||
|
||||
// Room 4
|
||||
private MotionSensor officer_somethingBigSensor;
|
||||
private ItemContainer officer_coilgunLoader;
|
||||
private ItemContainer officer_ammoShelf_1;
|
||||
private ItemContainer officer_ammoShelf_2;
|
||||
private PowerContainer officer_superCapacitor;
|
||||
private Item officer_coilgunPeriscope;
|
||||
private Character officer_hammerhead;
|
||||
private Vector2 officer_hammerheadSpawnPos;
|
||||
private Door officer_thirdDoor;
|
||||
private LightComponent officer_thirdDoorLight;
|
||||
|
||||
// Room 5
|
||||
private MotionSensor officer_rangedWeaponSensor;
|
||||
private ItemContainer officer_rangedWeaponCabinet;
|
||||
private ItemContainer officer_rangedWeaponHolder;
|
||||
private Door officer_fourthDoor;
|
||||
private LightComponent officer_fourthDoorLight;
|
||||
|
||||
// Room 6
|
||||
private MotionSensor officer_mudraptorObjectiveSensor;
|
||||
private Vector2 officer_mudraptorSpawnPos;
|
||||
private Character officer_mudraptor;
|
||||
private Door tutorial_securityFinalDoor;
|
||||
private LightComponent tutorial_securityFinalDoorLight;
|
||||
|
||||
// Submarine
|
||||
private Door tutorial_submarineDoor;
|
||||
private LightComponent tutorial_submarineDoorLight;
|
||||
private MotionSensor tutorial_enteredSubmarineSensor;
|
||||
private Item officer_subAmmoBox_1;
|
||||
private Item officer_subAmmoBox_2;
|
||||
private ItemContainer officer_subAmmoShelf;
|
||||
private ItemContainer officer_subLoader_1;
|
||||
private ItemContainer officer_subLoader_2;
|
||||
private PowerContainer officer_subSuperCapacitor_1;
|
||||
private PowerContainer officer_subSuperCapacitor_2;
|
||||
|
||||
// Variables
|
||||
private LocalizedString radioSpeakerName;
|
||||
private Character officer;
|
||||
private float superCapacitorRechargeRate = 10;
|
||||
private Sprite officer_gunIcon;
|
||||
private Color officer_gunIconColor;
|
||||
|
||||
public OfficerTutorial() : base("tutorial.securityofficertraining".ToIdentifier(),
|
||||
new Segment(
|
||||
"Mechanic.Equipment".ToIdentifier(),
|
||||
"Mechanic.EquipmentObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Mechanic.EquipmentText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Officer.MeleeWeapon".ToIdentifier(),
|
||||
"Officer.MeleeWeaponObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Officer.MeleeWeaponText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Officer.Crawler".ToIdentifier(),
|
||||
"Officer.CrawlerObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Officer.CrawlerText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Officer.SomethingBig".ToIdentifier(),
|
||||
"Officer.SomethingBigObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Officer.SomethingBigText".ToIdentifier(), Width = 700, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_loaders.webm", TextTag = "Officer.SomethingBigText".ToIdentifier(), Width = 700, Height = 80 }),
|
||||
new Segment(
|
||||
"Officer.Hammerhead".ToIdentifier(),
|
||||
"Officer.HammerheadObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Officer.HammerheadText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Officer.RangedWeapon".ToIdentifier(),
|
||||
"Officer.RangedWeaponObjective".ToIdentifier(),
|
||||
TutorialContentType.ManualVideo,
|
||||
textContent: new Segment.Text { Tag = "Officer.RangedWeaponText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center },
|
||||
videoContent: new Segment.Video { File = "tutorial_ranged.webm", TextTag = "Officer.RangedWeaponText".ToIdentifier(), Width = 450, Height = 80 }),
|
||||
new Segment(
|
||||
"Officer.Mudraptor".ToIdentifier(),
|
||||
"Officer.MudraptorObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Officer.MudraptorText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }),
|
||||
new Segment(
|
||||
"Officer.ArmSubmarine".ToIdentifier(),
|
||||
"Officer.ArmSubmarineObjective".ToIdentifier(),
|
||||
TutorialContentType.TextOnly,
|
||||
textContent: new Segment.Text { Tag = "Officer.ArmSubmarineText".ToIdentifier(), Width = 450, Height = 80, Anchor = Anchor.Center }))
|
||||
{ }
|
||||
|
||||
protected override CharacterInfo GetCharacterInfo()
|
||||
{
|
||||
return new CharacterInfo(
|
||||
CharacterPrefab.HumanSpeciesName,
|
||||
jobOrJobPrefab: new Job(
|
||||
JobPrefab.Prefabs["securityofficer"], Rand.RandSync.Unsynced, 0,
|
||||
new Skill("medical".ToIdentifier(), 20),
|
||||
new Skill("weapons".ToIdentifier(), 70),
|
||||
new Skill("mechanical".ToIdentifier(), 20),
|
||||
new Skill("electrical".ToIdentifier(), 20),
|
||||
new Skill("helm".ToIdentifier(), 20)));
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
officer = Character.Controlled;
|
||||
|
||||
foreach (Item item in officer.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var gunOrder = OrderPrefab.Prefabs["operateweapons"];
|
||||
officer_gunIcon = gunOrder.SymbolSprite;
|
||||
officer_gunIconColor = gunOrder.Color;
|
||||
|
||||
var bandage = FindOrGiveItem(officer, "antibleeding1".ToIdentifier());
|
||||
bandage.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(bandage);
|
||||
FindOrGiveItem(officer, "antibleeding1".ToIdentifier());
|
||||
|
||||
// Other tutorial items
|
||||
tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent<LightComponent>();
|
||||
tutorial_submarineSteering = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
|
||||
|
||||
tutorial_submarineSteering.CanBeSelected = false;
|
||||
foreach (ItemComponent ic in tutorial_submarineSteering.Item.Components)
|
||||
{
|
||||
ic.CanBeSelected = false;
|
||||
}
|
||||
|
||||
SetDoorAccess(null, tutorial_mechanicFinalDoorLight, false);
|
||||
|
||||
// Room 2
|
||||
officer_equipmentObjectiveSensor = Item.ItemList.Find(i => i.HasTag("officer_equipmentobjectivesensor")).GetComponent<MotionSensor>();
|
||||
officer_equipmentCabinet = Item.ItemList.Find(i => i.HasTag("officer_equipmentcabinet")).GetComponent<ItemContainer>();
|
||||
officer_firstDoor = Item.ItemList.Find(i => i.HasTag("officer_firstdoor")).GetComponent<Door>();
|
||||
officer_firstDoorLight = Item.ItemList.Find(i => i.HasTag("officer_firstdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(officer_firstDoor, officer_firstDoorLight, false);
|
||||
|
||||
// Room 3
|
||||
officer_crawlerSensor = Item.ItemList.Find(i => i.HasTag("officer_crawlerobjectivesensor")).GetComponent<MotionSensor>();
|
||||
officer_crawlerSpawnPos = Item.ItemList.Find(i => i.HasTag("officer_crawlerspawn")).WorldPosition;
|
||||
officer_secondDoor = Item.ItemList.Find(i => i.HasTag("officer_seconddoor")).GetComponent<Door>();
|
||||
officer_secondDoorLight = Item.ItemList.Find(i => i.HasTag("officer_seconddoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(officer_secondDoor, officer_secondDoorLight, false);
|
||||
|
||||
// Room 4
|
||||
officer_somethingBigSensor = Item.ItemList.Find(i => i.HasTag("officer_somethingbigobjectivesensor")).GetComponent<MotionSensor>();
|
||||
officer_coilgunLoader = Item.ItemList.Find(i => i.HasTag("officer_coilgunloader")).GetComponent<ItemContainer>();
|
||||
officer_superCapacitor = Item.ItemList.Find(i => i.HasTag("officer_supercapacitor")).GetComponent<PowerContainer>();
|
||||
officer_coilgunPeriscope = Item.ItemList.Find(i => i.HasTag("officer_coilgunperiscope"));
|
||||
officer_hammerheadSpawnPos = Item.ItemList.Find(i => i.HasTag("officer_hammerheadspawn")).WorldPosition;
|
||||
officer_thirdDoor = Item.ItemList.Find(i => i.HasTag("officer_thirddoor")).GetComponent<Door>();
|
||||
officer_thirdDoorLight = Item.ItemList.Find(i => i.HasTag("officer_thirddoorlight")).GetComponent<LightComponent>();
|
||||
officer_ammoShelf_1 = Item.ItemList.Find(i => i.HasTag("officer_ammoshelf_1")).GetComponent<ItemContainer>();
|
||||
officer_ammoShelf_2 = Item.ItemList.Find(i => i.HasTag("officer_ammoshelf_2")).GetComponent<ItemContainer>();
|
||||
|
||||
SetDoorAccess(officer_thirdDoor, officer_thirdDoorLight, false);
|
||||
|
||||
// Room 5
|
||||
officer_rangedWeaponSensor = Item.ItemList.Find(i => i.HasTag("officer_rangedweaponobjectivesensor")).GetComponent<MotionSensor>();
|
||||
officer_rangedWeaponCabinet = Item.ItemList.Find(i => i.HasTag("officer_rangedweaponcabinet")).GetComponent<ItemContainer>();
|
||||
officer_rangedWeaponHolder = Item.ItemList.Find(i => i.HasTag("officer_rangedweaponholder")).GetComponent<ItemContainer>();
|
||||
officer_fourthDoor = Item.ItemList.Find(i => i.HasTag("officer_fourthdoor")).GetComponent<Door>();
|
||||
officer_fourthDoorLight = Item.ItemList.Find(i => i.HasTag("officer_fourthdoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, false);
|
||||
|
||||
// Room 6
|
||||
officer_mudraptorObjectiveSensor = Item.ItemList.Find(i => i.HasTag("officer_mudraptorobjectivesensor")).GetComponent<MotionSensor>();
|
||||
officer_mudraptorSpawnPos = Item.ItemList.Find(i => i.HasTag("officer_mudraptorspawn")).WorldPosition;
|
||||
tutorial_securityFinalDoor = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoor")).GetComponent<Door>();
|
||||
tutorial_securityFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoorlight")).GetComponent<LightComponent>();
|
||||
|
||||
SetDoorAccess(tutorial_securityFinalDoor, tutorial_securityFinalDoorLight, false);
|
||||
|
||||
// Submarine
|
||||
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
|
||||
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
|
||||
tutorial_enteredSubmarineSensor = Item.ItemList.Find(i => i.HasTag("tutorial_enteredsubmarinesensor")).GetComponent<MotionSensor>();
|
||||
officer_subAmmoBox_1 = Item.ItemList.Find(i => i.HasTag("officer_subammobox_1"));
|
||||
officer_subAmmoBox_2 = Item.ItemList.Find(i => i.HasTag("officer_subammobox_2"));
|
||||
officer_subLoader_1 = Item.ItemList.Find(i => i.HasTag("officer_subloader_1")).GetComponent<ItemContainer>();
|
||||
officer_subLoader_2 = Item.ItemList.Find(i => i.HasTag("officer_subloader_2")).GetComponent<ItemContainer>();
|
||||
officer_subSuperCapacitor_1 = Item.ItemList.Find(i => i.HasTag("officer_subsupercapacitor_1")).GetComponent<PowerContainer>();
|
||||
officer_subSuperCapacitor_2 = Item.ItemList.Find(i => i.HasTag("officer_subsupercapacitor_2")).GetComponent<PowerContainer>();
|
||||
officer_subAmmoShelf = Item.ItemList.Find(i => i.HasTag("officer_subammoshelf")).GetComponent<ItemContainer>();
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Started");
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Started");
|
||||
}
|
||||
|
||||
public override IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen) yield return null;
|
||||
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
|
||||
// Room 1
|
||||
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
|
||||
while (shakeTimer > 0.0f) // Wake up, shake
|
||||
{
|
||||
shakeTimer -= 0.1f;
|
||||
GameMain.GameScreen.Cam.Shake = shakeAmount;
|
||||
yield return new WaitForSeconds(0.1f, false);
|
||||
}
|
||||
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.WakeUp"), ChatMessageType.Radio, null);
|
||||
|
||||
// Room 2
|
||||
do { yield return null; } while (!officer_equipmentObjectiveSensor.MotionDetected);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(3f, false);
|
||||
//TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Select], GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Deselect]); // Retrieve equipment
|
||||
SetHighlight(officer_equipmentCabinet.Item, true);
|
||||
bool firstSlotRemoved = false;
|
||||
bool secondSlotRemoved = false;
|
||||
bool thirdSlotRemoved = false;
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(officer_equipmentCabinet.Item))
|
||||
{
|
||||
if (!firstSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
if (officer_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!secondSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
|
||||
if (officer_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
|
||||
}
|
||||
|
||||
if (!thirdSlotRemoved)
|
||||
{
|
||||
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
|
||||
if (officer_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
|
||||
}
|
||||
|
||||
for (int i = 0; i < officer.Inventory.visualSlots.Length; i++)
|
||||
{
|
||||
if (officer.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(officer.Inventory, i, highlightColor, .5f, .5f, 0f); }
|
||||
}
|
||||
}
|
||||
|
||||
yield return null;
|
||||
} while (!officer_equipmentCabinet.Inventory.IsEmpty()); // Wait until looted
|
||||
//RemoveCompletedObjective(segments[0]);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective0");
|
||||
SetHighlight(officer_equipmentCabinet.Item, false);
|
||||
do { yield return null; } while (IsSelectedItem(officer_equipmentCabinet.Item));
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Equip melee weapon & armor
|
||||
do
|
||||
{
|
||||
if (!officer.HasEquippedItem("stunbaton".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "stunbaton".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
if (!officer.HasEquippedItem("bodyarmor".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "bodyarmor".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
if (!officer.HasEquippedItem("ballistichelmet1".ToIdentifier()))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "ballistichelmet1".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
} while (!officer.HasEquippedItem("stunbaton".ToIdentifier()) || !officer.HasEquippedItem("bodyarmor".ToIdentifier()) || !officer.HasEquippedItem("ballistichelmet1".ToIdentifier()));
|
||||
RemoveCompletedObjective(1);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective1");
|
||||
SetDoorAccess(officer_firstDoor, officer_firstDoorLight, true);
|
||||
|
||||
// Room 3
|
||||
do { yield return null; } while (!officer_crawlerSensor.MotionDetected);
|
||||
TriggerTutorialSegment(2);
|
||||
officer_crawler = SpawnMonster("crawler", officer_crawlerSpawnPos);
|
||||
do { yield return null; } while (!officer_crawler.IsDead);
|
||||
RemoveCompletedObjective(2);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective2");
|
||||
Heal(officer);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.CrawlerDead"), ChatMessageType.Radio, null);
|
||||
SetDoorAccess(officer_secondDoor, officer_secondDoorLight, true);
|
||||
|
||||
// Room 4
|
||||
do { yield return null; } while (!officer_somethingBigSensor.MotionDetected);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.SomethingBig"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(3); // Arm coilgun
|
||||
do
|
||||
{
|
||||
SetHighlight(officer_coilgunLoader.Item, officer_coilgunLoader.Inventory.GetItemAt(0) == null || officer_coilgunLoader.Inventory.GetItemAt(0).Condition == 0);
|
||||
HighlightInventorySlot(officer_coilgunLoader.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
SetHighlight(officer_superCapacitor.Item, officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate);
|
||||
SetHighlight(officer_ammoShelf_1.Item, officer_coilgunLoader.Item.ExternalHighlight );
|
||||
SetHighlight(officer_ammoShelf_2.Item, officer_coilgunLoader.Item.ExternalHighlight );
|
||||
if (IsSelectedItem(officer_coilgunLoader.Item))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "coilgunammobox".ToIdentifier(), highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (officer_coilgunLoader.Inventory.GetItemAt(0) == null || officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate || officer_coilgunLoader.Inventory.GetItemAt(0).Condition == 0);
|
||||
SetHighlight(officer_coilgunLoader.Item, false);
|
||||
SetHighlight(officer_superCapacitor.Item, false);
|
||||
SetHighlight(officer_ammoShelf_1.Item, false);
|
||||
SetHighlight(officer_ammoShelf_2.Item, false);
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective3");
|
||||
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(4, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Kill hammerhead
|
||||
officer_hammerhead = SpawnMonster("hammerhead", officer_hammerheadSpawnPos);
|
||||
officer_hammerhead.Params.AI.AvoidAbyss = false;
|
||||
officer_hammerhead.Params.AI.StayInAbyss = false;
|
||||
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
|
||||
SetHighlight(officer_coilgunPeriscope, true);
|
||||
float originalDistance = Vector2.Distance(officer_coilgunPeriscope.WorldPosition, officer_hammerheadSpawnPos);
|
||||
do
|
||||
{
|
||||
float distance = Vector2.Distance(officer_coilgunPeriscope.WorldPosition, officer_hammerhead.WorldPosition);
|
||||
if (distance > originalDistance * 1.5f || officer_hammerhead.WorldPosition.Y > officer_coilgunPeriscope.WorldPosition.Y)
|
||||
{
|
||||
// Don't let the Hammerhead go too far.
|
||||
officer_hammerhead.TeleportTo(officer_hammerheadSpawnPos + new Vector2(0, -1000));
|
||||
}
|
||||
if (distance > originalDistance)
|
||||
{
|
||||
// Ensure that the Hammerhead targets the player
|
||||
officer.AiTarget.SoundRange = float.MaxValue;
|
||||
officer.AiTarget.SightRange = float.MaxValue;
|
||||
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
|
||||
if ((officer_hammerhead.AIController as EnemyAIController)?.SelectedTargetingParams != null)
|
||||
{
|
||||
((EnemyAIController)officer_hammerhead.AIController).SelectedTargetingParams.ReactDistance = 5000.0f;
|
||||
}
|
||||
/*var ai = officer_hammerhead.AIController as EnemyAIController;
|
||||
ai.sight = 2.0f;*/
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
while(!officer_hammerhead.IsDead);
|
||||
Heal(officer);
|
||||
SetHighlight(officer_coilgunPeriscope, false);
|
||||
RemoveCompletedObjective(4);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective4");
|
||||
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.HammerheadDead"), ChatMessageType.Radio, null);
|
||||
SetDoorAccess(officer_thirdDoor, officer_thirdDoorLight, true);
|
||||
|
||||
// Room 5
|
||||
//do { yield return null; } while (!officer_rangedWeaponSensor.MotionDetected);
|
||||
do { yield return null; } while (!officer_thirdDoor.IsOpen);
|
||||
yield return new WaitForSeconds(3f, false);
|
||||
TriggerTutorialSegment(5, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Ranged weapons
|
||||
SetHighlight(officer_rangedWeaponHolder.Item, true);
|
||||
do { yield return null; } while (!officer_rangedWeaponHolder.Inventory.IsEmpty()); // Wait until looted
|
||||
SetHighlight(officer_rangedWeaponHolder.Item, false);
|
||||
do
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
yield return null;
|
||||
} while (!officer.HasEquippedItem("shotgun".ToIdentifier())); // Wait until equipped
|
||||
ItemContainer shotGunChamber = officer.Inventory.FindItemByIdentifier("shotgun".ToIdentifier()).GetComponent<ItemContainer>();
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, true);
|
||||
do
|
||||
{
|
||||
if (IsSelectedItem(officer_rangedWeaponCabinet.Item))
|
||||
{
|
||||
if (officer_rangedWeaponCabinet.Inventory.visualSlots != null)
|
||||
{
|
||||
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Capacity; i++)
|
||||
{
|
||||
if (officer_rangedWeaponCabinet.Inventory.GetItemAt(i)?.Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer_rangedWeaponCabinet.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < officer.Inventory.Capacity; i++)
|
||||
{
|
||||
if (officer.Inventory.GetItemAt(i)?.Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (officer.Inventory.FindItemByIdentifier("shotgunshell".ToIdentifier()) != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("shotgunshell".ToIdentifier()) != null))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun".ToIdentifier(), highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (!shotGunChamber.Inventory.IsFull(takeStacksIntoAccount: true)); // Wait until all six harpoons loaded
|
||||
RemoveCompletedObjective(5);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective5");
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, false);
|
||||
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);
|
||||
|
||||
// Room 6
|
||||
do { yield return null; } while (!officer_mudraptorObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(6);
|
||||
officer_mudraptor = SpawnMonster("mudraptor", officer_mudraptorSpawnPos);
|
||||
do { yield return null; } while (!officer_mudraptor.IsDead);
|
||||
Heal(officer);
|
||||
RemoveCompletedObjective(6);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective6");
|
||||
SetDoorAccess(tutorial_securityFinalDoor, tutorial_securityFinalDoorLight, true);
|
||||
|
||||
// Submarine
|
||||
do { yield return null; } while (!tutorial_enteredSubmarineSensor.MotionDetected);
|
||||
TriggerTutorialSegment(7);
|
||||
while (ContentRunning) yield return null;
|
||||
officer.AddActiveObjectiveEntity(officer_subAmmoBox_1, officer_gunIcon, officer_gunIconColor);
|
||||
officer.AddActiveObjectiveEntity(officer_subAmmoBox_2, officer_gunIcon, officer_gunIconColor);
|
||||
officer.AddActiveObjectiveEntity(officer_subSuperCapacitor_1.Item, officer_gunIcon, officer_gunIconColor);
|
||||
officer.AddActiveObjectiveEntity(officer_subSuperCapacitor_2.Item, officer_gunIcon, officer_gunIconColor);
|
||||
SetHighlight(officer_subSuperCapacitor_1.Item, true);
|
||||
SetHighlight(officer_subSuperCapacitor_2.Item, true);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Submarine"), ChatMessageType.Radio, null);
|
||||
do
|
||||
{
|
||||
SetHighlight(officer_subLoader_1.Item, officer_subLoader_1.Inventory.GetItemAt(0) == null || officer_subLoader_1.Inventory.GetItemAt(0).Condition == 0);
|
||||
SetHighlight(officer_subLoader_2.Item, officer_subLoader_2.Inventory.GetItemAt(0) == null || officer_subLoader_2.Inventory.GetItemAt(0).Condition == 0);
|
||||
HighlightInventorySlot(officer_subLoader_1.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
HighlightInventorySlot(officer_subLoader_2.Inventory, 0, highlightColor, .5f, .5f, 0f);
|
||||
|
||||
if (officer_subSuperCapacitor_1.Item.ExternalHighlight && officer_subSuperCapacitor_1.RechargeSpeed >= superCapacitorRechargeRate)
|
||||
{
|
||||
SetHighlight(officer_subSuperCapacitor_1.Item, false);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subSuperCapacitor_1.Item);
|
||||
}
|
||||
|
||||
if (officer_subSuperCapacitor_2.Item.ExternalHighlight && officer_subSuperCapacitor_2.RechargeSpeed >= superCapacitorRechargeRate)
|
||||
{
|
||||
SetHighlight(officer_subSuperCapacitor_2.Item, false);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subSuperCapacitor_2.Item);
|
||||
}
|
||||
|
||||
SetHighlight(officer_subAmmoBox_1, officer_subAmmoBox_1.ParentInventory != officer_subLoader_1.Inventory && officer_subAmmoBox_1.ParentInventory != officer_subLoader_2.Inventory);
|
||||
SetHighlight(officer_subAmmoBox_2, officer_subAmmoBox_2.ParentInventory != officer_subLoader_1.Inventory && officer_subAmmoBox_2.ParentInventory != officer_subLoader_2.Inventory);
|
||||
SetHighlight(officer_subAmmoShelf.Item, officer_subLoader_1.Item.ExternalHighlight || officer_subLoader_2.Item.ExternalHighlight);
|
||||
if (officer_subAmmoBox_1.ParentInventory == officer_subLoader_1.Inventory || officer_subAmmoBox_1.ParentInventory == officer_subLoader_2.Inventory) officer.RemoveActiveObjectiveEntity(officer_subAmmoBox_1);
|
||||
if (officer_subAmmoBox_2.ParentInventory == officer_subLoader_1.Inventory || officer_subAmmoBox_2.ParentInventory == officer_subLoader_2.Inventory) officer.RemoveActiveObjectiveEntity(officer_subAmmoBox_2);
|
||||
yield return null;
|
||||
} while (officer_subLoader_1.Item.ExternalHighlight || officer_subLoader_2.Item.ExternalHighlight || officer_subSuperCapacitor_1.Item.ExternalHighlight || officer_subSuperCapacitor_2.Item.ExternalHighlight);
|
||||
SetHighlight(officer_subLoader_1.Item, false);
|
||||
SetHighlight(officer_subLoader_2.Item, false);
|
||||
SetHighlight(officer_subSuperCapacitor_1.Item, false);
|
||||
SetHighlight(officer_subSuperCapacitor_2.Item, false);
|
||||
SetHighlight(officer_subAmmoBox_1, false);
|
||||
SetHighlight(officer_subAmmoBox_2, false);
|
||||
SetHighlight(officer_subAmmoShelf.Item, false);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subSuperCapacitor_1.Item);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subSuperCapacitor_2.Item);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subAmmoBox_1);
|
||||
officer.RemoveActiveObjectiveEntity(officer_subAmmoBox_2);
|
||||
RemoveCompletedObjective(7);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Objective7");
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:OfficerTutorial:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
private bool IsSelectedItem(Item item)
|
||||
{
|
||||
return officer?.SelectedItem == item;
|
||||
}
|
||||
|
||||
private Character SpawnMonster(string speciesName, Vector2 pos)
|
||||
{
|
||||
var character = Character.Create(speciesName, pos, ToolBox.RandomSeed(8));
|
||||
var ai = character.AIController as EnemyAIController;
|
||||
ai.TargetOutposts = true;
|
||||
character.CharacterHealth.SetVitality(character.Health / 2);
|
||||
character.AnimController.Limbs.Where(l => l.attack != null).Select(l => l.attack).ForEach(a => a.AfterAttack = AIBehaviorAfterAttack.FallBack);
|
||||
return character;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
abstract class ScenarioTutorial : Tutorial
|
||||
{
|
||||
private CoroutineHandle tutorialCoroutine;
|
||||
|
||||
private Character character;
|
||||
|
||||
private const string submarinePath = "Content/Tutorials/Dugong_Tutorial.sub";
|
||||
private const string startOutpostPath = "Content/Tutorials/TutorialOutpost.sub";
|
||||
//private const string endOutpostPath = "";
|
||||
|
||||
private const string levelSeed = "nLoZLLtza";
|
||||
private const string levelParams = "ColdCavernsTutorial";
|
||||
|
||||
//private const string spawnSub = "startoutpost";
|
||||
private const SpawnType spawnPointType = SpawnType.Human;
|
||||
|
||||
private SubmarineInfo startOutpost = null;
|
||||
private SubmarineInfo endOutpost = null;
|
||||
private bool currentTutorialCompleted = false;
|
||||
private float fadeOutTime = 3f;
|
||||
protected float waitBeforeFade = 4f;
|
||||
|
||||
// Colors
|
||||
protected Color highlightColor = Color.OrangeRed;
|
||||
protected Color uiHighlightColor = new Color(150, 50, 0);
|
||||
protected Color buttonHighlightColor = new Color(255, 100, 0);
|
||||
protected Color inaccessibleColor = GUIStyle.Red;
|
||||
protected Color accessibleColor = GUIStyle.Green;
|
||||
|
||||
protected ScenarioTutorial(Identifier identifier, params Segment[] segments) : base(identifier, segments) { }
|
||||
|
||||
protected abstract void Initialize();
|
||||
|
||||
protected override IEnumerable<CoroutineStatus> Loading()
|
||||
{
|
||||
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
|
||||
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Identifier == levelParams);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
GameMain.GameSession = new GameSession(subInfo, GameModePreset.Tutorial, missionPrefabs: null);
|
||||
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
|
||||
|
||||
if (generationParams != null)
|
||||
{
|
||||
Biome biome =
|
||||
Biome.Prefabs.FirstOrDefault(b => generationParams.AllowedBiomeIdentifiers.Contains(b.Identifier)) ??
|
||||
Biome.Prefabs.First();
|
||||
|
||||
if (!string.IsNullOrEmpty(startOutpostPath))
|
||||
{
|
||||
startOutpost = new SubmarineInfo(startOutpostPath);
|
||||
}
|
||||
|
||||
/*if (!string.IsNullOrEmpty(endOutpostPath))
|
||||
{
|
||||
endOutpost = new SubmarineInfo(endOutpostPath);
|
||||
}*/
|
||||
|
||||
LevelData tutorialLevel = new LevelData(levelSeed, 0, 0, generationParams, biome);
|
||||
GameMain.GameSession.StartRound(tutorialLevel, startOutpost: startOutpost, endOutpost: endOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.GameSession.StartRound(levelSeed);
|
||||
}
|
||||
|
||||
GameMain.GameSession.EventManager.ActiveEvents.Clear();
|
||||
GameMain.GameSession.EventManager.Enabled = false;
|
||||
GameMain.GameScreen.Select();
|
||||
|
||||
|
||||
Submarine.MainSub.GodMode = true;
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
{
|
||||
if (wall.Submarine != null && wall.Submarine.Info.IsOutpost)
|
||||
{
|
||||
wall.Indestructible = true;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterInfo charInfo = GetCharacterInfo();
|
||||
|
||||
WayPoint wayPoint = GetSpawnPoint(charInfo);
|
||||
|
||||
if (wayPoint == null)
|
||||
{
|
||||
DebugConsole.ThrowError("A waypoint with the spawntype \"" + spawnPointType + "\" is required for the tutorial event");
|
||||
yield return CoroutineStatus.Failure;
|
||||
yield break;
|
||||
}
|
||||
|
||||
character = Character.Create(charInfo, wayPoint.WorldPosition, "", isRemotePlayer: false, hasAi: false);
|
||||
character.TeamID = CharacterTeamType.Team1;
|
||||
Character.Controlled = character;
|
||||
character.GiveJobItems(null);
|
||||
|
||||
var idCard = character.Inventory.FindItemByTag("identitycard".ToIdentifier());
|
||||
if (idCard == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
||||
yield return CoroutineStatus.Failure;
|
||||
yield break;
|
||||
}
|
||||
idCard.AddTag("com");
|
||||
idCard.AddTag("eng");
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
Door door = item.GetComponent<Door>();
|
||||
if (door != null)
|
||||
{
|
||||
door.CanBeWelded = false;
|
||||
}
|
||||
}
|
||||
|
||||
tutorialCoroutine = CoroutineManager.StartCoroutine(UpdateState());
|
||||
|
||||
Initialize();
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
protected abstract CharacterInfo GetCharacterInfo();
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
if (!currentTutorialCompleted)
|
||||
{
|
||||
base.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
|
||||
private WayPoint GetSpawnPoint(CharacterInfo charInfo)
|
||||
{
|
||||
/*Submarine spawnSub = null;
|
||||
|
||||
if (this.spawnSub != string.Empty)
|
||||
{
|
||||
switch (this.spawnSub)
|
||||
{
|
||||
case "startoutpost":
|
||||
spawnSub = Level.Loaded.StartOutpost;
|
||||
break;
|
||||
|
||||
case "endoutpost":
|
||||
spawnSub = Level.Loaded.EndOutpost;
|
||||
break;
|
||||
|
||||
default:
|
||||
spawnSub = Submarine.MainSub;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
Submarine spawnSub = Level.Loaded.StartOutpost;
|
||||
return WayPoint.GetRandom(spawnPointType, charInfo.Job?.Prefab, spawnSub);
|
||||
}
|
||||
|
||||
protected bool HasOrder(Character character, string identifier, string option = null)
|
||||
{
|
||||
var currentOrderInfo = character.GetCurrentOrderWithTopPriority();
|
||||
if (currentOrderInfo?.Identifier == identifier)
|
||||
{
|
||||
if (option == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return currentOrderInfo?.Option == option;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void SetHighlight(Item item, bool state)
|
||||
{
|
||||
if (item.ExternalHighlight == state) return;
|
||||
item.SpriteColor = (state) ? highlightColor : Color.White;
|
||||
item.ExternalHighlight = state;
|
||||
}
|
||||
|
||||
protected void SetHighlight(Structure structure, bool state)
|
||||
{
|
||||
structure.SpriteColor = (state) ? highlightColor : Color.White;
|
||||
structure.ExternalHighlight = state;
|
||||
}
|
||||
|
||||
protected void SetHighlight(Character character, bool state)
|
||||
{
|
||||
character.ExternalHighlight = state;
|
||||
}
|
||||
|
||||
protected void SetDoorAccess(Door door, LightComponent light, bool state)
|
||||
{
|
||||
if (state && door != null) door.requiredItems.Clear();
|
||||
if (light != null) light.LightColor = (state) ? accessibleColor : inaccessibleColor;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
if (character != null)
|
||||
{
|
||||
if (character.Oxygen < 1)
|
||||
{
|
||||
character.Oxygen = 1;
|
||||
}
|
||||
if (character.IsDead)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(Dead());
|
||||
}
|
||||
else if (Character.Controlled == null)
|
||||
{
|
||||
if (tutorialCoroutine != null)
|
||||
{
|
||||
CoroutineManager.StopCoroutines(tutorialCoroutine);
|
||||
}
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
ContentRunning = false;
|
||||
infoBox = null;
|
||||
}
|
||||
else if (Character.Controlled.IsDead)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(Dead());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if (tutorialCoroutine != null)
|
||||
{
|
||||
CoroutineManager.StopCoroutines(tutorialCoroutine);
|
||||
}
|
||||
base.Stop();
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> Dead()
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = true;
|
||||
Character.Controlled = character = null;
|
||||
Stop();
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Died");
|
||||
|
||||
yield return new WaitForSeconds(3.0f);
|
||||
|
||||
var messageBox = new GUIMessageBox(TextManager.Get("Tutorial.TryAgainHeader"), TextManager.Get("Tutorial.TryAgain"), new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
|
||||
messageBox.Buttons[0].OnClicked += Restart;
|
||||
messageBox.Buttons[0].OnClicked += messageBox.Close;
|
||||
|
||||
|
||||
messageBox.Buttons[1].OnClicked = GameMain.MainMenuScreen.ReturnToMainMenu;
|
||||
messageBox.Buttons[1].OnClicked += messageBox.Close;
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
protected IEnumerable<CoroutineStatus> TutorialCompleted()
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = true;
|
||||
|
||||
Character.Controlled.ClearInputs();
|
||||
Character.Controlled = null;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Completed");
|
||||
|
||||
yield return new WaitForSeconds(waitBeforeFade);
|
||||
|
||||
var endCinematic = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null, Alignment.Center, panDuration: fadeOutTime);
|
||||
currentTutorialCompleted = Completed = true;
|
||||
while (endCinematic.Running) yield return null;
|
||||
Stop();
|
||||
GameMain.MainMenuScreen.ReturnToMainMenu(null, null);
|
||||
}
|
||||
|
||||
protected void Heal(Character character)
|
||||
{
|
||||
character.SetAllDamage(0.0f, 0.0f, 0.0f);
|
||||
character.Oxygen = 100.0f;
|
||||
character.Bloodloss = 0.0f;
|
||||
character.SetStun(0.0f, true);
|
||||
}
|
||||
|
||||
protected Item FindOrGiveItem(Character character, Identifier identifier)
|
||||
{
|
||||
var item = character.Inventory.FindItemByIdentifier(identifier);
|
||||
if (item != null && !item.Removed) { return item; }
|
||||
|
||||
ItemPrefab itemPrefab = MapEntityPrefab.Find(name: null, identifier: identifier) as ItemPrefab;
|
||||
item = new Item(itemPrefab, Vector2.Zero, submarine: null);
|
||||
character.Inventory.TryPutItem(item, character, item.AllowedSlots);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,32 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
enum TutorialContentType { None = 0, Video = 1, ManualVideo = 2, TextOnly = 3 };
|
||||
enum AutoPlayVideo { Yes, No };
|
||||
|
||||
/// <summary>
|
||||
/// If you're seeing this and are currently working on improving the tutorials, consider
|
||||
/// deleting this class and all that derive from it, and starting from scratch.
|
||||
/// </summary>
|
||||
abstract class Tutorial
|
||||
enum TutorialSegmentType { MessageBox, InfoBox };
|
||||
|
||||
class Tutorial
|
||||
{
|
||||
#region Constants
|
||||
public const string PlayableContentPath = "Content/Tutorials/TutorialVideos/";
|
||||
|
||||
private const string PlayableContentPath = "Content/Tutorials/TutorialVideos/";
|
||||
private const SpawnType SpawnPointType = SpawnType.Human;
|
||||
private const float FadeOutTime = 3f;
|
||||
private const float WaitBeforeFade = 4f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tutorial variables
|
||||
|
||||
public static ImmutableHashSet<Type> Types;
|
||||
|
||||
static Tutorial()
|
||||
{
|
||||
Types = ReflectionUtils.GetDerivedNonAbstract<Tutorial>()
|
||||
@@ -37,30 +39,41 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
public bool ContentRunning { get; protected set; }
|
||||
|
||||
protected GUIComponent infoBox;
|
||||
private GUIComponent infoBox;
|
||||
private Action infoBoxClosedCallback;
|
||||
|
||||
protected VideoPlayer videoPlayer;
|
||||
protected Point screenResolution;
|
||||
protected WindowMode windowMode;
|
||||
protected float prevUIScale;
|
||||
private VideoPlayer videoPlayer;
|
||||
private Point screenResolution;
|
||||
private WindowMode windowMode;
|
||||
private float prevUIScale;
|
||||
|
||||
private GUIFrame holderFrame, objectiveFrame;
|
||||
private readonly List<Index> activeObjectives;
|
||||
private readonly LocalizedString objectiveTranslated;
|
||||
private GUILayoutGroup objectiveGroup;
|
||||
private readonly LocalizedString objectiveTextTranslated;
|
||||
|
||||
protected readonly ImmutableArray<Segment> segments;
|
||||
protected Index activeContentSegmentIndex;
|
||||
protected Segment activeContentSegment => segments[activeContentSegmentIndex];
|
||||
private readonly List<Segment> ActiveObjectives = new List<Segment>();
|
||||
private const float ObjectiveComponentRemovalTime = 1.5f;
|
||||
private Segment ActiveContentSegment { get; set; }
|
||||
|
||||
protected class Segment
|
||||
public class Segment
|
||||
{
|
||||
public struct Text
|
||||
{
|
||||
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
|
||||
@@ -69,36 +82,63 @@ namespace Barotrauma.Tutorials
|
||||
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 bool IsTriggered;
|
||||
public GUIButton ReplayButton;
|
||||
public GUITextBlock LinkedTitle, LinkedText;
|
||||
public object[] Args;
|
||||
public LocalizedString Objective;
|
||||
private const int DefaultWidth = 450;
|
||||
private const int DefaultHeight = 80;
|
||||
|
||||
public GUIImage ObjectiveStateIndicator;
|
||||
public GUIButton ObjectiveButton;
|
||||
public GUITextBlock LinkedTextBlock;
|
||||
public LocalizedString ObjectiveText;
|
||||
|
||||
public readonly Identifier Id;
|
||||
public readonly Text? TextContent;
|
||||
public readonly Video? VideoContent;
|
||||
public readonly TutorialContentType ContentType;
|
||||
public readonly AutoPlayVideo AutoPlayVideo;
|
||||
|
||||
public Segment(Identifier id, Identifier objectiveTextTag, TutorialContentType contentType, Text? textContent = null, Video? videoContent = null)
|
||||
public Action OnClickToDisplayMessage;
|
||||
|
||||
public readonly TutorialSegmentType SegmentType;
|
||||
|
||||
public Segment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text? textContent = null, Video? videoContent = null)
|
||||
{
|
||||
Id = id;
|
||||
Objective = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
|
||||
ContentType = contentType;
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
|
||||
AutoPlayVideo = autoPlayVideo;
|
||||
TextContent = textContent;
|
||||
VideoContent = videoContent;
|
||||
SegmentType = TutorialSegmentType.InfoBox;
|
||||
}
|
||||
|
||||
IsTriggered = false;
|
||||
public Segment(Identifier id, Action onClickToDisplayMessage)
|
||||
{
|
||||
Id = id;
|
||||
var objetiveTextTag = $"{id}.objective".ToIdentifier();
|
||||
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objetiveTextTag));
|
||||
OnClickToDisplayMessage = onClickToDisplayMessage;
|
||||
SegmentType = TutorialSegmentType.MessageBox;
|
||||
}
|
||||
}
|
||||
|
||||
private bool completed;
|
||||
public bool Completed
|
||||
{
|
||||
get { return completed; }
|
||||
protected set
|
||||
get
|
||||
{
|
||||
return completed;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (completed == value) { return; }
|
||||
completed = value;
|
||||
@@ -109,26 +149,150 @@ namespace Barotrauma.Tutorials
|
||||
GameSettings.SaveCurrentConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public readonly TutorialPrefab TutorialPrefab;
|
||||
private readonly EventPrefab eventPrefab;
|
||||
|
||||
private CoroutineHandle tutorialCoroutine;
|
||||
|
||||
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 SubmarineInfo startOutpost = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tutorial Controls
|
||||
protected Tutorial(Identifier identifier, params Segment[] segments)
|
||||
|
||||
public Tutorial(TutorialPrefab prefab)
|
||||
{
|
||||
Identifier = identifier;
|
||||
this.segments = segments.ToImmutableArray();
|
||||
Identifier = $"tutorial.{prefab?.Identifier ?? Identifier.Empty}".ToIdentifier();
|
||||
DisplayName = TextManager.Get(Identifier);
|
||||
activeObjectives = new List<Index>();
|
||||
objectiveTranslated = TextManager.Get("Tutorial.Objective");
|
||||
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);
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<CoroutineStatus> Loading();
|
||||
private IEnumerable<CoroutineStatus> Loading()
|
||||
{
|
||||
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
|
||||
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Identifier == levelParams);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
GameMain.GameSession = new GameSession(subInfo, GameModePreset.Tutorial, missionPrefabs: null);
|
||||
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
|
||||
|
||||
if (generationParams != null)
|
||||
{
|
||||
Biome biome =
|
||||
Biome.Prefabs.FirstOrDefault(b => generationParams.AllowedBiomeIdentifiers.Contains(b.Identifier)) ??
|
||||
Biome.Prefabs.First();
|
||||
|
||||
if (!string.IsNullOrEmpty(startOutpostPath))
|
||||
{
|
||||
startOutpost = new SubmarineInfo(startOutpostPath);
|
||||
}
|
||||
|
||||
LevelData tutorialLevel = new LevelData(levelSeed, 0, 0, generationParams, biome);
|
||||
GameMain.GameSession.StartRound(tutorialLevel, startOutpost: startOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.GameSession.StartRound(levelSeed);
|
||||
}
|
||||
|
||||
GameMain.GameSession.EventManager.ActiveEvents.Clear();
|
||||
GameMain.GameSession.EventManager.Enabled = true;
|
||||
GameMain.GameScreen.Select();
|
||||
|
||||
if (Submarine.MainSub != null)
|
||||
{
|
||||
Submarine.MainSub.GodMode = true;
|
||||
}
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
{
|
||||
if (wall.Submarine != null && wall.Submarine.Info.IsOutpost)
|
||||
{
|
||||
wall.Indestructible = true;
|
||||
}
|
||||
}
|
||||
|
||||
var charInfo = TutorialPrefab.GetTutorialCharacterInfo();
|
||||
|
||||
var wayPoint = WayPoint.GetRandom(SpawnPointType, charInfo.Job?.Prefab, Level.Loaded.StartOutpost);
|
||||
|
||||
if (wayPoint == null)
|
||||
{
|
||||
DebugConsole.ThrowError("A waypoint with the spawntype \"" + SpawnPointType + "\" is required for the tutorial event");
|
||||
yield return CoroutineStatus.Failure;
|
||||
yield break;
|
||||
}
|
||||
|
||||
character = Character.Create(charInfo, wayPoint.WorldPosition, "", isRemotePlayer: false, hasAi: false);
|
||||
character.TeamID = CharacterTeamType.Team1;
|
||||
Character.Controlled = character;
|
||||
character.GiveJobItems(null);
|
||||
|
||||
var idCard = character.Inventory.FindItemByTag("identitycard".ToIdentifier());
|
||||
if (idCard == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
||||
yield return CoroutineStatus.Failure;
|
||||
yield break;
|
||||
}
|
||||
idCard.AddTag("com");
|
||||
idCard.AddTag("eng");
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
Door door = item.GetComponent<Door>();
|
||||
if (door != null)
|
||||
{
|
||||
door.CanBeWelded = false;
|
||||
}
|
||||
}
|
||||
|
||||
tutorialCoroutine = CoroutineManager.StartCoroutine(UpdateState());
|
||||
|
||||
Initialize();
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = TutorialPrefab.AllowCharacterSwitch;
|
||||
|
||||
if (Character.Controlled is Character character)
|
||||
{
|
||||
foreach (Item item in character.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag(TutorialPrefab.StartingItemTags)) { continue; }
|
||||
item.Unequip(character);
|
||||
character.Inventory.RemoveItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
videoPlayer = new VideoPlayer();
|
||||
GameMain.Instance.ShowLoading(Loading());
|
||||
|
||||
activeObjectives.Clear();
|
||||
ActiveObjectives.Clear();
|
||||
ActiveContentSegment = null;
|
||||
|
||||
CreateObjectiveFrame();
|
||||
|
||||
// Setup doors: Clear all requirements, unless the door is setup as locked.
|
||||
@@ -145,35 +309,73 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale || GameSettings.CurrentConfig.Graphics.DisplayMode != windowMode)
|
||||
{
|
||||
CreateObjectiveFrame();
|
||||
}
|
||||
|
||||
if (objectiveFrame != null && activeObjectives.Count > 0)
|
||||
if (ActiveObjectives.Count > 0)
|
||||
{
|
||||
objectiveFrame.AddToGUIUpdateList(order: -1);
|
||||
objectiveGroup?.AddToGUIUpdateList(order: -1);
|
||||
}
|
||||
|
||||
if (infoBox != null) infoBox.AddToGUIUpdateList(order: 100);
|
||||
if (videoPlayer != null) videoPlayer.AddToGUIUpdateList(order: 100);
|
||||
infoBox?.AddToGUIUpdateList(order: 100);
|
||||
videoPlayer?.AddToGUIUpdateList(order: 100);
|
||||
}
|
||||
|
||||
public virtual void Update(float deltaTime)
|
||||
public void Update()
|
||||
{
|
||||
videoPlayer?.Update();
|
||||
|
||||
if (activeObjectives != null)
|
||||
if (character != null)
|
||||
{
|
||||
for (int i = 0; i < activeObjectives.Count; i++)
|
||||
if (character.Oxygen < 1)
|
||||
{
|
||||
CheckActiveObjectives(activeObjectives[i], deltaTime);
|
||||
character.Oxygen = 1;
|
||||
}
|
||||
if (character.IsDead)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(Dead());
|
||||
}
|
||||
else if (Character.Controlled == null)
|
||||
{
|
||||
if (tutorialCoroutine != null)
|
||||
{
|
||||
CoroutineManager.StopCoroutines(tutorialCoroutine);
|
||||
}
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
ContentRunning = false;
|
||||
infoBox = null;
|
||||
}
|
||||
else if (Character.Controlled.IsDead)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(Dead());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> Dead()
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = true;
|
||||
Character.Controlled = character = null;
|
||||
Stop();
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Died");
|
||||
|
||||
yield return new WaitForSeconds(3.0f);
|
||||
|
||||
var messageBox = new GUIMessageBox(TextManager.Get("Tutorial.TryAgainHeader"), TextManager.Get("Tutorial.TryAgain"), new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
|
||||
messageBox.Buttons[0].OnClicked += Restart;
|
||||
messageBox.Buttons[0].OnClicked += messageBox.Close;
|
||||
|
||||
|
||||
messageBox.Buttons[1].OnClicked = GameMain.MainMenuScreen.ReturnToMainMenu;
|
||||
messageBox.Buttons[1].OnClicked += messageBox.Close;
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void CloseActiveContentGUI()
|
||||
{
|
||||
if (videoPlayer.IsPlaying)
|
||||
@@ -182,257 +384,307 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
else if (infoBox != null)
|
||||
{
|
||||
CloseInfoFrame(null, null);
|
||||
CloseInfoFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<CoroutineStatus> UpdateState()
|
||||
public IEnumerable<CoroutineStatus> UpdateState()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen || Level.Loaded == null || Level.Loaded.Generating)
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
|
||||
if (eventPrefab == null)
|
||||
{
|
||||
DebugConsole.ShowError($"No tutorial event defined for the tutorial (identifier: \"{TutorialPrefab?.Identifier.ToString() ?? "null"})\"");
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
if (eventPrefab.CreateInstance() is Event eventInstance)
|
||||
{
|
||||
GameMain.GameSession.EventManager.QueuedEvents.Enqueue(eventInstance);
|
||||
while (!eventInstance.IsFinished)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ShowError($"Failed to create an instance for a tutorial event (identifier: \"{eventPrefab.Identifier}\"");
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
protected bool Restart(GUIButton button, object obj)
|
||||
public void Complete()
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent($"Tutorial:{Identifier}:Completed");
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
|
||||
IEnumerable<CoroutineStatus> TutorialCompleted()
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = true;
|
||||
Character.Controlled.ClearInputs();
|
||||
Character.Controlled = null;
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:Completed");
|
||||
|
||||
yield return new WaitForSeconds(WaitBeforeFade);
|
||||
|
||||
var endCinematic = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null, Alignment.Center, panDuration: FadeOutTime);
|
||||
Completed = true;
|
||||
|
||||
while (endCinematic.Running) { yield return null; }
|
||||
|
||||
Stop();
|
||||
GameMain.MainMenuScreen.ReturnToMainMenu(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
private bool Restart(GUIButton button, object obj)
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void TriggerTutorialSegment(Index index, params object[] args)
|
||||
public void TriggerTutorialSegment(Segment segment)
|
||||
{
|
||||
if (segment.SegmentType == TutorialSegmentType.MessageBox)
|
||||
{
|
||||
ActiveObjectives.Add(segment);
|
||||
AddToObjectiveList(segment);
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory.DraggingItems.Clear();
|
||||
ContentRunning = true;
|
||||
activeContentSegmentIndex = index;
|
||||
segments[index].Args = args;
|
||||
ActiveContentSegment = segment;
|
||||
|
||||
LocalizedString tutorialText = TextManager.GetFormatted(segments[index].TextContent.Value.Tag, args);
|
||||
var title = TextManager.Get(segment.Id);
|
||||
LocalizedString tutorialText = TextManager.GetFormatted(segment.TextContent.Value.Tag);
|
||||
tutorialText = TextManager.ParseInputTypes(tutorialText);
|
||||
LocalizedString objectiveText = string.Empty;
|
||||
|
||||
if (!segments[index].Objective.IsNullOrEmpty())
|
||||
switch (segment.AutoPlayVideo)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
objectiveText = segments[index].Objective;
|
||||
}
|
||||
else
|
||||
{
|
||||
objectiveText = TextManager.GetFormatted(segments[index].Objective, args);
|
||||
}
|
||||
objectiveText = TextManager.ParseInputTypes(objectiveText);
|
||||
segments[index].Objective = objectiveText;
|
||||
}
|
||||
else
|
||||
{
|
||||
segments[index].IsTriggered = true; // Complete at this stage only if no related objective
|
||||
}
|
||||
|
||||
|
||||
switch (segments[index].ContentType)
|
||||
{
|
||||
case TutorialContentType.None:
|
||||
case AutoPlayVideo.Yes:
|
||||
infoBox = CreateInfoFrame(
|
||||
title,
|
||||
tutorialText,
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: LoadActiveContentVideo);
|
||||
break;
|
||||
case TutorialContentType.Video:
|
||||
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
|
||||
activeContentSegment.TextContent.Value.Width,
|
||||
activeContentSegment.TextContent.Value.Height,
|
||||
activeContentSegment.TextContent.Value.Anchor, true, () => LoadVideo(activeContentSegment));
|
||||
break;
|
||||
case TutorialContentType.ManualVideo:
|
||||
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
|
||||
activeContentSegment.TextContent.Value.Width,
|
||||
activeContentSegment.TextContent.Value.Height,
|
||||
activeContentSegment.TextContent.Value.Anchor, true, StopCurrentContentSegment, () => LoadVideo(activeContentSegment));
|
||||
break;
|
||||
case TutorialContentType.TextOnly:
|
||||
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
|
||||
activeContentSegment.TextContent.Value.Width,
|
||||
activeContentSegment.TextContent.Value.Height,
|
||||
activeContentSegment.TextContent.Value.Anchor, true, StopCurrentContentSegment);
|
||||
case AutoPlayVideo.No:
|
||||
infoBox = CreateInfoFrame(
|
||||
title,
|
||||
tutorialText,
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: StopCurrentContentSegment,
|
||||
onVideoButtonClicked: LoadActiveContentVideo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Stop()
|
||||
public void CompleteTutorialSegment(Identifier segmentId)
|
||||
{
|
||||
if (!(GetActiveObjective(segmentId) is Segment segment))
|
||||
{
|
||||
DebugConsole.AddWarning($"Warning: tried to complete the tutorial segment \"{segmentId}\" in tutorial \"{Identifier}\" but it isn't active!");
|
||||
return;
|
||||
}
|
||||
if (GUIStyle.GetComponentStyle("ObjectiveIndicatorCompleted") is GUIComponentStyle style)
|
||||
{
|
||||
segment.ObjectiveStateIndicator.ApplyStyle(style);
|
||||
segment.ObjectiveStateIndicator.Flash(color: GUIStyle.Green);
|
||||
}
|
||||
segment.ObjectiveButton.OnClicked = null;
|
||||
segment.ObjectiveButton.CanBeFocused = false;
|
||||
}
|
||||
|
||||
public void RemoveTutorialSegment(Identifier segmentId)
|
||||
{
|
||||
if (!(GetActiveObjective(segmentId) is 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);
|
||||
var parent = segment.LinkedTextBlock.Parent;
|
||||
parent.FadeOut(ObjectiveComponentRemovalTime, true, onRemove: () =>
|
||||
{
|
||||
ActiveObjectives.Remove(segment);
|
||||
objectiveGroup?.Recalculate();
|
||||
});
|
||||
var targetPos = new Point(GameMain.GraphicsWidth - parent.Rect.X, 0);
|
||||
parent.RectTransform.MoveOverTime(targetPos, ObjectiveComponentRemovalTime);
|
||||
segment.ObjectiveButton.OnClicked = null;
|
||||
segment.ObjectiveButton.CanBeFocused = false;
|
||||
}
|
||||
|
||||
private Segment GetActiveObjective(Identifier id) => ActiveObjectives.FirstOrDefault(s => s.Id == id);
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (tutorialCoroutine != null)
|
||||
{
|
||||
CoroutineManager.StopCoroutines(tutorialCoroutine);
|
||||
}
|
||||
ContentRunning = false;
|
||||
infoBox = null;
|
||||
videoPlayer.Remove();
|
||||
videoPlayer?.Remove();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Objectives
|
||||
|
||||
/// <summary>
|
||||
/// Create the objective list that holds the objectives (called on start and on resolution change)
|
||||
/// </summary>
|
||||
private void CreateObjectiveFrame()
|
||||
{
|
||||
holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center));
|
||||
objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null);
|
||||
|
||||
for (int i = 0; i < activeObjectives.Count; i++)
|
||||
var objectiveListFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.TutorialObjectiveListArea, GUI.Canvas), style: null);
|
||||
objectiveGroup = new GUILayoutGroup(new RectTransform(Vector2.One, objectiveListFrame.RectTransform))
|
||||
{
|
||||
CreateObjectiveGUI(activeObjectives[i], i, segments[activeObjectives[i]].ContentType);
|
||||
AbsoluteSpacing = (int)GUIStyle.Font.LineHeight
|
||||
};
|
||||
for (int i = 0; i < ActiveObjectives.Count; i++)
|
||||
{
|
||||
AddToObjectiveList(ActiveObjectives[i]);
|
||||
}
|
||||
|
||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
windowMode = GameSettings.CurrentConfig.Graphics.DisplayMode;
|
||||
prevUIScale = GUI.Scale;
|
||||
}
|
||||
|
||||
protected void StopCurrentContentSegment()
|
||||
/// <summary>
|
||||
/// Stops content running and adds the active segment to the objective list
|
||||
/// </summary>
|
||||
private void StopCurrentContentSegment()
|
||||
{
|
||||
if (!activeContentSegment.Objective.IsNullOrEmpty())
|
||||
if (!ActiveContentSegment.ObjectiveText.IsNullOrEmpty())
|
||||
{
|
||||
AddNewObjective(activeContentSegmentIndex, activeContentSegment.ContentType);
|
||||
ActiveObjectives.Add(ActiveContentSegment);
|
||||
AddToObjectiveList(ActiveContentSegment);
|
||||
}
|
||||
|
||||
ContentRunning = false;
|
||||
activeContentSegmentIndex = Index.End;
|
||||
ActiveContentSegment = null;
|
||||
}
|
||||
|
||||
protected virtual void CheckActiveObjectives(Index objective, float deltaTime)
|
||||
/// <summary>
|
||||
/// Adds the segment to the objective list
|
||||
/// </summary>
|
||||
private void AddToObjectiveList(Segment segment)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected bool HasObjective(Index segment)
|
||||
{
|
||||
return activeObjectives.Contains(segment);
|
||||
}
|
||||
|
||||
protected void AddNewObjective(Index segment, TutorialContentType type)
|
||||
{
|
||||
activeObjectives.Add(segment);
|
||||
CreateObjectiveGUI(segment, activeObjectives.Count - 1, type);
|
||||
}
|
||||
|
||||
private void CreateObjectiveGUI(Index segmentIndex, int index, TutorialContentType type)
|
||||
{
|
||||
var segment = segments[segmentIndex];
|
||||
LocalizedString objectiveText = TextManager.ParseInputTypes(segment.Objective);
|
||||
Point replayButtonSize = new Point((int)(GUIStyle.LargeFont.MeasureString(objectiveText).X), (int)(GUIStyle.LargeFont.MeasureString(objectiveText).Y * 1.45f));
|
||||
|
||||
segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
|
||||
segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||
var frameRt = new RectTransform(new Vector2(1.0f, 0.1f), objectiveGroup.RectTransform)
|
||||
{
|
||||
if (type == TutorialContentType.Video)
|
||||
{
|
||||
ReplaySegmentVideo(segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowSegmentText(segment);
|
||||
}
|
||||
return true;
|
||||
MinSize = new Point(0, objectiveGroup.AbsoluteSpacing)
|
||||
};
|
||||
var frame = new GUIFrame(frameRt, style: null)
|
||||
{
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
LocalizedString objectiveTitleText = TextManager.ParseInputTypes(objectiveTranslated);
|
||||
int yOffset = (int)((GUIStyle.SubHeadingFont.MeasureString(objectiveTitleText).Y + 5));
|
||||
segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point((int)GUIStyle.SubHeadingFont.MeasureString(objectiveTitleText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterLeft, Pivot.BottomLeft) /*{ AbsoluteOffset = new Point((int)(-10 * GUI.Scale), 0) }*/,
|
||||
objectiveTitleText, textColor: Color.White, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
ForceUpperCase = ForceUpperCase.Yes
|
||||
};
|
||||
segment.LinkedTextBlock = new GUITextBlock(
|
||||
new RectTransform(new Point(frameRt.Rect.Width - objectiveGroup.AbsoluteSpacing, 0), frame.RectTransform, anchor: Anchor.TopRight),
|
||||
TextManager.ParseInputTypes(segment.ObjectiveText),
|
||||
wrap: true);
|
||||
|
||||
segment.LinkedText = new GUITextBlock(new RectTransform(new Point((int)GUIStyle.LargeFont.MeasureString(objectiveText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterLeft, Pivot.TopLeft) /*{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }*/,
|
||||
objectiveText, textColor: new Color(4, 180, 108), font: GUIStyle.LargeFont, textAlignment: Alignment.CenterLeft);
|
||||
|
||||
segment.LinkedTitle.Color = segment.LinkedTitle.HoverColor = segment.LinkedTitle.PressedColor = segment.LinkedTitle.SelectedColor = Color.Transparent;
|
||||
segment.LinkedText.Color = segment.LinkedText.HoverColor = segment.LinkedText.PressedColor = segment.LinkedText.SelectedColor = Color.Transparent;
|
||||
segment.ReplayButton.Color = segment.ReplayButton.HoverColor = segment.ReplayButton.PressedColor = segment.ReplayButton.SelectedColor = Color.Transparent;
|
||||
var size = new Point(segment.LinkedTextBlock.Rect.Width, segment.LinkedTextBlock.Rect.Height);
|
||||
segment.LinkedTextBlock.RectTransform.NonScaledSize = size;
|
||||
segment.LinkedTextBlock.RectTransform.MinSize = size;
|
||||
segment.LinkedTextBlock.RectTransform.MaxSize = size;
|
||||
segment.LinkedTextBlock.RectTransform.IsFixedSize = true;
|
||||
frame.RectTransform.Resize(new Point(frame.Rect.Width, segment.LinkedTextBlock.RectTransform.Rect.Height), resizeChildren: false);
|
||||
frame.RectTransform.IsFixedSize = true;
|
||||
|
||||
var indicatorRt = new RectTransform(new Point(objectiveGroup.AbsoluteSpacing), frame.RectTransform, isFixedSize: true);
|
||||
segment.ObjectiveStateIndicator = new GUIImage(indicatorRt, "ObjectiveIndicatorIncomplete");;
|
||||
|
||||
SetTransparent(segment.LinkedTextBlock);
|
||||
|
||||
segment.ObjectiveButton = new GUIButton(new RectTransform(Vector2.One, segment.LinkedTextBlock.RectTransform, Anchor.TopLeft, Pivot.TopLeft), style: null)
|
||||
{
|
||||
ToolTip = objectiveTextTranslated,
|
||||
OnClicked = (GUIButton btn, object userdata) =>
|
||||
{
|
||||
if (segment.SegmentType == TutorialSegmentType.InfoBox)
|
||||
{
|
||||
if (segment.AutoPlayVideo == AutoPlayVideo.Yes)
|
||||
{
|
||||
ReplaySegmentVideo(segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowSegmentText(segment);
|
||||
}
|
||||
}
|
||||
else if (segment.SegmentType == TutorialSegmentType.MessageBox)
|
||||
{
|
||||
segment.OnClickToDisplayMessage?.Invoke();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
SetTransparent(segment.ObjectiveButton);
|
||||
|
||||
static void SetTransparent(GUIComponent component) => component.Color = component.HoverColor = component.PressedColor = component.SelectedColor = Color.Transparent;
|
||||
}
|
||||
|
||||
private void ReplaySegmentVideo(Segment segment)
|
||||
{
|
||||
if (ContentRunning) return;
|
||||
if (ContentRunning) { return; }
|
||||
Inventory.DraggingItems.Clear();
|
||||
ContentRunning = true;
|
||||
LoadVideo(segment);
|
||||
//videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false);
|
||||
}
|
||||
|
||||
private void ShowSegmentText(Segment segment)
|
||||
{
|
||||
if (ContentRunning) return;
|
||||
if (ContentRunning) { return; }
|
||||
Inventory.DraggingItems.Clear();
|
||||
ContentRunning = true;
|
||||
|
||||
LocalizedString tutorialText = TextManager.GetFormatted(segment.TextContent.Value.Tag, segment.Args);
|
||||
|
||||
Action videoAction = null;
|
||||
|
||||
if (segment.ContentType != TutorialContentType.TextOnly)
|
||||
{
|
||||
videoAction = () => LoadVideo(segment);
|
||||
}
|
||||
|
||||
infoBox = CreateInfoFrame(TextManager.Get(segment.Id), tutorialText,
|
||||
segment.TextContent.Value.Width,
|
||||
segment.TextContent.Value.Height,
|
||||
segment.TextContent.Value.Anchor, true, () => ContentRunning = false, videoAction);
|
||||
}
|
||||
|
||||
protected void RemoveCompletedObjective(Index segmentIndex)
|
||||
{
|
||||
if (!HasObjective(segmentIndex)) return;
|
||||
var segment = segments[segmentIndex];
|
||||
segment.IsTriggered = true;
|
||||
segment.ReplayButton.OnClicked = null;
|
||||
|
||||
int checkMarkHeight = (int)(segment.ReplayButton.Rect.Height * 1.2f);
|
||||
int checkMarkWidth = (int)(checkMarkHeight * 0.93f);
|
||||
|
||||
Color color = new Color(4, 180, 108);
|
||||
|
||||
int objectiveTextWidth = segment.LinkedText.Rect.Width;
|
||||
int objectiveTitleWidth = segment.LinkedTitle.Rect.Width;
|
||||
|
||||
RectTransform rectTA;
|
||||
if (objectiveTextWidth > objectiveTitleWidth)
|
||||
{
|
||||
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomRight, Pivot.BottomRight);
|
||||
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(25 * GUI.Scale), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomRight, Pivot.BottomRight);
|
||||
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - (int)(25 * GUI.Scale) - (objectiveTitleWidth - objectiveTextWidth), 0);
|
||||
}
|
||||
|
||||
GUIImage checkmark = new GUIImage(rectTA, "CheckMark");
|
||||
checkmark.Color = checkmark.SelectedColor = checkmark.HoverColor = checkmark.PressedColor = color;
|
||||
|
||||
RectTransform rectTB = new RectTransform(new Vector2(1.0f, .8f), segment.LinkedText.RectTransform, Anchor.Center, Pivot.Center);
|
||||
GUIImage stroke = new GUIImage(rectTB, "Stroke");
|
||||
stroke.Color = stroke.SelectedColor = stroke.HoverColor = stroke.PressedColor = color;
|
||||
|
||||
CoroutineManager.StartCoroutine(WaitForObjectiveEnd(segmentIndex));
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> WaitForObjectiveEnd(Index objectiveIndex)
|
||||
{
|
||||
var objective = segments[objectiveIndex];
|
||||
yield return new WaitForSeconds(2.0f);
|
||||
objectiveFrame.RemoveChild(objective.ReplayButton);
|
||||
activeObjectives.Remove(objectiveIndex);
|
||||
|
||||
for (int i = 0; i < activeObjectives.Count; i++)
|
||||
{
|
||||
var activeObjective = segments[activeObjectives[i]];
|
||||
activeObjective.ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjective.ReplayButton.Rect.Height + 20) * i);
|
||||
}
|
||||
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,
|
||||
hasButton: true,
|
||||
onInfoBoxClosed: () => ContentRunning = false,
|
||||
onVideoButtonClicked: () => LoadVideo(segment));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region InfoFrame
|
||||
protected bool CloseInfoFrame(GUIButton button, object userData)
|
||||
|
||||
private void CloseInfoFrame() => CloseInfoFrame(null, null);
|
||||
|
||||
private bool CloseInfoFrame(GUIButton button, object userData)
|
||||
{
|
||||
infoBox = null;
|
||||
infoBoxClosedCallback?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected GUIComponent CreateInfoFrame(LocalizedString title, LocalizedString text, int width = 300, int height = 80, Anchor anchor = Anchor.TopRight, bool hasButton = false, Action callback = null, Action showVideo = null)
|
||||
/// <summary>
|
||||
// Creates and displays a tutorial info box
|
||||
/// </summary>
|
||||
private GUIComponent CreateInfoFrame(LocalizedString title, LocalizedString text, int width = 300, int height = 80, Anchor anchor = Anchor.TopRight, bool hasButton = false, Action onInfoBoxClosed = null, Action onVideoButtonClicked = null)
|
||||
{
|
||||
if (hasButton) height += 60;
|
||||
if (hasButton)
|
||||
{
|
||||
height += 60;
|
||||
}
|
||||
|
||||
width = (int)(width * GUI.Scale);
|
||||
height = (int)(height * GUI.Scale);
|
||||
@@ -467,7 +719,7 @@ namespace Barotrauma.Tutorials
|
||||
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), text, wrap: true);
|
||||
|
||||
textBlock.RectTransform.IsFixedSize = true;
|
||||
infoBoxClosedCallback = callback;
|
||||
infoBoxClosedCallback = onInfoBoxClosed;
|
||||
|
||||
if (hasButton)
|
||||
{
|
||||
@@ -477,7 +729,7 @@ namespace Barotrauma.Tutorials
|
||||
};
|
||||
buttonContainer.RectTransform.IsFixedSize = true;
|
||||
|
||||
if (showVideo != null)
|
||||
if (onVideoButtonClicked != null)
|
||||
{
|
||||
buttonContainer.Stretch = true;
|
||||
var videoButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform),
|
||||
@@ -485,7 +737,7 @@ namespace Barotrauma.Tutorials
|
||||
{
|
||||
OnClicked = (GUIButton button, object obj) =>
|
||||
{
|
||||
showVideo();
|
||||
onVideoButtonClicked();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -509,57 +761,39 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Video
|
||||
protected void LoadVideo(Segment segment)
|
||||
|
||||
private void LoadVideo(Segment segment)
|
||||
{
|
||||
if (videoPlayer == null) videoPlayer = new VideoPlayer();
|
||||
if (segment.ContentType != TutorialContentType.ManualVideo)
|
||||
videoPlayer ??= new VideoPlayer();
|
||||
if (segment.AutoPlayVideo == AutoPlayVideo.Yes)
|
||||
{
|
||||
videoPlayer.LoadContent(
|
||||
PlayableContentPath,
|
||||
new VideoPlayer.VideoSettings(segment.VideoContent.Value.File),
|
||||
new VideoPlayer.TextSettings(segment.VideoContent.Value.TextTag, segment.VideoContent.Value.Width),
|
||||
segment.Id, true, segment.Objective, StopCurrentContentSegment);
|
||||
contentPath: PlayableContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.Value.File),
|
||||
textSettings: new VideoPlayer.TextSettings(segment.VideoContent.Value.TextTag, segment.VideoContent.Value.Width),
|
||||
contentId: segment.Id,
|
||||
startPlayback: true,
|
||||
objective: segment.ObjectiveText,
|
||||
onStop: StopCurrentContentSegment);
|
||||
}
|
||||
else
|
||||
{
|
||||
videoPlayer.LoadContent(PlayableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent.Value.File), null, segment.Id, true, string.Empty, null);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Highlights
|
||||
protected void HighlightInventorySlot(Inventory inventory, Identifier identifier, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
|
||||
{
|
||||
if (inventory.visualSlots == null) { return; }
|
||||
for (int i = 0; i < inventory.Capacity; i++)
|
||||
{
|
||||
if (inventory.GetItemAt(i)?.Prefab.Identifier == identifier)
|
||||
{
|
||||
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
|
||||
}
|
||||
videoPlayer.LoadContent(
|
||||
contentPath: PlayableContentPath,
|
||||
videoSettings: new VideoPlayer.VideoSettings(segment.VideoContent.Value.File),
|
||||
textSettings: null,
|
||||
contentId: segment.Id,
|
||||
startPlayback: true,
|
||||
objective: string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
protected void HighlightInventorySlotWithTag(Inventory inventory, Identifier tag, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
|
||||
{
|
||||
if (inventory.visualSlots == null) { return; }
|
||||
for (int i = 0; i < inventory.Capacity; i++)
|
||||
{
|
||||
if (inventory.GetItemAt(i)?.HasTag(tag) ?? false)
|
||||
{
|
||||
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void LoadActiveContentVideo() => LoadVideo(ActiveContentSegment);
|
||||
|
||||
protected void HighlightInventorySlot(Inventory inventory, int index, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
|
||||
{
|
||||
if (inventory.visualSlots == null || index < 0 || inventory.visualSlots[index].HighlightTimer > 0) { return; }
|
||||
inventory.visualSlots[index].ShowBorderHighlight(color, fadeInDuration, fadeOutDuration, scaleUpAmount);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
public Tutorial Tutorial;
|
||||
|
||||
public TutorialMode(GameModePreset preset)
|
||||
: base(preset)
|
||||
{
|
||||
}
|
||||
public TutorialMode(GameModePreset preset) : base(preset) { }
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
@@ -31,7 +28,7 @@ namespace Barotrauma
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
Tutorial.Update(deltaTime);
|
||||
Tutorial.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user