Unstable v0.19.3.0

This commit is contained in:
Juan Pablo Arce
2022-09-02 15:10:56 -03:00
parent 28789616bd
commit 3f2c843247
336 changed files with 7152 additions and 7739 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
}
}

View File

@@ -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();
}
}
}