Merge commit '1841836c4bd505bc2f0a50762fbae2cbbf5033c2'

# Conflicts:
#	Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
#	Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs
This commit is contained in:
Joonas Rikkonen
2019-04-26 11:31:36 +03:00
223 changed files with 7725 additions and 1910 deletions

View File

@@ -0,0 +1,35 @@
#!/bin/bash
# MonoKickstart Shell Script
# Written by Ethan "flibitijibibo" Lee
# Move to script's directory
cd "`dirname "$0"`"
# Get the system architecture
UNAME=`uname`
ARCH=`uname -m`
# MonoKickstart picks the right libfolder, so just execute the right binary.
if [ "$UNAME" == "Darwin" ]; then
# ... Except on OSX.
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./osx/
# El Capitan is a total idiot and wipes this variable out, making the
# Steam overlay disappear. This sidesteps "System Integrity Protection"
# and resets the variable with Valve's own variable (they provided this
# fix by the way, thanks Valve!). Note that you will need to update your
# launch configuration to the script location, NOT just the app location
# (i.e. Kick.app/Contents/MacOS/Kick, not just Kick.app).
# -flibit
if [ "$STEAM_DYLD_INSERT_LIBRARIES" != "" ] && [ "$DYLD_INSERT_LIBRARIES" == "" ]; then
export DYLD_INSERT_LIBRARIES="$STEAM_DYLD_INSERT_LIBRARIES"
fi
./Barotrauma.bin.osx $@
else
if [ "$ARCH" == "x86_64" ]; then
./Barotrauma.bin.x86_64 $@
else
./Barotrauma.bin.x86 $@
fi
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -43,8 +43,12 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\SinglePlayerCampaign.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\BasicTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\ContextualTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\CaptainTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\DoctorTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\EditorTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\EngineerTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\MechanicTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\OfficerTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\ScenarioTutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\Tutorial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\TutorialMode.cs" />

View File

@@ -193,6 +193,60 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="Barotrauma">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Barotrauma.bin.x86">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Barotrauma.bin.x86_64">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Mono.Posix.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Mono.Security.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="monoconfig">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="monomachineconfig">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="mscorlib.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Configuration.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Core.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Data.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Drawing.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Numerics.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Runtime.Serialization.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Security.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Xml.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Xml.Linq.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@@ -188,7 +188,62 @@
<None Include="libvlc.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="libMonoPosixHelper.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="Barotrauma">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Barotrauma.bin.osx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Mono.Posix.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Mono.Security.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="monoconfig">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="monomachineconfig">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="mscorlib.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Configuration.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Core.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Data.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Drawing.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Numerics.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Runtime.Serialization.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Security.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Xml.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Xml.Linq.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="barotrauma.icns" />
</ItemGroup>
<ItemGroup />
<Import Project="ClientCode.projitems" Label="Shared" />

Binary file not shown.

Binary file not shown.

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.8.9.10")]
[assembly: AssemblyFileVersion("0.8.9.10")]
[assembly: AssemblyVersion("0.8.10.0")]
[assembly: AssemblyFileVersion("0.8.10.0")]

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<dllmap dll="freetype6" os="linux" target="libfreetype.so.6" />
<dllmap dll="freetype6" os="osx" target="/Library/Frameworks/Mono.framework/Libraries/libfreetype.6.dylib" />
<dllmap dll="freetype6" os="osx" target="libvlc.dylib" />
<dllmap dll="freetype6" os="freebsd" target="libfreetype.so.6" />
</configuration>

View File

@@ -264,35 +264,17 @@ namespace Barotrauma
partial void ImpactProjSpecific(float impact, Body body)
{
float volume = Math.Min(impact - 3.0f, 1.0f);
float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f);
if (body.UserData is Limb && character.Stun <= 0f)
if (body.UserData is Limb limb && character.Stun <= 0f)
{
Limb limb = (Limb)body.UserData;
if (impact > 3.0f && limb.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
{
limb.LastImpactSoundTime = (float)Timing.TotalTime;
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
{
SoundPlayer.PlaySound(limb.HitSoundTag, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
}
foreach (WearableSprite wearable in limb.WearingItems)
{
if (limb.type == wearable.Limb && !string.IsNullOrWhiteSpace(wearable.Sound))
{
SoundPlayer.PlaySound(wearable.Sound, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
}
}
}
if (impact > 3.0f) { PlayImpactSound(limb); }
}
else if (body.UserData is Limb || body == Collider.FarseerBody)
{
if (!character.IsRemotePlayer)
if (!character.IsRemotePlayer && impact > ImpactTolerance)
{
if (impact > ImpactTolerance)
{
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
}
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
}
}
if (Character.Controlled == character)
@@ -301,6 +283,29 @@ namespace Barotrauma
}
}
public void PlayImpactSound(Limb limb)
{
limb.LastImpactSoundTime = (float)Timing.TotalTime;
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
{
bool inWater = limb.inWater;
if (character.CurrentHull != null &&
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height &&
limb.SimPosition.Y < ConvertUnits.ToSimUnits(character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height) + limb.body.GetMaxExtent())
{
inWater = true;
}
SoundPlayer.PlaySound(inWater ? "footstep_water" : limb.HitSoundTag, limb.WorldPosition, hullGuess: character.CurrentHull);
}
foreach (WearableSprite wearable in limb.WearingItems)
{
if (limb.type == wearable.Limb && !string.IsNullOrWhiteSpace(wearable.Sound))
{
SoundPlayer.PlaySound(wearable.Sound, limb.WorldPosition, hullGuess: character.CurrentHull);
}
}
}
partial void Splash(Limb limb, Hull limbHull)
{
//create a splash particle
@@ -363,6 +368,8 @@ namespace Barotrauma
partial void UpdateProjSpecific(float deltaTime)
{
if (!character.Enabled || SimplePhysicsEnabled) { return; }
LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime));
foreach (var deformation in SpriteDeformations)
{
@@ -393,7 +400,7 @@ namespace Barotrauma
}
}
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint)
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint, bool playSound = true)
{
foreach (Limb limb in new Limb[] { limbJoint.LimbA, limbJoint.LimbB })
{
@@ -411,6 +418,11 @@ namespace Barotrauma
character.CurrentHull?.AddDecal(character.BloodDecalName, limb.WorldPosition, MathHelper.Clamp(limb.Mass, 0.5f, 2.0f));
}
}
if (playSound)
{
SoundPlayer.PlayDamageSound("Gore", 1.0f, limbJoint.LimbA.body);
}
}
public virtual void Draw(SpriteBatch spriteBatch, Camera cam)
@@ -428,14 +440,15 @@ namespace Barotrauma
return;
}
//foreach (Limb limb in Limbs)
//{
// limb.Draw(spriteBatch, cam);
//}
Color? color = null;
if (character.ExternalHighlight)
{
color = Color.Lerp(Color.White, Color.OrangeRed, (float)Math.Sin(Timing.TotalTime * 3.5f));
}
for (int i = 0; i < limbs.Length; i++)
{
inversedLimbDrawOrder[i].Draw(spriteBatch, cam);
inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color);
}
LimbJoints.ForEach(j => j.Draw(spriteBatch));
}

View File

@@ -50,7 +50,7 @@ namespace Barotrauma
if (sound != null)
{
SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, worldPosition);
SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range);
}
}
}

View File

@@ -33,6 +33,8 @@ namespace Barotrauma
private List<CharacterSound> sounds;
public bool ExternalHighlight;
//the Character that the player is currently controlling
private static Character controlled;
@@ -109,6 +111,33 @@ namespace Barotrauma
get { return gibEmitters; }
}
public class ObjectiveEntity
{
public Entity Entity;
public Sprite Sprite;
public Color Color;
public ObjectiveEntity(Entity entity, Sprite sprite, Color? color = null)
{
Entity = entity;
Sprite = sprite;
if (color.HasValue)
{
Color = color.Value;
}
else
{
Color = Color.White;
}
}
}
private List<ObjectiveEntity> activeObjectiveEntities = new List<ObjectiveEntity>();
public IEnumerable<ObjectiveEntity> ActiveObjectiveEntities
{
get { return activeObjectiveEntities; }
}
partial void InitProjSpecific(XDocument doc)
{
soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f);
@@ -728,15 +757,29 @@ namespace Barotrauma
var matchingSoundsList = matchingSounds.ToList();
var selectedSound = matchingSoundsList[Rand.Int(matchingSoundsList.Count)];
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, AnimController.WorldPosition, CurrentHull);
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, CurrentHull);
soundTimer = soundInterval;
}
public void AddActiveObjectiveEntity(Entity entity, Sprite sprite, Color? color = null)
{
if (activeObjectiveEntities.Any(aoe => aoe.Entity == entity)) return;
ObjectiveEntity objectiveEntity = new ObjectiveEntity(entity, sprite, color);
activeObjectiveEntities.Add(objectiveEntity);
}
public void RemoveActiveObjectiveEntity(Entity entity)
{
ObjectiveEntity found = activeObjectiveEntities.Find(aoe => aoe.Entity == entity);
if (found == null) return;
activeObjectiveEntities.Remove(found);
}
partial void ImplodeFX()
{
Vector2 centerOfMass = AnimController.GetCenterOfMass();
SoundPlayer.PlaySound("implode", 1.0f, 150.0f, WorldPosition);
SoundPlayer.PlaySound("implode", WorldPosition);
for (int i = 0; i < 10; i++)
{

View File

@@ -168,7 +168,12 @@ namespace Barotrauma
DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f);
}
}
foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities)
{
DrawObjectiveIndicator(spriteBatch, cam, character, objectiveEntity, 1.0f);
}
foreach (Item brokenItem in brokenItems)
{
float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition);
@@ -371,5 +376,13 @@ namespace Barotrauma
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
}
private static void DrawObjectiveIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Character.ObjectiveEntity objectiveEntity, float iconAlpha = 1.0f)
{
if (objectiveEntity == null) return;
Vector2 drawPos = objectiveEntity.Entity.WorldPosition;// + Vector2.UnitX * objectiveEntity.Sprite.size.X * 1.5f;
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, objectiveEntity.Sprite, objectiveEntity.Color * iconAlpha);
}
}
}

View File

@@ -96,6 +96,11 @@ namespace Barotrauma
private const float UpdateDisplayedAfflictionsInterval = 0.5f;
private List<Affliction> currentDisplayedAfflictions = new List<Affliction>();
public bool MouseOnElement
{
get { return highlightedLimbIndex > -1 || GUI.MouseOn == dropItemArea; }
}
private static CharacterHealth openHealthWindow;
public static CharacterHealth OpenHealthWindow
{
@@ -131,6 +136,17 @@ namespace Barotrauma
}
}
public GUIButton CPRButton
{
get { return cprButton; }
}
public float HealthBarPulsateTimer
{
get { return healthBarPulsateTimer; }
set { healthBarPulsateTimer = MathHelper.Clamp(value, 0.0f, 10.0f); }
}
static CharacterHealth()
{
damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero);
@@ -172,18 +188,16 @@ namespace Barotrauma
afflictionInfoContainer = new GUIListBox(new RectTransform(new Vector2(0.7f, 0.85f), paddedInfoFrame.RectTransform, Anchor.BottomLeft));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.08f), paddedInfoFrame.RectTransform), TextManager.Get("SuitableTreatments"), textAlignment: Alignment.TopRight);
lowSkillIndicator = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.07f), paddedInfoFrame.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.08f) },
TextManager.Get("LowMedicalSkillWarning"), Color.Orange, textAlignment: Alignment.Center, font: GUI.SmallFont, wrap: true)
lowSkillIndicator = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedInfoFrame.RectTransform, Anchor.TopRight),
TextManager.Get("LowMedicalSkillWarning"), Color.Orange, textAlignment: Alignment.TopRight, font: GUI.SmallFont, wrap: true)
{
Visible = false
};
recommendedTreatmentContainer = new GUIListBox(new RectTransform(new Vector2(0.28f, 0.5f), paddedInfoFrame.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.15f) })
{
Spacing = 10
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedInfoFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.05f) }, TextManager.Get("SuitableTreatments"), textAlignment: Alignment.BottomRight);
recommendedTreatmentContainer = new GUIListBox(new RectTransform(new Vector2(0.28f, 0.5f), paddedInfoFrame.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.12f) });
dropItemArea = new GUIFrame(new RectTransform(new Vector2(0.28f, 0.3f), paddedInfoFrame.RectTransform, Anchor.BottomRight)
{ RelativeOffset = new Vector2(0.0f, 0.0f) }, style: null)
{ RelativeOffset = new Vector2(0.02f, 0.0f) }, style: null)
{
ToolTip = TextManager.Get("HealthItemUseTip")
};
@@ -584,9 +598,18 @@ namespace Barotrauma
var affliction = GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None)
.OrderByDescending(a => a.DamagePerSecond)
.ThenByDescending(a => a.Strength).FirstOrDefault();
var limbHealth = GetMathingLimbHealth(affliction);
if (limbHealth != null)
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
{
var limbHealth = GetMathingLimbHealth(affliction);
if (limbHealth != null)
{
selectedLimbIndex = limbHealths.IndexOf(limbHealth);
}
}
else
{
// If no affliction is critical, select the limb which has most damage.
var limbHealth = limbHealths.OrderByDescending(l => l.TotalDamage).FirstOrDefault();
selectedLimbIndex = limbHealths.IndexOf(limbHealth);
}
}
@@ -928,7 +951,7 @@ namespace Barotrauma
{
afflictionInfoContainer.Content.ClearChildren();
recommendedTreatmentContainer.Content.ClearChildren();
float characterSkillLevel = Character.Controlled == null ? 0.0f : Character.Controlled.GetSkillLevel("medical");
//random variance is 200% when the skill is 0
@@ -1023,14 +1046,15 @@ namespace Barotrauma
{
ItemPrefab item = MapEntityPrefab.Find(name: null, identifier: treatment.Key, showErrorMessages: false) as ItemPrefab;
if (item == null) continue;
int slotSize = (int)(recommendedTreatmentContainer.Content.Rect.Width * 0.8f);
int slotSize = (int)(recommendedTreatmentContainer.Content.Rect.Width * 0.5f);
var itemSlot = new GUIButton(new RectTransform(new Point(slotSize), recommendedTreatmentContainer.Content.RectTransform, Anchor.TopCenter),
text: "", style: "InventorySlotSmall")
var itemSlot = new GUIFrame(new RectTransform(new Point(recommendedTreatmentContainer.Content.Rect.Width, slotSize), recommendedTreatmentContainer.Content.RectTransform, Anchor.TopCenter),
style: "InnerGlow")
{
UserData = item
UserData = item,
CanBeFocused = false
};
itemSlot.Color = ToolBox.GradientLerp(treatment.Value, Color.Red, Color.White, Color.LightGreen);
itemSlot.Color = ToolBox.GradientLerp(treatment.Value, Color.Red, Color.Orange, Color.LightGreen);
Sprite itemSprite = item.InventoryIcon ?? item.sprite;
Color itemColor = itemSprite == item.sprite ? item.SpriteColor : item.InventoryIconColor;
@@ -1414,6 +1438,8 @@ namespace Barotrauma
{
foreach (Limb limb in Character.AnimController.Limbs)
{
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }
limb.BurnOverlayStrength = 0.0f;
limb.DamageOverlayStrength = 0.0f;
if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue;

View File

@@ -292,10 +292,10 @@ namespace Barotrauma
if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound))
{
damageSoundType = damageModifier.DamageSound;
SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition);
break;
}
}
SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), WorldPosition);
}
// Always spawn damage particles

View File

@@ -346,7 +346,7 @@ namespace Barotrauma
}
}));
commands.Add(new Command("mainmenuscreen|mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
commands.Add(new Command("mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
{
GameMain.GameSession = null;
@@ -359,12 +359,16 @@ namespace Barotrauma
GameMain.MainMenuScreen.Select();
}));
commands.Add(new Command("gamescreen|game", "gamescreen/game: Go to the \"in-game\" view.", (string[] args) =>
commands.Add(new Command("game", "gamescreen/game: Go to the \"in-game\" view.", (string[] args) =>
{
if (Screen.Selected == GameMain.SubEditorScreen)
{
NewMessage("WARNING: Switching directly from the submarine editor to the game view may cause bugs and crashes. Use with caution.", Color.Orange);
}
GameMain.GameScreen.Select();
}));
commands.Add(new Command("editsubscreen|editsub|subeditor", "editsub/subeditor: Switch to the submarine editor.", (string[] args) =>
commands.Add(new Command("editsubs|subeditor", "editsubs/subeditor: Switch to the Submarine Editor to create or edit submarines.", (string[] args) =>
{
if (args.Length > 0)
{
@@ -373,23 +377,27 @@ namespace Barotrauma
GameMain.SubEditorScreen.Select();
}));
commands.Add(new Command("editparticles|particleeditor", "", (string[] args) =>
commands.Add(new Command("editparticles|particleeditor", "editparticles/particleeditor: Switch to the Particle Editor to edit particle effects.", (string[] args) =>
{
GameMain.ParticleEditorScreen.Select();
}));
commands.Add(new Command("editlevels|editlevel|leveleditor", "", (string[] args) =>
commands.Add(new Command("editlevels|leveleditor", "editlevels/leveleditor: Switch to the Level Editor to edit levels.", (string[] args) =>
{
GameMain.LevelEditorScreen.Select();
}));
commands.Add(new Command("editsprites|editsprite|spriteeditor|spriteedit", "", (string[] args) =>
commands.Add(new Command("editsprites|spriteeditor", "editsprites/spriteeditor: Switch to the Sprite Editor to edit the source rects and origins of sprites.", (string[] args) =>
{
GameMain.SpriteEditorScreen.Select();
}));
commands.Add(new Command("charactereditor|editcharacter|editcharacters|editanimation|editanimations|animedit|animationeditor|animeditor|animationedit", "charactereditor: Edit characters, animations, ragdolls....", (string[] args) =>
commands.Add(new Command("editcharacters|charactereditor", "editcharacters/charactereditor: Switch to the Character Editor to edit/create the ragdolls and animations of characters.", (string[] args) =>
{
if (Screen.Selected == GameMain.GameScreen)
{
NewMessage("WARNING: Switching between the character editor and the game view may cause odd behaviour or bugs. Use with caution.", Color.Orange);
}
GameMain.CharacterEditorScreen.Select();
}));
@@ -555,6 +563,37 @@ namespace Barotrauma
}
}));
commands.Add(new Command("resetselected", "Reset selected items and structures to prefabs. Only applicable in the subeditor.", args =>
{
if (Screen.Selected == GameMain.SubEditorScreen)
{
foreach (MapEntity entity in MapEntity.SelectedList)
{
if (entity is Item item)
{
item.Reset();
}
else if (entity is Structure structure)
{
structure.Reset();
}
}
foreach (MapEntity entity in MapEntity.SelectedList)
{
if (entity is Item item)
{
item.CreateEditingHUD();
break;
}
else if (entity is Structure structure)
{
structure.CreateEditingHUD();
break;
}
}
}
}));
commands.Add(new Command("alpha", "Change the alpha (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) =>
{
if (Screen.Selected == GameMain.SubEditorScreen)
@@ -1057,8 +1096,8 @@ namespace Barotrauma
List<string> lines = new List<string>();
foreach (MapEntityPrefab me in MapEntityPrefab.List)
{
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</" + me.Identifier + ".Name>");
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</" + me.Identifier + ".Description>");
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</EntityName." + me.Identifier + ">");
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</EntityDescription." + me.Identifier + ">");
}
File.WriteAllLines(filePath, lines);
}));
@@ -1488,7 +1527,7 @@ namespace Barotrauma
character.AnimController.ResetRagdoll();
}, isCheat: true));
commands.Add(new Command("reloadwearables|reloadlimbs", "Reloads the sprites of all limbs and wearable sprites (clothing) of the controlled character. Provide id or name if you want to target another character.", args =>
commands.Add(new Command("reloadwearables", "Reloads the sprites of all limbs and wearable sprites (clothing) of the controlled character. Provide id or name if you want to target another character.", args =>
{
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
if (character == null)
@@ -1499,6 +1538,26 @@ namespace Barotrauma
ReloadWearables(character);
}, isCheat: true));
commands.Add(new Command("loadwearable", "Force select certain variant for the selected character.", args =>
{
var character = Character.Controlled;
if (character == null)
{
ThrowError("Not controlling any character.");
return;
}
if (args.Length == 0)
{
ThrowError("No arguments provided! Give an index number for the variant starting from 1.");
return;
}
if (int.TryParse(args[0], out int variant))
{
ReloadWearables(character, variant);
}
}, isCheat: true));
commands.Add(new Command("reloadsprite|reloadsprites", "Reloads the sprites of the selected item(s)/structure(s) (hovering over or selecting in the subeditor) or the controlled character. Can also reload sprites by entity id or by the name attribute (sprite element). Example 1: reloadsprite id itemid. Example 2: reloadsprite name \"Sprite name\"", args =>
{
if (Screen.Selected is SpriteEditorScreen)
@@ -1646,7 +1705,7 @@ namespace Barotrauma
}, isCheat: true));
}
private static void ReloadWearables(Character character)
private static void ReloadWearables(Character character, int variant = 0)
{
foreach (var limb in character.AnimController.Limbs)
{
@@ -1655,11 +1714,17 @@ namespace Barotrauma
limb.DeformSprite?.Sprite.ReloadTexture();
foreach (var wearable in limb.WearingItems)
{
if (variant > 0 && wearable.Variant > 0)
{
wearable.Variant = variant;
}
wearable.RefreshPath();
wearable.Sprite.ReloadXML();
wearable.Sprite.ReloadTexture();
}
foreach (var wearable in limb.OtherWearables)
{
wearable.RefreshPath();
wearable.Sprite.ReloadXML();
wearable.Sprite.ReloadTexture();
}

View File

@@ -7,7 +7,7 @@ using System.Xml.Linq;
namespace Barotrauma
{
public class ScalableFont
public class ScalableFont : IDisposable
{
private static List<ScalableFont> FontList = new List<ScalableFont>();
private static Library Lib = null;
@@ -30,7 +30,7 @@ namespace Barotrauma
set
{
size = value;
if (graphicsDevice!=null) RenderAtlas(graphicsDevice, charRanges, texDims, baseChar);
if (graphicsDevice != null) RenderAtlas(graphicsDevice, charRanges, texDims, baseChar);
}
}
@@ -279,7 +279,7 @@ namespace Barotrauma
if (text[i] == '\n')
{
currentLineX = 0.0f;
retVal.Y += baseHeight * 18 / 10;
retVal.Y += baseHeight * 1.8f;
continue;
}
uint charIndex = text[i];
@@ -302,5 +302,15 @@ namespace Barotrauma
}
return retVal;
}
public void Dispose()
{
FontList.Remove(this);
foreach (Texture2D texture in textures)
{
texture.Dispose();
}
textures.Clear();
}
}
}

View File

@@ -18,15 +18,27 @@ namespace Barotrauma
private GUITextBox inputBox;
private GUIButton toggleButton;
private GUIButton radioButton;
private Point screenResolution;
private bool isSinglePlayer;
public bool IsSinglePlayer => isSinglePlayer;
private bool toggleOpen = true;
private bool _toggleOpen = true;
public bool ToggleOpen
{
get { return _toggleOpen; }
set
{
if (_toggleOpen == value) { return; }
_toggleOpen = GameMain.Config.ChatOpen = value;
foreach (GUIComponent child in ToggleButton.Children)
{
child.SpriteEffects = _toggleOpen == (HUDLayoutSettings.ChatBoxAlignment == Alignment.Right) ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
}
}
private float openState;
private float prevUIScale;
@@ -46,12 +58,7 @@ namespace Barotrauma
{
get { return guiFrame; }
}
public GUIButton RadioButton
{
get { return radioButton; }
}
public GUITextBox InputBox
{
get { return inputBox; }
@@ -81,12 +88,7 @@ namespace Barotrauma
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
{
toggleOpen = !toggleOpen;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = toggleOpen == (HUDLayoutSettings.ChatBoxAlignment == Alignment.Right) ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
ToggleOpen = !ToggleOpen;
return true;
};
@@ -100,30 +102,8 @@ namespace Barotrauma
{
gui.Text = "";
};
radioButton = new GUIButton(new RectTransform(new Vector2(0.1f, 2.0f), inputBox.RectTransform,
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Anchor.BottomRight : Anchor.BottomLeft,
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Pivot.TopRight : Pivot.TopLeft),
style: null);
new GUIImage(new RectTransform(Vector2.One, radioButton.RectTransform), radioIcon, scaleToFit: true);
radioButton.OnClicked = (GUIButton btn, object userData) =>
{
if (inputBox.Selected)
{
inputBox.Text = "";
inputBox.Deselect();
}
else
{
inputBox.Select();
var radioItem = Character.Controlled?.Inventory?.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
if (radioItem != null && Character.Controlled.HasEquippedItem(radioItem) && radioItem.GetComponent<WifiComponent>().CanTransmit())
{
inputBox.Text = "r; ";
}
}
return true;
};
ToggleOpen = GameMain.Config.ChatOpen;
}
public bool TypingChatMessage(GUITextBox textBox, string text)
@@ -228,7 +208,7 @@ namespace Barotrauma
chatBox.UpdateScrollBarSize();
if (!toggleOpen)
if (!ToggleOpen)
{
var popupMsg = new GUIFrame(new RectTransform(Vector2.One, guiFrame.RectTransform), style: "GUIToolTip")
{
@@ -313,9 +293,7 @@ namespace Barotrauma
prevUIScale = GUI.Scale;
}
if (toggleOpen || (inputBox != null && inputBox.Selected))
if (ToggleOpen || (inputBox != null && inputBox.Selected))
{
openState += deltaTime * 5.0f;
//delete all popup messages when the chatbox is open
@@ -359,7 +337,6 @@ namespace Barotrauma
}
openState = MathHelper.Clamp(openState, 0.0f, 1.0f);
int hiddenBoxOffset = guiFrame.Rect.Width + toggleButton.Rect.Width;
if (radioButton != null) hiddenBoxOffset += (int)(radioButton.Rect.Width * 1.5f);
guiFrame.RectTransform.AbsoluteOffset =
new Point((int)MathHelper.SmoothStep(hiddenBoxOffset * (HUDLayoutSettings.ChatBoxAlignment == Alignment.Left ? -1 : 1), 0, openState), 0);
}

View File

@@ -129,6 +129,8 @@ namespace Barotrauma
get { return pauseMenuOpen; }
}
public static bool PreventPauseMenuToggle = false;
public static Color ScreenOverlayColor
{
get;
@@ -1413,6 +1415,7 @@ namespace Barotrauma
public static void TogglePauseMenu()
{
if (Screen.Selected == GameMain.MainMenuScreen) return;
if (PreventPauseMenuToggle) return;
settingsMenuOpen = false;
@@ -1546,9 +1549,9 @@ namespace Barotrauma
if (GameMain.GameSession != null)
{
if (ContextualTutorial.Initialized && GameMain.GameSession.GameMode is SinglePlayerCampaign)
if (Tutorial.Initialized)
{
((SinglePlayerCampaign)GameMain.GameSession.GameMode).ContextualTutorial.Stop();
((TutorialMode)GameMain.GameSession.GameMode).Tutorial.Stop();
}
if (GameSettings.SendUserStatistics)
@@ -1559,6 +1562,8 @@ namespace Barotrauma
}
GameMain.GameSession = null;
}
GUIMessageBox.CloseAll();
GameMain.MainMenuScreen.Select();
@@ -1566,7 +1571,7 @@ namespace Barotrauma
}
/// <summary>
/// Displays a message at the center of the screen, automatically preventing overlapping with other centered messages
/// Displays a message at the center of the screen, automatically preventing overlapping with other centered messages. TODO: Allow to show messages at the middle of the screen (instead of the top center).
/// </summary>
public static void AddMessage(string message, Color color, float? lifeTime = null, bool playSound = true, ScalableFont font = null)
{

View File

@@ -168,6 +168,11 @@ namespace Barotrauma
if (frame != null) frame.ApplyStyle(style);
}
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null)
{
Frame.Flash(color, flashDuration, useRectangleFlash, flashRectInflate);
}
protected override void Draw(SpriteBatch spriteBatch)
{
//do nothing

View File

@@ -121,11 +121,19 @@ namespace Barotrauma
protected Color selectedColor;
protected Color pressedColor;
private CoroutineHandle pulsateCoroutine;
protected ComponentState state;
protected Color flashColor;
protected float flashDuration = 1.5f;
private bool useRectangleFlash;
public float FlashTimer
{
get { return flashTimer; }
}
protected float flashTimer;
private Vector2 flashRectInflate;
public bool IgnoreLayoutGroups;
@@ -261,6 +269,8 @@ namespace Barotrauma
set { pressedColor = value; }
}
public bool ExternalHighlight = false;
private RectTransform rectTransform;
public RectTransform RectTransform
{
@@ -435,11 +445,21 @@ namespace Barotrauma
int flashCycleCount = (int)Math.Max(flashDuration, 1);
float flashCycleDuration = flashDuration / flashCycleCount;
Rectangle flashRect = Rect;
flashRect.Inflate(flashRectInflate.X, flashRectInflate.Y);
//MathHelper.Pi * 0.8f -> the curve goes from 144 deg to 0,
//i.e. quickly bumps up from almost full brightness to full and then fades out
GUI.UIGlow.Draw(spriteBatch,
rect,
flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
if (!useRectangleFlash)
{
GUI.UIGlow.Draw(spriteBatch,
flashRect,
flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
}
else
{
GUI.DrawRectangle(spriteBatch, flashRect, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), true);
}
}
}
@@ -487,9 +507,11 @@ namespace Barotrauma
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
}
public virtual void Flash(Color? color = null, float flashDuration = 1.5f)
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null)
{
flashTimer = flashDuration;
this.flashRectInflate = flashRectInflate ?? Vector2.Zero;
this.useRectangleFlash = useRectangleFlash;
this.flashDuration = flashDuration;
flashColor = (color == null) ? Color.Red : (Color)color;
}
@@ -507,9 +529,7 @@ namespace Barotrauma
while (t < duration)
{
t += CoroutineManager.DeltaTime;
SetAlpha(MathHelper.Lerp(startA, to, t / duration));
yield return CoroutineStatus.Running;
}
@@ -523,6 +543,28 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
public void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
{
if (CoroutineManager.IsCoroutineRunning(pulsateCoroutine))
{
return;
}
pulsateCoroutine = CoroutineManager.StartCoroutine(DoPulsate(startScale, endScale, duration), "Pulsate" + ToString());
}
private IEnumerable<object> DoPulsate(Vector2 startScale, Vector2 endScale, float duration)
{
float t = 0.0f;
while (t < duration)
{
t += CoroutineManager.DeltaTime;
RectTransform.LocalScale = Vector2.Lerp(startScale, endScale, (float)Math.Sin(t / duration * MathHelper.Pi));
yield return CoroutineStatus.Running;
}
RectTransform.LocalScale = startScale;
yield return CoroutineStatus.Success;
}
public virtual void ApplyStyle(GUIComponentStyle style)
{
if (style == null) return;

View File

@@ -511,10 +511,8 @@ namespace Barotrauma
pos = 0;
totalSize += child.Rect.Width + spacing;
}
else
{
pos += child.Rect.Height + spacing;
}
pos += child.Rect.Height + spacing;
if (child == children.Last())
{
totalSize += child.Rect.Width + spacing;
@@ -527,10 +525,7 @@ namespace Barotrauma
pos = 0;
totalSize += child.Rect.Height + spacing;
}
else
{
pos += child.Rect.Width + spacing;
}
pos += child.Rect.Width + spacing;
if (child == children.Last())
{

View File

@@ -38,35 +38,25 @@ namespace Barotrauma
public GUIMessageBox(string headerText, string text, string[] buttons, int width = DefaultWidth, int height = 0, Alignment textAlignment = Alignment.TopLeft, string tag = "")
: base(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "")
{
int headerHeight = 30;
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, Anchor.Center) { IsFixedSize = false }, style: null);
GUI.Style.Apply(InnerFrame, "", this);
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
Tag = tag;
if (height == 0)
{
string wrappedText = ToolBox.WrapText(text, Content.Rect.Width, GUI.Font);
string[] lines = wrappedText.Split('\n');
foreach (string line in lines)
{
height += (int)GUI.Font.MeasureString(line).Y;
}
height += string.IsNullOrWhiteSpace(headerText) ? 220 : 220 - headerHeight;
}
InnerFrame.RectTransform.NonScaledSize = new Point(InnerFrame.Rect.Width, height);
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
headerText, textAlignment: Alignment.Center, wrap: true);
GUI.Style.Apply(Header, "", this);
GUI.Style.Apply(Header, "", this);
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
if (!string.IsNullOrWhiteSpace(text))
{
Text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
text, textAlignment: textAlignment, wrap: true);
GUI.Style.Apply(Text, "", this);
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
new Point(Text.Rect.Width, Text.Rect.Height);
Text.RectTransform.IsFixedSize = true;
}
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter, maxSize: new Point(1000, 50)),
@@ -75,7 +65,22 @@ namespace Barotrauma
AbsoluteSpacing = 5,
IgnoreLayoutGroups = true
};
buttonContainer.RectTransform.NonScaledSize = buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.MaxSize =
new Point(buttonContainer.Rect.Width, (int)(30 * GUI.Scale));
buttonContainer.RectTransform.IsFixedSize = true;
if (height == 0)
{
height += Header.Rect.Height + Content.AbsoluteSpacing;
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
height += buttonContainer.Rect.Height;
InnerFrame.RectTransform.NonScaledSize =
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + 50));
Content.RectTransform.NonScaledSize =
new Point(Content.Rect.Width, height);
}
Buttons = new List<GUIButton>(buttons.Length);
for (int i = 0; i < buttons.Length; i++)
{

View File

@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
@@ -9,6 +10,8 @@ namespace Barotrauma
{
private Dictionary<string, GUIComponentStyle> componentStyles;
private XElement configElement;
public ScalableFont Font { get; private set; }
public ScalableFont SmallFont { get; private set; }
public ScalableFont LargeFont { get; private set; }
@@ -26,6 +29,8 @@ namespace Barotrauma
{
componentStyles = new Dictionary<string, GUIComponentStyle>();
GameMain.Instance.OnResolutionChanged += () => { RescaleFonts(); };
XDocument doc;
try
{
@@ -37,29 +42,11 @@ namespace Barotrauma
DebugConsole.ThrowError("Loading style \"" + file + "\" failed", e);
return;
}
configElement = doc.Root;
foreach (XElement subElement in doc.Root.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "font":
Font = new ScalableFont(subElement, graphicsDevice);
break;
case "smallfont":
SmallFont = new ScalableFont(subElement, graphicsDevice);
break;
case "largefont":
LargeFont = new ScalableFont(subElement, graphicsDevice);
break;
case "objectivetitle":
ObjectiveTitleFont = new ScalableFont(subElement, graphicsDevice);
break;
case "objectivename":
ObjectiveNameFont = new ScalableFont(subElement, graphicsDevice);
break;
case "videotitle":
VideoTitleFont = new ScalableFont(subElement, graphicsDevice);
break;
case "cursor":
CursorSprite = new Sprite(subElement);
break;
@@ -69,6 +56,24 @@ namespace Barotrauma
case "focusindicator":
FocusIndicator = new SpriteSheet(subElement);
break;
case "font":
Font = LoadFont(subElement, graphicsDevice);
break;
case "smallfont":
SmallFont = LoadFont(subElement, graphicsDevice);
break;
case "largefont":
LargeFont = LoadFont(subElement, graphicsDevice);
break;
case "objectivetitle":
ObjectiveTitleFont = LoadFont(subElement, graphicsDevice);
break;
case "objectivename":
ObjectiveNameFont = LoadFont(subElement, graphicsDevice);
break;
case "videotitle":
VideoTitleFont = LoadFont(subElement, graphicsDevice);
break;
default:
GUIComponentStyle componentStyle = new GUIComponentStyle(subElement);
componentStyles.Add(subElement.Name.ToString().ToLowerInvariant(), componentStyle);
@@ -77,6 +82,54 @@ namespace Barotrauma
}
}
private void RescaleFonts()
{
foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "font":
Font.Size = GetFontSize(subElement);
break;
case "smallfont":
SmallFont.Size = GetFontSize(subElement);
break;
case "largefont":
LargeFont.Size = GetFontSize(subElement);
break;
case "objectivetitle":
ObjectiveTitleFont.Size = GetFontSize(subElement);
break;
case "objectivename":
ObjectiveNameFont.Size = GetFontSize(subElement);
break;
case "videotitle":
VideoTitleFont.Size = GetFontSize(subElement);
break;
}
}
}
private ScalableFont LoadFont(XElement element, GraphicsDevice graphicsDevice)
{
string file = element.GetAttributeString("file", "");
uint size = GetFontSize(element);
return new ScalableFont(file, size, graphicsDevice);
}
private uint GetFontSize(XElement element)
{
foreach (XElement subElement in element.Elements())
{
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{
return (uint)subElement.GetAttributeInt("size", 14);
}
}
return 14;
}
public GUIComponentStyle GetComponentStyle(string name)
{
componentStyles.TryGetValue(name.ToLowerInvariant(), out GUIComponentStyle style);

View File

@@ -27,6 +27,11 @@ namespace Barotrauma
private bool overflowClipActive;
public bool OverflowClip;
public bool OverflowClipActive
{
get { return overflowClipActive; }
}
private float textDepth;
public Vector2 TextOffset { get; set; }
@@ -88,6 +93,7 @@ namespace Barotrauma
public Vector2 TextPos
{
get { return textPos; }
set { textPos = value; }
}
public float TextScale
@@ -327,7 +333,7 @@ namespace Barotrauma
{
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
spriteBatch.Begin(SpriteSortMode.Deferred);
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
}
if (OutlineColor.A * currColor.A > 0.0f) GUI.DrawRectangle(spriteBatch, rect, OutlineColor * (currColor.A / 255.0f), false);

View File

@@ -118,11 +118,17 @@ namespace Barotrauma
get { return maxTextLength; }
set
{
textBlock.OverflowClip = true;
textBlock.OverflowClip = value != null;
maxTextLength = value;
}
}
public bool OverflowClip
{
get { return textBlock.OverflowClip; }
set { textBlock.OverflowClip = value; }
}
public override bool Enabled
{
get { return enabled; }
@@ -318,7 +324,7 @@ namespace Barotrauma
for (int i = 0; i <= textBlock.Text.Length; i++)
{
Vector2 textSize = Font.MeasureString(textBlock.Text.Substring(0, i));
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y);
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y) + textBlock.TextPos - textBlock.Origin;
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
positions.Add(new Tuple<Vector2, int>(textBlock.Rect.Location.ToVector2() + indexPos, i));
}
@@ -359,9 +365,9 @@ namespace Barotrauma
OnDeselected?.Invoke(this, Keys.None);
}
public override void Flash(Color? color = null, float flashDuration = 1.5f)
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectOffset = null)
{
textBlock.Flash(color, flashDuration);
textBlock.Flash(color, flashDuration, useRectangleFlash, flashRectOffset);
}
protected override void Update(float deltaTime)
@@ -405,9 +411,22 @@ namespace Barotrauma
{
isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
}
if (CaretEnabled)
{
if (textBlock.OverflowClipActive)
{
if (CaretScreenPos.X < Rect.X + textBlock.Padding.X)
{
textBlock.TextPos = new Vector2(textBlock.TextPos.X + ((Rect.X + textBlock.Padding.X) - CaretScreenPos.X), textBlock.TextPos.Y);
CalculateCaretPos();
}
else if (CaretScreenPos.X > Rect.Right - textBlock.Padding.Z)
{
textBlock.TextPos = new Vector2(textBlock.TextPos.X - (CaretScreenPos.X - (Rect.Right - textBlock.Padding.Z)), textBlock.TextPos.Y);
CalculateCaretPos();
}
}
caretTimer += deltaTime;
caretVisible = ((caretTimer * 1000.0f) % 1000) < 500;
if (caretVisible && caretPosDirty)
@@ -415,7 +434,7 @@ namespace Barotrauma
CalculateCaretPos();
}
}
if (GUI.KeyboardDispatcher.Subscriber == this)
{
state = ComponentState.Selected;
@@ -534,15 +553,7 @@ namespace Barotrauma
public void ReceiveTextInput(char inputChar)
{
if (selectedCharacters > 0)
{
RemoveSelectedText();
}
if (SetText(Text.Insert(CaretIndex, inputChar.ToString())))
{
CaretIndex = Math.Min(Text.Length, CaretIndex + 1);
OnTextChanged?.Invoke(this, Text);
}
ReceiveTextInput(inputChar.ToString());
}
public void ReceiveTextInput(string input)
@@ -551,10 +562,16 @@ namespace Barotrauma
{
RemoveSelectedText();
}
Vector2 textPos = textBlock.TextPos;
bool wasOverflowClipActive = textBlock.OverflowClipActive;
if (SetText(Text.Insert(CaretIndex, input)))
{
CaretIndex = Math.Min(Text.Length, CaretIndex + input.Length);
OnTextChanged?.Invoke(this, Text);
if (textBlock.OverflowClipActive && wasOverflowClipActive && !MathUtils.NearlyEqual(textBlock.TextPos, textPos))
{
textBlock.TextPos = textPos + Vector2.UnitX * Font.MeasureString(input).X;
}
}
}

View File

@@ -10,9 +10,10 @@ namespace Barotrauma
{
class VideoPlayer
{
public bool IsPlaying;
private Video currentVideo;
private string filePath;
private bool isPlaying;
private GUIFrame background, videoFrame, textFrame;
private GUITextBlock title, textContent, objectiveTitle, objectiveText;
@@ -24,12 +25,14 @@ namespace Barotrauma
private Point scaledVideoResolution;
private readonly int borderSize = 20;
private readonly Point buttonSize = new Point(160, 50);
private readonly Point buttonSize = new Point(120, 30);
private readonly int titleHeight = 30;
private readonly int objectiveFrameHeight = 60;
private readonly int textHeight = 25;
public struct TextSettings
private bool useTextOnRightSide = false;
public class TextSettings
{
public string Text;
public int Width;
@@ -41,7 +44,7 @@ namespace Barotrauma
}
}
public struct VideoSettings
public class VideoSettings
{
public string File;
@@ -62,7 +65,14 @@ namespace Barotrauma
background = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor);
videoFrame = new GUIFrame(new RectTransform(Point.Zero, background.RectTransform, Anchor.Center, Pivot.Center), "SonarFrame");
textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame");
if (useTextOnRightSide)
{
textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame");
}
else
{
textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), "TextFrame");
}
videoView = new GUICustomComponent(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.Center), (spriteBatch, guiCustomComponent) => { DrawVideo(spriteBatch, guiCustomComponent.Rect); });
title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.VideoTitleFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left);
@@ -70,7 +80,7 @@ namespace Barotrauma
textContent = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.Font, textAlignment: Alignment.TopLeft);
objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight, textColor: Color.White);
objectiveTitle.Text = TextManager.Get("NewObjective");
objectiveTitle.Text = TextManager.Get("Tutorial.NewObjective");
objectiveText = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveNameFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight);
objectiveTitle.Visible = objectiveText.Visible = false;
@@ -78,12 +88,12 @@ namespace Barotrauma
public void Play()
{
isPlaying = true;
IsPlaying = true;
}
public void Stop()
{
isPlaying = false;
IsPlaying = false;
if (currentVideo == null) return;
currentVideo.Dispose();
currentVideo = null;
@@ -99,13 +109,6 @@ namespace Barotrauma
public void Update()
{
if (currentVideo == null) return;
if (PlayerInput.KeyHit(Keys.Enter) || PlayerInput.KeyHit(Keys.Escape))
{
DisposeVideo(null, null);
return;
}
if (currentVideo.IsPlaying) return;
currentVideo.Dispose();
@@ -115,7 +118,7 @@ namespace Barotrauma
public void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
{
if (!isPlaying) return;
if (!IsPlaying) return;
background.AddToGUIUpdateList(ignoreChildren, order);
}
@@ -139,7 +142,7 @@ namespace Barotrauma
currentVideo = CreateVideo(scaledVideoResolution);
title.Text = TextManager.Get(contentId);
textContent.Text = textSettings.Text;
textContent.Text = textSettings != null ? textSettings.Text : string.Empty;
objectiveText.Text = objective;
AdjustFrames(videoSettings, textSettings);
@@ -165,7 +168,8 @@ namespace Barotrauma
title.TextScale = textContent.TextScale = objectiveText.TextScale = objectiveTitle.TextScale = GUI.Scale;
int scaledBorderSize = (int)(borderSize * GUI.Scale);
int scaledTextWidth = (int)(textSettings.Width * GUI.Scale);
int scaledTextWidth = 0;
if (textSettings != null) scaledTextWidth = useTextOnRightSide ? (int)(textSettings.Width * GUI.Scale) : scaledVideoResolution.X / 2;
int scaledTitleHeight = (int)(titleHeight * GUI.Scale);
int scaledTextHeight = (int)(textHeight * GUI.Scale);
int scaledObjectiveFrameHeight = (int)(objectiveFrameHeight * GUI.Scale);
@@ -180,13 +184,21 @@ namespace Barotrauma
title.RectTransform.NonScaledSize += new Point(scaledTextWidth, scaledTitleHeight);
title.RectTransform.AbsoluteOffset = new Point((int)(5 * GUI.Scale), (int)(10 * GUI.Scale));
if (!string.IsNullOrEmpty(textSettings.Text))
if (textSettings != null && !string.IsNullOrEmpty(textSettings.Text))
{
textSettings.Text = ToolBox.WrapText(textSettings.Text, scaledTextWidth, GUI.Font);
int wrappedHeight = textSettings.Text.Split('\n').Length * scaledTextHeight;
textFrame.RectTransform.NonScaledSize += new Point(scaledTextWidth + scaledBorderSize, wrappedHeight + scaledBorderSize + scaledButtonSize.Y + scaledTitleHeight);
textFrame.RectTransform.AbsoluteOffset = new Point(scaledVideoResolution.X + scaledBorderSize * 2, 0);
if (useTextOnRightSide)
{
textFrame.RectTransform.AbsoluteOffset = new Point(scaledVideoResolution.X + scaledBorderSize * 2, 0);
}
else
{
textFrame.RectTransform.AbsoluteOffset = new Point(0, scaledVideoResolution.Y + scaledBorderSize * 2);
}
textContent.RectTransform.NonScaledSize += new Point(scaledTextWidth, wrappedHeight);
textContent.RectTransform.AbsoluteOffset = new Point(0, scaledBorderSize + scaledTitleHeight);
@@ -209,22 +221,41 @@ namespace Barotrauma
objectiveTitle.Visible = objectiveText.Visible = false;
}
int totalFrameWidth = videoFrame.Rect.Width + textFrame.Rect.Width + scaledBorderSize * 2;
int xOffset = videoFrame.Rect.Width / 2 + scaledBorderSize - (videoFrame.Rect.Width / 2 - textFrame.Rect.Width / 2);
videoFrame.RectTransform.AbsoluteOffset = new Point(-xOffset, (int)(50 * GUI.Scale));
if (okButton != null)
{
textFrame.RemoveChild(okButton);
okButton = null;
}
okButton = new GUIButton(new RectTransform(scaledButtonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("OK"))
if (textSettings != null)
{
OnClicked = DisposeVideo
};
if (useTextOnRightSide)
{
int totalFrameWidth = videoFrame.Rect.Width + textFrame.Rect.Width + scaledBorderSize * 2;
int xOffset = videoFrame.Rect.Width / 2 + scaledBorderSize - (videoFrame.Rect.Width / 2 - textFrame.Rect.Width / 2);
videoFrame.RectTransform.AbsoluteOffset = new Point(-xOffset, (int)(50 * GUI.Scale));
}
else
{
int totalFrameHeight = videoFrame.Rect.Height + textFrame.Rect.Height + scaledBorderSize * 2;
int yOffset = videoFrame.Rect.Height / 2 + scaledBorderSize - (videoFrame.Rect.Height / 2 - textFrame.Rect.Height / 2);
videoFrame.RectTransform.AbsoluteOffset = new Point(0, -yOffset);
}
okButton = new GUIButton(new RectTransform(scaledButtonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("OK"))
{
OnClicked = DisposeVideo
};
}
else
{
videoFrame.RectTransform.AbsoluteOffset = new Point(0, (int)(100 * GUI.Scale));
okButton = new GUIButton(new RectTransform(scaledButtonSize, videoFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("Back"))
{
OnClicked = DisposeVideo
};
}
}
private Video CreateVideo(Point resolution)
@@ -245,7 +276,7 @@ namespace Barotrauma
private void DrawVideo(SpriteBatch spriteBatch, Rectangle rect)
{
if (!isPlaying) return;
if (!IsPlaying) return;
spriteBatch.Draw(currentVideo.GetTexture(), rect, Color.White);
}

View File

@@ -159,6 +159,15 @@ namespace Barotrauma
public GameMain()
{
#if !DEBUG && OSX
// Use a separate path for content that's editable due to macOS's .app bundles crashing when edited during runtime
string macPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library/Barotrauma");
Directory.SetCurrentDirectory(macPath);
Content.RootDirectory = macPath + "/Content";
#else
Content.RootDirectory = "Content";
#endif
GraphicsDeviceManager = new GraphicsDeviceManager(this);
Window.Title = "Barotrauma";
@@ -169,7 +178,6 @@ namespace Barotrauma
GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window);
Content.RootDirectory = "Content";
PerformanceCounter = new PerformanceCounter();
@@ -318,8 +326,16 @@ namespace Barotrauma
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume);
if (Config.EnableSplashScreen)
{
(TitleScreen as LoadingScreen).SplashScreen = new Video(base.GraphicsDevice, SoundManager, "Content/splashscreen.mp4", 1280, 720);
}
try
{
(TitleScreen as LoadingScreen).SplashScreen = new Video(base.GraphicsDevice, SoundManager, "Content/splashscreen.mp4", 1280, 720);
}
catch (Exception e)
{
Config.EnableSplashScreen = false;
DebugConsole.ThrowError("Playing the splash screen failed.", e);
}
}
GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
DebugConsole.Init();
@@ -602,8 +618,12 @@ namespace Barotrauma
{
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
}
else if (Tutorial.Initialized && Tutorial.ContentRunning)
{
(GameMain.GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI();
}
else if ((Character.Controlled?.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null)
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null)
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
@@ -611,7 +631,7 @@ namespace Barotrauma
}
GUI.ClearUpdateList();
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || ContextualTutorial.ContentRunning) &&
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning) &&
(NetworkMember == null || !NetworkMember.GameStarted);
Screen.Selected.AddToGUIUpdateList();
@@ -630,9 +650,9 @@ namespace Barotrauma
{
Screen.Selected.Update(Timing.Step);
}
else if (ContextualTutorial.Initialized && ContextualTutorial.ContentRunning && GameSession.GameMode is SinglePlayerCampaign)
else if (Tutorial.Initialized && Tutorial.ContentRunning)
{
(GameSession.GameMode as SinglePlayerCampaign).ContextualTutorial.Update((float)Timing.Step);
(GameSession.GameMode as TutorialMode).Update((float)Timing.Step);
}
if (NetworkMember != null)
@@ -697,6 +717,85 @@ namespace Barotrauma
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks / (float)TimeSpan.TicksPerMillisecond);
}
public void ShowCampaignDisclaimer(Action onContinue)
{
var msgBox = new GUIMessageBox(TextManager.Get("CampaignDisclaimerTitle"), TextManager.Get("CampaignDisclaimerText"),
new string[] { TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("OK") });
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
{
var roadMap = new GUIMessageBox(TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("CampaignRoadMapText"),
new string[] { TextManager.Get("Back"), TextManager.Get("OK") });
roadMap.Buttons[0].OnClicked += roadMap.Close;
roadMap.Buttons[0].OnClicked += (_, __) => { ShowCampaignDisclaimer(onContinue); return true; };
roadMap.Buttons[1].OnClicked += roadMap.Close;
roadMap.Buttons[1].OnClicked += (_, __) => { onContinue?.Invoke(); return true; };
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += (_, __) => { onContinue?.Invoke(); return true; };
Config.CampaignDisclaimerShown = true;
Config.SaveNewPlayerConfig();
}
public void ShowEditorDisclaimer()
{
var msgBox = new GUIMessageBox(TextManager.Get("EditorDisclaimerTitle"), TextManager.Get("EditorDisclaimerText"));
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), msgBox.Content.RectTransform)) { Stretch = true, RelativeSpacing = 0.025f };
linkHolder.RectTransform.MaxSize = new Point(int.MaxValue, linkHolder.Rect.Height);
List<Pair<string, string>> links = new List<Pair<string, string>>()
{
new Pair<string, string>(TextManager.Get("EditorDisclaimerWikiLink"),TextManager.Get("EditorDisclaimerWikiUrl")),
new Pair<string, string>(TextManager.Get("EditorDisclaimerDiscordLink"),TextManager.Get("EditorDisclaimerDiscordUrl")),
new Pair<string, string>(TextManager.Get("EditorDisclaimerForumLink"),TextManager.Get("EditorDisclaimerForumUrl")),
};
foreach (var link in links)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), linkHolder.RectTransform), link.First, style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
UserData = link.Second,
OnClicked = (btn, userdata) =>
{
Process.Start(userdata as string);
return true;
}
};
}
msgBox.InnerFrame.RectTransform.MinSize = new Point(0,
msgBox.InnerFrame.Rect.Height + linkHolder.Rect.Height + msgBox.Content.AbsoluteSpacing * 2 + 10);
Config.EditorDisclaimerShown = true;
Config.SaveNewPlayerConfig();
}
// ToDo: Move texts/links to localization, when possible.
public void ShowBugReporter()
{
var msgBox = new GUIMessageBox("", "");
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform)) { Stretch = true, RelativeSpacing = 0.05f };
List<Pair<string, string>> links = new List<Pair<string, string>>()
{
new Pair<string, string>("Barotrauma Feedback Form","https://barotraumagame.com/feedback"),
new Pair<string, string>("Github Issue Form (Needs account)","https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md")
};
foreach (var link in links)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), linkHolder.RectTransform), link.First, style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
UserData = link.Second,
OnClicked = (btn, userdata) =>
{
Process.Start(userdata as string);
msgBox.Close();
return true;
}
};
}
}
static bool waitForKeyHit = true;
public CoroutineHandle ShowLoading(IEnumerable<object> loader, bool waitKeyHit = true)
{

View File

@@ -4,7 +4,6 @@ using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -41,18 +40,33 @@ namespace Barotrauma
private bool toggleCrewAreaOpen = true;
private int characterInfoWidth;
private ChatBox chatBox;
/// <summary>
/// Present only in single player games. In multiplayer. The chatbox is found from GameSession.Client.
/// </summary>
public ChatBox ChatBox { get; private set; }
private float prevUIScale;
private GUIComponent orderTargetFrame, orderTargetFrameShadow;
public bool AllowCharacterSwitch = true;
public bool ToggleCrewAreaOpen
{
get { return toggleCrewAreaOpen; }
set { toggleCrewAreaOpen = value; }
set
{
if (toggleCrewAreaOpen == value) { return; }
toggleCrewAreaOpen = GameMain.Config.CrewMenuOpen = value;
foreach (GUIComponent child in toggleCrewButton.Children)
{
child.SpriteEffects = toggleCrewAreaOpen ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
}
}
}
public List<GUIButton> OrderOptionButtons = new List<GUIButton>();
#endregion
#region Constructors
@@ -93,11 +107,7 @@ namespace Barotrauma
"", style: "UIToggleButton");
toggleCrewButton.OnClicked += (GUIButton btn, object userdata) =>
{
toggleCrewAreaOpen = !toggleCrewAreaOpen;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = toggleCrewAreaOpen ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
}
ToggleCrewAreaOpen = !ToggleCrewAreaOpen;
return true;
};
@@ -125,7 +135,7 @@ namespace Barotrauma
if (isSinglePlayer)
{
chatBox = new ChatBox(guiFrame, isSinglePlayer: true)
ChatBox = new ChatBox(guiFrame, isSinglePlayer: true)
{
OnEnterMessage = (textbox, text) =>
{
@@ -158,7 +168,7 @@ namespace Barotrauma
}
};
chatBox.InputBox.OnTextChanged += chatBox.TypingChatMessage;
ChatBox.InputBox.OnTextChanged += ChatBox.TypingChatMessage;
}
var reports = Order.PrefabList.FindAll(o => o.TargetAllCharacters && o.SymbolSprite != null);
@@ -208,6 +218,8 @@ namespace Barotrauma
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
prevUIScale = GUI.Scale;
ToggleCrewAreaOpen = GameMain.Config.CrewMenuOpen;
}
@@ -465,7 +477,10 @@ namespace Barotrauma
orderButtonFrame.RectTransform;
var btn = new GUIButton(new RectTransform(new Point(iconSize, iconSize), btnParent, Anchor.CenterLeft),
style: null);
style: null)
{
UserData = order
};
new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow")
{
@@ -557,6 +572,7 @@ namespace Barotrauma
/// </summary>
public bool CharacterClicked(GUIComponent component, object selection)
{
if (!AllowCharacterSwitch) { return false; }
Character character = selection as Character;
if (character == null || character.IsDead || character.IsUnconscious) return false;
SelectCharacter(character);
@@ -646,7 +662,11 @@ namespace Barotrauma
}
if (string.IsNullOrEmpty(text)) { return; }
chatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender));
if (sender != null)
{
GameMain.GameSession.CrewManager.SetCharacterSpeaking(sender);
}
ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender));
}
private WifiComponent GetHeadset(Character character, bool requireEquipped)
@@ -697,15 +717,19 @@ namespace Barotrauma
soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ? "MutedLocally" : "MutedGlobally");
}
public void SetPlayerSpeaking(Client client)
public void SetClientSpeaking(Client client)
{
if (client?.Character == null) { return; }
if (client?.Character != null) { SetCharacterSpeaking(client.Character); }
}
var playerFrame = characterListBox.Content.FindChild(client.Character)?.FindChild(client.Character);
public void SetCharacterSpeaking(Character character)
{
var playerFrame = characterListBox.Content.FindChild(character)?.FindChild(character);
if (playerFrame == null) { return; }
var soundIcon = playerFrame.FindChild("soundicon");
soundIcon.Color = new Color(soundIcon.Color, 1.0f);
}
#endregion
/// <summary>
@@ -722,7 +746,7 @@ namespace Barotrauma
if (IsSinglePlayer)
{
orderGiver.Speak(
order.GetChatMessage("", orderGiver.CurrentHull?.RoomName, givingOrderToSelf: character == orderGiver), ChatMessageType.Order);
order.GetChatMessage("", orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver), ChatMessageType.Order);
}
else
{
@@ -739,7 +763,7 @@ namespace Barotrauma
if (IsSinglePlayer)
{
orderGiver?.Speak(
order.GetChatMessage(character.Name, orderGiver.CurrentHull?.RoomName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
}
else if (orderGiver != null)
{
@@ -892,9 +916,12 @@ namespace Barotrauma
if (Character.Controlled == null) return false;
SetCharacterOrder(character, userData as Order, option, Character.Controlled);
orderTargetFrame = null;
OrderOptionButtons.Clear();
return true;
}
};
OrderOptionButtons.Add(optionButton);
}
}
@@ -927,9 +954,13 @@ namespace Barotrauma
if (Character.Controlled == null) return false;
SetCharacterOrder(character, userData as Order, option, Character.Controlled);
orderTargetFrame = null;
OrderOptionButtons.Clear();
return true;
}
};
OrderOptionButtons.Add(optionButton);
//lines between the order buttons
if (i < order.Options.Length - 1)
{
@@ -945,6 +976,24 @@ namespace Barotrauma
color: matchingItems.Count > 1 ? Color.Black * 0.9f : Color.Black * 0.7f);
}
public void HighlightOrderButton(Character character, string orderAiTag, Color color, Vector2? flashRectInflate = null)
{
var order = Order.PrefabList.Find(o => o.AITag == orderAiTag);
if (order == null)
{
DebugConsole.ThrowError("Could not find an order with the AI tag \"" + orderAiTag + "\".\n" + Environment.StackTrace);
return;
}
var characterElement = characterListBox.Content.FindChild(character);
GUIButton orderBtn = characterElement.FindChild(order, recursive: true) as GUIButton;
if (orderBtn.Frame.FlashTimer <= 0)
{
orderBtn.Flash(color, 1.5f, false, flashRectInflate);
}
//orderBtn.Pulsate(Vector2.One, Vector2.One * 2.0f, 1.5f);
}
#region Updating and drawing the UI
private void DrawMiniMapOverlay(SpriteBatch spriteBatch, GUICustomComponent container)
@@ -1002,6 +1051,7 @@ namespace Barotrauma
public void SelectNextCharacter()
{
if (!AllowCharacterSwitch) { return; }
if (GameMain.IsMultiplayer) { return; }
if (characters.None()) { return; }
SelectCharacter(characters[TryAdjustIndex(1)]);
@@ -1009,6 +1059,7 @@ namespace Barotrauma
public void SelectPreviousCharacter()
{
if (!AllowCharacterSwitch) { return; }
if (GameMain.IsMultiplayer) { return; }
if (characters.None()) { return; }
SelectCharacter(characters[TryAdjustIndex(-1)]);
@@ -1016,6 +1067,7 @@ namespace Barotrauma
private void SelectCharacter(Character character)
{
if (!AllowCharacterSwitch) { return; }
//make the previously selected character wait in place for some time
//(so they don't immediately start idling and walking away from their station)
if (Character.Controlled?.AIController?.ObjectiveManager != null)
@@ -1056,24 +1108,24 @@ namespace Barotrauma
}
if (GUI.DisableHUD || GUI.DisableUpperHUD) return;
if (chatBox != null)
if (ChatBox != null)
{
chatBox.Update(deltaTime);
chatBox.InputBox.Visible = Character.Controlled != null;
ChatBox.Update(deltaTime);
ChatBox.InputBox.Visible = Character.Controlled != null;
if (!DebugConsole.IsOpen && chatBox.InputBox.Visible)
if (!DebugConsole.IsOpen && ChatBox.InputBox.Visible)
{
if (PlayerInput.KeyHit(InputType.Chat) && !chatBox.InputBox.Selected)
if (PlayerInput.KeyHit(InputType.Chat) && !ChatBox.InputBox.Selected)
{
chatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
chatBox.InputBox.Select();
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
ChatBox.InputBox.Select();
}
if (PlayerInput.KeyHit(InputType.RadioChat) && !chatBox.InputBox.Selected)
if (PlayerInput.KeyHit(InputType.RadioChat) && !ChatBox.InputBox.Selected)
{
chatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
chatBox.InputBox.Select();
chatBox.InputBox.Text = "r; ";
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
ChatBox.InputBox.Select();
ChatBox.InputBox.Text = "r; ";
}
}
}
@@ -1143,7 +1195,7 @@ namespace Barotrauma
crewArea.RectTransform.AbsoluteOffset =
Vector2.SmoothStep(new Vector2(-crewArea.Rect.Width, 0), new Vector2(toggleCrewButton.Rect.Width, 0), crewAreaOpenState).ToPoint();
crewAreaOpenState = toggleCrewAreaOpen ?
crewAreaOpenState = ToggleCrewAreaOpen ?
Math.Min(crewAreaOpenState + deltaTime * 2.0f, 1.0f) :
Math.Max(crewAreaOpenState - deltaTime * 2.0f, 0.0f);
@@ -1156,7 +1208,7 @@ namespace Barotrauma
{
Character.Controlled.SelectedConstruction = null;
}
toggleCrewAreaOpen = !toggleCrewAreaOpen;
ToggleCrewAreaOpen = !ToggleCrewAreaOpen;
}
UpdateReports(deltaTime);
@@ -1284,7 +1336,7 @@ namespace Barotrauma
{
reportButtonFrame.Visible = true;
var reportButtonParent = chatBox ?? GameMain.Client.ChatBox;
var reportButtonParent = ChatBox ?? GameMain.Client.ChatBox;
reportButtonFrame.RectTransform.AbsoluteOffset = new Point(
Math.Min(reportButtonParent.GUIFrame.Rect.X, reportButtonParent.ToggleButton.Rect.X) - reportButtonFrame.Rect.Width - (int)(10 * GUI.Scale),
reportButtonParent.GUIFrame.Rect.Y);

View File

@@ -135,6 +135,8 @@ namespace Barotrauma
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
msg.Write(PurchasedHullRepairs);
msg.Write(PurchasedItemRepairs);
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
@@ -159,6 +161,8 @@ namespace Barotrauma
UInt16 endWatchmanID = msg.ReadUInt16();
int money = msg.ReadInt32();
bool purchasedHullRepairs = msg.ReadBoolean();
bool purchasedItemRepairs = msg.ReadBoolean();
UInt16 purchasedItemCount = msg.ReadUInt16();
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
@@ -217,6 +221,8 @@ namespace Barotrauma
campaign.endWatchmanID = endWatchmanID;
campaign.Money = money;
campaign.PurchasedHullRepairs = purchasedHullRepairs;
campaign.PurchasedItemRepairs = purchasedItemRepairs;
campaign.CargoManager.SetPurchasedItems(purchasedItems);
if (myCharacterInfo != null)

View File

@@ -65,11 +65,6 @@ namespace Barotrauma
endTimer = 5.0f;
isRunning = true;
CrewManager.InitSinglePlayerRound();
if (ContextualTutorial.Initialized)
{
ContextualTutorial.Start();
}
}
public bool TryHireCharacter(Location location, CharacterInfo characterInfo)
@@ -175,11 +170,6 @@ namespace Barotrauma
base.Update(deltaTime);
if (ContextualTutorial.Initialized)
{
ContextualTutorial.Update(deltaTime);
}
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
{
endRoundButton.UpdateManually(deltaTime);
@@ -440,12 +430,6 @@ namespace Barotrauma
new XAttribute("cheatsenabled", CheatsEnabled));
CrewManager.Save(modeElement);
Map.Save(modeElement);
if (ContextualTutorial.Initialized)
{
ContextualTutorial.SavePartiallyComplete(modeElement);
}
element.Add(modeElement);
}
}

View File

@@ -38,13 +38,13 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(4.0f);
infoBox = CreateInfoFrame("Use WASD to move and the mouse to look around");
infoBox = CreateInfoFrame("", "Use WASD to move and the mouse to look around");
yield return new WaitForSeconds(5.0f);
//-----------------------------------
infoBox = CreateInfoFrame("Open the door at your right side by highlighting the button next to it with your cursor and pressing E");
infoBox = CreateInfoFrame("", "Open the door at your right side by highlighting the button next to it with your cursor and pressing E");
Door tutorialDoor = Item.ItemList.Find(i => i.HasTag("tutorialdoor")).GetComponent<Door>();
@@ -57,7 +57,7 @@ namespace Barotrauma.Tutorials
//-----------------------------------
infoBox = CreateInfoFrame("Hold W or S to walk up or down stairs. Use shift to run.", true);
infoBox = CreateInfoFrame("", "Hold W or S to walk up or down stairs. Use shift to run.", hasButton: true);
while (infoBox != null)
{
@@ -66,7 +66,7 @@ namespace Barotrauma.Tutorials
//-----------------------------------
infoBox = CreateInfoFrame("At the moment the submarine has no power, which means that crucial systems such as the oxygen generator or the engine aren't running. Let's fix this: go to the upper left corner of the submarine, where you'll find a nuclear reactor.");
infoBox = CreateInfoFrame("", "At the moment the submarine has no power, which means that crucial systems such as the oxygen generator or the engine aren't running. Let's fix this: go to the upper left corner of the submarine, where you'll find a nuclear reactor.");
Reactor reactor = Item.ItemList.Find(i => i.HasTag("tutorialreactor")).GetComponent<Reactor>();
//reactor.MeltDownTemp = 20000.0f;
@@ -76,21 +76,21 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("The reactor requires fuel rods to generate power. You can grab one from the steel cabinet by walking next to it and pressing E.");
infoBox = CreateInfoFrame("", "The reactor requires fuel rods to generate power. You can grab one from the steel cabinet by walking next to it and pressing E.");
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Prefab.Identifier != "steelcabinet")
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Pick up one of the fuel rods either by double-clicking or dragging and dropping it into your inventory.");
infoBox = CreateInfoFrame("", "Pick up one of the fuel rods either by double-clicking or dragging and dropping it into your inventory.");
while (!HasItem("fuelrod"))
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Select the reactor by walking next to it and pressing E.");
infoBox = CreateInfoFrame("", "Select the reactor by walking next to it and pressing E.");
while (Controlled.SelectedConstruction != reactor.Item)
{
@@ -98,14 +98,14 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(0.5f);
infoBox = CreateInfoFrame("Load the fuel rod into the reactor by dropping it into any of the 5 slots.");
infoBox = CreateInfoFrame("", "Load the fuel rod into the reactor by dropping it into any of the 5 slots.");
while (reactor.AvailableFuel <= 0.0f)
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("The reactor is now fueled up. Try turning it on by increasing the fission rate.");
infoBox = CreateInfoFrame("", "The reactor is now fueled up. Try turning it on by increasing the fission rate.");
while (reactor.FissionRate <= 0.0f)
{
@@ -113,8 +113,8 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(0.5f);
infoBox = CreateInfoFrame("The reactor core has started generating heat, which in turn generates power for the submarine. The power generation is very low at the moment,"
+ " because the reactor is set to shut itself down when the temperature rises above 500 degrees Celsius. You can adjust the temperature limit by changing the \"Shutdown Temperature\" in the control panel.", true);
infoBox = CreateInfoFrame("", "The reactor core has started generating heat, which in turn generates power for the submarine. The power generation is very low at the moment,"
+ " because the reactor is set to shut itself down when the temperature rises above 500 degrees Celsius. You can adjust the temperature limit by changing the \"Shutdown Temperature\" in the control panel.", hasButton: true);
//TODO: reimplement
/*while (infoBox != null)
@@ -146,7 +146,7 @@ namespace Barotrauma.Tutorials
}*/
yield return new WaitForSeconds(0.5f);
infoBox = CreateInfoFrame("That's the basics of operating the reactor! Now that there's power available for the engines, it's time to get the submarine moving. "
infoBox = CreateInfoFrame("", "That's the basics of operating the reactor! Now that there's power available for the engines, it's time to get the submarine moving. "
+ "Deselect the reactor by pressing E and head to the command room at the right edge of the vessel.");
Steering steering = Item.ItemList.Find(i => i.HasTag("tutorialsteering")).GetComponent<Steering>();
@@ -159,7 +159,7 @@ namespace Barotrauma.Tutorials
CoroutineManager.StartCoroutine(KeepReactorRunning(reactor));
infoBox = CreateInfoFrame("Select the navigation terminal by walking next to it and pressing E.");
infoBox = CreateInfoFrame("", "Select the navigation terminal by walking next to it and pressing E.");
while (Controlled.SelectedConstruction != steering.Item)
{
@@ -167,7 +167,7 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(0.5f);
infoBox = CreateInfoFrame("There seems to be something wrong with the navigation terminal." +
infoBox = CreateInfoFrame("", "There seems to be something wrong with the navigation terminal." +
" There's nothing on the monitor, so it's probably out of power. The reactor must still be"
+ " running or the lights would've gone out, so it's most likely a problem with the wiring."
+ " Deselect the terminal by pressing E to start checking the wiring.");
@@ -178,7 +178,7 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(1.0f);
infoBox = CreateInfoFrame("You need a screwdriver to check the wiring of the terminal."
infoBox = CreateInfoFrame("", "You need a screwdriver to check the wiring of the terminal."
+ " Equip a screwdriver by pulling it to either of the slots with a hand symbol, and then use it on the terminal by left clicking.");
while (Controlled.SelectedConstruction != steering.Item ||
@@ -188,7 +188,7 @@ namespace Barotrauma.Tutorials
}
infoBox = CreateInfoFrame("Here you can see all the wires connected to the terminal. Apparently there's no wire"
infoBox = CreateInfoFrame("", "Here you can see all the wires connected to the terminal. Apparently there's no wire"
+ " going into the to the power connection - that's why the monitor isn't working."
+ " You should find a piece of wire to connect it. Try searching some of the cabinets scattered around the sub.");
@@ -197,7 +197,7 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Head back to the navigation terminal to fix the wiring.");
infoBox = CreateInfoFrame("", "Head back to the navigation terminal to fix the wiring.");
PowerTransfer junctionBox = Item.ItemList.Find(i => i != null && i.HasTag("tutorialjunctionbox")).GetComponent<PowerTransfer>();
@@ -210,7 +210,7 @@ namespace Barotrauma.Tutorials
if (Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent<Wire>() != null) == null)
{
infoBox = CreateInfoFrame("Equip the wire by dragging it to one of the slots with a hand symbol.");
infoBox = CreateInfoFrame("", "Equip the wire by dragging it to one of the slots with a hand symbol.");
while (Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent<Wire>() != null) == null)
{
@@ -218,7 +218,7 @@ namespace Barotrauma.Tutorials
}
}
infoBox = CreateInfoFrame("You can see the equipped wire at the middle of the connection panel. Drag it to the power connector.");
infoBox = CreateInfoFrame("", "You can see the equipped wire at the middle of the connection panel. Drag it to the power connector.");
var steeringConnection = steering.Item.Connections.Find(c => c.Name.Contains("power"));
@@ -228,7 +228,7 @@ namespace Barotrauma.Tutorials
}
infoBox = CreateInfoFrame("Now you have to connect the other end of the wire to a power source. "
infoBox = CreateInfoFrame("", "Now you have to connect the other end of the wire to a power source. "
+ "The junction box in the room just below the command room should do.");
while (Controlled.SelectedConstruction != null)
@@ -238,7 +238,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(2.0f);
infoBox = CreateInfoFrame("You can now move the other end of the wire around, and attach it on the wall by left clicking or "
infoBox = CreateInfoFrame("", "You can now move the other end of the wire around, and attach it on the wall by left clicking or "
+ "remove the previous attachment by right clicking. Or if you don't care for neatly laid out wiring, you can just "
+ "run it straight to the junction box.");
@@ -247,14 +247,14 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Connect the wire to the junction box by pulling it to the power connection, the same way you did with the navigation terminal.");
infoBox = CreateInfoFrame("", "Connect the wire to the junction box by pulling it to the power connection, the same way you did with the navigation terminal.");
while (sonar.Voltage < 0.1f)
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Great! Now we should be able to get moving.");
infoBox = CreateInfoFrame("", "Great! Now we should be able to get moving.");
while (Controlled.SelectedConstruction != steering.Item)
@@ -262,7 +262,7 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("You can take a look at the area around the sub by selecting the \"Active Sonar\" checkbox.");
infoBox = CreateInfoFrame("", "You can take a look at the area around the sub by selecting the \"Active Sonar\" checkbox.");
while (!sonar.IsActive)
{
@@ -270,7 +270,7 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(0.5f);
infoBox = CreateInfoFrame("The blue rectangle in the middle is the submarine, and the flickering shapes outside it are the walls of an underwater cavern. "
infoBox = CreateInfoFrame("", "The blue rectangle in the middle is the submarine, and the flickering shapes outside it are the walls of an underwater cavern. "
+ "Try moving the submarine by clicking somewhere on the monitor and dragging the pointer to the direction you want to go to.");
while (steering.TargetVelocity == Vector2.Zero && steering.TargetVelocity.Length() < 50.0f)
@@ -279,15 +279,15 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(4.0f);
infoBox = CreateInfoFrame("The submarine moves up and down by pumping water in and out of the two ballast tanks at the bottom of the submarine. "
+ "The engine at the back of the sub moves it forwards and backwards.", true);
infoBox = CreateInfoFrame("", "The submarine moves up and down by pumping water in and out of the two ballast tanks at the bottom of the submarine. "
+ "The engine at the back of the sub moves it forwards and backwards.", hasButton: true);
while (infoBox != null)
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Steer the submarine downwards, heading further into the cavern.");
infoBox = CreateInfoFrame("", "Steer the submarine downwards, heading further into the cavern.");
while (Submarine.MainSub.WorldPosition.Y > 32000.0f)
{
@@ -303,7 +303,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(1.0f);
infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the sonar.");
infoBox = CreateInfoFrame("", "Uh-oh... Something enormous just appeared on the sonar.");
List<Structure> windows = new List<Structure>();
foreach (Structure s in Structure.WallList)
@@ -370,7 +370,7 @@ namespace Barotrauma.Tutorials
var capacitor2 = Item.ItemList.Find(i => i.HasTag("capacitor1")).GetComponent<PowerContainer>();
CoroutineManager.StartCoroutine(KeepEnemyAway(moloch, new PowerContainer[] { capacitor1, capacitor2 }));
infoBox = CreateInfoFrame("The hull has been breached! Close all the doors to the command room to stop the water from flooding the entire sub!");
infoBox = CreateInfoFrame("", "The hull has been breached! Close all the doors to the command room to stop the water from flooding the entire sub!");
Door commandDoor1 = Item.ItemList.Find(i => i.HasTag("commanddoor1")).GetComponent<Door>();
Door commandDoor2 = Item.ItemList.Find(i => i.HasTag("commanddoor2")).GetComponent<Door>();
@@ -385,7 +385,7 @@ namespace Barotrauma.Tutorials
}
infoBox = CreateInfoFrame("You should quickly find yourself a diving mask or a diving suit. " +
infoBox = CreateInfoFrame("", "You should quickly find yourself a diving mask or a diving suit. " +
"There are some in the room next to the airlock.");
bool divingMaskSelected = false;
@@ -395,7 +395,7 @@ namespace Barotrauma.Tutorials
if (!divingMaskSelected &&
Controlled.FocusedItem != null && Controlled.FocusedItem.Prefab.Identifier == "divingsuit")
{
infoBox = CreateInfoFrame("There can only be one item in each inventory slot, so you need to take off "
infoBox = CreateInfoFrame("", "There can only be one item in each inventory slot, so you need to take off "
+ "the jumpsuit if you wish to wear a diving suit.");
divingMaskSelected = true;
@@ -406,13 +406,13 @@ namespace Barotrauma.Tutorials
if (HasItem("divingmask"))
{
infoBox = CreateInfoFrame("The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. " +
infoBox = CreateInfoFrame("", "The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. " +
"It should be fine for the situation at hand, but you still need to find an oxygen tank and drag it into the same slot as the mask." +
"You should grab one or two from one of the cabinets.");
}
else if (HasItem("divingsuit"))
{
infoBox = CreateInfoFrame("In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " +
infoBox = CreateInfoFrame("", "In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " +
"(unlike the diving mask). However, you still need to drag an oxygen tank into the same slot as the suit to supply oxygen. " +
"You should grab one or two from one of the cabinets.");
}
@@ -424,7 +424,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(5.0f);
infoBox = CreateInfoFrame("Now you should stop the creature attacking the submarine before it does any more damage. Head to the railgun room at the upper right corner of the sub.");
infoBox = CreateInfoFrame("", "Now you should stop the creature attacking the submarine before it does any more damage. Head to the railgun room at the upper right corner of the sub.");
var railGun = Item.ItemList.Find(i => i.GetComponent<Turret>() != null);
@@ -433,7 +433,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(1.0f);
}
infoBox = CreateInfoFrame("The railgun requires a large power surge to fire. The reactor can't provide a surge large enough, so we need to use the "
infoBox = CreateInfoFrame("", "The railgun requires a large power surge to fire. The reactor can't provide a surge large enough, so we need to use the "
+ " supercapacitors in the railgun room. The capacitors need to be charged first; select them and crank up the recharge rate.");
while (capacitor1.RechargeSpeed < 0.5f && capacitor2.RechargeSpeed < 0.5f)
@@ -441,7 +441,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(1.0f);
}
infoBox = CreateInfoFrame("The capacitors take some time to recharge, so now is a good " +
infoBox = CreateInfoFrame("", "The capacitors take some time to recharge, so now is a good " +
"time to head to the room below and load some shells for the railgun.");
@@ -452,7 +452,7 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. "
infoBox = CreateInfoFrame("", "Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. "
+ "one of the free slots. You need two hands to carry a shell, so make sure you don't have anything else in either hand.");
while (loader.Item.ContainedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "railgunshell") == null)
@@ -465,7 +465,7 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("Now we're ready to shoot! Select the railgun controller.");
infoBox = CreateInfoFrame("", "Now we're ready to shoot! Select the railgun controller.");
while (Controlled.SelectedConstruction == null || Controlled.SelectedConstruction.Prefab.Identifier != "railguncontroller")
{
@@ -474,7 +474,7 @@ namespace Barotrauma.Tutorials
moloch.AnimController.SetPosition(ConvertUnits.ToSimUnits(Controlled.WorldPosition + Vector2.UnitY * 600.0f));
infoBox = CreateInfoFrame("Use the right mouse button to aim and wait for the creature to come closer. When you're ready to shoot, "
infoBox = CreateInfoFrame("", "Use the right mouse button to aim and wait for the creature to come closer. When you're ready to shoot, "
+ "press the left mouse button.");
while (!moloch.IsDead)
@@ -490,7 +490,7 @@ namespace Barotrauma.Tutorials
Submarine.MainSub.GodMode = false;
infoBox = CreateInfoFrame("The creature has died. Now you should fix the damages in the control room: " +
infoBox = CreateInfoFrame("", "The creature has died. Now you should fix the damages in the control room: " +
"Grab a welding tool from the closet in the railgun room.");
while (!HasItem("weldingtool"))
@@ -498,7 +498,7 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("The welding tool requires fuel to work. Grab a welding fuel tank and attach it to the tool " +
infoBox = CreateInfoFrame("", "The welding tool requires fuel to work. Grab a welding fuel tank and attach it to the tool " +
"by dragging it into the same slot.");
do
@@ -511,7 +511,7 @@ namespace Barotrauma.Tutorials
} while (true);
infoBox = CreateInfoFrame("You can aim with the tool using the right mouse button and weld using the left button. " +
infoBox = CreateInfoFrame("", "You can aim with the tool using the right mouse button and weld using the left button. " +
"Head to the command room to fix the leaks there.");
do
@@ -531,7 +531,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(1.0f);
} while (broken);
infoBox = CreateInfoFrame("The hull is fixed now, but there's still quite a bit of water inside the sub. It should be pumped out "
infoBox = CreateInfoFrame("", "The hull is fixed now, but there's still quite a bit of water inside the sub. It should be pumped out "
+ "using the bilge pump in the room at the bottom of the submarine.");
Pump pump = Item.ItemList.Find(i => i.HasTag("tutorialpump")).GetComponent<Pump>();
@@ -541,10 +541,10 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("The two pumps inside the ballast tanks "
infoBox = CreateInfoFrame("", "The two pumps inside the ballast tanks "
+ "are connected straight to the navigation terminal and can't be manually controlled unless you mess with their wiring, " +
"so you should only use the pump in the middle room to pump out the water. Select it, turn it on and adjust the pumping speed " +
"to start pumping water out.", true);
"to start pumping water out.", hasButton: true);
while (infoBox != null)
{
@@ -562,8 +562,8 @@ namespace Barotrauma.Tutorials
{
brokenMsgShown = true;
infoBox = CreateInfoFrame("Looks like the pump isn't getting any power. The water must have short-circuited some of the junction "
+"boxes. You can check which boxes are broken by selecting them.");
infoBox = CreateInfoFrame("", "Looks like the pump isn't getting any power. The water must have short-circuited some of the junction "
+ "boxes. You can check which boxes are broken by selecting them.");
while (true)
{
@@ -573,8 +573,8 @@ namespace Barotrauma.Tutorials
{
brokenBox = Controlled.SelectedConstruction;
infoBox = CreateInfoFrame("Here's our problem: this junction box is broken. Luckily engineers are adept at fixing electrical devices - "
+"you just need to find a spare wire and click the \"Fix\"-button to repair the box.");
infoBox = CreateInfoFrame("", "Here's our problem: this junction box is broken. Luckily engineers are adept at fixing electrical devices - "
+ "you just need to find a spare wire and click the \"Fix\"-button to repair the box.");
break;
}
@@ -590,7 +590,7 @@ namespace Barotrauma.Tutorials
if (pump.Voltage < pump.MinVoltage)
{
infoBox = CreateInfoFrame("The pump is still not running. Check if there are more broken junction boxes between the pump and the reactor.");
infoBox = CreateInfoFrame("", "The pump is still not running. Check if there are more broken junction boxes between the pump and the reactor.");
}
brokenBox = null;
}
@@ -598,14 +598,14 @@ namespace Barotrauma.Tutorials
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("The pump is up and running. Wait for the water to be drained out.");
infoBox = CreateInfoFrame("", "The pump is up and running. Wait for the water to be drained out.");
while (pump.Item.CurrentHull.WaterVolume > 1000.0f)
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
infoBox = CreateInfoFrame("That was all there is to this tutorial! Now you should be able to handle " +
infoBox = CreateInfoFrame("", "That was all there is to this tutorial! Now you should be able to handle " +
"most of the basic tasks on board the submarine.");
Completed = true;

View File

@@ -0,0 +1,271 @@
using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
namespace Barotrauma.Tutorials
{
class CaptainTutorial : ScenarioTutorial
{
// Room 1
private float shakeTimer = 1f;
private float shakeAmount = 20f;
// Room 2
private MotionSensor captain_equipmentObjectiveSensor;
private ItemContainer captain_equipmentCabinet;
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 CustomInterface captain_navConsoleCustomInterface;
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 string radioSpeakerName;
private Sprite captain_steerIcon;
private Color captain_steerIconColor;
public CaptainTutorial(XElement element) : base(element)
{
}
public override void Start()
{
base.Start();
captain = Character.Controlled;
radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman");
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
var revolver = captain.Inventory.FindItemByIdentifier("revolver");
revolver.Unequip(captain);
captain.Inventory.RemoveItem(revolver);
var captainscap = captain.Inventory.FindItemByIdentifier("captainscap");
captainscap.Unequip(captain);
captain.Inventory.RemoveItem(captainscap);
var captainsuniform = captain.Inventory.FindItemByIdentifier("captainsuniform");
captainsuniform.Unequip(captain);
captain.Inventory.RemoveItem(captainsuniform);
var steerOrder = Order.PrefabList.Find(order => order.AITag == "steer");
captain_steerIcon = steerOrder.SymbolSprite;
captain_steerIconColor = steerOrder.Color;
// Room 2
captain_equipmentObjectiveSensor = Item.ItemList.Find(i => i.HasTag("captain_equipmentobjectivesensor")).GetComponent<MotionSensor>();
captain_equipmentCabinet = Item.ItemList.Find(i => i.HasTag("captain_equipmentcabinet")).GetComponent<ItemContainer>();
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(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "medicaldoctor"));
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_navConsoleCustomInterface = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<CustomInterface>();
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(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "mechanic"));
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "mechanic");
captain_mechanic.GiveJobItems();
var securityInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "securityofficer"));
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "securityofficer");
captain_security.GiveJobItems();
var engineerInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer"));
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, 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;
}
public override IEnumerable<object> 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);
}
// 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);
GameMain.GameSession.CrewManager.ToggleCrewAreaOpen = true;
GameMain.GameSession.CrewManager.AddCharacter(captain_medic);
TriggerTutorialSegment(0);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_medic, "follow", highlightColor, new Vector2(5, 5));
}
while (!HasOrder(captain_medic, "follow"));
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
RemoveCompletedObjective(segments[0]);
// Submarine
do { yield return null; } while (!captain_enteredSubmarineSensor.MotionDetected);
yield return new WaitForSeconds(3f);
captain_mechanic.AIController.Enabled = captain_security.AIController.Enabled = captain_engineer.AIController.Enabled = true;
TriggerTutorialSegment(1);
GameMain.GameSession.CrewManager.AddCharacter(captain_mechanic);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
HighlightOrderOption("jobspecific");
}
while (!HasOrder(captain_mechanic, "repairsystems", "jobspecific"));
RemoveCompletedObjective(segments[1]);
yield return new WaitForSeconds(2f);
TriggerTutorialSegment(2);
GameMain.GameSession.CrewManager.AddCharacter(captain_security);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_security, "operateweapons", highlightColor, new Vector2(5, 5));
HighlightOrderOption("fireatwill");
}
while (!HasOrder(captain_security, "operateweapons", "fireatwill"));
RemoveCompletedObjective(segments[2]);
yield return new WaitForSeconds(4f);
TriggerTutorialSegment(3);
GameMain.GameSession.CrewManager.AddCharacter(captain_engineer);
do
{
yield return null;
GameMain.GameSession.CrewManager.HighlightOrderButton(captain_engineer, "operatereactor", highlightColor, new Vector2(5, 5));
HighlightOrderOption("powerup");
}
while (!HasOrder(captain_engineer, "operatereactor", "powerup"));
RemoveCompletedObjective(segments[3]);
tutorial_submarineReactor.CanBeSelected = true;
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);
} while (Submarine.MainSub.DockedTo.Count > 0);
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(2f);
TriggerTutorialSegment(5); // Navigate to destination
do
{
if (IsSelectedItem(captain_navConsole.Item))
{
if (captain_sonar.ActiveTickBox.Box.FlashTimer <= 0)
{
captain_sonar.ActiveTickBox.Box.Flash(highlightColor, 1.5f, false, new Vector2(2.5f, 2.5f));
//captain_sonar.ActiveTickBox.Box.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.5f);
}
}
yield return null;
} while (!captain_sonar.IsActive);
do { yield return null; } while (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 4000f);
RemoveCompletedObjective(segments[5]);
yield return new WaitForSeconds(4f);
TriggerTutorialSegment(6); // Docking
do
{
captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0);
RemoveCompletedObjective(segments[6]);
yield return new WaitForSeconds(3f);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Captain.Radio.Complete").Replace("[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);
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].Frame.FlashTimer <= 0)
{
GameMain.GameSession.CrewManager.OrderOptionButtons[i].Frame.Flash(highlightColor);
}
}
orderIndex++;
}
}
private bool IsSelectedItem(Item item)
{
return captain?.SelectedConstruction == item;
}
}
}

View File

@@ -1,25 +1,20 @@
using System.Collections.Generic;
/*using System.Collections.Generic;
using System.Xml.Linq;
using System;
using Microsoft.Xna.Framework;
using Barotrauma.Items.Components;
using System.Linq;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma.Tutorials
{
class ContextualTutorial : Tutorial
{
public ContextualTutorial(XElement element) : base(element)
{
//Name = "ContextualTutorial";
}
public static bool Selected = false;
public static bool ContentRunning = false;
public static bool Initialized = false;
private enum ContentTypes { None = 0, Video = 1, TextOnly = 2 };
private TutorialSegment activeSegment;
private List<TutorialSegment> segments;
private VideoPlayer videoPlayer;
private Steering navConsole;
private Reactor reactor;
@@ -33,83 +28,24 @@ namespace Barotrauma.Tutorials
private List<Pair<Character, float>> characterTimeOnSonar;
private float requiredTimeOnSonar = 5f;
private bool started = false;
private string playableContentPath;
private float tutorialTimer;
private bool disableTutorialOnDeficiencyFound = true;
private GUIFrame holderFrame, objectiveFrame;
private List<TutorialSegment> activeObjectives = new List<TutorialSegment>();
private string objectiveTranslated;
private float floodTutorialTimer = 0.0f;
private const float floodTutorialDelay = 2.0f;
private float medicalTutorialTimer = 0.0f;
private const float medicalTutorialDelay = 2.0f;
private Point screenResolution;
private float prevUIScale;
private class TutorialSegment
{
public string Id;
public string Objective;
public ContentTypes ContentType;
public XElement TextContent;
public XElement VideoContent;
public bool IsTriggered;
public GUIButton ReplayButton;
public GUITextBlock LinkedTitle, LinkedText;
public TutorialSegment(XElement config)
{
Id = config.GetAttributeString("id", "Missing ID");
Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true);
Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType);
IsTriggered = config.GetAttributeBool("istriggered", false);
switch (ContentType)
{
case ContentTypes.None:
break;
case ContentTypes.Video:
VideoContent = config.Element("Video");
TextContent = config.Element("Text");
break;
case ContentTypes.TextOnly:
TextContent = config.Element("Text");
break;
}
}
}
public ContextualTutorial(XElement element) : base(element)
{
playableContentPath = element.GetAttributeString("playablecontentpath", "");
segments = new List<TutorialSegment>();
foreach (var segment in element.Elements("Segment"))
{
segments.Add(new TutorialSegment(segment));
}
Name = "ContextualTutorial";
}
public override void Initialize()
{
base.Initialize();
for (int i = 0; i < segments.Count; i++)
{
segments[i].IsTriggered = false;
}
if (Initialized) return;
Initialized = true;
base.Initialize();
videoPlayer = new VideoPlayer();
characterTimeOnSonar = new List<Pair<Character, float>>();
}
@@ -167,10 +103,7 @@ namespace Barotrauma.Tutorials
base.Start();
injuredMember = null;
activeObjectives.Clear();
objectiveTranslated = TextManager.Get("Objective");
CreateObjectiveFrame();
activeSegment = null;
activeContentSegment = null;
tutorialTimer = floodTutorialTimer = medicalTutorialTimer = 0.0f;
subStartingPosition = Vector2.Zero;
characterTimeOnSonar.Clear();
@@ -183,10 +116,10 @@ namespace Barotrauma.Tutorials
#if DEBUG
if (reactor == null || navConsole == null || sonar == null)
{
infoBox = CreateInfoFrame("Submarine not compatible with the tutorial:"
infoBox = CreateInfoFrame("Error", "Submarine not compatible with the tutorial:"
+ "\nReactor - " + (reactor != null ? "OK" : "Tag 'reactor' not found")
+ "\nNavigation Console - " + (navConsole != null ? "OK" : "Tag 'command' not found")
+ "\nSonar - " + (sonar != null ? "OK" : "Not found under Navigation Console"), true);
+ "\nSonar - " + (sonar != null ? "OK" : "Not found under Navigation Console"), hasButton: true);
CoroutineManager.StartCoroutine(WaitForErrorClosed());
return;
}
@@ -222,62 +155,15 @@ namespace Barotrauma.Tutorials
}
#endif
public void Stop()
public override void Stop()
{
started = ContentRunning = Initialized = false;
videoPlayer.Remove();
videoPlayer = null;
base.Stop();
characterTimeOnSonar = null;
}
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++)
{
CreateObjectiveGUI(activeObjectives[i], i);
}
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
prevUIScale = GUI.Scale;
}
public override void AddToGUIUpdateList()
{
if (videoPlayer != null)
{
videoPlayer.AddToGUIUpdateList(order: 100);
}
if (GUI.DisableHUD) return;
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
{
CreateObjectiveFrame();
}
if (objectiveFrame != null && activeObjectives.Count > 0)
{
objectiveFrame.AddToGUIUpdateList(order: -1);
}
base.AddToGUIUpdateList();
}
public override void Update(float deltaTime)
{
if (videoPlayer != null)
{
videoPlayer.Update();
}
if (infoBox != null)
{
if (PlayerInput.KeyHit(Keys.Enter) || PlayerInput.KeyHit(Keys.Escape))
{
CloseInfoFrame(null, null);
}
}
base.Update(deltaTime);
if (!started || ContentRunning) return;
@@ -285,93 +171,12 @@ namespace Barotrauma.Tutorials
for (int i = 0; i < segments.Count; i++)
{
if (segments[i].IsTriggered || activeObjectives.Contains(segments[i])) continue;
if (segments[i].IsTriggered || HasObjective(segments[i])) continue;
if (CheckContextualTutorials(i, deltaTime)) // Found a relevant tutorial, halt finding new ones
{
break;
}
}
for (int i = 0; i < activeObjectives.Count; i++)
{
CheckActiveObjectives(activeObjectives[i], deltaTime);
}
}
private void ClosePreTextAndTriggerVideoCallback()
{
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, activeSegment.Objective, CurrentSegmentStopCallback);
}
private void CurrentSegmentStopCallback()
{
if (!string.IsNullOrEmpty(activeSegment.Objective))
{
AddNewObjective(activeSegment);
}
activeSegment = null;
ContentRunning = false;
}
private void AddNewObjective(TutorialSegment segment)
{
activeObjectives.Add(segment);
CreateObjectiveGUI(segment, activeObjectives.Count - 1);
}
private void CreateObjectiveGUI(TutorialSegment segment, int index)
{
Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X * GUI.Scale), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f * GUI.Scale));
segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) =>
{
ReplaySegmentVideo(segment);
return true;
};
int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveTranslated).Y / 2f + 5) * GUI.Scale);
segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.BottomCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, objectiveTranslated, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight);
segment.LinkedText = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.TopCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, segment.Objective, textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight);
segment.LinkedTitle.TextScale = segment.LinkedText.TextScale = GUI.Scale;
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;
}
private void RemoveCompletedObjective(TutorialSegment objective)
{
objective.IsTriggered = true;
int checkMarkHeight = (int)(objective.ReplayButton.Rect.Height * 1.2f);
int checkMarkWidth = (int)(checkMarkHeight * 0.93f);
Color color = new Color(4, 180, 108);
RectTransform rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), objective.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5, 0);
GUIImage checkmark = new GUIImage(rectTA, "CheckMark");
checkmark.Color = color;
RectTransform rectTB = new RectTransform(new Vector2(1.1f, .8f), objective.LinkedText.RectTransform, Anchor.Center, Pivot.Center);
GUIImage stroke = new GUIImage(rectTB, "Stroke");
stroke.Color = color;
CoroutineManager.StartCoroutine(WaitForObjectiveEnd(objective));
}
private IEnumerable<object> WaitForObjectiveEnd(TutorialSegment objective)
{
yield return new WaitForSeconds(2.0f);
objectiveFrame.RemoveChild(objective.ReplayButton);
activeObjectives.Remove(objective);
for (int i = 0; i < activeObjectives.Count; i++)
{
activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjectives[i].ReplayButton.Rect.Height + 20) * i);
}
}
private bool CheckContextualTutorials(int index, float deltaTime)
@@ -526,17 +331,7 @@ namespace Barotrauma.Tutorials
return true;
}
private bool HasObjective(string objectiveName)
{
for (int i = 0; i < activeObjectives.Count; i++)
{
if (activeObjectives[i].Id == objectiveName) return true;
}
return false;
}
private void CheckActiveObjectives(TutorialSegment objective, float deltaTime)
protected override void CheckActiveObjectives(TutorialSegment objective, float deltaTime)
{
switch(objective.Id)
{
@@ -704,50 +499,9 @@ namespace Barotrauma.Tutorials
return characterTimeOnSonar.Find(ct => ct.Second >= requiredTimeOnSonar && !ct.First.IsDead) != null;
}
private void TriggerTutorialSegment(int index, params object[] args)
protected override void TriggerTutorialSegment(int index, params object[] args)
{
Inventory.draggingItem = null;
ContentRunning = true;
activeSegment = segments[index];
string tutorialText = TextManager.GetFormatted(activeSegment.TextContent.GetAttributeString("tag", ""), true, args);
string objectiveText = string.Empty;
if (!string.IsNullOrEmpty(activeSegment.Objective))
{
if (args.Length == 0)
{
objectiveText = activeSegment.Objective;
}
else
{
objectiveText = string.Format(activeSegment.Objective, args);
}
activeSegment.Objective = objectiveText;
}
else
{
activeSegment.IsTriggered = true; // Complete at this stage only if no related objective
}
switch (activeSegment.ContentType)
{
case ContentTypes.None:
break;
case ContentTypes.Video:
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText,
activeSegment.TextContent.GetAttributeInt("width", 300),
activeSegment.TextContent.GetAttributeInt("height", 80),
activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, ClosePreTextAndTriggerVideoCallback);
break;
case ContentTypes.TextOnly:
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText,
activeSegment.TextContent.GetAttributeInt("width", 300),
activeSegment.TextContent.GetAttributeInt("height", 80),
activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, CurrentSegmentStopCallback);
break;
}
base.TriggerTutorialSegment(index, args);
for (int i = 0; i < segments.Count; i++)
{
@@ -757,17 +511,10 @@ namespace Barotrauma.Tutorials
CoroutineManager.StartCoroutine(WaitToStop()); // Completed
}
private void ReplaySegmentVideo(TutorialSegment segment)
{
if (ContentRunning) return;
ContentRunning = true;
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false);
}
private IEnumerable<object> WaitToStop()
{
while (ContentRunning) yield return null;
Stop();
}
}
}
}*/

View File

@@ -0,0 +1,422 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma.Tutorials
{
class DoctorTutorial : ScenarioTutorial
{
// Room 1
private float shakeTimer = 1f;
private float shakeAmount = 20f;
private string radioSpeakerName;
private Character doctor;
private ItemContainer doctor_suppliesCabinet;
private ItemContainer doctor_medBayCabinet;
private Character patient1, patient2;
private List<Character> subPatients = new List<Character>();
private Hull startRoom;
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 Color doctor_iconColor = new Color(178, 118, 139);
public DoctorTutorial(XElement element) : base(element)
{
}
public override void Start()
{
base.Start();
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
doctor = Character.Controlled;
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 = Hull.hullList.Find(h => h.RoomName == "Waiting room" && h.Submarine == doctor.Submarine);
var patientHull2 = Hull.hullList.Find(h => h.RoomName == "Airlock" && h.Submarine == doctor.Submarine);
medBay = Hull.hullList.Find(h => h.RoomName == "Med bay" && h.Submarine == doctor.Submarine);
var assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant"));
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
patient1.GiveJobItems(null);
patient1.CanSpeak = false;
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 45.0f) }, stun: 0, playSound: false);
patient1.AIController.Enabled = false;
assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant"));
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
patient2.GiveJobItems(null);
patient2.CanSpeak = false;
patient2.AIController.Enabled = false;
var mechanicInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer"));
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient1);
var securityInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "securityofficer"));
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient2);
var engineerInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer"));
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "3");
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;
}
public override IEnumerable<object> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
// explosions and radio messages ------------------------------------------------------
yield return new WaitForSeconds(3.0f);
//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);
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);
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);
}
yield return new WaitForSeconds(3.0f);
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);
SetHighlight(doctor_suppliesCabinet.Item, true);
/*while (doctor.CurrentHull != doctor_suppliesCabinet.Item.CurrentHull)
{
yield return new WaitForSeconds(2.0f);
}*/
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Use), GameMain.Config.KeyBind(InputType.Deselect)); // Medical supplies objective
do
{
for (int i = 0; i < doctor_suppliesCabinet.Inventory.Items.Length; i++)
{
if (doctor_suppliesCabinet.Inventory.Items[i] != null)
{
HighlightInventorySlot(doctor_suppliesCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_suppliesCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.slots.Length; i++)
{
if (doctor.Inventory.Items[i] == null) HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (doctor.Inventory.FindItemByIdentifier("antidama1") == null); // Wait until looted
yield return new WaitForSeconds(1.0f);
SetHighlight(doctor_suppliesCabinet.Item, false);
RemoveCompletedObjective(segments[0]);
yield return new WaitForSeconds(1.0f);
// 2nd tutorial segment, treat self -------------------------------------------------------------------------
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Health)); // Open health interface
while (CharacterHealth.OpenHealthWindow == null)
{
yield return new WaitForSeconds(1.0f);
}
RemoveCompletedObjective(segments[1]);
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", highlightColor, .5f, .5f, 0f);
}
yield return null;
}
RemoveCompletedObjective(segments[2]);
SetDoorAccess(doctor_firstDoor, doctor_firstDoorLight, true);
while (CharacterHealth.OpenHealthWindow != null)
{
yield return new WaitForSeconds(1.0f);
}
// treat patient --------------------------------------------------------------------------------------------
//patient 1 requests first aid
patient1.CanSpeak = true;
var newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), patient1.CurrentHull, null);
GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
patient1.Speak(newOrder.GetChatMessage("", patient1.CurrentHull?.RoomName, givingOrderToSelf: false), ChatMessageType.Order);
patient1.AIController.Enabled = true;
while (doctor.CurrentHull != patient1.CurrentHull)
{
yield return new WaitForSeconds(1.0f);
}
yield return new WaitForSeconds(0.0f);
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.ToggleCrewAreaOpen = true;
yield return new WaitForSeconds(3.0f);
TriggerTutorialSegment(3); // Get the patient to medbay
while (patient1.CurrentOrder == null || patient1.CurrentOrder.AITag != "follow")
{
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);
}
RemoveCompletedObjective(segments[3]);
SetHighlight(doctor_medBayCabinet.Item, true);
SetDoorAccess(doctor_thirdDoor, doctor_thirdDoorLight, true);
yield return new WaitForSeconds(2.0f);
TriggerTutorialSegment(4, GameMain.Config.KeyBind(InputType.Health)); // treat burns
do
{
for (int i = 0; i < 3; i++)
{
if (doctor_medBayCabinet.Inventory.Items[i] != null)
{
HighlightInventorySlot(doctor_medBayCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_medBayCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.slots.Length; i++)
{
if (doctor.Inventory.Items[i] == null) HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (doctor.Inventory.FindItemByIdentifier("antibleeding1") == 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", highlightColor, .5f, .5f, 0f);
}
yield return null;
}
RemoveCompletedObjective(segments[4]);
SetHighlight(patient1, false);
yield return new WaitForSeconds(1.0f);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.AssistantBurnsHealed"), ChatMessageType.Radio, null);
// treat unconscious patient ------------------------------------------------------
//patient calls for help
patient2.CanSpeak = true;
newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), patient2.CurrentHull, null);
GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
patient2.Speak(newOrder.GetChatMessage("", patient1.CurrentHull?.RoomName, givingOrderToSelf: false), ChatMessageType.Order);
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);
TriggerTutorialSegment(5, GameMain.Config.KeyBind(InputType.Health)); // perform CPR
SetHighlight(patient2, true);
while (patient2.IsUnconscious)
{
if (CharacterHealth.OpenHealthWindow != null && doctor.AnimController.Anim != AnimController.Animation.CPR)
{
CharacterHealth.OpenHealthWindow.CPRButton.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f);
CharacterHealth.OpenHealthWindow.CPRButton.Flash();
}
yield return null;
}
RemoveCompletedObjective(segments[5]);
SetHighlight(patient2, false);
CoroutineManager.StopCoroutines("KeepPatient2Alive");
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
while (doctor.Submarine != Submarine.MainSub)
{
yield return new WaitForSeconds(1.0f);
}
yield return new WaitForSeconds(5.0f);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Doctor.Radio.EnteredSub"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(3.0f);
TriggerTutorialSegment(6, GameMain.Config.KeyBind(InputType.Health)); // give treatment to anyone in need
foreach (var patient in subPatients)
{
patient.CanSpeak = true;
patient.AIController.Enabled = true;
SetHighlight(patient, true);
}
subPatients[2].Oxygen = -50;
CoroutineManager.StartCoroutine(KeepPatientAlive(subPatients[2]), "KeepPatient3Alive");
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))
{
newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), subPatients[i].CurrentHull, null);
GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
string message = newOrder.GetChatMessage("", subPatients[i].CurrentHull?.RoomName, givingOrderToSelf: false);
if (subPatients[i].CanSpeak)
{
subPatients[i].Speak(message, ChatMessageType.Order);
}
else
{
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, message, ChatMessageType.Radio, null);
}
patientCalledHelp[i] = true;
}
if (subPatients[i].ExternalHighlight && subPatients[i].Vitality >= subPatients[i].MaxVitality * 0.9f)
{
SetHighlight(subPatients[i], false);
}
}
yield return new WaitForSeconds(1.0f);
}
RemoveCompletedObjective(segments[6]);
foreach (var patient in subPatients)
{
SetHighlight(patient, false);
}
// END TUTORIAL
CoroutineManager.StartCoroutine(TutorialCompleted());
}
public IEnumerable<object> KeepPatientAlive(Character patient)
{
while (patient != null && !patient.Removed)
{
patient.Oxygen = Math.Max(patient.Oxygen, -50);
yield return null;
}
}
}
}

View File

@@ -0,0 +1,567 @@
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 MotionSensor engineer_reactorObjectiveSensor;
private Powered tutorial_oxygenGenerator;
private Reactor engineer_reactor;
private Door engineer_secondDoor;
private LightComponent engineer_secondDoorLight;
// Room 4
private MotionSensor engineer_repairJunctionBoxObjectiveSensor;
private Item engineer_brokenJunctionBox;
private Door engineer_thirdDoor;
private LightComponent engineer_thirdDoorLight;
// Room 5
private MotionSensor engineer_disconnectedJunctionBoxObjectiveSensor;
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 string 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(XElement element) : base(element)
{
}
public override void Start()
{
base.Start();
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
engineer = Character.Controlled;
var toolbox = engineer.Inventory.FindItemByIdentifier("toolbox");
toolbox.Unequip(engineer);
engineer.Inventory.RemoveItem(toolbox);
var repairOrder = Order.PrefabList.Find(order => order.AITag == "repairsystems");
engineer_repairIcon = repairOrder.SymbolSprite;
engineer_repairIconColor = repairOrder.Color;
var reactorOrder = Order.PrefabList.Find(order => order.AITag == "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
engineer_reactorObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_reactorobjectivesensor")).GetComponent<MotionSensor>();
tutorial_oxygenGenerator = Item.ItemList.Find(i => i.HasTag("tutorial_oxygengenerator")).GetComponent<Powered>();
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.OnOffSwitch.BarScroll = 1f;
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_repairJunctionBoxObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_repairjunctionboxobjectivesensor")).GetComponent<MotionSensor>();
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_disconnectedJunctionBoxObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_disconnectedjunctionboxobjectivesensor")).GetComponent<MotionSensor>();
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_2 = Item.ItemList.Find(i => i.HasTag("engineer_wire_2"));
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.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;
}
public override IEnumerable<object> 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);
}
//// 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);
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(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.Items[0] == null) firstSlotRemoved = true;
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
}
if (!fourthSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 3, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[2] == null) fourthSlotRemoved = true;
}
for (int i = 0; i < engineer.Inventory.slots.Length; i++)
{
if (engineer.Inventory.Items[i] == null) HighlightInventorySlot(engineer.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (!engineer_equipmentCabinet.Inventory.IsEmpty()); // Wait until looted
RemoveCompletedObjective(segments[0]);
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);
TriggerTutorialSegment(1);
do
{
if (IsSelectedItem(engineer_reactor.Item))
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
if (engineer_reactor.OnOffSwitch.FlashTimer <= 0)
{
engineer_reactor.OnOffSwitch.Flash(highlightColor, 1.5f, false);
}
}
yield return null;
} while (engineer_reactor.OnOffSwitch.BarScroll > 0.45f);
do
{
if (IsSelectedItem(engineer_reactor.Item) && engineer_reactor.Item.OwnInventory.slots != null)
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
HighlightInventorySlot(engineer.Inventory, "fuelrod", highlightColor, 0.5f, 0.5f, 0f);
for (int i = 0; i < engineer_reactor.Item.OwnInventory.slots.Length; i++)
{
HighlightInventorySlot(engineer_reactor.Item.OwnInventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
}
yield return null;
} while (engineer_reactor.AvailableFuel == 0);
CoroutineManager.StartCoroutine(ReactorOperatedProperly());
do
{
if (IsSelectedItem(engineer_reactor.Item))
{
engineer_reactor.AutoTempSlider.BarScrollValue = 1.0f;
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);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.ReactorStable"), ChatMessageType.Radio, null);
do
{
if (IsSelectedItem(engineer_reactor.Item))
{
if (engineer_reactor.AutoTempSlider.FlashTimer <= 0)
{
engineer_reactor.AutoTempSlider.Flash(highlightColor, 1.5f, false, new Vector2(10, 10));
}
}
yield return null;
} while (!engineer_reactor.AutoTemp);
float wait = 1.5f;
do
{
yield return new WaitForSeconds(0.1f);
wait -= 0.1f;
engineer_reactor.AutoTempSlider.BarScrollValue = 0.0f;
} while (wait > 0.0f);
engineer.SelectedConstruction = null;
engineer_reactor.CanBeSelected = false;
RemoveCompletedObjective(segments[1]);
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);
TriggerTutorialSegment(2, GameMain.Config.KeyBind(InputType.Select)); // Repair the junction box
do { yield return null; } while (!engineer_brokenJunctionBox.IsFullCondition); // Wait until repaired
SetHighlight(engineer_brokenJunctionBox, false);
RemoveCompletedObjective(segments[2]);
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);
TriggerTutorialSegment(3, GameMain.Config.KeyBind(InputType.Use), GameMain.Config.KeyBind(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(segments[3]);
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);
TriggerTutorialSegment(4); // Repair junction box
while (ContentRunning) yield return null;
SetHighlight(engineer_submarineJunctionBox_1, true);
SetHighlight(engineer_submarineJunctionBox_2, true);
SetHighlight(engineer_submarineJunctionBox_3, true);
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);
// Remove highlights when each individual machine is repaired
do { CheckJunctionBoxHighlights(); yield return null; } while (!engineer_submarineJunctionBox_1.IsFullCondition || !engineer_submarineJunctionBox_2.IsFullCondition || !engineer_submarineJunctionBox_3.IsFullCondition);
CheckJunctionBoxHighlights();
RemoveCompletedObjective(segments[4]);
TriggerTutorialSegment(5); // 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(segments[5]);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Complete"), ChatMessageType.Radio, null);
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?.SelectedConstruction == item;
}
private IEnumerable<object> ReactorOperatedProperly()
{
float timer;
for (int i = 0; i < reactorLoads.Length; i++)
{
timer = reactorLoadChangeTime;
tutorial_oxygenGenerator.PowerConsumption = reactorLoads[i];
while (timer > 0)
{
yield return new WaitForSeconds(0.1f);
if (IsReactorPoweredUp(engineer_reactor))
{
timer -= 0.1f;
}
}
}
reactorOperatedProperly = true;
}
private void CheckGhostWires()
{
if (engineer_wire_1 != null && engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
{
engineer_wire_1.Remove();
engineer_wire_1 = null;
}
if (engineer_wire_2 != null && engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
{
engineer_wire_2.Remove();
engineer_wire_2 = null;
}
}
private void HandleJunctionBoxWiringHighlights()
{
Item selected = engineer.SelectedConstruction;
if (!engineer.HasEquippedItem("screwdriver"))
{
HighlightInventorySlot(engineer.Inventory, "screwdriver", 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"))
{
HighlightInventorySlotWithTag(engineer.Inventory, "wire", 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()
{
if (engineer_submarineJunctionBox_1.IsFullCondition && engineer_submarineJunctionBox_1.ExternalHighlight)
{
SetHighlight(engineer_submarineJunctionBox_1, false);
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_1);
}
if (engineer_submarineJunctionBox_2.IsFullCondition && engineer_submarineJunctionBox_2.ExternalHighlight)
{
SetHighlight(engineer_submarineJunctionBox_2, false);
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_2);
}
if (engineer_submarineJunctionBox_3.IsFullCondition && 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

@@ -0,0 +1,592 @@
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;
private MotionSensor mechanic_ladderSensor;
// 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 string radioSpeakerName;
private Character mechanic;
private Sprite mechanic_repairIcon;
private Color mechanic_repairIconColor;
public MechanicTutorial(XElement element) : base(element)
{
}
public override void Start()
{
base.Start();
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
mechanic = Character.Controlled;
var toolbox = mechanic.Inventory.FindItemByIdentifier("toolbox");
toolbox.Unequip(mechanic);
mechanic.Inventory.RemoveItem(toolbox);
var crowbar = mechanic.Inventory.FindItemByIdentifier("crowbar");
crowbar.Unequip(mechanic);
mechanic.Inventory.RemoveItem(crowbar);
var repairOrder = Order.PrefabList.Find(order => order.AITag == "repairsystems");
mechanic_repairIcon = repairOrder.SymbolSprite;
mechanic_repairIconColor = repairOrder.Color;
// 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, 165);
}
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>();
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.Items.Length; i++)
{
foreach (ItemComponent ic in mechanic_divingSuitContainer.Inventory.Items[i].Components)
{
ic.CanBePicked = true;
}
}
mechanic_oxygenContainer = Item.ItemList.Find(i => i.HasTag("mechanic_oxygencontainer")).GetComponent<ItemContainer>();
for (int i = 0; i < mechanic_oxygenContainer.Inventory.Items.Length; i++)
{
foreach (ItemComponent ic in mechanic_oxygenContainer.Inventory.Items[i].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_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, 165);
}
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;
}
public override void Update(float deltaTime)
{
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
base.Update(deltaTime);
}
public override IEnumerable<object> 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);
}
yield return new WaitForSeconds(2.5f);
mechanic_fabricator.RemoveFabricationRecipes(new List<string>() { "extinguisher", "wrench", "weldingtool", "weldingfuel", "divingmask", "railgunshell", "nuclearshell", "uex", "harpoongun" });
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.WakeUp"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(2.5f);
TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Up), GameMain.Config.KeyBind(InputType.Left), GameMain.Config.KeyBind(InputType.Down), GameMain.Config.KeyBind(InputType.Right), GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Select)); // Open door objective
yield return new WaitForSeconds(0.0f);
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);
RemoveCompletedObjective(segments[0]);
// Room 2
yield return new WaitForSeconds(0.0f);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(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.Items[0] == null) firstSlotRemoved = true;
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (mechanic_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (mechanic_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
}
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("divingmask") == null || mechanic.Inventory.FindItemByIdentifier("weldingtool") == null || mechanic.Inventory.FindItemByIdentifier("wrench") == null); // Wait until looted
SetHighlight(mechanic_equipmentCabinet.Item, false);
yield return new WaitForSeconds(1.5f);
RemoveCompletedObjective(segments[1]);
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, GameMain.Config.KeyBind(InputType.Shoot), GameMain.Config.KeyBind(InputType.Aim)); // Welding objective
do
{
if (!mechanic.HasEquippedItem("divingmask"))
{
HighlightInventorySlot(mechanic.Inventory, "divingmask", highlightColor, .5f, .5f, 0f);
}
if (!mechanic.HasEquippedItem("weldingtool"))
{
HighlightInventorySlot(mechanic.Inventory, "weldingtool", highlightColor, .5f, .5f, 0f);
}
yield return null;
} while (!mechanic.HasEquippedItem("divingmask") || !mechanic.HasEquippedItem("weldingtool")); // Wait until equipped
SetDoorAccess(mechanic_secondDoor, mechanic_secondDoorLight, true);
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_1, mechanic_repairIcon, mechanic_repairIconColor);
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_1)); // Highlight until repaired
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_1);
RemoveCompletedObjective(segments[2]);
yield return new WaitForSeconds(1f);
TriggerTutorialSegment(3, GameMain.Config.KeyBind(InputType.Select)); // Pump objective
SetHighlight(mechanic_workingPump.Item, true);
do
{
yield return null;
if (IsSelectedItem(mechanic_brokenPump.Item))
{
if (mechanic_workingPump.IsActiveSlider.FlashTimer <= 0)
{
mechanic_workingPump.IsActiveSlider.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.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
RemoveCompletedObjective(segments[3]);
SetDoorAccess(mechanic_thirdDoor, mechanic_thirdDoorLight, true);
yield return new WaitForSeconds(1.5f);
//TriggerTutorialSegment(11, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Up), GameMain.Config.KeyBind(InputType.Down), GameMain.Config.KeyBind(InputType.Select)); // Ladder objective
//do { yield return null; } while (!mechanic_ladderSensor.MotionDetected);
//RemoveCompletedObjective(segments[11]);
yield return new WaitForSeconds(2f);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.News"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(1f);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Fire"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(6f);
// Room 4
do { yield return null; } while (!mechanic_thirdDoor.IsOpen);
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);
do
{
for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
{
if (mechanic_craftingCabinet.Inventory.Items[i] != null)
{
HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (mechanic.SelectedConstruction == mechanic_craftingCabinet.Item)
{
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("oxygentank") == null || mechanic.Inventory.FindItemByIdentifier("sodium") == null); // Wait until looted
yield return new WaitForSeconds(1.0f);
SetHighlight(mechanic_craftingCabinet.Item, false);
SetHighlight(mechanic_deconstructor.Item, true);
do
{
if (IsSelectedItem(mechanic_deconstructor.Item))
{
if (mechanic.Inventory.FindItemByIdentifier("oxygentank") != null)
{
HighlightInventorySlot(mechanic.Inventory, "oxygentank", highlightColor, .5f, .5f, 0f);
if (mechanic_deconstructor.InputContainer.Inventory.slots != null)
{
for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.slots.Length; i++)
{
HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
}
if (mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") != null && !mechanic_deconstructor.IsActive)
{
if (mechanic_deconstructor.ActivateButton.Frame.FlashTimer <= 0)
{
mechanic_deconstructor.ActivateButton.Frame.Flash(highlightColor, 1.5f, false);
}
}
if (mechanic_deconstructor.OutputContainer.Inventory.FindItemByIdentifier("aluminium") != null)
{
HighlightInventorySlot(mechanic_deconstructor.OutputContainer.Inventory, "aluminium", highlightColor, .5f, .5f, 0f);
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("aluminium") == null); // Wait until deconstructed
SetHighlight(mechanic_deconstructor.Item, false);
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(1f);
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") != null)
{
HighlightInventorySlot(mechanic_fabricator.OutputContainer.Inventory, "extinguisher", highlightColor, .5f, .5f, 0f);
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
else if (mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("aluminium") != null && mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("sodium") != null && !mechanic_fabricator.IsActive)
{
if (mechanic_fabricator.ActivateButton.Frame.FlashTimer <= 0)
{
mechanic_fabricator.ActivateButton.Frame.Flash(highlightColor, 1.5f, false);
}
}
else if (mechanic.Inventory.FindItemByIdentifier("aluminium") != null || mechanic.Inventory.FindItemByIdentifier("sodium") != null)
{
HighlightInventorySlot(mechanic.Inventory, "aluminium", highlightColor, .5f, .5f, 0f);
HighlightInventorySlot(mechanic.Inventory, "sodium", highlightColor, .5f, .5f, 0f);
if (mechanic_fabricator.InputContainer.Inventory.Items[0] == null)
{
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 0, highlightColor, .5f, .5f, 0f);
}
if (mechanic_fabricator.InputContainer.Inventory.Items[1] == null)
{
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 1, highlightColor, .5f, .5f, 0f);
}
}
}
}
yield return null;
} while (mechanic.Inventory.FindItemByIdentifier("extinguisher") == null); // Wait until extinguisher is created
RemoveCompletedObjective(segments[5]);
SetHighlight(mechanic_fabricator.Item, false);
SetDoorAccess(mechanic_fourthDoor, mechanic_fourthDoorLight, true);
// Room 5
do { yield return null; } while (!mechanic_fireSensor.MotionDetected);
TriggerTutorialSegment(6, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Using the extinguisher
do { yield return null; } while (!mechanic_fire.Removed); // Wait until extinguished
yield return new WaitForSeconds(3f);
RemoveCompletedObjective(segments[6]);
if (mechanic.HasEquippedItem("extinguisher")) // do not trigger if dropped already
{
TriggerTutorialSegment(7);
do
{
HighlightInventorySlot(mechanic.Inventory, "extinguisher", highlightColor, 0.5f, 0.5f, 0f);
yield return null;
} while (mechanic.HasEquippedItem("extinguisher"));
RemoveCompletedObjective(segments[7]);
}
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.slots != null)
{
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.slots.Length; i++)
{
HighlightInventorySlot(mechanic_divingSuitContainer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
}
}
yield return null;
} while (!mechanic.HasEquippedItem("divingsuit"));
SetHighlight(mechanic_divingSuitContainer.Item, false);
RemoveCompletedObjective(segments[8]);
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, true);
// Room 7
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_repairIcon, mechanic_repairIconColor);
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2));
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Select)); // Repairing machinery (pump)
SetHighlight(mechanic_brokenPump.Item, true);
Repairable repairablePumpComponent = mechanic_brokenPump.Item.GetComponent<Repairable>();
do
{
yield return null;
if (!mechanic_brokenPump.Item.IsFullCondition)
{
if (!mechanic.HasEquippedItem("wrench"))
{
HighlightInventorySlot(mechanic.Inventory, "wrench", highlightColor, 0.5f, 0.5f, 0f);
}
else if (IsSelectedItem(mechanic_brokenPump.Item) && repairablePumpComponent.CurrentFixer == null)
{
if (repairablePumpComponent.RepairButton.Frame.FlashTimer <= 0)
{
repairablePumpComponent.RepairButton.Frame.Flash();
}
}
}
} while (!mechanic_brokenPump.Item.IsFullCondition || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
RemoveCompletedObjective(segments[9]);
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);
// Remove highlights when each individual machine is repaired
do { CheckHighlights(); yield return null; } while (!mechanic_ballastPump_1.Item.IsFullCondition || !mechanic_ballastPump_2.Item.IsFullCondition || !mechanic_submarineEngine.Item.IsFullCondition);
CheckHighlights();
RemoveCompletedObjective(segments[10]);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Complete"), ChatMessageType.Radio, null);
// END TUTORIAL
CoroutineManager.StartCoroutine(TutorialCompleted());
}
private bool IsSelectedItem(Item item)
{
return mechanic?.SelectedConstruction == 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()
{
if (mechanic_ballastPump_1.Item.IsFullCondition && mechanic_ballastPump_1.Item.ExternalHighlight)
{
SetHighlight(mechanic_ballastPump_1.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_1.Item);
}
if (mechanic_ballastPump_2.Item.IsFullCondition && mechanic_ballastPump_2.Item.ExternalHighlight)
{
SetHighlight(mechanic_ballastPump_2.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_2.Item);
}
if (mechanic_submarineEngine.Item.IsFullCondition && mechanic_submarineEngine.Item.ExternalHighlight)
{
SetHighlight(mechanic_submarineEngine.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_submarineEngine.Item);
}
}
}
}

View File

@@ -0,0 +1,452 @@
using System;
using System.Collections.Generic;
using System.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 string radioSpeakerName;
private Character officer;
private string crawlerCharacterFile;
private string hammerheadCharacterFile;
private string mudraptorCharacterFile;
private float superCapacitorRechargeRate = 10;
private Sprite officer_gunIcon;
private Color officer_gunIconColor;
public OfficerTutorial(XElement element) : base(element)
{
crawlerCharacterFile = Character.GetConfigFile("crawler");
hammerheadCharacterFile = Character.GetConfigFile("hammerhead");
mudraptorCharacterFile = Character.GetConfigFile("mudraptor");
}
public override void Start()
{
base.Start();
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
officer = Character.Controlled;
var handcuffs = officer.Inventory.FindItemByIdentifier("handcuffs");
handcuffs.Unequip(officer);
officer.Inventory.RemoveItem(handcuffs);
var stunbaton = officer.Inventory.FindItemByIdentifier("stunbaton");
stunbaton.Unequip(officer);
officer.Inventory.RemoveItem(stunbaton);
var ballistichelmet = officer.Inventory.FindItemByIdentifier("ballistichelmet");
ballistichelmet.Unequip(officer);
officer.Inventory.RemoveItem(ballistichelmet);
var bodyarmor = officer.Inventory.FindItemByIdentifier("bodyarmor");
bodyarmor.Unequip(officer);
officer.Inventory.RemoveItem(bodyarmor);
var gunOrder = Order.PrefabList.Find(order => order.AITag == "operateweapons");
officer_gunIcon = gunOrder.SymbolSprite;
officer_gunIconColor = gunOrder.Color;
// 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);
}
public override IEnumerable<object> 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);
}
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);
//TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(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.Items[0] == null) firstSlotRemoved = true;
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (officer_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (officer_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
}
for (int i = 0; i < officer.Inventory.slots.Length; i++)
{
if (officer.Inventory.Items[i] == null) HighlightInventorySlot(officer.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
yield return null;
} while (!officer_equipmentCabinet.Inventory.IsEmpty()); // Wait until looted
//RemoveCompletedObjective(segments[0]);
SetHighlight(officer_equipmentCabinet.Item, false);
do { yield return null; } while (IsSelectedItem(officer_equipmentCabinet.Item));
TriggerTutorialSegment(1, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(InputType.Shoot)); // Equip melee weapon & armor
do
{
if (!officer.HasEquippedItem("stunbaton"))
{
HighlightInventorySlot(officer.Inventory, "stunbaton", highlightColor, .5f, .5f, 0f);
}
if (!officer.HasEquippedItem("bodyarmor"))
{
HighlightInventorySlot(officer.Inventory, "bodyarmor", highlightColor, .5f, .5f, 0f);
}
if (!officer.HasEquippedItem("ballistichelmet"))
{
HighlightInventorySlot(officer.Inventory, "ballistichelmet", highlightColor, .5f, .5f, 0f);
}
yield return new WaitForSeconds(1f);
} while (!officer.HasEquippedItem("stunbaton") || !officer.HasEquippedItem("bodyarmor") || !officer.HasEquippedItem("ballistichelmet"));
RemoveCompletedObjective(segments[1]);
SetDoorAccess(officer_firstDoor, officer_firstDoorLight, true);
// Room 3
do { yield return null; } while (!officer_crawlerSensor.MotionDetected);
TriggerTutorialSegment(2);
officer_crawler = SpawnMonster(crawlerCharacterFile, officer_crawlerSpawnPos);
do { yield return null; } while (!officer_crawler.IsDead);
RemoveCompletedObjective(segments[2]);
Heal(officer);
yield return new WaitForSeconds(1f);
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);
TriggerTutorialSegment(3); // Arm railgun
do
{
SetHighlight(officer_coilgunLoader.Item, officer_coilgunLoader.Inventory.Items[0] == null || officer_coilgunLoader.Inventory.Items[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", highlightColor, .5f, .5f, 0f);
}
yield return null;
} while (officer_coilgunLoader.Inventory.Items[0] == null || officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate || officer_coilgunLoader.Inventory.Items[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(segments[3]);
yield return new WaitForSeconds(2f);
TriggerTutorialSegment(4, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Shoot), GameMain.Config.KeyBind(InputType.Deselect)); // Kill hammerhead
officer_hammerhead = SpawnMonster(hammerheadCharacterFile, officer_hammerheadSpawnPos);
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)
{
// Don't let the Hammerhead go too far from the periscope.
officer_hammerhead.TeleportTo(officer_hammerheadSpawnPos);
}
yield return null;
}
while(!officer_hammerhead.IsDead);
Heal(officer);
SetHighlight(officer_coilgunPeriscope, false);
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(1f);
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);
TriggerTutorialSegment(5, GameMain.Config.KeyBind(InputType.Aim), GameMain.Config.KeyBind(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, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
yield return null;
} while (!officer.HasEquippedItem("harpoongun")); // Wait until equipped
ItemContainer harpoonGunChamber = officer.Inventory.FindItemByIdentifier("harpoongun").GetComponent<ItemContainer>();
SetHighlight(officer_rangedWeaponCabinet.Item, true);
do
{
if (IsSelectedItem(officer_rangedWeaponCabinet.Item))
{
if (officer_rangedWeaponCabinet.Inventory.slots != null)
{
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Items.Length; i++)
{
if (officer_rangedWeaponCabinet.Inventory.Items[i] == null) continue;
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "spear")
{
HighlightInventorySlot(officer_rangedWeaponCabinet.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
}
}
}
for (int i = 0; i < officer.Inventory.Items.Length; i++)
{
if (officer.Inventory.Items[i] == null) continue;
if (officer.Inventory.Items[i].Prefab.Identifier == "spear")
{
HighlightInventorySlot(officer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
}
if (officer.Inventory.FindItemByIdentifier("spear") != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("spear") != null))
{
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
}
yield return null;
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all five harpons loaded
RemoveCompletedObjective(segments[5]);
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(mudraptorCharacterFile, officer_mudraptorSpawnPos);
do { yield return null; } while (!officer_mudraptor.IsDead);
Heal(officer);
RemoveCompletedObjective(segments[6]);
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_1.Item, officer_gunIcon, officer_gunIconColor);
officer.AddActiveObjectiveEntity(officer_subSuperCapacitor_2.Item, officer_gunIcon, officer_gunIconColor);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Submarine"), ChatMessageType.Radio, null);
do
{
SetHighlight(officer_subLoader_1.Item, officer_subLoader_1.Inventory.Items[0] == null || officer_subLoader_1.Inventory.Items[0].Condition == 0);
SetHighlight(officer_subLoader_2.Item, officer_subLoader_2.Inventory.Items[0] == null || officer_subLoader_2.Inventory.Items[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_subLoader_1.Item.ExternalHighlight || officer_subLoader_2.Item.ExternalHighlight);
SetHighlight(officer_subAmmoBox_2, officer_subLoader_1.Item.ExternalHighlight || officer_subLoader_2.Item.ExternalHighlight);
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(segments[7]);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Complete"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(4f);
CoroutineManager.StartCoroutine(TutorialCompleted());
}
private bool IsSelectedItem(Item item)
{
return officer?.SelectedConstruction == item;
}
private Character SpawnMonster(string characterFile, Vector2 pos)
{
var character = Character.Create(characterFile, 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,44 +1,118 @@
using System;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Tutorials
{
class ScenarioTutorial : Tutorial
{
private CoroutineHandle tutorialCoroutine;
private Character character;
private string spawnSub;
private SpawnType spawnPointType;
private string submarinePath;
private string startOutpostPath;
private string endOutpostPath;
private string levelSeed;
private string levelParams;
private Submarine startOutpost = null;
private Submarine 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 = Color.Red;
protected Color accessibleColor = Color.Green;
public ScenarioTutorial(XElement element) : base(element)
{
submarinePath = element.GetAttributeString("submarinepath", "");
startOutpostPath = element.GetAttributeString("startoutpostpath", "");
endOutpostPath = element.GetAttributeString("endoutpostpath", "");
levelSeed = element.GetAttributeString("levelseed", "tuto");
Enum.TryParse(element.GetAttributeString("spawnpointtype", "Human"), true, out spawnPointType);
levelParams = element.GetAttributeString("levelparams", "");
spawnSub = element.GetAttributeString("spawnsub", "");
Enum.TryParse(element.GetAttributeString("spawnpointtype", "Human"), true, out spawnPointType);
}
public override void Initialize()
{
base.Initialize();
currentTutorialCompleted = false;
GameMain.Instance.ShowLoading(Loading());
}
private IEnumerable<object> Loading()
{
Submarine.MainSub = Submarine.Load(submarinePath, "", true);
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Name == levelParams);
yield return CoroutineStatus.Running;
GameMain.GameSession = new GameSession(Submarine.MainSub, "",
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
if (generationParams != null)
{
Biome biome = LevelGenerationParams.GetBiomes().Find(b => generationParams.AllowedBiomes.Contains(b));
if (startOutpostPath != string.Empty)
{
startOutpost = Submarine.Load(startOutpostPath, "", false);
}
if (endOutpostPath != string.Empty)
{
endOutpost = Submarine.Load(endOutpostPath, "", false);
}
Level tutorialLevel = new Level(levelSeed, 0, 0, generationParams, biome, startOutpost, endOutpost);
GameMain.GameSession.StartRound(tutorialLevel);
}
else
{
GameMain.GameSession.StartRound(levelSeed);
}
GameMain.GameSession.EventManager.Events.Clear();
GameMain.GameSession.EventManager.Enabled = false;
GameMain.GameScreen.Select();
yield return CoroutineStatus.Success;
}
public override void Start()
{
base.Start();
WayPoint wayPoint = WayPoint.GetRandom(spawnPointType, null);
Submarine.MainSub.GodMode = true;
CharacterInfo charInfo = configElement.Element("Character") == null ?
new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer")) :
new CharacterInfo(configElement.Element("Character"));
WayPoint wayPoint = GetSpawnPoint(charInfo);
if (wayPoint == null)
{
DebugConsole.ThrowError("A waypoint with the spawntype \"" + spawnPointType + "\" is required for the tutorial event");
return;
}
CharacterInfo charInfo = configElement.Element("Character") == null ?
new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer")) :
new CharacterInfo(configElement.Element("Character"));
character = Character.Create(charInfo, wayPoint.WorldPosition, "", false, false);
Character.Controlled = character;
character.GiveJobItems(null);
@@ -52,22 +126,82 @@ namespace Barotrauma.Tutorials
idCard.AddTag("com");
idCard.AddTag("eng");
CoroutineManager.StartCoroutine(UpdateState());
tutorialCoroutine = CoroutineManager.StartCoroutine(UpdateState());
}
private IEnumerable<object> Loading()
public override void AddToGUIUpdateList()
{
Submarine.MainSub = Submarine.Load(submarinePath, "", true);
yield return CoroutineStatus.Running;
if (!currentTutorialCompleted)
{
base.AddToGUIUpdateList();
}
}
GameMain.GameSession = new GameSession(Submarine.MainSub, "",
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
(GameMain.GameSession.GameMode as TutorialMode).tutorial = this;
GameMain.GameSession.StartRound(levelSeed);
GameMain.GameSession.EventManager.Events.Clear();
GameMain.GameScreen.Select();
private WayPoint GetSpawnPoint(CharacterInfo charInfo)
{
Submarine spawnSub = null;
yield return CoroutineStatus.Success;
if (this.spawnSub != string.Empty)
{
switch (this.spawnSub)
{
case "startoutpost":
spawnSub = startOutpost;
break;
case "endoutpost":
spawnSub = endOutpost;
break;
default:
spawnSub = Submarine.MainSub;
break;
}
}
return WayPoint.GetRandom(spawnPointType, charInfo.Job, spawnSub);
}
protected bool HasOrder(Character character, string aiTag, string option = null)
{
if (character.CurrentOrder?.AITag == aiTag)
{
if (option == null)
{
return true;
}
else
{
HumanAIController humanAI = character.AIController as HumanAIController;
return humanAI.CurrentOrderOption == 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)
@@ -75,27 +209,47 @@ namespace Barotrauma.Tutorials
base.Update(deltaTime);
if (character != null)
{
if (Character.Controlled == null)
if (character.Oxygen < 1)
{
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
character.Oxygen = 1;
}
if (character.IsDead)
{
CoroutineManager.StartCoroutine(Dead());
}
else if (Character.Controlled == null)
{
if (tutorialCoroutine != null)
{
CoroutineManager.StopCoroutines(tutorialCoroutine);
}
infoBox = null;
}
else if (Character.Controlled.IsDead)
{
Character.Controlled = null;
CoroutineManager.StopCoroutines("TutorialMode.UpdateState");
infoBox = null;
CoroutineManager.StartCoroutine(Dead());
}
}
}
public override void Stop()
{
if (tutorialCoroutine != null)
{
CoroutineManager.StopCoroutines(tutorialCoroutine);
}
base.Stop();
}
private IEnumerable<object> Dead()
{
GUI.PreventPauseMenuToggle = true;
Character.Controlled = character = null;
Stop();
yield return new WaitForSeconds(3.0f);
var messageBox = new GUIMessageBox("You have died", "Do you want to try again?", new string[] { "Yes", "No" });
var messageBox = new GUIMessageBox(TextManager.Get("Tutorial.TryAgainHeader"), TextManager.Get("Tutorial.TryAgain"), new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
messageBox.Buttons[0].OnClicked += Restart;
messageBox.Buttons[0].OnClicked += messageBox.Close;
@@ -106,5 +260,29 @@ namespace Barotrauma.Tutorials
yield return CoroutineStatus.Success;
}
protected IEnumerable<object> TutorialCompleted()
{
GUI.PreventPauseMenuToggle = true;
Character.Controlled.ClearInputs();
Character.Controlled = null;
yield return new WaitForSeconds(waitBeforeFade);
var endCinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 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);
}
}
}

View File

@@ -1,21 +1,74 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
namespace Barotrauma.Tutorials
{
abstract class Tutorial
{
#region Tutorial variables
public static bool Initialized = false;
public static bool ContentRunning = false;
public static List<Tutorial> Tutorials;
protected bool started = false;
protected GUIComponent infoBox;
private Action infoBoxClosedCallback;
protected XElement configElement;
private enum TutorialType { None, Scenario, Contextual };
private TutorialType tutorialType = TutorialType.None;
protected VideoPlayer videoPlayer;
protected enum TutorialContentTypes { None = 0, Video = 1, ManualVideo = 2, TextOnly = 3 };
protected string playableContentPath;
protected Point screenResolution;
protected float prevUIScale;
private GUIFrame holderFrame, objectiveFrame;
private List<TutorialSegment> activeObjectives = new List<TutorialSegment>();
private string objectiveTranslated;
protected TutorialSegment activeContentSegment;
protected List<TutorialSegment> segments;
protected class TutorialSegment
{
public string Id;
public string Objective;
public TutorialContentTypes ContentType;
public XElement TextContent;
public XElement VideoContent;
public bool IsTriggered;
public GUIButton ReplayButton;
public GUITextBlock LinkedTitle, LinkedText;
public object[] Args;
public TutorialSegment(XElement config)
{
Id = config.GetAttributeString("id", "Missing ID");
Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true);
Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType);
IsTriggered = config.GetAttributeBool("istriggered", false);
switch (ContentType)
{
case TutorialContentTypes.None:
break;
case TutorialContentTypes.Video:
case TutorialContentTypes.ManualVideo:
VideoContent = config.Element("Video");
TextContent = config.Element("Text");
break;
case TutorialContentTypes.TextOnly:
TextContent = config.Element("Text");
break;
}
}
}
public string Name
{
@@ -34,7 +87,9 @@ namespace Barotrauma.Tutorials
GameMain.Config.SaveNewPlayerConfig();
}
}
#endregion
#region Tutorial Controls
public static void Init()
{
Tutorials = new List<Tutorial>();
@@ -106,27 +161,85 @@ namespace Barotrauma.Tutorials
configElement = element;
Name = element.GetAttributeString("name", "Unnamed");
completed = GameMain.Config.CompletedTutorialNames.Contains(Name);
Enum.TryParse(element.GetAttributeString("tutorialtype", "Scenario"), true, out tutorialType);
playableContentPath = element.GetAttributeString("playablecontentpath", "");
segments = new List<TutorialSegment>();
foreach (var segment in element.Elements("Segment"))
{
segments.Add(new TutorialSegment(segment));
}
}
public virtual void Initialize()
{
if (Initialized) return;
Initialized = true;
videoPlayer = new VideoPlayer();
}
public virtual void Start()
{
activeObjectives.Clear();
objectiveTranslated = TextManager.Get("Tutorial.Objective");
CreateObjectiveFrame();
// Setup doors: Clear all requirements, unless the door is setup as locked.
foreach (var item in Item.ItemList)
{
var door = item.GetComponent<Door>();
if (door != null)
{
if (door.requiredItems.Values.None(ris => ris.None(ri => ri.Identifiers.None(i => i == "locked"))))
{
door.requiredItems.Clear();
}
}
}
}
public virtual void AddToGUIUpdateList()
{
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
{
CreateObjectiveFrame();
}
if (objectiveFrame != null && activeObjectives.Count > 0)
{
objectiveFrame.AddToGUIUpdateList(order: -1);
}
if (infoBox != null) infoBox.AddToGUIUpdateList(order: 100);
if (videoPlayer != null) videoPlayer.AddToGUIUpdateList(order: 100);
}
public virtual void Update(float deltaTime)
{
if (videoPlayer != null)
{
videoPlayer.Update();
}
if (activeObjectives != null)
{
for (int i = 0; i < activeObjectives.Count; i++)
{
CheckActiveObjectives(activeObjectives[i], deltaTime);
}
}
}
public void CloseActiveContentGUI()
{
if (videoPlayer.IsPlaying)
{
videoPlayer.Stop();
}
else if (infoBox != null)
{
CloseInfoFrame(null, null);
}
}
public virtual IEnumerable<object> UpdateState()
@@ -134,6 +247,231 @@ namespace Barotrauma.Tutorials
yield return CoroutineStatus.Success;
}
protected bool Restart(GUIButton button, object obj)
{
GUI.PreventPauseMenuToggle = false;
TutorialMode.StartTutorial(this);
return true;
}
protected virtual void TriggerTutorialSegment(int index, params object[] args)
{
Inventory.draggingItem = null;
ContentRunning = true;
activeContentSegment = segments[index];
segments[index].Args = args;
string tutorialText = TextManager.GetFormatted(activeContentSegment.TextContent.GetAttributeString("tag", ""), true, args);
tutorialText = TextManager.ParseInputTypes(tutorialText);
string objectiveText = string.Empty;
if (!string.IsNullOrEmpty(activeContentSegment.Objective))
{
if (args.Length == 0)
{
objectiveText = activeContentSegment.Objective;
}
else
{
objectiveText = string.Format(activeContentSegment.Objective, args);
}
objectiveText = TextManager.ParseInputTypes(objectiveText);
activeContentSegment.Objective = objectiveText;
}
else
{
activeContentSegment.IsTriggered = true; // Complete at this stage only if no related objective
}
switch (activeContentSegment.ContentType)
{
case TutorialContentTypes.None:
break;
case TutorialContentTypes.Video:
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
activeContentSegment.TextContent.GetAttributeInt("width", 300),
activeContentSegment.TextContent.GetAttributeInt("height", 80),
activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, () => LoadVideo(activeContentSegment));
break;
case TutorialContentTypes.ManualVideo:
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
activeContentSegment.TextContent.GetAttributeInt("width", 300),
activeContentSegment.TextContent.GetAttributeInt("height", 80),
activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, StopCurrentContentSegment, () => LoadVideo(activeContentSegment, false));
break;
case TutorialContentTypes.TextOnly:
infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText,
activeContentSegment.TextContent.GetAttributeInt("width", 300),
activeContentSegment.TextContent.GetAttributeInt("height", 80),
activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, StopCurrentContentSegment);
break;
}
}
public virtual void Stop()
{
started = ContentRunning = Initialized = false;
infoBox = null;
if (videoPlayer != null)
{
videoPlayer.Remove();
videoPlayer = null;
}
}
#endregion
#region Objectives
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++)
{
CreateObjectiveGUI(activeObjectives[i], i, activeObjectives[i].ContentType);
}
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
prevUIScale = GUI.Scale;
}
protected void StopCurrentContentSegment()
{
if (!string.IsNullOrEmpty(activeContentSegment.Objective))
{
AddNewObjective(activeContentSegment, activeContentSegment.ContentType);
}
activeContentSegment = null;
ContentRunning = false;
}
protected virtual void CheckActiveObjectives(TutorialSegment objective, float deltaTime)
{
}
protected bool HasObjective(TutorialSegment segment)
{
return activeObjectives.Contains(segment);
}
protected void AddNewObjective(TutorialSegment segment, TutorialContentTypes type)
{
activeObjectives.Add(segment);
CreateObjectiveGUI(segment, activeObjectives.Count - 1, type);
}
private void CreateObjectiveGUI(TutorialSegment segment, int index, TutorialContentTypes type)
{
Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X * GUI.Scale), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f * GUI.Scale));
segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) =>
{
if (type == TutorialContentTypes.Video)
{
ReplaySegmentVideo(segment);
}
else
{
ShowSegmentText(segment);
}
return true;
};
string objectiveText = TextManager.ParseInputTypes(objectiveTranslated);
int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveText).Y / 2f + 5));
segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point((int)GUI.ObjectiveNameFont.MeasureString(objectiveText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterRight, Pivot.BottomRight) { AbsoluteOffset = new Point((int)(-10 * GUI.Scale), 0) },
objectiveText, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight);
segment.LinkedText = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.TopCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) },
TextManager.ParseInputTypes(segment.Objective), textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight);
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;
}
private void ReplaySegmentVideo(TutorialSegment segment)
{
if (ContentRunning) return;
ContentRunning = true;
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false);
}
private void ShowSegmentText(TutorialSegment segment)
{
if (ContentRunning) return;
Inventory.draggingItem = null;
ContentRunning = true;
string tutorialText = TextManager.GetFormatted(segment.TextContent.GetAttributeString("tag", ""), true, segment.Args);
Action videoAction = null;
if (segment.ContentType != TutorialContentTypes.TextOnly)
{
videoAction = () => LoadVideo(segment, false);
}
infoBox = CreateInfoFrame(TextManager.Get(segment.Id), tutorialText,
segment.TextContent.GetAttributeInt("width", 300),
segment.TextContent.GetAttributeInt("height", 80),
segment.TextContent.GetAttributeString("anchor", "Center"), true, () => ContentRunning = false, videoAction);
}
protected void RemoveCompletedObjective(TutorialSegment segment)
{
if (!HasObjective(segment)) return;
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.BottomLeft, Pivot.BottomLeft);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5, 0);
}
else
{
rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft);
rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5 - (objectiveTitleWidth), 0);
}
GUIImage checkmark = new GUIImage(rectTA, "CheckMark");
checkmark.Color = checkmark.SelectedColor = checkmark.HoverColor = checkmark.PressedColor = color;
RectTransform rectTB = new RectTransform(new Vector2(1.1f, .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(segment));
}
private IEnumerable<object> WaitForObjectiveEnd(TutorialSegment objective)
{
yield return new WaitForSeconds(2.0f);
objectiveFrame.RemoveChild(objective.ReplayButton);
activeObjectives.Remove(objective);
for (int i = 0; i < activeObjectives.Count; i++)
{
activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjectives[i].ReplayButton.Rect.Height + 20) * i);
}
}
#endregion
#region InfoFrame
protected bool CloseInfoFrame(GUIButton button, object userData)
{
infoBox = null;
@@ -141,87 +479,130 @@ namespace Barotrauma.Tutorials
return true;
}
protected GUIComponent CreateInfoFrame(string text, bool hasButton = false, Action callback = null)
protected GUIComponent CreateInfoFrame(string title, string text, int width = 300, int height = 80, string anchorStr = "", bool hasButton = false, Action callback = null, Action showVideo = null)
{
int width = 300;
int height = hasButton ? 110 : 80;
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
height += wrappedText.Split('\n').Length * 25;
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, Anchor.TopRight) { AbsoluteOffset = new Point(20) });
infoBlock.Flash(Color.Green);
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.7f), infoBlock.RectTransform, Anchor.Center),
text, wrap: true);
infoBoxClosedCallback = callback;
if (hasButton)
{
var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) },
TextManager.Get("OK"))
{
OnClicked = CloseInfoFrame
};
}
if (hasButton) height += 60;
GUI.PlayUISound(GUISoundType.UIMessage);
return infoBlock;
}
protected GUIComponent CreateInfoFrame(string title, string text, int width, int height, string anchorStr, bool hasButton = false, Action callback = null)
{
if (hasButton) height += 30;
string wrappedText = ToolBox.WrapText(text, width, GUI.Font);
height += wrappedText.Split('\n').Length * 25;
height += (int)(GUI.Font.MeasureString(wrappedText).Y + 50);
if (title.Length > 0)
{
height += 35;
}
Anchor anchor = Anchor.TopRight;
Enum.TryParse(anchorStr, out anchor);
var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), GUI.Canvas, anchor) { AbsoluteOffset = new Point(20) });
if (anchorStr != string.Empty)
{
Enum.TryParse(anchorStr, out anchor);
}
var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", new Color(0, 0, 0, 1f));
var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), background.RectTransform, anchor) { AbsoluteOffset = new Point(20) });
infoBlock.Flash(Color.Green);
var infoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), infoBlock.RectTransform, Anchor.Center))
{
Stretch = true,
AbsoluteSpacing = 5
};
if (title.Length > 0)
{
var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1f, .35f), infoBlock.RectTransform, Anchor.TopCenter,
Pivot.TopCenter), title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0));
titleBlock.TextScale = GUI.Scale;
var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform),
title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0));
titleBlock.RectTransform.IsFixedSize = true;
}
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1f), infoBlock.RectTransform, Anchor.BottomCenter),
text, wrap: true);
textBlock.TextScale = GUI.Scale;
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), text, wrap: true);
textBlock.RectTransform.IsFixedSize = true;
infoBoxClosedCallback = callback;
if (hasButton)
{
var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) },
TextManager.Get("OK"))
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), infoContent.RectTransform) { MinSize = new Point(0, 30), MaxSize = new Point((int) infoContent.Rect.X, 60) }, isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.1f
};
buttonContainer.RectTransform.IsFixedSize = true;
if (showVideo != null)
{
var videoButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("Video"), style: "GUIButtonLarge")
{
OnClicked = (GUIButton button, object obj) =>
{
showVideo();
return true;
}
};
}
var okButton = new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("OK"), style: "GUIButtonLarge")
{
OnClicked = CloseInfoFrame
};
}
infoBlock.RectTransform.NonScaledSize = new Point(infoBlock.Rect.Width, (int)(infoContent.Children.Sum(c => c.Rect.Height + infoContent.AbsoluteSpacing) / infoContent.RectTransform.RelativeSize.Y));
GUI.PlayUISound(GUISoundType.UIMessage);
return infoBlock;
return background;
}
#endregion
#region Video
protected void LoadVideo(TutorialSegment segment, bool showText = true)
{
if (videoPlayer == null) videoPlayer = new VideoPlayer();
if (showText)
{
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, segment.Objective, StopCurrentContentSegment);
}
else
{
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), null, segment.Id, true, segment.Objective, null);
}
}
#endregion
#region Highlights
protected void HighlightInventorySlot(Inventory inventory, string identifier, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
if (inventory.slots == null) { return; }
for (int i = 0; i < inventory.Items.Length; i++)
{
if (inventory.Items[i] != null && inventory.Items[i].Prefab.Identifier == identifier)
{
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
}
}
protected bool Restart(GUIButton button, object obj)
protected void HighlightInventorySlotWithTag(Inventory inventory, string tag, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
TutorialMode.StartTutorial(this);
return true;
if (inventory.slots == null) { return; }
for (int i = 0; i < inventory.Items.Length; i++)
{
if (inventory.Items[i] != null && inventory.Items[i].HasTag(tag))
{
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
}
}
protected void HighlightInventorySlot(Inventory inventory, int index, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
if (inventory.slots == null || index < 0 || inventory.slots[index].HighlightTimer > 0) return;
inventory.slots[index].ShowBorderHighlight(color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
#endregion
}
}

View File

@@ -1,11 +1,10 @@
using Barotrauma.Tutorials;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma
{
class TutorialMode : GameMode
{
public Tutorial tutorial;
public Tutorial Tutorial;
public static void StartTutorial(Tutorial tutorial)
{
@@ -20,18 +19,20 @@ namespace Barotrauma
public override void Start()
{
base.Start();
tutorial.Start();
GameMain.GameSession.CrewManager = new CrewManager(true);
Tutorial.Start();
}
public override void AddToGUIUpdateList()
{
tutorial.AddToGUIUpdateList();
base.AddToGUIUpdateList();
Tutorial.AddToGUIUpdateList();
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
tutorial.Update(deltaTime);
Tutorial.Update(deltaTime);
}
}
}

View File

@@ -6,6 +6,7 @@ using Microsoft.Xna.Framework.Input;
using OpenTK.Audio.OpenAL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Barotrauma
@@ -80,8 +81,16 @@ namespace Barotrauma
var leftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 1.0f), settingsFramePadding.RectTransform, Anchor.TopLeft));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform),
TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont);
var settingsTitle = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform),
TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont)
{ ForceUpperCase = true };
//TODO: enable when new texts can be added
/*new GUIButton(new RectTransform(new Vector2(1.0f, 0.75f), settingsTitle.RectTransform, Anchor.CenterRight), style: "GUIBugButton")
{
ToolTip = "Bug Reporter",
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};*/
var generalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), leftPanel.RectTransform, Anchor.TopLeft));
@@ -155,7 +164,7 @@ namespace Barotrauma
{
UserData = tab
};
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform),
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform),
TextManager.Get("SettingsTab." + tab.ToString()), style: "GUITabButton")
{
UserData = tab,
@@ -193,7 +202,7 @@ namespace Barotrauma
var resolutionDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), elementCount: supportedDisplayModes.Count)
{
OnSelected = SelectResolution,
#if OSX
#if !LINUX
ButtonEnabled = GameMain.Config.WindowMode == WindowMode.Windowed
#endif
};
@@ -233,7 +242,7 @@ namespace Barotrauma
{
UnsavedSettings = true;
GameMain.Config.WindowMode = (WindowMode)guiComponent.UserData;
#if OSX
#if !LINUX
resolutionDD.ButtonEnabled = GameMain.Config.WindowMode == WindowMode.Windowed;
#endif
return true;
@@ -429,7 +438,7 @@ namespace Barotrauma
UnsavedSettings = true;
return true;
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChat"));
IList<string> deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier);
@@ -438,6 +447,17 @@ namespace Barotrauma
DebugConsole.NewMessage(name + " " + name.Length.ToString(), Color.Lime);
}
GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get("DirectionalVoiceChat"));
directionalVoiceChat.Selected = UseDirectionalVoiceChat;
directionalVoiceChat.ToolTip = TextManager.Get("DirectionalVoiceChatToolTip");
directionalVoiceChat.OnSelected = (tickBox) =>
{
UseDirectionalVoiceChat = tickBox.Selected;
UnsavedSettings = true;
return true;
};
if (string.IsNullOrWhiteSpace(VoiceCaptureDevice)) VoiceCaptureDevice = deviceNames[0];
#if (!OSX)
var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), VoiceCaptureDevice, deviceNames.Count);
@@ -627,7 +647,7 @@ namespace Barotrauma
return true;
}
};
var inputFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f), controlsLayoutGroup.RectTransform), isHorizontal: true)
{ Stretch = true, RelativeSpacing = 0.03f };

View File

@@ -1,4 +1,5 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
@@ -18,7 +19,7 @@ namespace Barotrauma
Right,
Center
}
private enum QuickUseAction
{
None,
@@ -33,6 +34,8 @@ namespace Barotrauma
}
private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
private Point screenResolution;
@@ -50,11 +53,42 @@ namespace Barotrauma
}
}
public bool Hidden { get; set; }
private bool hidePersonalSlots;
private float hidePersonalSlotsState;
private GUIButton hideButton;
private Rectangle personalSlotArea;
public bool HidePersonalSlots
{
get { return hidePersonalSlots; }
}
public Rectangle PersonalSlotArea
{
get { return personalSlotArea; }
}
partial void InitProjSpecific(XElement element)
{
Hidden = true;
hideButton = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), (int)(60 * GUI.Scale)), GUI.Canvas)
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
"", style: "UIToggleButton");
hideButton.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
hideButton.OnClicked += (GUIButton btn, object userdata) =>
{
hidePersonalSlots = !hidePersonalSlots;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = hidePersonalSlots ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
}
return true;
};
hidePersonalSlots = false;
if (limbSlotIcons == null)
{
limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
@@ -66,13 +100,13 @@ namespace Barotrauma
limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/IconAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(640 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2)));
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 896 + margin, 128 - margin * 2, 128 - margin * 2)));
}
SlotPositions = new Vector2[SlotTypes.Length];
CurrentLayout = Layout.Default;
SetSlotPositions(layout);
}
protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
{
base.PutItem(item, i, user, removeItem, createNetworkEvent);
@@ -158,6 +192,11 @@ namespace Barotrauma
{
if (slots[i].Disabled || (hideEmptySlot[i] && Items[i] == null)) return true;
if (layout == Layout.Default)
{
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(slots[i].Rect.Center + slots[i].DrawOffset.ToPoint())) return true;
}
//no need to draw the right hand slot if the item is in both hands
if (Items[i] != null && SlotTypes[i] == InvSlotType.RightHand && IsInLimbSlot(Items[i], InvSlotType.LeftHand))
{
@@ -175,7 +214,6 @@ namespace Barotrauma
return false;
}
private void SetSlotPositions(Layout layout)
{
int spacing = (int)(10 * UIScale);
@@ -184,27 +222,32 @@ namespace Barotrauma
if (slots == null) CreateSlots();
var upperSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.Head;
hideButton.Visible = false;
switch (layout)
{
case Layout.Default:
{
int personalSlotCount = SlotTypes.Count(s => upperSlots.HasFlag(s));
int normalSlotCount = SlotTypes.Count(s => !upperSlots.HasFlag(s));
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (slotSize.X + spacing) / 2;
int upperX = HUDLayoutSettings.PortraitArea.X - slotSize.X;
int upperX = HUDLayoutSettings.PortraitArea.X - slotSize.X * 2;
//make sure the rightmost normal slot doesn't overlap with the personal slots
x -= Math.Max((x + normalSlotCount * (slotSize.X + spacing)) - (upperX - personalSlotCount * (slotSize.X + spacing)), 0);
int hideButtonSlotIndex = -1;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (upperSlots.HasFlag(SlotTypes[i]))
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset);
upperX -= slotSize.X + spacing;
personalSlotArea = (hideButtonSlotIndex == -1) ?
new Rectangle(SlotPositions[i].ToPoint(), slotSize) :
Rectangle.Union(personalSlotArea, new Rectangle(SlotPositions[i].ToPoint(), slotSize));
hideButtonSlotIndex = i;
}
else
{
@@ -212,19 +255,29 @@ namespace Barotrauma
x += slotSize.X + spacing;
}
}
if (hideButtonSlotIndex > -1)
{
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
hideButton.RectTransform.NonScaledSize = new Point(slotSize.X / 2, slotSize.Y + slots[hideButtonSlotIndex].EquipButtonRect.Height);
hideButton.RectTransform.AbsoluteOffset = new Point(
personalSlotArea.Right + spacing,
personalSlotArea.Y - slots[hideButtonSlotIndex].EquipButtonRect.Height);
hideButton.Visible = true;
}
}
break;
case Layout.Right:
{
int extraOffset = 0;
int x = HUDLayoutSettings.InventoryAreaLower.Right;
int upperX = HUDLayoutSettings.InventoryAreaLower.Right;
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - slotSize.X - spacing;
for (int i = 0; i < slots.Length; i++)
{
if (HideSlot(i)) continue;
if (upperSlots.HasFlag(SlotTypes[i]))
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
upperX -= slotSize.X + spacing;
//upperX -= slotSize.X + spacing;
}
else
{
@@ -236,10 +289,10 @@ namespace Barotrauma
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (upperSlots.HasFlag(SlotTypes[i]))
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - spacing * 2);
upperX += slots[i].Rect.Width + spacing;
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - spacing * 2);
personalSlotX -= slots[i].Rect.Width + spacing;
}
else
{
@@ -260,14 +313,14 @@ namespace Barotrauma
case Layout.Left:
{
int x = HUDLayoutSettings.InventoryAreaLower.X;
int upperX = x;
int personalSlotX = x;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (upperSlots.HasFlag(SlotTypes[i]))
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset * 2 - spacing * 2);
upperX += slots[i].Rect.Width + spacing;
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - spacing * 2);
personalSlotX += slots[i].Rect.Width + spacing;
}
else
{
@@ -353,6 +406,27 @@ namespace Barotrauma
((selectedSlot != null && selectedSlot.IsSubSlot) || (draggingItem != null && (draggingSlot == null || !draggingSlot.MouseOn())));
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
if (layout == Layout.Default && hideButton.Visible)
{
hideButton.AddToGUIUpdateList();
hideButton.UpdateManually(deltaTime, alsoChildren: true);
hidePersonalSlotsState = hidePersonalSlots ?
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
for (int i = 0; i < slots.Length; i++)
{
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
if (HidePersonalSlots)
{
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
}
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
}
}
if (hoverOnInventory) HideTimer = 0.5f;
if (HideTimer > 0.0f) HideTimer -= deltaTime;
@@ -365,7 +439,23 @@ namespace Barotrauma
QuickUseItem(Items[i], true, false, true);
}
}
//force personal slots open if an item is running out of battery/fuel/oxygen/etc
if (hidePersonalSlots)
{
for (int i = 0; i < slots.Length; i++)
{
if (Items[i]?.OwnInventory != null && Items[i].OwnInventory.Capacity == 1 && PersonalSlots.HasFlag(SlotTypes[i]))
{
if (Items[i].OwnInventory.Items[0].Condition > 0.0f &&
Items[i].OwnInventory.Items[0].Condition / Items[i].OwnInventory.Items[0].MaxCondition < 0.15f)
{
hidePersonalSlots = false;
}
}
}
}
List<SlotReference> hideSubInventories = new List<SlotReference>();
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
{
@@ -702,7 +792,12 @@ namespace Barotrauma
}
base.Draw(spriteBatch);
if (hideButton != null && hideButton.Visible)
{
hideButton.DrawManually(spriteBatch, alsoChildren: true);
}
InventorySlot highlightedQuickUseSlot = null;
for (int i = 0; i < capacity; i++)
{
@@ -716,7 +811,7 @@ namespace Barotrauma
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
{
var icon = limbSlotIcons[SlotTypes[i]];
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2(), Color.White * 0.3f, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, Color.White * 0.3f, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
}
continue;
}
@@ -726,12 +821,12 @@ namespace Barotrauma
if (IsInLimbSlot(Items[i], InvSlotType.LeftHand))
{
var icon = limbSlotIcons[InvSlotType.LeftHand];
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.X, slots[i].Rect.Bottom), Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.X, slots[i].Rect.Bottom) + slots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
}
if (IsInLimbSlot(Items[i], InvSlotType.RightHand))
{
var icon = limbSlotIcons[InvSlotType.RightHand];
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.Right, slots[i].Rect.Bottom), Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.Right, slots[i].Rect.Bottom) + slots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
}
Color color = slots[i].EquipButtonState == GUIComponent.ComponentState.Pressed ? Color.Gray : Color.White * 0.8f;

View File

@@ -48,6 +48,7 @@ namespace Barotrauma.Items.Components
partial class ItemComponent : ISerializableEntity
{
private bool[] hasSoundsOfType;
private Dictionary<ActionType, List<ItemSound>> sounds;
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
@@ -183,6 +184,8 @@ namespace Barotrauma.Items.Components
private SoundChannel loopingSoundChannel;
public void PlaySound(ActionType type, Vector2 position, Character user = null)
{
if (!hasSoundsOfType[(int)type]) { return; }
if (loopingSound != null)
{
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range)
@@ -224,10 +227,9 @@ namespace Barotrauma.Items.Components
}
return;
}
if (!sounds.TryGetValue(type, out List<ItemSound> matchingSounds)) return;
ItemSound itemSound = null;
var matchingSounds = sounds[type];
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
SoundSelectionMode soundSelectionMode = soundSelectionModes[type];
@@ -262,7 +264,7 @@ namespace Barotrauma.Items.Components
private void PlaySound(ItemSound itemSound, Vector2 position, Character user = null)
{
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > itemSound.Range * itemSound.Range)
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > itemSound.Range * itemSound.Range)
{
return;
}
@@ -290,7 +292,7 @@ namespace Barotrauma.Items.Components
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0f) return;
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, volume, itemSound.Range, position, item.CurrentHull);
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
}
}
@@ -377,6 +379,10 @@ namespace Barotrauma.Items.Components
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
public virtual void CreateEditingHUD(SerializableEntityEditor editor)
{
}
private bool LoadElemProjSpecific(XElement subElement)
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -447,6 +453,7 @@ namespace Barotrauma.Items.Components
{
soundList = new List<ItemSound>();
sounds.Add(itemSound.Type, soundList);
hasSoundsOfType[(int)itemSound.Type] = true;
}
soundList.Add(itemSound);

View File

@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
}
private string text;
[Serialize("", true), Editable(100)]
[Serialize("", true, translationTextTag: "Label."), Editable(100)]
public string Text
{
get { return text; }
@@ -40,13 +40,20 @@ namespace Barotrauma.Items.Components
{
textBlock = null;
}
text = value;
TextBlock.Text = value;
DisplayText = TextManager.Get(text, returnNull: true) ?? value;
TextBlock.Text = DisplayText;
SetScrollingText();
}
}
public string DisplayText
{
get;
private set;
}
[Editable, Serialize("0.0,0.0,0.0,1.0", true)]
public Color TextColor
{
@@ -115,7 +122,7 @@ namespace Barotrauma.Items.Components
{
if (!scrollable) return;
float totalWidth = textBlock.Font.MeasureString(text).X;
float totalWidth = textBlock.Font.MeasureString(DisplayText).X;
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
if (totalWidth >= textAreaWidth)
{
@@ -123,13 +130,13 @@ namespace Barotrauma.Items.Components
//(so the text can scroll entirely out of view before we reset it back to start)
needsScrolling = true;
float spaceWidth = textBlock.Font.MeasureChar(' ').X;
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + text;
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + DisplayText;
}
else
{
//whole text can fit in the textblock, no need to scroll
needsScrolling = false;
scrollingText = text;
scrollingText = DisplayText;
scrollAmount = 0.0f;
scrollIndex = 0;
return;
@@ -145,7 +152,7 @@ namespace Barotrauma.Items.Components
charWidths[i] = charWidth;
}
scrollIndex = MathHelper.Clamp(scrollIndex, 0, text.Length);
scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length);
}
public override void Update(float deltaTime, Camera cam)

View File

@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f)
{
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.SpriteDepth - 0.0001f);
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, item.Scale, SpriteEffects.None, item.SpriteDepth - 0.0001f);
}
}

View File

@@ -14,5 +14,59 @@ namespace Barotrauma.Items.Components
}
}
}
private bool crewAreaOriginalState;
private bool chatBoxOriginalState;
private bool isHUDsHidden;
partial void HideHUDs(bool value)
{
if (isHUDsHidden == value) { return; }
if (value == true)
{
ToggleCrewArea(false, storeOriginalState: true);
ToggleChatBox(false, storeOriginalState: true);
}
else
{
ToggleCrewArea(crewAreaOriginalState, storeOriginalState: false);
ToggleChatBox(chatBoxOriginalState, storeOriginalState: false);
}
isHUDsHidden = value;
}
private void ToggleCrewArea(bool value, bool storeOriginalState)
{
var crewManager = GameMain.GameSession.CrewManager;
if (storeOriginalState)
{
crewAreaOriginalState = crewManager.ToggleCrewAreaOpen;
}
crewManager.ToggleCrewAreaOpen = value;
}
private void ToggleChatBox(bool value, bool storeOriginalState)
{
var crewManager = GameMain.GameSession.CrewManager;
if (crewManager.IsSinglePlayer)
{
if (crewManager.ChatBox != null)
{
if (storeOriginalState)
{
chatBoxOriginalState = crewManager.ChatBox.ToggleOpen;
}
crewManager.ChatBox.ToggleOpen = value;
}
}
else if (GameMain.Client != null)
{
if (storeOriginalState)
{
chatBoxOriginalState = GameMain.Client.ChatBox.ToggleOpen;
}
GameMain.Client.ChatBox.ToggleOpen = value;
}
}
}
}

View File

@@ -9,6 +9,10 @@ namespace Barotrauma.Items.Components
{
partial class Deconstructor : Powered, IServerSerializable, IClientSerializable
{
public GUIButton ActivateButton
{
get { return activateButton; }
}
private GUIButton activateButton;
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUICustomComponent inputInventoryOverlay;
@@ -44,7 +48,6 @@ namespace Barotrauma.Items.Components
Visible = false,
CanBeFocused = false
};
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), paddedFrame.RectTransform), style: null);
}
@@ -71,7 +74,7 @@ namespace Barotrauma.Items.Components
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage;
activateButton.Enabled = !inSufficientPowerWarning.Visible;
//activateButton.Enabled = !inSufficientPowerWarning.Visible;
}
private bool ToggleActive(GUIButton button, object obj)

View File

@@ -15,6 +15,10 @@ namespace Barotrauma.Items.Components
private GUIFrame selectedItemFrame;
public GUIButton ActivateButton
{
get { return activateButton; }
}
private GUIButton activateButton;
private GUITextBox itemFilterBox;
@@ -22,6 +26,10 @@ namespace Barotrauma.Items.Components
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUICustomComponent inputInventoryOverlay, outputInventoryOverlay;
public FabricationRecipe SelectedItem
{
get { return selectedItem; }
}
private FabricationRecipe selectedItem;
private GUIComponent inSufficientPowerWarning;
@@ -73,7 +81,31 @@ namespace Barotrauma.Items.Components
{
CanBeFocused = false
};
CreateRecipes();
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform),
TextManager.Get("FabricatorCreate"), style: "GUIButtonLarge")
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
Enabled = false
};
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("FabricatorNoPower"),
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
Visible = false,
CanBeFocused = false
};
}
partial void CreateRecipes()
{
itemList.Content.RectTransform.ClearChildren();
foreach (FabricationRecipe fi in fabricationRecipes)
{
GUIFrame frame = new GUIFrame(new RectTransform(new Point(itemList.Rect.Width, 30), itemList.Content.RectTransform), style: null)
@@ -101,23 +133,6 @@ namespace Barotrauma.Items.Components
};
}
}
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform),
TextManager.Get("FabricatorCreate"), style: "GUIButtonLarge")
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
Enabled = false
};
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("FabricatorNoPower"),
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
Visible = false,
CanBeFocused = false
};
}
partial void OnItemLoadedProjSpecific()
@@ -241,6 +256,7 @@ namespace Barotrauma.Items.Components
}
}
}
private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
@@ -363,6 +379,29 @@ namespace Barotrauma.Items.Components
return true;
}
public void HighlightRecipe(string identifier, Color color)
{
foreach (GUIComponent child in itemList.Content.Children)
{
FabricationRecipe recipe = child.UserData as FabricationRecipe;
if (recipe?.DisplayName == null) { continue; }
if (recipe.TargetItem.Identifier == identifier)
{
if (child.FlashTimer > 0.0f) return;
child.Flash(color, 1.5f, false);
for (int i = 0; i < child.CountChildren; i++)
{
var grandChild = child.GetChild(i);
if (grandChild is GUITextBlock) continue;
grandChild.Flash(color, 1.5f, false);
}
return;
}
}
}
private bool StartButtonClicked(GUIButton button, object obj)
{
if (selectedItem == null) { return false; }

View File

@@ -221,7 +221,7 @@ namespace Barotrauma.Items.Components
{
hullInfoFrame.RectTransform.ScreenSpaceOffset = hullFrame.Rect.Center;
hullInfoFrame.Visible = true;
hullNameText.Text = hull.RoomName;
hullNameText.Text = hull.DisplayName;
foreach (Hull linkedHull in hullData.LinkedHulls)
{

View File

@@ -10,6 +10,10 @@ namespace Barotrauma.Items.Components
{
partial class Pump : Powered, IServerSerializable, IClientSerializable
{
public GUIScrollBar IsActiveSlider
{
get { return isActiveSlider; }
}
private GUIScrollBar isActiveSlider;
private GUIScrollBar pumpSpeedSlider;
private GUITickBox powerIndicator;
@@ -49,7 +53,6 @@ namespace Barotrauma.Items.Components
};
var sliderHandle = isActiveSlider.GetChild<GUIButton>();
sliderHandle.RectTransform.NonScaledSize = new Point(84, sliderHandle.Rect.Height);
isActiveSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
bool active = scrollBar.BarScroll < 0.5f;

View File

@@ -11,7 +11,16 @@ namespace Barotrauma.Items.Components
{
partial class Reactor : Powered, IServerSerializable, IClientSerializable
{
public GUIScrollBar AutoTempSlider
{
get { return autoTempSlider; }
}
private GUIScrollBar autoTempSlider;
public GUIScrollBar OnOffSwitch
{
get { return onOffSwitch; }
}
private GUIScrollBar onOffSwitch;
private const int GraphSize = 25;
@@ -27,7 +36,16 @@ namespace Barotrauma.Items.Components
private Sprite graphLine;
public GUIScrollBar FissionRateScrollBar
{
get { return fissionRateScrollBar; }
}
private GUIScrollBar fissionRateScrollBar;
public GUIScrollBar TurbineOutputScrollBar
{
get { return turbineOutputScrollBar; }
}
private GUIScrollBar turbineOutputScrollBar;
private float[] outputGraph = new float[GraphSize];
@@ -554,6 +572,8 @@ namespace Barotrauma.Items.Components
fissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
turbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
onOffSwitch.BarScroll = shutDown ? Math.Max(onOffSwitch.BarScroll, 0.55f) : Math.Min(onOffSwitch.BarScroll, 0.45f);
IsActive = true;
}
}
}

View File

@@ -20,6 +20,10 @@ namespace Barotrauma.Items.Components
private bool unsentChanges;
private float networkUpdateTimer;
public GUITickBox ActiveTickBox
{
get { return activeTickBox; }
}
private GUITickBox activeTickBox, passiveTickBox;
private GUITextBlock signalWarningText;
@@ -439,11 +443,14 @@ namespace Barotrauma.Items.Components
{
var mission = GameMain.GameSession.Mission;
if (!string.IsNullOrWhiteSpace(mission.SonarLabel) && mission.SonarPosition != Vector2.Zero)
if (!string.IsNullOrWhiteSpace(mission.SonarLabel))
{
DrawMarker(spriteBatch,
mission.SonarLabel,
mission.SonarPosition - transducerCenter, displayScale, center, (rect.Width * 0.47f));
foreach (Vector2 sonarPosition in mission.SonarPositions)
{
DrawMarker(spriteBatch,
mission.SonarLabel,
sonarPosition - transducerCenter, displayScale, center, (rect.Width * 0.47f));
}
}
}
@@ -785,15 +792,32 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.CurrentHull != null || !c.Enabled) continue;
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) continue;
if (c.AnimController.CurrentHull != null || !c.Enabled) { continue; }
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) { continue; }
if (c.AnimController.SimplePhysicsEnabled)
{
float pointDist = ((c.WorldPosition - pingSource) * displayScale).LengthSquared();
if (pointDist > DisplayRadius * DisplayRadius) { continue; }
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
{
var blip = new SonarBlip(
c.WorldPosition,
MathHelper.Clamp(c.Mass, 0.1f, pingStrength),
MathHelper.Clamp(c.Mass * 0.03f, 0.1f, 2.0f));
if (!passive && !CheckBlipVisibility(blip, transducerPos)) { continue; }
sonarBlips.Add(blip);
}
continue;
}
foreach (Limb limb in c.AnimController.Limbs)
{
if (!limb.body.Enabled) { continue; }
float pointDist = ((limb.WorldPosition - pingSource) * displayScale).LengthSquared();
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) continue;
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) { continue; }
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
{
@@ -801,13 +825,13 @@ namespace Barotrauma.Items.Components
limb.WorldPosition + Rand.Vector(limb.Mass / 10.0f),
MathHelper.Clamp(limb.Mass, 0.1f, pingStrength),
MathHelper.Clamp(limb.Mass * 0.1f, 0.1f, 2.0f));
if (!passive && !CheckBlipVisibility(blip, transducerPos)) continue;
if (!passive && !CheckBlipVisibility(blip, transducerPos)) { continue; }
sonarBlips.Add(blip);
}
}
}
}
private void CreateBlipsForLine(Vector2 point1, Vector2 point2, Vector2 pingSource, Vector2 transducerPos, float pingRadius, float prevPingRadius,
float lineStep, float zStep, float range, float pingStrength, bool passive)
{

View File

@@ -10,6 +10,10 @@ namespace Barotrauma.Items.Components
{
partial class Repairable : ItemComponent, IDrawableComponent
{
public GUIButton RepairButton
{
get { return repairButton; }
}
private GUIButton repairButton;
private GUIProgressBar progressBar;

View File

@@ -18,6 +18,14 @@ namespace Barotrauma.Items.Components
private static Wire draggingConnected;
private Color flashColor;
private float flashDuration = 1.5f;
public float FlashTimer
{
get { return flashTimer; }
}
private float flashTimer;
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
{
Rectangle panelRect = panel.GuiFrame.Rect;
@@ -174,14 +182,38 @@ namespace Barotrauma.Items.Components
}
}
}
if (flashTimer > 0.0f)
{
//the number of flashes depends on the duration, 1 flash per 1 full second
int flashCycleCount = (int)Math.Max(flashDuration, 1);
float flashCycleDuration = flashDuration / flashCycleCount;
//MathHelper.Pi * 0.8f -> the curve goes from 144 deg to 0,
//i.e. quickly bumps up from almost full brightness to full and then fades out
connectionSpriteHighlight.Draw(spriteBatch, position, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f));
}
if (Wires.Any(w => w != null && w != draggingConnected))
{
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
screwSprites[screwIndex].Draw(spriteBatch, position);
}
}
public void Flash(Color? color = null, float flashDuration = 1.5f)
{
flashTimer = flashDuration;
this.flashDuration = flashDuration;
flashColor = (color == null) ? Color.Red : (Color)color;
}
public void UpdateFlashTimer(float deltaTime)
{
if (flashTimer <= 0) return;
flashTimer -= deltaTime;
}
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel, string label)
{
if (draggingConnected == wire)

View File

@@ -3,6 +3,7 @@ using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;
@@ -16,16 +17,22 @@ namespace Barotrauma.Items.Components
{
uiElements.Clear();
var visibleElements = customInterfaceElementList.Where(ciElement => !string.IsNullOrEmpty(ciElement.Label));
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center),
childAnchor: customInterfaceElementList.Count > 1 ? Anchor.TopCenter : Anchor.Center)
{ RelativeSpacing = 0.05f };
{
RelativeSpacing = 0.05f,
Stretch = visibleElements.Count() > 2
};
float elementSize = Math.Min(1.0f / customInterfaceElementList.Count, 0.5f);
foreach (CustomInterfaceElement ciElement in customInterfaceElementList)
float elementSize = Math.Min(1.0f / visibleElements.Count(), 0.5f);
foreach (CustomInterfaceElement ciElement in visibleElements)
{
if (ciElement.ContinuousSignal)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementSize), paddedFrame.RectTransform), ciElement.Label)
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementSize), paddedFrame.RectTransform),
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label)
{
UserData = ciElement
};
@@ -45,7 +52,8 @@ namespace Barotrauma.Items.Components
}
else
{
var btn = new GUIButton(new RectTransform(new Vector2(1.0f, elementSize), paddedFrame.RectTransform), ciElement.Label, style: "GUIButtonLarge")
var btn = new GUIButton(new RectTransform(new Vector2(1.0f, elementSize), paddedFrame.RectTransform),
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label, style: "GUIButtonLarge")
{
UserData = ciElement
};
@@ -66,6 +74,43 @@ namespace Barotrauma.Items.Components
}
}
public override void CreateEditingHUD(SerializableEntityEditor editor)
{
base.CreateEditingHUD(editor);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(customInterfaceElementList[0]);
PropertyDescriptor labelProperty = properties.Find("Label", false);
PropertyDescriptor signalProperty = properties.Find("Signal", false);
for (int i = 0; i< customInterfaceElementList.Count; i++)
{
editor.CreateStringField(customInterfaceElementList[i],
new SerializableProperty(labelProperty, customInterfaceElementList[i]),
customInterfaceElementList[i].Label, "Label #" + (i + 1), "");
editor.CreateStringField(customInterfaceElementList[i],
new SerializableProperty(signalProperty, customInterfaceElementList[i]),
customInterfaceElementList[i].Signal, "Signal #" + (i + 1), "");
}
}
public void HighlightElement(int index, Color color, float duration, float pulsateAmount = 0.0f)
{
if (index < 0 || index >= uiElements.Count) { return; }
uiElements[index].Flash(color, duration);
if (pulsateAmount > 0.0f)
{
if (uiElements[index] is GUIButton button)
{
button.Frame.Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration);
button.Frame.RectTransform.SetPosition(Anchor.Center);
}
else
{
uiElements[index].Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration);
}
}
}
partial void UpdateLabelsProjSpecific()
{
for (int i = 0; i < labels.Length && i < uiElements.Count; i++)

View File

@@ -154,11 +154,22 @@ namespace Barotrauma.Items.Components
Vector2 nodeWorldPos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex];
nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);
if (selectedNodeIndex.HasValue)
{
nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);
draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos;
draggingWire.UpdateSections();
}
else
{
if (Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X)
{
selectedNodeIndex = highlightedNodeIndex;
}
}
draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos;
draggingWire.UpdateSections();
MapEntity.SelectEntity(draggingWire.item);
}
@@ -213,7 +224,8 @@ namespace Barotrauma.Items.Components
Character.Controlled.ClearInputs();
}
draggingWire = selectedWire;
selectedNodeIndex = closestIndex;
//selectedNodeIndex = closestIndex;
return;
}
//remove the node
else if (PlayerInput.RightButtonClicked() && closestIndex > 0 && closestIndex < selectedWire.nodes.Count - 1)
@@ -259,19 +271,11 @@ namespace Barotrauma.Items.Components
}
}
}
}
}
if (highlighted != null)
{
highlighted.item.IsHighlighted = true;
if (Character.Controlled != null)
{
Character.Controlled.FocusedItem = null;
Character.Controlled.ResetInteract = true;
Character.Controlled.ClearInputs();
}
if (PlayerInput.LeftButtonClicked())
{
MapEntity.DisableSelect = true;

View File

@@ -150,14 +150,14 @@ namespace Barotrauma.Items.Components
{
if (moveSoundChannel == null && startMoveSound != null)
{
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, startMoveSound.Volume, startMoveSound.Range, item.WorldPosition);
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, item.WorldPosition, startMoveSound.Volume, startMoveSound.Range);
}
else if (moveSoundChannel == null || !moveSoundChannel.IsPlaying)
{
if (moveSound != null)
{
moveSoundChannel.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, moveSound.Volume, moveSound.Range, item.WorldPosition);
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, item.WorldPosition, moveSound.Volume, moveSound.Range);
if (moveSoundChannel != null) moveSoundChannel.Looping = true;
}
}
@@ -169,7 +169,7 @@ namespace Barotrauma.Items.Components
if (endMoveSound != null && moveSoundChannel.Sound != endMoveSound.Sound)
{
moveSoundChannel.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, endMoveSound.Volume, endMoveSound.Range, item.WorldPosition);
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, item.WorldPosition, endMoveSound.Volume, endMoveSound.Range);
if (moveSoundChannel != null) moveSoundChannel.Looping = false;
}
else if (!moveSoundChannel.IsPlaying)

View File

@@ -26,6 +26,7 @@ namespace Barotrauma
public Color Color;
public Color HighlightColor;
public float HighlightScaleUpAmount;
private CoroutineHandle highlightCoroutine;
public float HighlightTimer;
@@ -80,7 +81,7 @@ namespace Barotrauma
return rect.Contains(PlayerInput.MousePosition);
}
public void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration)
public void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount = 0.5f)
{
if (highlightCoroutine != null)
{
@@ -88,6 +89,7 @@ namespace Barotrauma
highlightCoroutine = null;
}
HighlightScaleUpAmount = scaleUpAmount;
highlightCoroutine = CoroutineManager.StartCoroutine(UpdateBorderHighlight(color, fadeInDuration, fadeOutDuration));
}
@@ -154,8 +156,6 @@ namespace Barotrauma
public SlotReference(Inventory parentInventory, InventorySlot slot, int slotIndex, bool isSubSlot, Inventory subInventory = null)
{
ParentInventory = parentInventory;
Slot = slot;
SlotIndex = slotIndex;
@@ -714,12 +714,15 @@ namespace Barotrauma
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
Vector2 itemPos = PlayerInput.MousePosition;
if (GUI.MouseOn == null && selectedSlot == null)
bool mouseOnHealthInterface = CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.MouseOnElement;
if ((GUI.MouseOn == null || mouseOnHealthInterface) && selectedSlot == null)
{
var shadowSprite = GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0];
string toolTip = Character.Controlled.FocusedItem != null ?
TextManager.Get("PutItemIn").Replace("[itemname]", Character.Controlled.FocusedItem.Name) :
TextManager.Get("DropItem");
string toolTip = mouseOnHealthInterface ? TextManager.Get("QuickUseAction.UseTreatment") :
Character.Controlled.FocusedItem != null ?
TextManager.Get("PutItemIn").Replace("[itemname]", Character.Controlled.FocusedItem.Name) :
TextManager.Get("DropItem");
int textWidth = (int)Math.Max(GUI.Font.MeasureString(draggingItem.Name).X, GUI.SmallFont.MeasureString(toolTip).X);
int textSpacing = (int)(15 * GUI.Scale);
Point shadowBorders = (new Point(40, 10)).Multiply(GUI.Scale);
@@ -727,7 +730,7 @@ namespace Barotrauma
new Rectangle(itemPos.ToPoint() - new Point(iconSize / 2) - shadowBorders, new Point(iconSize + textWidth + textSpacing, iconSize) + shadowBorders.Multiply(2)), Color.Black * 0.8f);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y - iconSize / 2), draggingItem.Name, Color.White);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y), toolTip,
color: Character.Controlled.FocusedItem == null ? Color.Red : Color.LightGreen,
color: Character.Controlled.FocusedItem == null && !mouseOnHealthInterface ? Color.Red : Color.LightGreen,
font: GUI.SmallFont);
}
sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black, scale: scale);
@@ -799,8 +802,7 @@ namespace Barotrauma
if (slot.HighlightColor.A > 0)
{
float scaleUpAmount = 0.5f;
float inflateAmount = (slot.HighlightColor.A / 255.0f) * scaleUpAmount * 0.5f;
float inflateAmount = (slot.HighlightColor.A / 255.0f) * slot.HighlightScaleUpAmount * 0.5f;
rect.Inflate(rect.Width * inflateAmount, rect.Height * inflateAmount);
}
@@ -853,7 +855,7 @@ namespace Barotrauma
if (itemContainer.ContainedStateIndicator?.Texture == null)
{
containedIndicatorArea.Inflate(0, -2);
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.DarkGray * 0.8f, true);
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.DarkGray * 0.9f, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height),
Color.Lerp(Color.Red, Color.Green, containedState) * 0.8f, true);
@@ -867,11 +869,11 @@ namespace Barotrauma
if (containedState > 0.0f && containedState < 0.25f)
{
indicatorScale += ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) * 0.1f;
indicatorScale += ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) * 0.25f;
}
indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
Color.DarkGray * 0.6f,
Color.DarkGray * 0.9f,
origin: indicatorSprite.size / 2,
rotate: 0.0f,
scale: indicatorScale);

View File

@@ -101,9 +101,22 @@ namespace Barotrauma
return color;
}
partial void SetActiveSprite()
partial void SetActiveSpriteProjSpecific()
{
activeSprite = prefab.sprite;
Holdable holdable = GetComponent<Holdable>();
if (holdable != null && holdable.Attached)
{
foreach (ContainedItemSprite containedSprite in Prefab.ContainedSprites)
{
if (containedSprite.UseWhenAttached)
{
activeSprite = containedSprite.Sprite;
return;
}
}
}
if (Container != null)
{
foreach (ContainedItemSprite containedSprite in Prefab.ContainedSprites)
@@ -171,10 +184,9 @@ namespace Barotrauma
if (!Visible || (!editing && hiddenInGame)) return;
if (editing && !ShowItems) return;
Color color = isHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? Color.Orange : GetSpriteColor();
Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? Color.Orange : GetSpriteColor();
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
Sprite activeSprite = prefab.sprite;
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
if (condition < Prefab.Health)
@@ -372,7 +384,7 @@ namespace Barotrauma
Timing.TotalTime > LastImpactSoundTime + ImpactSoundInterval)
{
LastImpactSoundTime = (float)Timing.TotalTime;
SoundPlayer.PlaySound(Prefab.ImpactSoundTag, 1.0f, 500.0f, WorldPosition, CurrentHull);
SoundPlayer.PlaySound(Prefab.ImpactSoundTag, WorldPosition, hullGuess: CurrentHull);
}
}
@@ -565,8 +577,13 @@ namespace Barotrauma
}
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame);
if (inGame) continue;
if (inGame)
{
ic.CreateEditingHUD(componentEditor);
componentEditor.Recalculate();
continue;
}
foreach (var kvp in ic.requiredItems)
{
@@ -599,6 +616,9 @@ namespace Barotrauma
};
}
}
ic.CreateEditingHUD(componentEditor);
componentEditor.Recalculate();
}
PositionEditingHUD();
@@ -783,7 +803,7 @@ namespace Barotrauma
{
if (!ic.CanBeSelected) { continue; }
bool useAlternativeLayout = ic.Item != this;
bool useAlternativeLayout = activeHUDs.Count > 1;
bool wasUsingAlternativeLayout = ic.UseAlternativeLayout;
ic.UseAlternativeLayout = useAlternativeLayout;
needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout;
@@ -817,14 +837,28 @@ namespace Barotrauma
case NetEntityEvent.Type.ComponentState:
{
int componentIndex = msg.ReadRangedInteger(0, components.Count - 1);
(components[componentIndex] as IServerSerializable).ClientRead(type, msg, sendingTime);
if (components[componentIndex] is IServerSerializable serverSerializable)
{
serverSerializable.ClientRead(type, msg, sendingTime);
}
else
{
throw new Exception("Failed to read component state - " + components[componentIndex].GetType() + " is not IServerSerializable.");
}
}
break;
case NetEntityEvent.Type.InventoryState:
{
{
int containerIndex = msg.ReadRangedInteger(0, components.Count - 1);
(components[containerIndex] as ItemContainer).Inventory.ClientRead(type, msg, sendingTime);
if (components[containerIndex] is ItemContainer container)
{
container.Inventory.ClientRead(type, msg, sendingTime);
}
else
{
throw new Exception("Failed to read inventory state - " + components[containerIndex].GetType() + " is not an ItemContainer.");
}
}
break;
case NetEntityEvent.Type.Status:

View File

@@ -25,12 +25,14 @@ namespace Barotrauma
class ContainedItemSprite
{
public readonly Sprite Sprite;
public readonly bool UseWhenAttached;
public readonly string[] AllowedContainerIdentifiers;
public readonly string[] AllowedContainerTags;
public ContainedItemSprite(XElement element, string path = "", bool lazyLoad = false)
{
Sprite = new Sprite(element, path, lazyLoad: lazyLoad);
UseWhenAttached = element.GetAttributeBool("usewhenattached", false);
AllowedContainerIdentifiers = element.GetAttributeStringArray("allowedcontaineridentifiers", new string[0], convertToLowerInvariant: true);
AllowedContainerTags = element.GetAttributeStringArray("allowedcontainertags", new string[0], convertToLowerInvariant: true);
}
@@ -231,11 +233,11 @@ namespace Barotrauma
}
}
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f)
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f, SpriteEffects spriteEffects = SpriteEffects.None)
{
if (!ResizeHorizontal && !ResizeVertical)
{
sprite.Draw(spriteBatch, new Vector2(placeRect.Center.X, -(placeRect.Y - placeRect.Height / 2)), SpriteColor * 0.8f, scale: Scale * scale);
sprite.Draw(spriteBatch, new Vector2(placeRect.Center.X, -(placeRect.Y - placeRect.Height / 2)), SpriteColor * 0.8f, scale: scale);
}
else
{

View File

@@ -33,7 +33,7 @@ namespace Barotrauma
if (!editing || !ShowGaps) return;
Color clr = (open == 0.0f) ? Color.Red : Color.Cyan;
if (isHighlighted) clr = Color.Gold;
if (IsHighlighted) clr = Color.Gold;
float depth = (ID % 255) * 0.000001f;

View File

@@ -292,12 +292,12 @@ namespace Barotrauma
}*/
}
if ((IsSelected || isHighlighted) && editing)
if ((IsSelected || IsHighlighted) && editing)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X + 5, -drawRect.Y + 5),
new Vector2(rect.Width - 10, rect.Height - 10),
isHighlighted ? Color.LightBlue * 0.5f : Color.Red * 0.5f, true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
IsHighlighted ? Color.LightBlue * 0.5f : Color.Red * 0.5f, true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
}
foreach (MapEntity e in linkedTo)

View File

@@ -22,7 +22,7 @@ namespace Barotrauma
drawRect = new Rectangle(
(int)(drawRect.X * scale) + drawArea.Center.X, -((int)((drawRect.Y - drawRect.Height) * scale) + drawArea.Center.Y),
(int)(drawRect.Width * scale), (int)(drawRect.Height * scale));
entity.First.DrawPlacing(spriteBatch, drawRect, scale);
entity.First.DrawPlacing(spriteBatch, drawRect, entity.First.Scale * scale);
}
}
@@ -34,7 +34,7 @@ namespace Barotrauma
{
Rectangle drawRect = entity.Second;
drawRect.Location += Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
entity.First.DrawPlacing(spriteBatch, drawRect);
entity.First.DrawPlacing(spriteBatch, drawRect, entity.First.Scale);
}
}

View File

@@ -105,7 +105,7 @@ namespace Barotrauma
if (Vector2.DistanceSquared(bodyPos, levelWall.Body.Position) > 0.5f)
{
levelWall.Body.SetTransform(bodyPos, levelWall.Body.Rotation);
levelWall.Body.SetTransformIgnoreContacts(ref bodyPos, levelWall.Body.Rotation);
}
}
}

View File

@@ -217,7 +217,7 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred,
BlendState.AlphaBlend,
SamplerState.LinearClamp, DepthStencilState.Default, null, null,
SamplerState.LinearClamp, DepthStencilState.DepthRead, null, null,
cam.Transform);
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: true);
spriteBatch.End();

View File

@@ -495,6 +495,8 @@ namespace Barotrauma.Lights
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.White);
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
foreach (Character c in Character.CharacterList)
{
if (c.Enabled) { c.Draw(spriteBatch, cam); }

View File

@@ -13,7 +13,7 @@ namespace Barotrauma
{
if (!editing || wallVertices == null) return;
Color color = (isHighlighted) ? Color.Orange : Color.Green;
Color color = (IsHighlighted) ? Color.Orange : Color.Green;
if (IsSelected) color = Color.Red;
Vector2 pos = Position;

View File

@@ -504,8 +504,19 @@ namespace Barotrauma
{
foreach (MapEntity e in selectedList)
{
SpriteEffects spriteEffects = SpriteEffects.None;
if (e is Item item)
{
if (item.FlippedX && item.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (item.flippedY && item.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
}
else if (e is Structure structure)
{
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
}
e.prefab?.DrawPlacing(spriteBatch,
new Rectangle(e.WorldRect.Location + new Point((int)moveAmount.X, (int)-moveAmount.Y), e.WorldRect.Size));
new Rectangle(e.WorldRect.Location + new Point((int)moveAmount.X, (int)-moveAmount.Y), e.WorldRect.Size), e.Scale, spriteEffects);
GUI.DrawRectangle(spriteBatch,
new Vector2(e.WorldRect.X, -e.WorldRect.Y) + moveAmount,
new Vector2(e.rect.Width, e.rect.Height),

View File

@@ -37,7 +37,7 @@ namespace Barotrauma
}
}
public virtual void DrawPlacing(SpriteBatch spriteBatch, Rectangle drawRect, float scale = 1.0f)
public virtual void DrawPlacing(SpriteBatch spriteBatch, Rectangle drawRect, float scale = 1.0f, SpriteEffects spriteEffects = SpriteEffects.None)
{
if (Submarine.MainSub != null)
{

View File

@@ -1,4 +1,5 @@
using Barotrauma.Lights;
using Barotrauma.Extensions;
using Barotrauma.Lights;
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
@@ -42,6 +43,14 @@ namespace Barotrauma
}
}
private string specialTag;
[Editable, Serialize("", true)]
public string SpecialTag
{
get { return specialTag; }
set { specialTag = value; }
}
// Only for testing in the debug build. Not saved.
#if DEBUG
[Editable, Serialize(true, false)]
@@ -101,7 +110,7 @@ namespace Barotrauma
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null);
var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, elementHeight: 20);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, 20)), isHorizontal: true)
{
Stretch = true,
@@ -186,7 +195,7 @@ namespace Barotrauma
if (HasBody && !ShowWalls) return;
}
Color color = isHighlighted ? Color.Orange : spriteColor;
Color color = IsHighlighted ? Color.Orange : spriteColor;
if (IsSelected && editing)
{
//color = Color.Lerp(color, Color.Gold, 0.5f);
@@ -215,80 +224,54 @@ namespace Barotrauma
{
if (Prefab.BackgroundSprite != null)
{
bool drawDropShadow = Submarine != null && HasBody;
Vector2 dropShadowOffset = Vector2.Zero;
if (drawDropShadow)
if (UseDropShadow)
{
dropShadowOffset = Submarine.HiddenSubPosition - Position;
if (dropShadowOffset != Vector2.Zero)
dropShadowOffset = DropShadowOffset;
if (dropShadowOffset == Vector2.Zero)
{
if (IsHorizontal)
if (Submarine == null)
{
dropShadowOffset = new Vector2(0.0f, Math.Sign(dropShadowOffset.Y) * 10.0f);
dropShadowOffset = Vector2.UnitY * 10.0f;
}
else
{
dropShadowOffset = new Vector2(Math.Sign(dropShadowOffset.X) * 10.0f, 0.0f);
dropShadowOffset = IsHorizontal ?
new Vector2(0.0f, Math.Sign(Submarine.HiddenSubPosition.Y - Position.Y) * 10.0f) :
new Vector2(Math.Sign(Submarine.HiddenSubPosition.X - Position.X) * 10.0f, 0.0f);
}
dropShadowOffset.Y = -dropShadowOffset.Y;
}
dropShadowOffset.Y = -dropShadowOffset.Y;
}
SpriteEffects oldEffects = Prefab.BackgroundSprite.effects;
Prefab.BackgroundSprite.effects ^= SpriteEffects;
if (DrawTiled)
Point backGroundOffset = new Point(
MathUtils.PositiveModulo((int)-textureOffset.X, Prefab.BackgroundSprite.SourceRect.Width),
MathUtils.PositiveModulo((int)-textureOffset.Y, Prefab.BackgroundSprite.SourceRect.Height));
Prefab.BackgroundSprite.DrawTiled(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
new Vector2(rect.Width, rect.Height),
color: color,
textureScale: TextureScale * Scale,
startOffset: backGroundOffset);
if (UseDropShadow)
{
SpriteEffects oldEffects = Prefab.BackgroundSprite.effects;
Prefab.BackgroundSprite.effects ^= SpriteEffects;
Point backGroundOffset = new Point(
MathUtils.PositiveModulo((int)-textureOffset.X, Prefab.BackgroundSprite.SourceRect.Width),
MathUtils.PositiveModulo((int)-textureOffset.Y, Prefab.BackgroundSprite.SourceRect.Height));
Prefab.BackgroundSprite.DrawTiled(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)) + dropShadowOffset,
new Vector2(rect.Width, rect.Height),
color: color,
color: Color.Black * 0.5f,
textureScale: TextureScale * Scale,
startOffset: backGroundOffset);
if (drawDropShadow)
{
Prefab.BackgroundSprite.DrawTiled(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)) + dropShadowOffset,
new Vector2(rect.Width, rect.Height),
color: Color.Black * 0.5f,
textureScale: TextureScale * Scale,
startOffset: backGroundOffset,
depth: (depth + Prefab.BackgroundSprite.Depth) / 2.0f);
}
Prefab.BackgroundSprite.effects = oldEffects;
startOffset: backGroundOffset,
depth: (depth + Prefab.BackgroundSprite.Depth) / 2.0f);
}
else
{
Prefab.BackgroundSprite.Draw(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
color,
Vector2.Zero,
scale: Scale,
rotate: 0,
spriteEffect: SpriteEffects);
if (drawDropShadow)
{
Prefab.BackgroundSprite.Draw(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)) + dropShadowOffset,
Color.Black * 0.5f,
Vector2.Zero,
scale: Scale,
rotate: 0,
spriteEffect: SpriteEffects,
depth: (depth + Prefab.BackgroundSprite.Depth) / 2.0f);
}
}
Prefab.BackgroundSprite.effects = oldEffects;
}
}
@@ -315,39 +298,25 @@ namespace Barotrauma
Submarine.DamageEffectColor = color;
}
}
Point sectionOffset = new Point(
Math.Abs(rect.Location.X - Sections[i].rect.Location.X),
Math.Abs(rect.Location.Y - Sections[i].rect.Location.Y));
if (DrawTiled)
{
Point sectionOffset = new Point(
Math.Abs(rect.Location.X - Sections[i].rect.Location.X),
Math.Abs(rect.Location.Y - Sections[i].rect.Location.Y));
if (FlippedX && IsHorizontal) sectionOffset.X = Sections[i].rect.Right - rect.Right;
if (FlippedY && !IsHorizontal) sectionOffset.Y = (rect.Y - rect.Height) - (Sections[i].rect.Y - Sections[i].rect.Height);
if (FlippedX && IsHorizontal) sectionOffset.X = Sections[i].rect.Right - rect.Right;
if (FlippedY && !IsHorizontal) sectionOffset.Y = (rect.Y - rect.Height) - (Sections[i].rect.Y - Sections[i].rect.Height);
sectionOffset.X += MathUtils.PositiveModulo((int)-textureOffset.X, prefab.sprite.SourceRect.Width);
sectionOffset.Y += MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.sprite.SourceRect.Height);
sectionOffset.X += MathUtils.PositiveModulo((int)-textureOffset.X, prefab.sprite.SourceRect.Width);
sectionOffset.Y += MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.sprite.SourceRect.Height);
prefab.sprite.DrawTiled(
spriteBatch,
new Vector2(Sections[i].rect.X + drawOffset.X, -(Sections[i].rect.Y + drawOffset.Y)),
new Vector2(Sections[i].rect.Width, Sections[i].rect.Height),
color: color,
startOffset: sectionOffset,
depth: depth,
textureScale: TextureScale * Scale);
}
else
{
prefab.sprite.Draw(
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
color,
Vector2.Zero,
scale: Scale,
rotate: 0,
spriteEffect: SpriteEffects);
}
prefab.sprite.DrawTiled(
spriteBatch,
new Vector2(Sections[i].rect.X + drawOffset.X, -(Sections[i].rect.Y + drawOffset.Y)),
new Vector2(Sections[i].rect.Width, Sections[i].rect.Height),
color: color,
startOffset: sectionOffset,
depth: depth,
textureScale: TextureScale * Scale);
}
prefab.sprite.effects = oldEffects;
}
@@ -368,6 +337,20 @@ namespace Barotrauma
-Bodies[i].Rotation, Color.White);
}
}
if (SectionCount > 0 && HasBody)
{
for (int i = 0; i < SectionCount; i++)
{
if (GetSection(i).damage > 0)
{
var textPos = SectionPosition(i, true);
textPos.Y = -textPos.Y;
GUI.DrawString(spriteBatch, textPos, "Damage: " + (int)((GetSection(i).damage / Health) * 100f) + "%", Color.Yellow);
}
}
}
AiTarget?.Draw(spriteBatch);
}
}

View File

@@ -32,10 +32,19 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, new Rectangle(newRect.X, -newRect.Y - GameMain.GraphicsHeight, newRect.Width, newRect.Height + GameMain.GraphicsHeight * 2), Color.White);
}
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f)
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f, SpriteEffects spriteEffects = SpriteEffects.None)
{
// TODO: the scale property is not used
sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), new Vector2(placeRect.Width, placeRect.Height), color: Color.White * 0.8f, textureScale: TextureScale * Scale);
SpriteEffects oldEffects = sprite.effects;
sprite.effects ^= spriteEffects;
sprite.DrawTiled(
spriteBatch,
new Vector2(placeRect.X, -placeRect.Y),
new Vector2(placeRect.Width, placeRect.Height),
color: Color.White * 0.8f,
textureScale: TextureScale * scale);
sprite.effects = oldEffects;
}
}
}

View File

@@ -42,10 +42,17 @@ namespace Barotrauma
bool displace = moveAmount.LengthSquared() > 100.0f * 100.0f;
foreach (Submarine sub in subsToMove)
{
sub.PhysicsBody.SetTransform(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
sub.PhysicsBody.LinearVelocity = newVelocity;
if (displace) sub.SubBody.DisplaceCharacters(moveAmount);
if (displace)
{
sub.PhysicsBody.SetTransform(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
sub.SubBody.DisplaceCharacters(moveAmount);
}
else
{
sub.PhysicsBody.SetTransformIgnoreContacts(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
}
}
if (closestSub != null && subsToMove.Contains(closestSub))
@@ -55,7 +62,6 @@ namespace Barotrauma
if (Character.Controlled != null) Character.Controlled.CursorPosition += moveAmount;
}
}
}
}

View File

@@ -30,7 +30,7 @@ namespace Barotrauma
Color clr = currentHull == null ? Color.Blue : Color.White;
if (IsSelected) clr = Color.Red;
if (isHighlighted) clr = Color.DarkRed;
if (IsHighlighted) clr = Color.DarkRed;
int iconX = iconIndices[(int)spawnType] * IconSize % iconTexture.Width;
int iconY = (int)(Math.Floor(iconIndices[(int)spawnType] * IconSize / (float)iconTexture.Width)) * IconSize;

View File

@@ -61,7 +61,7 @@ namespace Barotrauma.Networking
{
orderOption = order.Options[optionIndex];
}
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.RoomName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
if (order.TargetAllCharacters)
{

View File

@@ -39,25 +39,33 @@ namespace Barotrauma.Networking
public void UpdateSoundPosition()
{
if (VoipSound != null)
if (VoipSound == null) { return; }
if (!VoipSound.IsPlaying)
{
if (!VoipSound.IsPlaying)
{
DebugConsole.Log("Destroying voipsound");
VoipSound.Dispose();
VoipSound = null;
return;
}
DebugConsole.Log("Destroying voipsound");
VoipSound.Dispose();
VoipSound = null;
return;
}
if (character != null)
if (character != null)
{
if (GameMain.Config.UseDirectionalVoiceChat)
{
VoipSound.SetPosition(new Vector3(character.WorldPosition.X, character.WorldPosition.Y, 0.0f));
}
else
{
VoipSound.SetPosition(null);
float dist = Vector3.Distance(new Vector3(character.WorldPosition, 0.0f), GameMain.SoundManager.ListenerPosition);
VoipSound.Gain = 1.0f - MathUtils.InverseLerp(VoipSound.Near, VoipSound.Far, dist);
}
}
else
{
VoipSound.SetPosition(null);
}
}
partial void InitProjSpecific()

View File

@@ -26,6 +26,7 @@ namespace Barotrauma.Networking
//TODO: move these to NetLobbyScreen
public GUIButton EndRoundButton;
public GUITickBox EndVoteTickBox;
private GUIComponent buttonContainer;
private NetStats netStats;
@@ -129,7 +130,7 @@ namespace Barotrauma.Networking
chatBox.OnEnterMessage += EnterChatMessage;
chatBox.InputBox.OnTextChanged += TypingChatMessage;
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, inGameHUD.RectTransform),
buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, inGameHUD.RectTransform),
isHorizontal: true, childAnchor: Anchor.CenterRight)
{
AbsoluteSpacing = 5,
@@ -630,13 +631,11 @@ namespace Barotrauma.Networking
}
else
{
GameMain.GameSession?.CrewManager?.SetPlayerSpeaking(myClient);
GameMain.GameSession?.CrewManager?.SetClientSpeaking(myClient);
}
}
}
if (gameStarted) SetRadioButtonColor();
if (ShowNetStats && client?.ServerConnection != null)
{
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
@@ -1114,7 +1113,9 @@ namespace Barotrauma.Networking
if (campaign == null)
{
GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, missionIndex < 0 ? null : MissionPrefab.List[missionIndex]);
GameMain.GameSession = missionIndex < 0 ?
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionType.None) :
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionPrefab.List[missionIndex]);
GameMain.GameSession.StartRound(levelSeed, levelDifficulty, loadSecondSub);
}
else
@@ -1126,6 +1127,18 @@ namespace Barotrauma.Networking
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
}
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (!loadSecondSub && i > 0) { break; }
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
Submarine.MainSubs[i].TeamID = teamID;
foreach (Submarine sub in Submarine.MainSubs[i].DockedTo)
{
sub.TeamID = teamID;
}
}
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
@@ -2110,9 +2123,7 @@ namespace Barotrauma.Networking
protected GUIFrame inGameHUD;
protected ChatBox chatBox;
public GUIButton ShowLogButton; //TODO: move to NetLobbyScreen
private float myCharacterFrameOpenState;
public GUIFrame InGameHUD
{
get { return inGameHUD; }
@@ -2122,22 +2133,7 @@ namespace Barotrauma.Networking
{
get { return chatBox; }
}
protected void SetRadioButtonColor()
{
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f)
{
chatBox.RadioButton.GetChild<GUIImage>().Color = new Color(60, 60, 60, 255);
}
else
{
var radioItem = Character.Controlled?.Inventory?.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
chatBox.RadioButton.GetChild<GUIImage>().Color =
(radioItem != null && Character.Controlled.HasEquippedItem(radioItem) && radioItem.GetComponent<WifiComponent>().CanTransmit()) ?
Color.White : new Color(60, 60, 60, 255);
}
}
public bool TypingChatMessage(GUITextBox textBox, string text)
{
return chatBox.TypingChatMessage(textBox, text);
@@ -2169,11 +2165,6 @@ namespace Barotrauma.Networking
Screen.Selected == GameMain.GameScreen)
{
inGameHUD.AddToGUIUpdateList();
if (Character.Controlled == null)
{
GameMain.NetLobbyScreen.MyCharacterFrame.AddToGUIUpdateList();
}
}
}
@@ -2192,24 +2183,17 @@ namespace Barotrauma.Networking
if (gameStarted && Screen.Selected == GameMain.GameScreen)
{
bool disableButtons =
Character.Controlled != null &&
Character.Controlled.SelectedConstruction?.GetComponent<Controller>() != null;
buttonContainer.Visible = !disableButtons;
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
{
inGameHUD.UpdateManually(deltaTime);
chatBox.Update(deltaTime);
cameraFollowsSub.Visible = Character.Controlled == null;
if (Character.Controlled == null)
{
myCharacterFrameOpenState = GameMain.NetLobbyScreen.MyCharacterFrameOpen ? myCharacterFrameOpenState + deltaTime * 5 : myCharacterFrameOpenState - deltaTime * 5;
myCharacterFrameOpenState = MathHelper.Clamp(myCharacterFrameOpenState, 0.0f, 1.0f);
var myCharFrame = GameMain.NetLobbyScreen.MyCharacterFrame;
int padding = GameMain.GraphicsWidth - myCharFrame.Parent.Rect.Right;
myCharFrame.RectTransform.AbsoluteOffset =
Vector2.SmoothStep(new Vector2(-myCharFrame.Rect.Width - padding, 0.0f), new Vector2(-padding, 0), myCharacterFrameOpenState).ToPoint();
}
}
if (Character.Controlled == null || Character.Controlled.IsDead)
{
@@ -2246,7 +2230,47 @@ namespace Barotrauma.Networking
public virtual void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
{
if (!gameStarted || Screen.Selected != GameMain.GameScreen || GUI.DisableHUD || GUI.DisableUpperHUD) return;
if (GUI.DisableHUD || GUI.DisableUpperHUD) return;
if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0)
{
Vector2 downloadBarSize = new Vector2(250, 35) * GUI.Scale;
Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - downloadBarSize.Y - 5);
GUI.DrawRectangle(spriteBatch, new Rectangle(
(int)pos.X,
(int)pos.Y,
(int)(fileReceiver.ActiveTransfers.Count * (downloadBarSize.X + 10)),
(int)downloadBarSize.Y),
Color.Black * 0.8f, true);
for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++)
{
var transfer = fileReceiver.ActiveTransfers[i];
GUI.DrawString(spriteBatch,
pos,
ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, (int)downloadBarSize.X),
Color.White, null, 0, GUI.SmallFont);
GUI.DrawProgressBar(spriteBatch, new Vector2(pos.X, -pos.Y - downloadBarSize.Y / 2), new Vector2(downloadBarSize.X * 0.7f, downloadBarSize.Y / 2), transfer.Progress, Color.Green);
GUI.DrawString(spriteBatch, pos + new Vector2(5, downloadBarSize.Y / 2),
MathUtils.GetBytesReadable((long)transfer.Received) + " / " + MathUtils.GetBytesReadable((long)transfer.FileSize),
Color.White, null, 0, GUI.SmallFont);
if (GUI.DrawButton(spriteBatch, new Rectangle(
(int)(pos.X + downloadBarSize.X * 0.7f), (int)(pos.Y + downloadBarSize.Y / 2),
(int)(downloadBarSize.X * 0.3f), (int)(downloadBarSize.Y / 2)),
TextManager.Get("Cancel"), new Color(0.47f, 0.13f, 0.15f, 0.08f)))
{
CancelFileTransfer(transfer);
fileReceiver.StopTransfer(transfer);
}
pos.X += (downloadBarSize.X + 10);
}
}
if (!gameStarted || Screen.Selected != GameMain.GameScreen) return;
inGameHUD.DrawManually(spriteBatch);
@@ -2297,40 +2321,6 @@ namespace Barotrauma.Networking
}
}
if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0)
{
Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - 35);
GUI.DrawRectangle(spriteBatch, new Rectangle(
(int)pos.X,
(int)pos.Y,
fileReceiver.ActiveTransfers.Count * 210 + 10,
32),
Color.Black * 0.8f, true);
for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++)
{
var transfer = fileReceiver.ActiveTransfers[i];
GUI.DrawString(spriteBatch,
pos,
ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, 200),
Color.White, null, 0, GUI.SmallFont);
GUI.DrawProgressBar(spriteBatch, new Vector2(pos.X, -pos.Y - 15), new Vector2(135, 15), transfer.Progress, Color.Green);
GUI.DrawString(spriteBatch, pos + new Vector2(5, 15),
MathUtils.GetBytesReadable((long)transfer.Received) + " / " + MathUtils.GetBytesReadable((long)transfer.FileSize),
Color.White, null, 0, GUI.SmallFont);
if (GUI.DrawButton(spriteBatch, new Rectangle((int)pos.X + 140, (int)pos.Y + 18, 60, 15), TextManager.Get("Cancel"), new Color(0.47f, 0.13f, 0.15f, 0.08f)))
{
CancelFileTransfer(transfer);
fileReceiver.StopTransfer(transfer);
}
pos.X += 210;
}
}
if (!ShowNetStats) return;
netStats.Draw(spriteBatch, new Rectangle(300, 10, 300, 150));

View File

@@ -57,10 +57,20 @@ namespace Barotrauma.Networking
return;
}
var newEvent = new ClientEntityEvent(entity, (UInt16)(ID + 1))
{
CharacterStateID = GameMain.Client.Character.LastNetworkUpdateID
};
if (extraData != null) { newEvent.SetData(extraData); }
for (int i = events.Count - 1; i >= 0; i--)
{
//we already have an identical event that's waiting to be sent
// -> no need to add a new one
if (!events[i].Sent && events[i].IsDuplicate(newEvent)) return;
}
ID++;
var newEvent = new ClientEntityEvent(entity, ID);
newEvent.CharacterStateID = GameMain.Client.Character.LastNetworkUpdateID;
if (extraData != null) newEvent.SetData(extraData);
events.Add(newEvent);
}
@@ -79,7 +89,10 @@ namespace Barotrauma.Networking
startIndex--;
}
for (int i = startIndex; i < events.Count; i++)
//remove events the server has already received
events.RemoveRange(0, startIndex);
for (int i = 0; i < events.Count; i++)
{
//find the first event that hasn't been sent in roundtriptime or at all
eventLastSent.TryGetValue(events[i].ID, out float lastSent);
@@ -232,6 +245,7 @@ namespace Barotrauma.Networking
if (clientEvent == null) return;
clientEvent.Write(buffer);
clientEvent.Sent = true;
}
protected void ReadEvent(NetIncomingMessage buffer, IServerSerializable entity, float sendingTime)

View File

@@ -25,6 +25,7 @@ namespace Barotrauma.Networking
public SelectionMode? ModeSelectionMode;
public SelectionMode? SubSelectionMode;
public bool? AllowSpectating;
public bool? VoipEnabled;
public bool? AllowRespawn;
public YesNoMaybe? TraitorsEnabled;
public string GameMode;
@@ -59,17 +60,32 @@ namespace Barotrauma.Networking
return contentPackageHashes.SetEquals(myContentPackageHashes);
}
public void CreatePreviewWindow(GUIMessageBox messageBox)
public void CreatePreviewWindow(GUIListBox listBox)
{
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), messageBox.Content.RectTransform), ServerName, textAlignment: Alignment.Center, font: GUI.LargeFont, wrap: true);
listBox.ClearChildren();
var serverMsg = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), messageBox.Content.RectTransform));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), serverMsg.Content.RectTransform), ServerMessage, wrap: true);
if (listBox == null) return;
var columnContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), messageBox.Content.RectTransform), isHorizontal: true)
var previewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), listBox.Content.RectTransform, Anchor.Center))
{
Stretch = true
};
var titleHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.07f), previewContainer.RectTransform))
{
IsHorizontal = true,
Stretch = true
};
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), titleHolder.RectTransform), ServerName, font: GUI.LargeFont, wrap: true);
new GUITextBlock(new RectTransform(Vector2.One, title.RectTransform),
TextManager.Get("ServerListVersion") + ": " + (string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion), textAlignment: Alignment.Right);
var columnContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), previewContainer.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
RelativeSpacing = 0.005f
};
var columnLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), columnContainer.RectTransform))
@@ -88,12 +104,75 @@ namespace Barotrauma.Networking
// left column -----------------------------------------------------------------------------
//new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnLeft.RectTransform), IP + ":" + Port);
new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnLeft.RectTransform),
TextManager.Get("ServerListVersion") + ": " + (string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), columnLeft.RectTransform),
var serverMsg = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), columnLeft.RectTransform)) { ScrollBarVisible = true };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), serverMsg.Content.RectTransform), ServerMessage, wrap: true) { CanBeFocused = false };
// right column -----------------------------------------------------------------------------
/*var playerCount = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListPlayers"));
new GUITextBlock(new RectTransform(Vector2.One, playerCount.RectTransform), PlayerCount + "/" + MaxPlayers, textAlignment: Alignment.Right);
new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), "Round running")
{
Selected = GameStarted,
CanBeFocused = false
};*/
var gameMode = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("GameMode"));
new GUITextBlock(new RectTransform(Vector2.One, gameMode.RectTransform), TextManager.Get(string.IsNullOrEmpty(GameMode) ? "Unknown" : GameMode), textAlignment: Alignment.Right);
var traitors = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("Traitors"));
new GUITextBlock(new RectTransform(Vector2.One, traitors.RectTransform), TextManager.Get(!TraitorsEnabled.HasValue ? "Unknown" : TraitorsEnabled.Value.ToString()), textAlignment: Alignment.Right);
var subSelection = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListSubSelection"));
new GUITextBlock(new RectTransform(Vector2.One, subSelection.RectTransform), TextManager.Get(!SubSelectionMode.HasValue ? "Unknown" : SubSelectionMode.Value.ToString()), textAlignment: Alignment.Right);
var modeSelection = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListModeSelection"));
new GUITextBlock(new RectTransform(Vector2.One, modeSelection.RectTransform), TextManager.Get(!ModeSelectionMode.HasValue ? "Unknown" : ModeSelectionMode.Value.ToString()), textAlignment: Alignment.Right);
var allowSpectating = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListAllowSpectating"))
{
CanBeFocused = false
};
if (!AllowSpectating.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), allowSpectating.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
allowSpectating.Selected = AllowSpectating.Value;
var allowRespawn = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), TextManager.Get("ServerSettingsAllowRespawning"))
{
CanBeFocused = false
};
if (!AllowRespawn.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), allowRespawn.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
allowRespawn.Selected = AllowRespawn.Value;
var voipEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("serversettingsvoicechatenabled"))
{
CanBeFocused = false
};
if (!VoipEnabled.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), voipEnabledTickBox.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
voipEnabledTickBox.Selected = VoipEnabled.Value;
var usingWhiteList = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListUsingWhitelist"))
{
CanBeFocused = false
};
if (!UsingWhiteList.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), usingWhiteList.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
usingWhiteList.Selected = UsingWhiteList.Value;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), columnRight.RectTransform),
TextManager.Get("ServerListContentPackages"));
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), columnLeft.RectTransform));
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), columnRight.RectTransform));
if (ContentPackageNames.Count == 0)
{
new GUITextBlock(new RectTransform(Vector2.One, contentPackageList.Content.RectTransform), TextManager.Get("Unknown"), textAlignment: Alignment.Center)
@@ -143,7 +222,7 @@ namespace Barotrauma.Networking
}
}
}
if (availableWorkshopUrls.Count > 0 )
if (availableWorkshopUrls.Count > 0)
{
var workshopBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.15f), columnLeft.RectTransform), TextManager.Get("ServerListSubscribeMissingPackages"))
{
@@ -159,64 +238,6 @@ namespace Barotrauma.Networking
workshopBtn.TextBlock.AutoScale = true;
}
}
// right column -----------------------------------------------------------------------------
var playerCount = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListPlayers"));
new GUITextBlock(new RectTransform(Vector2.One, playerCount.RectTransform), PlayerCount + "/" + MaxPlayers, textAlignment: Alignment.Right);
new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), "Round running")
{
Selected = GameStarted,
CanBeFocused = false
};
var gameMode = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("GameMode"));
new GUITextBlock(new RectTransform(Vector2.One, gameMode.RectTransform), string.IsNullOrEmpty(GameMode) ? "Unknown" : GameMode, textAlignment: Alignment.Right);
var traitors = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("Traitors"));
new GUITextBlock(new RectTransform(Vector2.One, traitors.RectTransform), !TraitorsEnabled.HasValue ? "Unknown" : TraitorsEnabled.Value.ToString(), textAlignment: Alignment.Right);
var subSelection = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListSubSelection"));
new GUITextBlock(new RectTransform(Vector2.One, subSelection.RectTransform), !SubSelectionMode.HasValue ? "Unknown" : SubSelectionMode.Value.ToString(), textAlignment: Alignment.Right);
var modeSelection = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListModeSelection"));
new GUITextBlock(new RectTransform(Vector2.One, modeSelection.RectTransform), (!ModeSelectionMode.HasValue ? "Unknown" : ModeSelectionMode.Value.ToString()), textAlignment: Alignment.Right);
var allowSpectating = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListAllowSpectating"))
{
CanBeFocused = false
};
if (!AllowSpectating.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), allowSpectating.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
allowSpectating.Selected = AllowSpectating.Value;
var allowRespawn = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), "Allow respawn")
{
CanBeFocused = false
};
if (!AllowRespawn.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), allowRespawn.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
allowRespawn.Selected = AllowRespawn.Value;
new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListHasPassword"))
{
Selected = HasPassword,
CanBeFocused = false
};
var usingWhiteList = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), columnRight.RectTransform), TextManager.Get("ServerListUsingWhitelist"))
{
CanBeFocused = false
};
if (!UsingWhiteList.HasValue)
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), usingWhiteList.Box.RectTransform, Anchor.Center), "?", textAlignment: Alignment.Center);
else
usingWhiteList.Selected = UsingWhiteList.Value;
// -----------------------------------------------------------------------------

View File

@@ -388,7 +388,7 @@ namespace Barotrauma.Networking
ToolTip = TextManager.Get("ServerSettingsMinRespawnToolTip")
};
string minRespawnLabel = TextManager.Get("ServerSettingsMinRespawn");
string minRespawnLabel = TextManager.Get("ServerSettingsMinRespawn") + " ";
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
slider.ToolTip = minRespawnText.ToolTip;
slider.UserData = minRespawnText;
@@ -407,7 +407,7 @@ namespace Barotrauma.Networking
ToolTip = TextManager.Get("ServerSettingsRespawnDurationToolTip")
};
string respawnDurationLabel = TextManager.Get("ServerSettingsRespawnDuration");
string respawnDurationLabel = TextManager.Get("ServerSettingsRespawnDuration") + " ";
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
slider.ToolTip = respawnDurationText.ToolTip;
slider.UserData = respawnDurationText;
@@ -471,7 +471,7 @@ namespace Barotrauma.Networking
{
string translatedLabel = TextManager.Get($"Character.{s}", true);
var monsterEnabledBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), monsterFrame.Content.RectTransform) { MinSize = new Point(0, 25) },
label: translatedLabel != null ? translatedLabel : s)
label: translatedLabel ?? s)
{
Selected = tempMonsterEnabled[s],
OnSelected = (GUITickBox tb) =>
@@ -573,7 +573,7 @@ namespace Barotrauma.Networking
//***********************************************
string autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay");
string autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay") + " ";
var startIntervalText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), autoRestartDelayLabel);
var startIntervalSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), barSize: 0.1f)
{
@@ -617,7 +617,7 @@ namespace Barotrauma.Networking
GetPropertyData("AllowVoteKick").AssignGUIComponent(voteKickBox);
CreateLabeledSlider(serverTab, "ServerSettingsKickVotesRequired", out slider, out sliderLabel);
string votesRequiredLabel = sliderLabel.Text;
string votesRequiredLabel = sliderLabel.Text + " ";
slider.Step = 0.2f;
slider.Range = new Vector2(0.5f, 1.0f);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
@@ -629,7 +629,7 @@ namespace Barotrauma.Networking
slider.OnMoved(slider, slider.BarScroll);
CreateLabeledSlider(serverTab, "ServerSettingsAutobanTime", out slider, out sliderLabel);
string autobanLabel = sliderLabel.Text;
string autobanLabel = sliderLabel.Text + " ";
slider.Step = 0.05f;
slider.Range = new Vector2(0.0f, MaxAutoBanTime);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
@@ -681,8 +681,8 @@ namespace Barotrauma.Networking
traitorRatioSlider.Range = new Vector2(1.0f, maxPlayers);
}
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio");
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount");
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio") + " ";
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount") + " ";
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>

View File

@@ -107,6 +107,56 @@ namespace Barotrauma.Steam
return true;
}
public static bool GetFavouriteServers(Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, Action onFinished)
{
if (instance == null || !instance.isInitialized)
{
return false;
}
var filter = new ServerList.Filter
{
{ "appid", AppID.ToString() },
{ "gamedir", "Barotrauma" },
{ "secure", "1" }
};
//include unresponsive servers in the server list
//the response is queried using the server's query port, not the game port,
//so it may be possible to play on the server even if it doesn't respond to server list queries
var query = instance.client.ServerList.Favourites(filter);
query.OnUpdate += () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
query.OnFinished = onFinished;
return true;
}
public static bool GetServersFromHistory(Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, Action onFinished)
{
if (instance == null || !instance.isInitialized)
{
return false;
}
var filter = new ServerList.Filter
{
{ "appid", AppID.ToString() },
{ "gamedir", "Barotrauma" },
{ "secure", "1" }
};
//include unresponsive servers in the server list
//the response is queried using the server's query port, not the game port,
//so it may be possible to play on the server even if it doesn't respond to server list queries
var query = instance.client.ServerList.History(filter);
query.OnUpdate += () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
query.OnFinished = onFinished;
return true;
}
private static void UpdateServerQuery(ServerList.Request query, Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, bool includeUnresponsive)
{
IEnumerable<ServerList.Server> servers = includeUnresponsive ?
@@ -164,6 +214,7 @@ namespace Barotrauma.Steam
}
if (s.Rules.ContainsKey("allowspectating")) serverInfo.AllowSpectating = s.Rules["allowspectating"] == "True";
if (s.Rules.ContainsKey("allowrespawn")) serverInfo.AllowRespawn = s.Rules["allowrespawn"] == "True";
if (s.Rules.ContainsKey("voicechatenabled")) serverInfo.VoipEnabled = s.Rules["voicechatenabled"] == "True";
if (s.Rules.ContainsKey("traitors"))
{
if (Enum.TryParse(s.Rules["traitors"], out YesNoMaybe traitorsEnabled)) serverInfo.TraitorsEnabled = traitorsEnabled;
@@ -548,6 +599,8 @@ namespace Barotrauma.Steam
if (!allowFileOverwrite)
{
// TODO: If you create a new mod via the workshop interface and enable it, it will show the error msg, but still allows you to enable the content.
if (File.Exists(newContentPackagePath))
{
errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable")

View File

@@ -115,7 +115,7 @@ namespace Barotrauma.Networking
}
}
GameMain.NetLobbyScreen.SetPlayerSpeaking(client);
GameMain.GameSession?.CrewManager?.SetPlayerSpeaking(client);
GameMain.GameSession?.CrewManager?.SetClientSpeaking(client);
}
}

View File

@@ -16,7 +16,6 @@ namespace Barotrauma
private GUIListBox saveList;
private GUITextBox saveNameBox, seedBox;
private GUITickBox contextualTutorialBox;
private GUILayoutGroup subPreviewContainer;
@@ -24,14 +23,6 @@ namespace Barotrauma
public Action<Submarine, string, string> StartNewGame;
public Action<string> LoadGame;
public bool TutorialSelected
{
get
{
if (contextualTutorialBox == null) return false;
return contextualTutorialBox.Selected;
}
}
private readonly bool isMultiplayer;
@@ -68,14 +59,23 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed") + ":");
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
if (!isMultiplayer)
{
contextualTutorialBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("TutorialActive"));
UpdateTutorialSelection();
}
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub") + ":");
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
{
Stretch = true
};
subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true };
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font);
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
var clearButton = new GUIButton(new RectTransform(new Vector2(0.075f, 1.0f), filterContainer.RectTransform), "x")
{
OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterSubs(subList, ""); searchBox.Flash(Color.White); return true; }
};
if (!isMultiplayer) { subList.OnSelected = OnSubSelected; }
@@ -186,6 +186,16 @@ namespace Barotrauma
seedBox.Text = ToolBox.RandomSeed(8);
}
private void FilterSubs(GUIListBox subList, string filter)
{
foreach (GUIComponent child in subList.Content.Children)
{
var sub = child.UserData as Submarine;
if (sub == null) { return; }
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.Name.ToLower().Contains(filter.ToLower());
}
}
private bool OnSubSelected(GUIComponent component, object obj)
{
if (subPreviewContainer == null) { return false; }
@@ -375,14 +385,7 @@ namespace Barotrauma
},
Enabled = false
};
}
public void UpdateTutorialSelection()
{
if (isMultiplayer) return;
Tutorial contextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial);
contextualTutorialBox.Selected = (contextualTutorial != null) ? !GameMain.Config.CompletedTutorialNames.Contains(contextualTutorial.Name) : true;
}
}
private bool SelectSaveFile(GUIComponent component, object obj)
{

View File

@@ -9,23 +9,25 @@ namespace Barotrauma
{
class CampaignUI
{
public enum Tab { Map, Crew, Store }
public enum Tab { Map, Crew, Store, Repair }
private Tab selectedTab;
private GUIFrame[] tabs;
private GUIButton startButton;
private GUIFrame topPanel;
private GUIListBox characterList;
private MapEntityCategory selectedItemCategory = MapEntityCategory.Equipment;
private GUIListBox myItemList;
private GUIListBox storeItemList;
private GUITextBox searchBox;
private GUIComponent missionPanel;
private GUIComponent selectedLocationInfo;
private GUIListBox selectedMissionInfo;
private GUIButton repairHullsButton, repairItemsButton;
private GUIFrame characterPreviewFrame;
private List<GUIButton> tabButtons = new List<GUIButton>();
@@ -39,10 +41,7 @@ namespace Barotrauma
public GUIComponent MapContainer { get; private set; }
public GUIButton StartButton
{
get { return startButton; }
}
public GUIButton StartButton { get; private set; }
public CampaignMode Campaign { get; }
@@ -70,7 +69,7 @@ namespace Barotrauma
var outpostBtn = new GUIButton(new RectTransform(new Vector2(0.15f, 0.55f), topPanelContent.RectTransform),
TextManager.Get("Outpost"), textAlignment: Alignment.Center, style: "GUISlopedHeader")
{
OnClicked = (btn, userdata) => { SelectTab(Tab.Map); return true; }
OnClicked = (btn, userdata) => { SelectTab(Tab.Map); return true; }
};
outpostBtn.TextBlock.Font = GUI.LargeFont;
outpostBtn.TextBlock.AutoScale = true;
@@ -112,7 +111,7 @@ namespace Barotrauma
tabs[(int)Tab.Crew] = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.7f), container.RectTransform, Anchor.TopLeft)
{
RelativeOffset = new Vector2(0.0f, topPanel.RectTransform.RelativeSize.Y)
}, color: Color.Black * 0.7f);
}, color: Color.Black * 0.9f);
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), tabs[(int)Tab.Crew].RectTransform, Anchor.Center), style: "OuterGlow", color: Color.Black * 0.7f)
{
CanBeFocused = false
@@ -157,7 +156,7 @@ namespace Barotrauma
tabs[(int)Tab.Store] = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.7f), container.RectTransform, Anchor.TopLeft)
{
RelativeOffset = new Vector2(0.1f, topPanel.RectTransform.RelativeSize.Y)
}, color: Color.Black * 0.7f);
}, color: Color.Black * 0.9f);
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), tabs[(int)Tab.Store].RectTransform, Anchor.Center), style: "OuterGlow", color: Color.Black * 0.7f)
{
CanBeFocused = false
@@ -174,15 +173,33 @@ namespace Barotrauma
RelativeSpacing = 0.02f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), storeContent.RectTransform), "", font: GUI.LargeFont)
var storeContentTop = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), storeContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), storeContentTop.RectTransform), "", font: GUI.LargeFont)
{
TextGetter = GetMoney
};
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.4f), storeContentTop.RectTransform), isHorizontal: true)
{
Stretch = true
};
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font);
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) => { FilterStoreItems(null, text); return true; };
var clearButton = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), filterContainer.RectTransform), "x")
{
OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterStoreItems(selectedItemCategory, ""); searchBox.Flash(Color.White); return true; }
};
var storeItemLists = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), storeContent.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.02f
Stretch = true
};
myItemList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), storeItemLists.RectTransform));
storeItemList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), storeItemLists.RectTransform))
@@ -200,7 +217,7 @@ namespace Barotrauma
"", style: "ItemCategory" + category.ToString())
{
UserData = category,
OnClicked = (btn, userdata) => { SelectItemCategory((MapEntityCategory)userdata); return true; }
OnClicked = (btn, userdata) => { FilterStoreItems((MapEntityCategory)userdata, searchBox.Text); return true; }
};
itemCategoryButtons.Add(categoryButton);
@@ -216,7 +233,115 @@ namespace Barotrauma
CanBeFocused = false
};
}
SelectItemCategory(MapEntityCategory.Equipment);
FillStoreItemList();
FilterStoreItems(MapEntityCategory.Equipment, "");
// repair tab -------------------------------------------------------------------------
tabs[(int)Tab.Repair] = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.5f), container.RectTransform, Anchor.TopLeft)
{
RelativeOffset = new Vector2(0.02f, topPanel.RectTransform.RelativeSize.Y)
}, color: Color.Black * 0.9f);
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), tabs[(int)Tab.Repair].RectTransform, Anchor.Center), style: "OuterGlow", color: Color.Black * 0.7f)
{
CanBeFocused = false
};
var repairContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), tabs[(int)Tab.Repair].RectTransform, Anchor.Center))
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), repairContent.RectTransform), "", font: GUI.LargeFont)
{
TextGetter = GetMoney
};
var repairHullsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Vector2(0.3f, 1.0f), repairHullsHolder.RectTransform, Anchor.CenterLeft), "RepairHullButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairHullsHolder.RectTransform), TextManager.Get("RepairAllWalls"), textAlignment: Alignment.Right, font: GUI.LargeFont)
{
ForceUpperCase = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairHullsHolder.RectTransform), "500", textAlignment: Alignment.Right, font: GUI.LargeFont);
repairHullsButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), repairHullsHolder.RectTransform), TextManager.Get("Repair"), style: "GUIButtonLarge")
{
OnClicked = (btn, userdata) =>
{
if (campaign.PurchasedHullRepairs)
{
campaign.Money += CampaignMode.HullRepairCost;
campaign.PurchasedHullRepairs = false;
}
else
{
if (campaign.Money >= CampaignMode.HullRepairCost)
{
campaign.Money -= CampaignMode.HullRepairCost;
campaign.PurchasedHullRepairs = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = campaign.PurchasedHullRepairs;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), repairHullsButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
var repairItemsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Vector2(0.3f, 1.0f), repairItemsHolder.RectTransform, Anchor.CenterLeft), "RepairItemsButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairItemsHolder.RectTransform), TextManager.Get("RepairAllItems"), textAlignment: Alignment.Right, font: GUI.LargeFont)
{
ForceUpperCase = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairItemsHolder.RectTransform), "500", textAlignment: Alignment.Right, font: GUI.LargeFont);
repairItemsButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), repairItemsHolder.RectTransform), TextManager.Get("Repair"), style: "GUIButtonLarge")
{
OnClicked = (btn, userdata) =>
{
if (campaign.PurchasedItemRepairs)
{
campaign.Money += CampaignMode.ItemRepairCost;
campaign.PurchasedItemRepairs = false;
}
else
{
if (campaign.Money >= CampaignMode.ItemRepairCost)
{
campaign.Money -= CampaignMode.ItemRepairCost;
campaign.PurchasedItemRepairs = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = campaign.PurchasedItemRepairs;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), repairItemsButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
// mission info -------------------------------------------------------------------------
@@ -330,8 +455,7 @@ namespace Barotrauma
bool purchaseableItemsFound = false;
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
{
var itemPrefab = mapEntityPrefab as ItemPrefab;
if (itemPrefab == null) { continue; }
if (!(mapEntityPrefab is ItemPrefab itemPrefab)) { continue; }
PriceInfo priceInfo = itemPrefab.GetPrice(Campaign.Map.CurrentLocation);
if (priceInfo != null) { purchaseableItemsFound = true; break; }
@@ -348,9 +472,9 @@ namespace Barotrauma
else
{
//refresh store view
SelectItemCategory(MapEntityCategory.Equipment);
}
FillStoreItemList();
FilterStoreItems(MapEntityCategory.Equipment, searchBox.Text);
}
}
private void DrawMap(SpriteBatch spriteBatch, GUICustomComponent mapContainer)
@@ -452,7 +576,7 @@ namespace Barotrauma
RefreshMissionTab(selectedMission);
startButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.7f), missionContent.RectTransform, Anchor.CenterRight),
StartButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.7f), missionContent.RectTransform, Anchor.CenterRight),
TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge")
{
IgnoreLayoutGroups = true,
@@ -461,7 +585,7 @@ namespace Barotrauma
};
if (GameMain.Client != null)
{
startButton.Visible = !GameMain.Client.GameStarted &&
StartButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
}
@@ -508,10 +632,10 @@ namespace Barotrauma
CanBeFocused = false
};
if (startButton != null)
if (StartButton != null)
{
startButton.Enabled = true;
startButton.Visible = GameMain.Client == null ||
StartButton.Enabled = true;
StartButton.Visible = GameMain.Client == null ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign);
}
@@ -597,8 +721,7 @@ namespace Barotrauma
private bool BuyItem(GUIComponent component, object obj)
{
PurchasedItem pi = obj as PurchasedItem;
if (pi == null || pi.ItemPrefab == null) return false;
if (!(obj is PurchasedItem pi) || pi.ItemPrefab == null) return false;
if (GameMain.Client != null && !GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign))
{
@@ -616,8 +739,7 @@ namespace Barotrauma
private bool SellItem(GUIComponent component, object obj)
{
PurchasedItem pi = obj as PurchasedItem;
if (pi == null || pi.ItemPrefab == null) return false;
if (!(obj is PurchasedItem pi) || pi.ItemPrefab == null) return false;
if (GameMain.Client != null && !GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign))
{
@@ -659,35 +781,59 @@ namespace Barotrauma
{
button.Selected = (Tab)button.UserData == tab;
}
switch (selectedTab)
{
case Tab.Repair:
repairHullsButton.Enabled =
(Campaign.PurchasedHullRepairs || Campaign.Money >= CampaignMode.HullRepairCost) &&
(GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
repairHullsButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedHullRepairs;
repairItemsButton.Enabled =
(Campaign.PurchasedItemRepairs || Campaign.Money >= CampaignMode.ItemRepairCost) &&
(GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
repairItemsButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedItemRepairs;
break;
}
}
private bool SelectItemCategory(MapEntityCategory category)
private void FillStoreItemList()
{
storeItemList.ClearChildren();
int width = storeItemList.Rect.Width;
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
{
var itemPrefab = mapEntityPrefab as ItemPrefab;
if (itemPrefab == null || !itemPrefab.Category.HasFlag(category)) continue;
if (!(mapEntityPrefab is ItemPrefab itemPrefab)) { continue; }
PriceInfo priceInfo = itemPrefab.GetPrice(Campaign.Map.CurrentLocation);
if (priceInfo == null) continue;
CreateItemFrame(new PurchasedItem(itemPrefab, 0), priceInfo, storeItemList, width);
}
storeItemList.Content.RectTransform.SortChildren(
(x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name));
}
private void FilterStoreItems(MapEntityCategory? category, string filter)
{
if (category.HasValue)
{
selectedItemCategory = category.Value;
}
foreach (GUIComponent child in storeItemList.Content.Children)
{
var item = child.UserData as PurchasedItem;
if (item?.ItemPrefab?.Name == null) { continue; }
child.Visible =
(!category.HasValue || item.ItemPrefab.Category.HasFlag(category.Value)) &&
(string.IsNullOrEmpty(filter) || item.ItemPrefab.Name.ToLower().Contains(searchBox.Text.ToLower()));
}
foreach (GUIButton btn in itemCategoryButtons)
{
btn.Selected = (MapEntityCategory)btn.UserData == category;
btn.Selected = (MapEntityCategory)btn.UserData == selectedItemCategory;
}
storeItemList.UpdateScrollBarSize();
storeItemList.BarScroll = 0.0f;
return true;
}
public string GetMoney()
@@ -707,9 +853,8 @@ namespace Barotrauma
}
if (prevInfoFrame != null) { tabs[(int)selectedTab].RemoveChild(prevInfoFrame); }
CharacterInfo characterInfo = selection as CharacterInfo;
if (characterInfo == null) { return false; }
if (!(selection is CharacterInfo characterInfo)) { return false; }
if (Character.Controlled != null && characterInfo == Character.Controlled.Info) { return false; }
if (characterPreviewFrame == null || characterPreviewFrame.UserData != characterInfo)
@@ -761,11 +906,9 @@ namespace Barotrauma
private bool HireCharacter(GUIButton button, object selection)
{
CharacterInfo characterInfo = selection as CharacterInfo;
if (characterInfo == null) { return false; }
if (!(selection is CharacterInfo characterInfo)) { return false; }
SinglePlayerCampaign spCampaign = Campaign as SinglePlayerCampaign;
if (spCampaign == null)
if (!(Campaign is SinglePlayerCampaign spCampaign))
{
DebugConsole.ThrowError("Characters can only be hired in the single player campaign.\n" + Environment.StackTrace);
return false;
@@ -784,11 +927,9 @@ namespace Barotrauma
private bool FireCharacter(GUIButton button, object selection)
{
CharacterInfo characterInfo = selection as CharacterInfo;
if (characterInfo == null) return false;
if (!(selection is CharacterInfo characterInfo)) return false;
SinglePlayerCampaign spCampaign = Campaign as SinglePlayerCampaign;
if (spCampaign == null)
if (!(Campaign is SinglePlayerCampaign spCampaign))
{
DebugConsole.ThrowError("Characters can only be fired in the single player campaign.\n" + Environment.StackTrace);
return false;

View File

@@ -42,16 +42,16 @@ namespace Barotrauma
private bool showParamsEditor;
private bool showSpritesheet;
private bool isFreezed;
private bool autoFreeze = true;
private bool limbPairEditing = true;
private bool uniformScaling = true;
private bool lockSpriteOrigin = true;
private bool autoFreeze;
private bool limbPairEditing;
private bool uniformScaling;
private bool lockSpriteOrigin;
private bool lockSpritePosition;
private bool lockSpriteSize;
private bool recalculateCollider;
private bool copyJointSettings;
private bool displayColliders;
private bool displayWearables = true;
private bool displayWearables;
private bool displayBackgroundColor;
private bool ragdollResetRequiresForceLoading;
private bool animationResetRequiresForceLoading;
@@ -89,10 +89,16 @@ namespace Barotrauma
public override void Select()
{
base.Select();
SoundPlayer.OverrideMusicType = "none";
SoundPlayer.OverrideMusicDuration = null;
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f);
GUI.ForceMouseOn(null);
CalculateSpritesheetPosition();
if (Submarine.MainSub == null)
{
ResetVariables();
Submarine.MainSub = new Submarine("Content/AnimEditor.sub");
Submarine.MainSub.Load(unloadPrevious: false, showWarningMessages: false);
originalWall = new WallGroup(new List<Structure>(Structure.WallList));
@@ -101,6 +107,10 @@ namespace Barotrauma
isEndlessRunner = true;
GameMain.LightManager.LightingEnabled = false;
}
else if (instance == null)
{
ResetVariables();
}
Submarine.MainSub.GodMode = true;
if (Character.Controlled == null)
{
@@ -116,33 +126,71 @@ namespace Barotrauma
OpenDoors();
GameMain.Instance.OnResolutionChanged += OnResolutionChanged;
instance = this;
if (!GameMain.Config.EditorDisclaimerShown)
{
GameMain.Instance.ShowEditorDisclaimer();
}
}
private void ResetVariables()
{
editAnimations = false;
editLimbs = false;
editJoints = false;
editIK = false;
showRagdoll = false;
showParamsEditor = false;
showSpritesheet = false;
isFreezed = false;
autoFreeze = true;
limbPairEditing = true;
uniformScaling = true;
lockSpriteOrigin = false;
lockSpritePosition = false;
lockSpriteSize = false;
recalculateCollider = false;
copyJointSettings = false;
displayColliders = false;
displayWearables = true;
displayBackgroundColor = false;
ragdollResetRequiresForceLoading = false;
animationResetRequiresForceLoading = false;
isExtrudingJoint = false;
isDrawingJoint = false;
Wizard.instance = null;
}
private void Reset()
{
AnimParams.ForEach(a => a.Reset(true));
RagdollParams.Reset(true);
RagdollParams.ClearHistory();
CurrentAnimation.ClearHistory();
if (!character.Removed)
ResetVariables();
if (character != null)
{
character.Remove();
AnimParams.ForEach(a => a.Reset(true));
RagdollParams.Reset(true);
RagdollParams.ClearHistory();
CurrentAnimation.ClearHistory();
if (!character.Removed)
{
character.Remove();
}
character = null;
}
character = null;
}
public override void Deselect()
{
base.Deselect();
SoundPlayer.OverrideMusicType = null;
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameMain.Config.SoundVolume);
GUI.ForceMouseOn(null);
if (isEndlessRunner)
{
Submarine.MainSub.Remove();
isEndlessRunner = false;
if (character != null)
{
Reset();
}
Reset();
GameMain.World.ProcessChanges();
}
else
@@ -175,7 +223,7 @@ namespace Barotrauma
{
//base.AddToGUIUpdateList();
rightPanel.AddToGUIUpdateList();
Wizard.Instance.AddToGUIUpdateList();
Wizard.instance?.AddToGUIUpdateList();
if (displayBackgroundColor)
{
backgroundColorPanel.AddToGUIUpdateList();
@@ -207,7 +255,7 @@ namespace Barotrauma
base.Update(deltaTime);
spriteSheetRect = CalculateSpritesheetRectangle();
// Handle shortcut keys
if (GUI.KeyboardDispatcher.Subscriber == null)
if (GUI.KeyboardDispatcher.Subscriber == null && Wizard.instance == null)
{
if (PlayerInput.KeyDown(Keys.LeftControl))
{
@@ -396,7 +444,7 @@ namespace Barotrauma
}
}
}
if (!isFreezed)
if (!isFreezed && Wizard.instance == null)
{
if (character.AnimController.Invalid)
{
@@ -1131,7 +1179,22 @@ namespace Barotrauma
character = Character.Create(configFile, spawnPosition, ToolBox.RandomSeed(8), hasAi: false, ragdoll: ragdoll);
selectedJob = null;
}
character.dontFollowCursor = dontFollowCursor;
if (character != null)
{
character.dontFollowCursor = dontFollowCursor;
}
if (character == null)
{
if (currentCharacterConfig == configFile)
{
return null;
}
else
{
// Respawn the current character;
SpawnCharacter(currentCharacterConfig);
}
}
OnPostSpawn();
return character;
}
@@ -1247,27 +1310,33 @@ namespace Barotrauma
string speciesName = name;
// Config file
string configFilePath = Path.Combine(mainFolder, $"{speciesName}.xml").Replace(@"\", @"/");
if (ContentPackage.GetFilesOfType(GameMain.SelectedPackages, ContentType.Character).None(path => path.Contains(speciesName)))
if (ContentPackage.GetFilesOfType(GameMain.SelectedPackages, ContentType.Character).Any(path => path.Contains(speciesName)))
{
// Create the config file
XElement mainElement = new XElement("Character",
new XAttribute("name", speciesName),
new XAttribute("humanoid", isHumanoid),
new XElement("ragdolls", new XAttribute("folder", Path.Combine(mainFolder, $"Ragdolls/").Replace(@"\", @"/"))),
new XElement("animations", new XAttribute("folder", Path.Combine(mainFolder, $"Animations/").Replace(@"\", @"/"))),
new XElement("health"),
new XElement("ai"));
XDocument doc = new XDocument(mainElement);
if (!Directory.Exists(mainFolder))
{
Directory.CreateDirectory(mainFolder);
}
doc.Save(configFilePath);
// Add to the selected content package
contentPackage.AddFile(configFilePath, ContentType.Character);
contentPackage.Save(contentPackage.Path);
DebugConsole.NewMessage(GetCharacterEditorTranslation("ContentPackageSaved").Replace("[path]", contentPackage.Path));
GUI.AddMessage(GetCharacterEditorTranslation("ExistingCharacterFound"), Color.Red, font: GUI.LargeFont);
// TODO: add a prompt: "Do you want to replace it?" + functionality
return false;
}
// Create the config file
XElement mainElement = new XElement("Character",
new XAttribute("name", speciesName),
new XAttribute("humanoid", isHumanoid),
new XElement("ragdolls", new XAttribute("folder", Path.Combine(mainFolder, $"Ragdolls/").Replace(@"\", @"/"))),
new XElement("animations", new XAttribute("folder", Path.Combine(mainFolder, $"Animations/").Replace(@"\", @"/"))),
new XElement("health"),
new XElement("ai"));
XDocument doc = new XDocument(mainElement);
if (!Directory.Exists(mainFolder))
{
Directory.CreateDirectory(mainFolder);
}
doc.Save(configFilePath);
// Add to the selected content package
contentPackage.AddFile(configFilePath, ContentType.Character);
contentPackage.Save(contentPackage.Path);
DebugConsole.NewMessage(GetCharacterEditorTranslation("ContentPackageSaved").Replace("[path]", contentPackage.Path));
// Ragdoll
string ragdollFolder = RagdollParams.GetFolder(speciesName);
string ragdollPath = RagdollParams.GetDefaultFile(speciesName);
@@ -1278,12 +1347,20 @@ namespace Barotrauma
string animFolder = AnimationParams.GetFolder(speciesName);
foreach (AnimationType animType in Enum.GetValues(typeof(AnimationType)))
{
if (animType != AnimationType.NotDefined)
switch (animType)
{
Type type = AnimationParams.GetParamTypeFromAnimType(animType, isHumanoid);
string fullPath = AnimationParams.GetDefaultFile(speciesName, animType);
AnimationParams.Create(fullPath, speciesName, animType, type);
case AnimationType.Walk:
case AnimationType.Run:
if (!ragdollParams.CanEnterSubmarine) { continue; }
break;
case AnimationType.SwimSlow:
case AnimationType.SwimFast:
break;
default: continue;
}
Type type = AnimationParams.GetParamTypeFromAnimType(animType, isHumanoid);
string fullPath = AnimationParams.GetDefaultFile(speciesName, animType);
AnimationParams.Create(fullPath, speciesName, animType, type);
}
if (!AllFiles.Contains(configFilePath))
{
@@ -1702,8 +1779,20 @@ namespace Barotrauma
Vector2 buttonSize = new Vector2(1, 0.04f);
Vector2 toggleSize = new Vector2(0.03f, 0.03f);
Point margin = new Point(40, 60);
rightPanel = new GUIFrame(new RectTransform(new Vector2(0.15f, 0.95f), parent: Frame.RectTransform, anchor: Anchor.CenterRight) { RelativeOffset = new Vector2(0.01f, 0) });
var layoutGroup = new GUILayoutGroup(new RectTransform(new Point(rightPanel.Rect.Width - margin.X, rightPanel.Rect.Height - margin.Y), rightPanel.RectTransform, Anchor.Center));
rightPanel = new GUIFrame(new RectTransform(new Vector2(0.15f, 1.0f), parent: Frame.RectTransform, anchor: Anchor.CenterRight), style: "GUIFrameRight");
var layoutGroup = new GUILayoutGroup(new RectTransform(new Point(rightPanel.Rect.Width - margin.X, rightPanel.Rect.Height - margin.Y), rightPanel.RectTransform, Anchor.Center))
{
Stretch = true
};
var disclaimerBtnHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.04f), layoutGroup.RectTransform), style: null);
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), disclaimerBtnHolder.RectTransform, Anchor.TopRight), style: "GUINotificationButton")
{
OnClicked = (btn, userdata) => { GameMain.Instance.ShowEditorDisclaimer(); return true; }
};
disclaimerBtn.RectTransform.MaxSize = new Point(disclaimerBtn.Rect.Height);
var characterDropDown = new GUIDropDown(new RectTransform(new Vector2(1, 0.04f), layoutGroup.RectTransform), elementCount: 10, style: null);
characterDropDown.ListBox.Color = new Color(characterDropDown.ListBox.Color.R, characterDropDown.ListBox.Color.G, characterDropDown.ListBox.Color.B, byte.MaxValue);
foreach (var file in AllFiles)
@@ -1734,14 +1823,16 @@ namespace Barotrauma
return true;
};
}
var charButtons = new GUIFrame(new RectTransform(buttonSize, parent: layoutGroup.RectTransform), style: null);
var prevCharacterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1), charButtons.RectTransform, Anchor.TopLeft), GetCharacterEditorTranslation("PreviousCharacter"));
var charButtons = new GUIFrame(new RectTransform(new Vector2(buttonSize.X, buttonSize.Y * 1.5f), parent: layoutGroup.RectTransform), style: null);
var prevCharacterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), charButtons.RectTransform, Anchor.TopLeft), GetCharacterEditorTranslation("PreviousCharacter"));
prevCharacterButton.TextBlock.AutoScale = true;
prevCharacterButton.OnClicked += (b, obj) =>
{
SpawnCharacter(GetPreviousConfigFile());
return true;
};
var nextCharacterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1), charButtons.RectTransform, Anchor.TopRight), GetCharacterEditorTranslation("NextCharacter"));
var nextCharacterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), charButtons.RectTransform, Anchor.TopRight), GetCharacterEditorTranslation("NextCharacter"));
prevCharacterButton.TextBlock.AutoScale = true;
nextCharacterButton.OnClicked += (b, obj) =>
{
SpawnCharacter(GetNextConfigFile());
@@ -3764,7 +3855,7 @@ namespace Barotrauma
void RecalculateCollider(Limb l)
{
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
float multiplier = 0.75f;
float multiplier = 0.85f;
l.body.SetSize(new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * RagdollParams.LimbScale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / RagdollParams.LimbScale / RagdollParams.TextureScale));
@@ -4283,7 +4374,7 @@ namespace Barotrauma
private List<XElement> jointXElements = new List<XElement>();
private List<GUIComponent> jointGUIElements = new List<GUIComponent>();
private static Wizard instance;
public static Wizard instance;
public static Wizard Instance
{
get
@@ -4314,7 +4405,6 @@ namespace Barotrauma
break;
case Tab.None:
default:
//activeView = null;
instance = null;
break;
}
@@ -4343,7 +4433,7 @@ namespace Barotrauma
GUITextBox xmlPathElement = null;
void UpdatePaths()
{
string pathBase = $"Content/Characters/{Name}/{Name}";
string pathBase = $"Mods/Characters/{Name}/{Name}";
XMLPath = $"{pathBase}.xml";
TexturePath = $"{pathBase}.png";
texturePathElement.Text = TexturePath;
@@ -4422,7 +4512,7 @@ namespace Barotrauma
// Cancel
box.Buttons[0].OnClicked += (b, d) =>
{
Instance.SelectTab(Tab.None);
Wizard.Instance.SelectTab(Tab.None);
return true;
};
// Next
@@ -4434,7 +4524,7 @@ namespace Barotrauma
texturePathElement.Flash(Color.Red);
return false;
}
Instance.SelectTab(Tab.Ragdoll);
Wizard.Instance.SelectTab(Tab.Ragdoll);
return true;
};
return box;
@@ -4575,7 +4665,7 @@ namespace Barotrauma
// Previous
box.Buttons[0].OnClicked += (b, d) =>
{
Instance.SelectTab(Tab.Character);
Wizard.Instance.SelectTab(Tab.Character);
return true;
};
// Parse and create
@@ -4666,7 +4756,7 @@ namespace Barotrauma
{
GUI.AddMessage(GetCharacterEditorTranslation("CharacterCreated").Replace("[name]", Name), Color.Green, font: GUI.Font);
}
Instance.SelectTab(Tab.None);
Wizard.Instance.SelectTab(Tab.None);
return true;
};
return box;
@@ -4846,23 +4936,27 @@ namespace Barotrauma
int width = rectInputs[2].IntValue;
int height = rectInputs[3].IntValue;
var colliderAttributes = new List<XAttribute>();
if (width == height)
{
colliderAttributes.Add(new XAttribute("radius", width / 2));
}
else
{
if (height > width)
{
colliderAttributes.Add(new XAttribute("radius", width / 2));
colliderAttributes.Add(new XAttribute("height", height - width));
}
else
{
colliderAttributes.Add(new XAttribute("radius", height / 2));
colliderAttributes.Add(new XAttribute("width", width - height));
}
}
// Capsules/Circles
//if (width == height)
//{
// colliderAttributes.Add(new XAttribute("radius", (int)(width / 2 * 0.85f)));
//}
//else
//{
// if (height > width)
// {
// colliderAttributes.Add(new XAttribute("radius", (int)(width / 2 * 0.85f)));
// colliderAttributes.Add(new XAttribute("height",(int) (height - width * 0.85f)));
// }
// else
// {
// colliderAttributes.Add(new XAttribute("radius", (int)(height / 2 * 0.85f)));
// colliderAttributes.Add(new XAttribute("width", (int)(width - height * 0.85f)));
// }
//}
// Rectangles
colliderAttributes.Add(new XAttribute("height", (int)(height * 0.85f)));
colliderAttributes.Add(new XAttribute("width", (int)(width * 0.85f)));
idToCodeName.TryGetValue(id, out string notes);
LimbXElements.Add(id.ToString(), new XElement("limb",
new XAttribute("id", id),

View File

@@ -59,10 +59,10 @@ namespace Barotrauma
Stretch = true,
RelativeSpacing = 0.02f
};
// === CAMPAIGN
var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true);
new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), campaignHolder.RectTransform), "MainMenuCampaignIcon")
{
CanBeFocused = false
@@ -84,6 +84,17 @@ namespace Barotrauma
RelativeSpacing = 0.035f
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), campaignList.RectTransform), "Tutorial", textAlignment: Alignment.Left, style: "MainMenuGUIButton")
{
ForceUpperCase = true,
UserData = Tab.Tutorials,
OnClicked = (tb, userdata) =>
{
SelectTab(tb, userdata);
return true;
}
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), campaignList.RectTransform), TextManager.Get("LoadGameButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
{
ForceUpperCase = true,
@@ -184,6 +195,10 @@ namespace Barotrauma
UserData = Tab.SteamWorkshop,
OnClicked = SelectTab
};
#if OSX && !DEBUG
steamWorkshopButton.Text += " (Not yet available on MacOS)";
#endif
}
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), TextManager.Get("SubEditorButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
@@ -320,13 +335,11 @@ namespace Barotrauma
return true;
};
UpdateTutorialList();
this.game = game;
}
#endregion
#endregion
#region Selection
#region Selection
public override void Select()
{
base.Select();
@@ -338,8 +351,6 @@ namespace Barotrauma
}
Submarine.Unload();
UpdateTutorialList();
ResetButtonStates(null);
@@ -386,9 +397,14 @@ namespace Barotrauma
switch (selectedTab)
{
case Tab.NewGame:
if (!GameMain.Config.CampaignDisclaimerShown)
{
selectedTab = 0;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.NewGame); });
return true;
}
campaignSetupUI.CreateDefaultSaveName();
campaignSetupUI.RandomizeSeed();
campaignSetupUI.UpdateTutorialSelection();
campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines);
break;
case Tab.LoadGame:
@@ -405,6 +421,13 @@ namespace Barotrauma
case Tab.HostServer:
break;
case Tab.Tutorials:
if (!GameMain.Config.CampaignDisclaimerShown)
{
selectedTab = 0;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.Tutorials); });
return true;
}
UpdateTutorialList();
break;
case Tab.CharacterEditor:
Submarine.MainSub = null;
@@ -435,6 +458,8 @@ namespace Barotrauma
public bool ReturnToMainMenu(GUIButton button, object obj)
{
GUI.PreventPauseMenuToggle = false;
if (Selected != this)
{
Select();
@@ -459,7 +484,7 @@ namespace Barotrauma
otherButton.Selected = false;
}
}
#endregion
#endregion
private void QuickStart()
{
@@ -626,21 +651,22 @@ namespace Barotrauma
" -ownerkey " + ownerKey.ToString();
string filename = "DedicatedServer.exe";
#if LINUX || OSX
#if LINUX
filename = "./DedicatedServer";
#elif OSX
filename = "mono";
arguments = "./DedicatedServer.exe " + arguments;
#endif
var processInfo = new ProcessStartInfo
{
FileName = filename,
Arguments = arguments,
Arguments = arguments
#if !DEBUG
,
WindowStyle = ProcessWindowStyle.Hidden
#endif
};
GameMain.ServerChildProcess = Process.Start(processInfo);
Thread.Sleep(1000); //wait until the server is ready before connecting
GameMain.Client = new GameClient(name, "127.0.0.1:" + port.ToString(),ownerKey);
@@ -676,6 +702,7 @@ namespace Barotrauma
GameMain.TitleScreen.TitleSize.Y / 2.0f * GameMain.TitleScreen.Scale + 30.0f),
0.1f);
#if !DEBUG
#if !OSX
if (Steam.SteamManager.USE_STEAM)
{
if (GameMain.Config.UseSteamMatchmaking)
@@ -685,6 +712,16 @@ namespace Barotrauma
}
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
}
#else
if (Steam.SteamManager.USE_STEAM)
{
if (GameMain.Config.UseSteamMatchmaking)
{
joinServerButton.Enabled = Steam.SteamManager.IsInitialized;
hostServerButton.Enabled = Steam.SteamManager.IsInitialized;
}
}
#endif
#else
joinServerButton.Enabled = true;
hostServerButton.Enabled = true;
@@ -769,13 +806,11 @@ namespace Barotrauma
}
selectedSub = new Submarine(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"), "");
ContextualTutorial.Selected = campaignSetupUI.TutorialSelected;
GameMain.GameSession = new GameSession(selectedSub, saveName,
GameModePreset.List.Find(g => g.Identifier == "singleplayercampaign"));
(GameMain.GameSession.GameMode as CampaignMode).GenerateMap(mapSeed);
GameMain.LobbyScreen.Select();
}
@@ -797,7 +832,7 @@ namespace Barotrauma
GameMain.LobbyScreen.Select();
}
#region UI Methods
#region UI Methods
private void CreateHostServerFields()
{
Vector2 textLabelSize = new Vector2(1.0f, 0.1f);
@@ -878,7 +913,7 @@ namespace Barotrauma
OnClicked = HostServerClicked
};
}
#endregion
#endregion
}
}

View File

@@ -158,14 +158,7 @@ namespace Barotrauma
get;
private set;
}
public GUIFrame MyCharacterFrame
{
get { return myCharacterFrame; }
}
public bool MyCharacterFrameOpen;
public GUIFrame InfoFrame
{
get { return infoFrame; }
@@ -261,7 +254,7 @@ namespace Barotrauma
public NetLobbyScreen()
{
defaultModeContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), Frame.RectTransform, Anchor.Center), style: null);
defaultModeContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), Frame.RectTransform, Anchor.Center) { MaxSize = new Point(int.MaxValue, GameMain.GraphicsHeight - 100) }, style: null);
campaignContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.75f), Frame.RectTransform, Anchor.TopCenter), style: null)
{
Visible = false
@@ -300,18 +293,7 @@ namespace Barotrauma
OnSelected = TogglePlayYourself,
UserData = "playyourself"
};
var toggleMyPlayerFrame = new GUIButton(new RectTransform(new Point(25, 70), myCharacterFrame.RectTransform, Anchor.TopLeft, Pivot.TopRight), "", style: "GUIButtonHorizontalArrow");
toggleMyPlayerFrame.OnClicked += (GUIButton btn, object userdata) =>
{
MyCharacterFrameOpen = !MyCharacterFrameOpen;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = MyCharacterFrameOpen ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
return true;
};
//player list ------------------------------------------------------------------
playerListFrame = new GUIFrame(new RectTransform(new Vector2(0.3f - panelSpacing, 0.35f - panelSpacing), defaultModeContainer.RectTransform, Anchor.BottomRight));
@@ -698,7 +680,6 @@ namespace Barotrauma
public override void Deselect()
{
textBox.Deselect();
myCharacterFrame.GetChild<GUIButton>().Visible = true;
CampaignCharacterDiscarded = false;
}
@@ -713,10 +694,7 @@ namespace Barotrauma
textBox.Select();
textBox.OnEnterPressed = GameMain.Client.EnterChatMessage;
textBox.OnTextChanged += GameMain.Client.TypingChatMessage;
myCharacterFrame.RectTransform.AbsoluteOffset = new Point(0, 0);
myCharacterFrame.GetChild<GUIButton>().Visible = false;
subList.Enabled = AllowSubSelection;// || GameMain.Server != null;
shuttleList.Enabled = AllowSubSelection;// || GameMain.Server != null;
@@ -737,11 +715,15 @@ namespace Barotrauma
spectateButton.Visible = GameMain.Client.GameStarted;
ReadyToStartBox.Visible = !GameMain.Client.GameStarted;
ReadyToStartBox.Selected = false;
if (campaignUI?.StartButton != null)
if (campaignUI != null)
{
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
//SelectTab(Tab.Map);
if (campaignUI.StartButton != null)
{
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
}
}
GameMain.Client.SetReadyToStart(ReadyToStartBox);
}

View File

@@ -22,6 +22,7 @@ namespace Barotrauma
private GUIFrame menu;
private GUIListBox serverList;
private GUIListBox serverPreview;
private GUIButton joinButton;
@@ -45,37 +46,31 @@ namespace Barotrauma
public ServerListScreen()
{
int width = Math.Min(GameMain.GraphicsWidth - 160, 1000);
int height = Math.Min(GameMain.GraphicsHeight - 160, 700);
menu = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.8f), GUI.Canvas, Anchor.Center) { MinSize = new Point(GameMain.GraphicsHeight, 0) });
Rectangle panelRect = new Rectangle(0, 0, width, height);
menu = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, Anchor.Center));
new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.133f), menu.RectTransform, Anchor.TopCenter),
TextManager.Get("JoinServer"), textAlignment: Alignment.Left, font: GUI.LargeFont) { ForceUpperCase = true };
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), menu.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.03f) }, style: null);
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.95f), menu.RectTransform, Anchor.Center), isHorizontal: true)
{ Stretch = true, RelativeSpacing = 0.02f };
//-------------------------------------------------------------------------------------
//left column
//-------------------------------------------------------------------------------------
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 0.92f), paddedFrame.RectTransform, Anchor.TopLeft));
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 1.0f), paddedFrame.RectTransform, Anchor.CenterLeft)) { Stretch = true, RelativeSpacing = 0.5f };
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), leftColumn.RectTransform), style: null);
var infoHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), leftColumn.RectTransform)) { RelativeSpacing = 0.05f };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("YourName"));
clientNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.045f), leftColumn.RectTransform), "")
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), infoHolder.RectTransform, Anchor.Center), TextManager.Get("JoinServer"), font: GUI.LargeFont)
{ ForceUpperCase = true };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoHolder.RectTransform), TextManager.Get("YourName"));
clientNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.13f), infoHolder.RectTransform), "")
{
Text = GameMain.Config.DefaultPlayerName
};
clientNameBox.OnTextChanged += RefreshJoinButtonState;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("ServerIP"));
// TODO: Show IP on server info window
ipBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.045f), leftColumn.RectTransform), "");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoHolder.RectTransform), TextManager.Get("ServerIP"));
ipBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.13f), infoHolder.RectTransform), "");
ipBox.OnTextChanged += RefreshJoinButtonState;
ipBox.OnSelected += (sender, key) =>
{
@@ -85,43 +80,53 @@ namespace Barotrauma
sender.UserData = null;
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.45f), leftColumn.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterServers"));
searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), "");
var filterHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), leftColumn.RectTransform)) { RelativeSpacing = 0.05f };
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), leftColumn.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), filterHolder.RectTransform), TextManager.Get("FilterServers"));
searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.13f), filterHolder.RectTransform), "");
var tickBoxHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), filterHolder.RectTransform));
searchBox.OnTextChanged += (txtBox, txt) => { FilterServers(); return true; };
filterPassword = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterPassword"));
filterPassword = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.27f), tickBoxHolder.RectTransform), TextManager.Get("FilterPassword"));
filterPassword.OnSelected += (tickBox) => { FilterServers(); return true; };
filterIncompatible = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterIncompatibleServers"));
filterIncompatible = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.27f), tickBoxHolder.RectTransform), TextManager.Get("FilterIncompatibleServers"));
filterIncompatible.OnSelected += (tickBox) => { FilterServers(); return true; };
filterFull = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterFullServers"));
filterFull = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.27f), tickBoxHolder.RectTransform), TextManager.Get("FilterFullServers"));
filterFull.OnSelected += (tickBox) => { FilterServers(); return true; };
filterEmpty = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterEmptyServers"));
filterEmpty = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.27f), tickBoxHolder.RectTransform), TextManager.Get("FilterEmptyServers"));
filterEmpty.OnSelected += (tickBox) => { FilterServers(); return true; };
//-------------------------------------------------------------------------------------
//right column
//-------------------------------------------------------------------------------------
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - leftColumn.RectTransform.RelativeSize.X - 0.017f, 0.97f),
paddedFrame.RectTransform, Anchor.TopRight))
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - leftColumn.RectTransform.RelativeSize.X - 0.017f, 1.0f),
paddedFrame.RectTransform, Anchor.CenterRight))
{
RelativeSpacing = 0.02f,
Stretch = true
};
serverList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.85f), rightColumn.RectTransform, Anchor.Center))
var serverListHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform)) { Stretch = true, RelativeSpacing = 0.02f };
serverList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), serverListHolder.RectTransform, Anchor.Center))
{
OnSelected = SelectServer
OnSelected = (btn, obj) => {
ServerInfo serverInfo = (ServerInfo)obj;
serverInfo.CreatePreviewWindow(serverPreview);
return true;
}
};
serverList.OnSelected += SelectServer;
serverPreview = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), serverListHolder.RectTransform, Anchor.Center));
columnRelativeWidth = new float[] { 0.04f, 0.02f, 0.044f, 0.77f, 0.02f, 0.075f, 0.06f };
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.075f), rightColumn.RectTransform), style: null);
@@ -239,6 +244,7 @@ namespace Barotrauma
{
if (waitingForRefresh) return false;
serverList.ClearChildren();
serverPreview.ClearChildren();
ipBox.Text = null;
joinButton.Enabled = false;
@@ -352,7 +358,7 @@ namespace Barotrauma
private void AddToServerList(ServerInfo serverInfo)
{
var serverFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), serverList.Content.RectTransform) { MinSize = new Point(0, 20) },
var serverFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), serverList.Content.RectTransform) { MinSize = new Point(0, 35) },
style: "InnerFrame", color: Color.White * 0.5f)
{
UserData = serverInfo
@@ -390,19 +396,6 @@ namespace Barotrauma
UserData = "password"
};
new GUIButton(new RectTransform(new Vector2(columnRelativeWidth[2], 0.8f), serverContent.RectTransform, Anchor.Center), style: "GUIButtonServerListInfo") {
ToolTip = TextManager.Get("ServerListInfo"),
OnClicked = (btn, obj) => {
SelectServer(null, serverInfo);
var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel"), TextManager.Get("ServerListJoin") }, 550, 400);
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += JoinServer;
msgBox.Buttons[1].OnClicked += msgBox.Close;
serverInfo.CreatePreviewWindow(msgBox);
return true;
}
};
var serverName = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[3], 1.0f), serverContent.RectTransform), serverInfo.ServerName, style: "GUIServerListTextBox");
var gameStartedBox = new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[4], 0.4f), serverContent.RectTransform, Anchor.Center),

View File

@@ -329,6 +329,8 @@ namespace Barotrauma
{
element.Elements("sprite").ForEach(s => CreateSprite(s));
element.Elements("Sprite").ForEach(s => CreateSprite(s));
element.Elements("backgroundsprite").ForEach(s => CreateSprite(s));
element.Elements("BackgroundSprite").ForEach(s => CreateSprite(s));
element.Elements("brokensprite").ForEach(s => CreateSprite(s));
element.Elements("BrokenSprite").ForEach(s => CreateSprite(s));
element.Elements("containedsprite").ForEach(s => CreateSprite(s));

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;
namespace Barotrauma
@@ -130,7 +131,7 @@ namespace Barotrauma
OutlineColor = new Color(72, 124, 77, 255),
OnClicked = (btn, userdata) =>
{
System.Diagnostics.Process.Start("steam://url/SteamWorkshopPage/" + SteamManager.AppID);
SteamManager.OverlayCustomURL("steam://url/SteamWorkshopPage/" + SteamManager.AppID);
return true;
}
};
@@ -369,7 +370,7 @@ namespace Barotrauma
catch (Exception e)
{
pendingPreviewImageDownloads.Remove(item.PreviewImageUrl);
DebugConsole.ThrowError("Downloading the preview image of the Workshop item \"" + item.Title + "\" failed.", e);
DebugConsole.ThrowError("Downloading the preview image of the Workshop item \"" + EnsureUTF8(item.Title) + "\" failed.", e);
}
}
@@ -380,7 +381,7 @@ namespace Barotrauma
CanBeFocused = false
};
var titleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), rightColumn.RectTransform), item.Title, textAlignment: Alignment.CenterLeft, wrap: true)
var titleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), rightColumn.RectTransform), EnsureUTF8(item.Title), textAlignment: Alignment.CenterLeft, wrap: true)
{
CanBeFocused = false
};
@@ -397,14 +398,14 @@ namespace Barotrauma
{
if (SteamManager.UpdateWorkshopItem(item, out string errorMsg))
{
new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title));
new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", EnsureUTF8(item.Title)));
}
else
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg));
TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", EnsureUTF8(item.Title)).Replace("[errormessage]", errorMsg));
}
btn.Enabled = false;
btn.Visible = false;
@@ -593,6 +594,7 @@ namespace Barotrauma
{
tickBox.Enabled = false;
}
GameMain.Config.EnsureCoreContentPackageSelected();
}
if (updateButton != null)
{
@@ -623,11 +625,11 @@ namespace Barotrauma
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.005f), content.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), item.Title, textAlignment: Alignment.TopLeft, font: GUI.LargeFont, wrap: true);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), EnsureUTF8(item.Title), textAlignment: Alignment.TopLeft, font: GUI.LargeFont, wrap: true);
var creatorHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), content.RectTransform)) { IsHorizontal = true, Stretch = true };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), creatorHolder.RectTransform), TextManager.Get("WorkshopItemCreator") + ": " + item.OwnerName, textAlignment: Alignment.BottomLeft, wrap: true);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), creatorHolder.RectTransform), TextManager.Get("WorkshopItemCreator") + ": " + EnsureUTF8(item.OwnerName), textAlignment: Alignment.BottomLeft, wrap: true);
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), creatorHolder.RectTransform, Anchor.BottomRight), TextManager.Get("WorkshopShowItemInSteam"), style: null)
{
@@ -637,7 +639,7 @@ namespace Barotrauma
OutlineColor = new Color(72, 124, 77, 255),
OnClicked = (btn, userdata) =>
{
System.Diagnostics.Process.Start("steam://url/CommunityFilePage/" + item.Id);
SteamManager.OverlayCustomURL("steam://url/CommunityFilePage/" + item.Id);
return true;
}
};
@@ -660,7 +662,7 @@ namespace Barotrauma
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), descriptionContainer.Content.RectTransform) { MinSize = new Point(0, 5) }, style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), descriptionContainer.Content.RectTransform), item.Description, wrap: true)
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), descriptionContainer.Content.RectTransform), EnsureUTF8(item.Description), wrap: true)
{
CanBeFocused = false
};
@@ -738,25 +740,28 @@ namespace Barotrauma
itemEditor.Tags.Add("Submarine");
itemEditor.Description = sub.Description;
string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName));
try
if (sub.PreviewImage != null)
{
using (Stream s = File.Create(previewImagePath))
string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName));
try
{
sub.PreviewImage.Texture.SaveAsPng(s, (int)sub.PreviewImage.size.X, (int)sub.PreviewImage.size.Y);
itemEditor.PreviewImage = previewImagePath;
using (Stream s = File.Create(previewImagePath))
{
sub.PreviewImage.Texture.SaveAsPng(s, (int)sub.PreviewImage.size.X, (int)sub.PreviewImage.size.Y);
itemEditor.PreviewImage = previewImagePath;
}
if (new FileInfo(previewImagePath).Length > 1024 * 1024)
{
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge"));
itemEditor.PreviewImage = SteamManager.DefaultPreviewImagePath;
}
}
if (new FileInfo(previewImagePath).Length > 1024 * 1024)
catch (Exception e)
{
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge"));
itemEditor.PreviewImage = SteamManager.DefaultPreviewImagePath;
DebugConsole.ThrowError("Saving submarine preview image failed.", e);
itemEditor.PreviewImage = null;
}
}
catch (Exception e)
{
DebugConsole.ThrowError("Saving submarine preview image failed.", e);
itemEditor.PreviewImage = null;
}
}
private void CreateWorkshopItem(ContentPackage contentPackage)
{
@@ -793,7 +798,7 @@ namespace Barotrauma
if (!item.Installed)
{
new GUIMessageBox(TextManager.Get("Error"),
TextManager.Get("WorkshopErrorInstallRequiredToEdit").Replace("[itemname]", item.Title));
TextManager.Get("WorkshopErrorInstallRequiredToEdit").Replace("[itemname]", EnsureUTF8(item.Title)));
return;
}
SteamManager.CreateWorkshopItemStaging(item, out itemEditor, out itemContentPackage);
@@ -1228,7 +1233,7 @@ namespace Barotrauma
string pleaseWaitText = TextManager.Get("WorkshopPublishPleaseWait");
var msgBox = new GUIMessageBox(
pleaseWaitText,
TextManager.Get("WorkshopPublishInProgress").Replace("[itemname]", item.Title),
TextManager.Get("WorkshopPublishInProgress").Replace("[itemname]", EnsureUTF8(item.Title)),
new string[] { TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
@@ -1250,13 +1255,13 @@ namespace Barotrauma
if (string.IsNullOrEmpty(item.Error))
{
new GUIMessageBox("", TextManager.Get("WorkshopItemPublished").Replace("[itemname]", item.Title));
new GUIMessageBox("", TextManager.Get("WorkshopItemPublished").Replace("[itemname]", EnsureUTF8(item.Title)));
}
else
{
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.Get("WorkshopItemPublishFailed").Replace("[itemname]", item.Title) + item.Error);
TextManager.Get("WorkshopItemPublishFailed").Replace("[itemname]", EnsureUTF8(item.Title)) + item.Error);
}
createItemFrame.ClearChildren();
@@ -1285,6 +1290,12 @@ namespace Barotrauma
{
}
private string EnsureUTF8(string text)
{
byte[] bytes = Encoding.Default.GetBytes(text);
return Encoding.UTF8.GetString(bytes);
}
#endregion
}
}

View File

@@ -183,6 +183,12 @@ namespace Barotrauma
TextGetter = GetSubName
};
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), paddedTopPanel.RectTransform, Anchor.CenterRight), style: "GUINotificationButton")
{
OnClicked = (btn, userdata) => { GameMain.Instance.ShowEditorDisclaimer(); return true; }
};
disclaimerBtn.RectTransform.MaxSize = new Point(disclaimerBtn.Rect.Height);
linkedSubBox = new GUIDropDown(new RectTransform(new Vector2(0.15f, 0.9f), paddedTopPanel.RectTransform) { RelativeOffset = new Vector2(0.385f, 0.0f) },
TextManager.Get("AddSubButton"), elementCount: 20)
{
@@ -310,6 +316,12 @@ namespace Barotrauma
RelativeSpacing = 0.01f,
Stretch = true
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), tabButtonHolder.RectTransform), TextManager.Get("MapEntityCategory.All"), style: "GUITabButton")
{
OnClicked = (btn, userdata) => { ClearFilter(); return true; }
};
foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory)))
{
entityCategoryButtons.Add(new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), tabButtonHolder.RectTransform),
@@ -446,9 +458,10 @@ namespace Barotrauma
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), showEntitiesHolder.RectTransform) { MinSize = new Point(0, 3) }, style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(10, 0) }, TextManager.Get("PreviouslyUsedLabel"));
previouslyUsedList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(10, 0) })
new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.025f), paddedLeftPanel.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(10, 0) }, TextManager.Get("PreviouslyUsedLabel"));
previouslyUsedList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform, Anchor.BottomCenter))
{
ScrollBarVisible = true,
OnSelected = SelectPrefab
};
@@ -620,6 +633,10 @@ namespace Barotrauma
cam.UpdateTransform();
GameAnalyticsManager.SetCustomDimension01("editor");
if (!GameMain.Config.EditorDisclaimerShown)
{
GameMain.Instance.ShowEditorDisclaimer();
}
}
public override void Deselect()
@@ -832,8 +849,10 @@ namespace Barotrauma
}
string savePath = nameBox.Text + ".sub";
string prevSavePath = null;
if (Submarine.MainSub != null)
{
prevSavePath = Submarine.MainSub.FilePath;
savePath = Path.Combine(Path.GetDirectoryName(Submarine.MainSub.FilePath), savePath);
}
else
@@ -872,6 +891,10 @@ namespace Barotrauma
GUI.AddMessage(TextManager.Get("SubSavedNotification").Replace("[filepath]", Submarine.MainSub.FilePath), Color.Green);
Submarine.RefreshSavedSub(savePath);
if (prevSavePath != null && prevSavePath != savePath)
{
Submarine.RefreshSavedSub(prevSavePath);
}
linkedSubBox.ClearChildren();
foreach (Submarine sub in Submarine.SavedSubmarines)
@@ -1011,7 +1034,7 @@ namespace Barotrauma
var previewImageButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageGenerate"))
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageCreate"))
{
OnClicked = (btn, userdata) =>
{
@@ -1263,9 +1286,8 @@ namespace Barotrauma
{
if (CharacterMode) SetCharacterMode(false);
if (WiringMode) SetWiringMode(false);
Submarine.RefreshSavedSubs();
loadFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
{
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) loadFrame = null; return true; },
@@ -1273,10 +1295,15 @@ namespace Barotrauma
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.36f), loadFrame.RectTransform, Anchor.Center) { MinSize = new Point(350, 500) });
var paddedLoadFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center)) { Stretch = true, RelativeSpacing = 0.05f };
var paddedLoadFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center)) { Stretch = true, RelativeSpacing = 0.02f };
var deleteButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedLoadFrame.RectTransform, Anchor.Center));
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedLoadFrame.RectTransform), isHorizontal: true)
{
Stretch = true
};
var subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedLoadFrame.RectTransform))
{
ScrollBarVisible = true,
@@ -1287,6 +1314,17 @@ namespace Barotrauma
}
};
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font);
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
var clearButton = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), filterContainer.RectTransform), "x")
{
OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterSubs(subList, ""); searchBox.Flash(Color.White); return true; }
};
foreach (Submarine sub in Submarine.SavedSubmarines)
{
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
@@ -1347,6 +1385,16 @@ namespace Barotrauma
return true;
}
private void FilterSubs(GUIListBox subList, string filter)
{
foreach (GUIComponent child in subList.Content.Children)
{
var sub = child.UserData as Submarine;
if (sub == null) { return; }
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.Name.ToLower().Contains(filter.ToLower());
}
}
private bool LoadSub(GUIButton button, object obj)
{
if (loadFrame == null)
@@ -1415,6 +1463,7 @@ namespace Barotrauma
{
sub.Remove();
File.Delete(sub.FilePath);
Submarine.RefreshSavedSubs();
CreateLoadScreen();
}
catch (Exception e)

View File

@@ -277,13 +277,17 @@ namespace Barotrauma
{
component.RectTransform.Parent = layoutGroup.RectTransform;
component.RectTransform.RepositionChildInHierarchy(childIndex);
Recalculate();
}
public void Recalculate()
{
int contentHeight = ContentHeight;
RectTransform.NonScaledSize = new Point(RectTransform.NonScaledSize.X, contentHeight);
layoutGroup.RectTransform.NonScaledSize = new Point(layoutGroup.RectTransform.NonScaledSize.X, contentHeight);
}
private GUIComponent CreateNewField(SerializableProperty property, ISerializableEntity entity)
public GUIComponent CreateNewField(SerializableProperty property, ISerializableEntity entity)
{
object value = property.GetValue(entity);
if (property.PropertyType == typeof(string) && value == null)
@@ -351,7 +355,7 @@ namespace Barotrauma
return propertyField;
}
private GUIComponent CreateBoolField(ISerializableEntity entity, SerializableProperty property, bool value, string displayName, string toolTip)
public GUIComponent CreateBoolField(ISerializableEntity entity, SerializableProperty property, bool value, string displayName, string toolTip)
{
GUITickBox propertyTickBox = new GUITickBox(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), displayName)
{
@@ -367,11 +371,11 @@ namespace Barotrauma
return true;
}
};
Fields.Add(property.Name, new GUIComponent[] { propertyTickBox });
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { propertyTickBox }); }
return propertyTickBox;
}
private GUIComponent CreateIntField(ISerializableEntity entity, SerializableProperty property, int value, string displayName, string toolTip)
public GUIComponent CreateIntField(ISerializableEntity entity, SerializableProperty property, int value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -395,11 +399,11 @@ namespace Barotrauma
TrySendNetworkUpdate(entity, property);
}
};
Fields.Add(property.Name, new GUIComponent[] { numberInput });
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { numberInput }); }
return frame;
}
private GUIComponent CreateFloatField(ISerializableEntity entity, SerializableProperty property, float value, string displayName, string toolTip)
public GUIComponent CreateFloatField(ISerializableEntity entity, SerializableProperty property, float value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -425,11 +429,11 @@ namespace Barotrauma
TrySendNetworkUpdate(entity, property);
}
};
Fields.Add(property.Name, new GUIComponent[] { numberInput });
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { numberInput }); }
return frame;
}
private GUIComponent CreateEnumField(ISerializableEntity entity, SerializableProperty property, object value, string displayName, string toolTip)
public GUIComponent CreateEnumField(ISerializableEntity entity, SerializableProperty property, object value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -454,11 +458,11 @@ namespace Barotrauma
return true;
};
enumDropDown.SelectItem(value);
Fields.Add(property.Name, new GUIComponent[] { enumDropDown });
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { enumDropDown }); }
return frame;
}
private GUIComponent CreateEnumFlagField(ISerializableEntity entity, SerializableProperty property, object value, string displayName, string toolTip)
public GUIComponent CreateEnumFlagField(ISerializableEntity entity, SerializableProperty property, object value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -487,22 +491,26 @@ namespace Barotrauma
return true;
};
Fields.Add(property.Name, new GUIComponent[] { enumDropDown });
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { enumDropDown }); }
return frame;
}
private GUIComponent CreateStringField(ISerializableEntity entity, SerializableProperty property, string value, string displayName, string toolTip)
public GUIComponent CreateStringField(ISerializableEntity entity, SerializableProperty property, string value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), color: Color.Transparent);
var frame = new GUILayoutGroup(new RectTransform(new Point(Rect.Width, elementHeight), layoutGroup.RectTransform), isHorizontal: true)
{
Stretch = true
};
var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: GUI.SmallFont, textAlignment: Alignment.Left)
{
ToolTip = toolTip
};
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform, Anchor.TopRight))
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1), frame.RectTransform))
{
ToolTip = toolTip,
Font = GUI.SmallFont,
Text = value,
OverflowClip = true,
OnEnterPressed = (textBox, text) =>
{
if (property.TrySetValue(entity, text))
@@ -514,11 +522,36 @@ namespace Barotrauma
return true;
}
};
Fields.Add(property.Name, new GUIComponent[] { propertyBox });
string translationTextTag = property.GetAttribute<Serialize>()?.translationTextTag;
if (translationTextTag != null)
{
new GUIButton(new RectTransform(new Vector2(0.1f, 1), frame.RectTransform, Anchor.TopRight), "...")
{
OnClicked = (bt, userData) => { CreateTextPicker(translationTextTag, entity, property, propertyBox); return true; }
};
propertyBox.OnTextChanged += (tb, text) =>
{
string translatedText = TextManager.Get(text, returnNull: true);
if (translatedText == null)
{
propertyBox.TextColor = Color.Gray;
propertyBox.ToolTip = TextManager.Get("StringPropertyCannotTranslate").Replace("[tag]", text ?? "");
}
else
{
propertyBox.TextColor = Color.LightGreen;
propertyBox.ToolTip = TextManager.Get("StringPropertyTranslate").Replace("[translation]", translatedText);
}
return true;
};
propertyBox.Text = value;
}
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { propertyBox }); }
return frame;
}
private GUIComponent CreatePointField(ISerializableEntity entity, SerializableProperty property, Point value, string displayName, string toolTip)
public GUIComponent CreatePointField(ISerializableEntity entity, SerializableProperty property, Point value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -566,11 +599,11 @@ namespace Barotrauma
};
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
private GUIComponent CreateVector2Field(ISerializableEntity entity, SerializableProperty property, Vector2 value, string displayName, string toolTip)
public GUIComponent CreateVector2Field(ISerializableEntity entity, SerializableProperty property, Vector2 value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -620,11 +653,11 @@ namespace Barotrauma
};
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
private GUIComponent CreateVector3Field(ISerializableEntity entity, SerializableProperty property, Vector3 value, string displayName, string toolTip)
public GUIComponent CreateVector3Field(ISerializableEntity entity, SerializableProperty property, Vector3 value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -678,11 +711,11 @@ namespace Barotrauma
};
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
private GUIComponent CreateVector4Field(ISerializableEntity entity, SerializableProperty property, Vector4 value, string displayName, string toolTip)
public GUIComponent CreateVector4Field(ISerializableEntity entity, SerializableProperty property, Vector4 value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -740,14 +773,14 @@ namespace Barotrauma
};
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
private GUIComponent CreateColorField(ISerializableEntity entity, SerializableProperty property, Color value, string displayName, string toolTip)
public GUIComponent CreateColorField(ISerializableEntity entity, SerializableProperty property, Color value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform) { MinSize = new Point(80, 26)}, displayName, font: GUI.SmallFont)
var label = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform) { MinSize = new Point(80, 26) }, displayName, font: GUI.SmallFont)
{
ToolTip = toolTip
};
@@ -807,11 +840,11 @@ namespace Barotrauma
colorBox.Color = (Color)property.GetValue(entity);
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
private GUIComponent CreateRectangleField(ISerializableEntity entity, SerializableProperty property, Rectangle value, string displayName, string toolTip)
public GUIComponent CreateRectangleField(ISerializableEntity entity, SerializableProperty property, Rectangle value, string displayName, string toolTip)
{
var frame = new GUIFrame(new RectTransform(new Point(Rect.Width, Math.Max(elementHeight, 26)), layoutGroup.RectTransform), color: Color.Transparent);
var label = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), frame.RectTransform), displayName, font: GUI.SmallFont)
@@ -867,9 +900,43 @@ namespace Barotrauma
};
fields[i] = numberInput;
}
Fields.Add(property.Name, fields);
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
return frame;
}
public void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox)
{
var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel") }, width: 300, height: 400);
msgBox.Buttons[0].OnClicked = msgBox.Close;
var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter))
{
OnSelected = (component, userData) =>
{
string text = userData as string ?? "";
if (property.TrySetValue(entity, text))
{
TrySendNetworkUpdate(entity, property);
textBox.Text = (string)property.GetValue(entity);
textBox.Deselect();
}
return true;
}
};
textTag = textTag.ToLowerInvariant();
var tagTextPairs = TextManager.GetAllTagTextPairs();
foreach (KeyValuePair<string, string> tagTextPair in tagTextPairs)
{
if (!tagTextPair.Key.StartsWith(textTag)) { continue; }
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), textList.Content.RectTransform) { MinSize = new Point(0, 20) },
ToolBox.LimitString(tagTextPair.Value, GUI.Font, textList.Content.Rect.Width))
{
UserData = tagTextPair.Key
};
}
}
private void TrySendNetworkUpdate(ISerializableEntity entity, SerializableProperty property)
{

View File

@@ -35,6 +35,7 @@ namespace Barotrauma
{
public readonly string File;
public readonly string Type;
public readonly bool DuckVolume;
public readonly Vector2 IntensityRange;
@@ -43,6 +44,7 @@ namespace Barotrauma
this.File = Path.GetFullPath(element.GetAttributeString("file", ""));
this.Type = element.GetAttributeString("type", "").ToLowerInvariant();
this.IntensityRange = element.GetAttributeVector2("intensityrange", new Vector2(0.0f, 100.0f));
this.DuckVolume = element.GetAttributeBool("duckvolume", false);
}
}
@@ -269,6 +271,13 @@ namespace Barotrauma
}
movementSoundVolume = Math.Max(movementSoundVolume, movementFactor);
if (!MathUtils.IsValid(movementSoundVolume))
{
string errorMsg = "Failed to update water ambience volume - submarine's movement value invalid (" + movementSoundVolume + ", sub velocity: " + sub.Velocity + ")";
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
movementSoundVolume = 0.0f;
}
}
if (waterAmbiences.Count > 1)
@@ -442,9 +451,9 @@ namespace Barotrauma
{
PlaySound(
"ambient",
new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y) + Rand.Vector(100.0f),
Rand.Range(0.5f, 1.0f),
1000.0f,
new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y) + Rand.Vector(100.0f));
1000.0f);
ambientSoundTimer = Rand.Range(ambientSoundInterval.X, ambientSoundInterval.Y);
}
@@ -458,23 +467,31 @@ namespace Barotrauma
return matchingSounds[Rand.Int(matchingSounds.Count)];
}
/// <summary>
/// Play a sound defined in a sound xml file without any positional effects.
/// </summary>
public static SoundChannel PlaySound(string soundTag, float volume = 1.0f)
{
var sound = GetSound(soundTag);
return sound?.Play(volume);
}
public static SoundChannel PlaySound(string soundTag, float volume, float range, Vector2 position, Hull hullGuess = null)
/// <summary>
/// Play a sound defined in a sound xml file. If the volume or range parameters are omitted, the volume and range defined in the sound xml are used.
/// </summary>
public static SoundChannel PlaySound(string soundTag, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
{
var sound = GetSound(soundTag);
if (sound == null) return null;
return PlaySound(sound, sound.BaseGain * volume, range, position, hullGuess);
return PlaySound(sound, position, volume ?? sound.BaseGain, range ?? sound.BaseFar, hullGuess);
}
public static SoundChannel PlaySound(Sound sound, float volume, float range, Vector2 position, Hull hullGuess = null)
public static SoundChannel PlaySound(Sound sound, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
{
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > range * range) return null;
return sound.Play(sound.BaseGain * volume, range, position, muffle: ShouldMuffleSound(Character.Controlled, position, range, hullGuess));
float far = range ?? sound.BaseFar;
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > far * far) return null;
return sound.Play(volume ?? sound.BaseGain, far, position, muffle: ShouldMuffleSound(Character.Controlled, position, far, hullGuess));
}
private static void UpdateMusic(float deltaTime)
@@ -508,7 +525,7 @@ namespace Barotrauma
//switch the music if nothing playing atm or the currently playing clip is not suitable anymore
else if (targetMusic[0] == null || currentMusic[0] == null || !suitableMusic.Any(m => m.File == currentMusic[0].Filename))
{
targetMusic[0] = suitableMusic.GetRandom();
targetMusic[0] = suitableMusic.GetRandom();
}
//get the appropriate intensity layers for current situation
@@ -543,6 +560,7 @@ namespace Barotrauma
updateMusicTimer = UpdateMusicInterval;
}
int activeTrackCount = targetMusic.Count(m => m != null);
for (int i = 0; i < MaxMusicChannels; i++)
{
//nothing should be playing on this channel
@@ -582,7 +600,12 @@ namespace Barotrauma
musicChannel[i] = currentMusic[i].Play(0.0f, "music");
musicChannel[i].Looping = true;
}
musicChannel[i].Gain = MathHelper.Lerp(musicChannel[i].Gain, 1.0f, MusicLerpSpeed * deltaTime);
float targetGain = 1.0f;
if (targetMusic[i].DuckVolume)
{
targetGain = (float)Math.Sqrt(1.0f / activeTrackCount);
}
musicChannel[i].Gain = MathHelper.Lerp(musicChannel[i].Gain, targetGain, MusicLerpSpeed * deltaTime);
}
}
}
@@ -650,8 +673,7 @@ namespace Barotrauma
foreach (Character character in Character.CharacterList)
{
if (character.IsDead || !character.Enabled) continue;
EnemyAIController enemyAI = character.AIController as EnemyAIController;
if (enemyAI == null || (!enemyAI.AttackHumans && !enemyAI.AttackRooms)) continue;
if (!(character.AIController is EnemyAIController enemyAI) || (!enemyAI.AttackHumans && !enemyAI.AttackRooms)) continue;
if (targetSubmarine != null)
{
@@ -669,9 +691,16 @@ namespace Barotrauma
}
}
if (GameMain.GameSession != null && Timing.TotalTime < GameMain.GameSession.RoundStartTime + 120.0)
if (GameMain.GameSession != null)
{
return "start";
if (Submarine.Loaded != null && Level.Loaded != null && Submarine.MainSub.AtEndPosition)
{
return "levelend";
}
if (Timing.TotalTime < GameMain.GameSession.RoundStartTime + 120.0)
{
return "start";
}
}
return "default";

View File

@@ -32,6 +32,9 @@ namespace Barotrauma.Sounds
public bool UseRadioFilter;
public bool UseMuffleFilter;
public float Near { get; private set; }
public float Far { get; private set; }
private static BiQuad[] muffleFilters = new BiQuad[]
{
new LowpassFilter(VoipConfig.FREQUENCY, 800)
@@ -41,6 +44,16 @@ namespace Barotrauma.Sounds
new BandpassFilter(VoipConfig.FREQUENCY, 2000)
};
public float Gain
{
get { return soundChannel == null ? 0.0f : soundChannel.Gain; }
set
{
if (soundChannel == null) { return; }
soundChannel.Gain = value;
}
}
public VoipSound(SoundManager owner, VoipQueue q) : base(owner, "voip", true, true)
{
VoipConfig.SetupEncoding();
@@ -64,8 +77,8 @@ namespace Barotrauma.Sounds
public void SetRange(float near, float far)
{
soundChannel.Near = near;
soundChannel.Far = far;
soundChannel.Near = Near = near;
soundChannel.Far = Far = far;
}
public void ApplyFilters(short[] buffer, int readSamples)

View File

@@ -104,14 +104,7 @@ namespace Barotrauma.SpriteDeformations
public Point Resolution
{
get
{
if (deformationParams.Resolution.X != Deformation.GetLength(0) || deformationParams.Resolution.Y != Deformation.GetLength(1))
{
Deformation = new Vector2[deformationParams.Resolution.X, deformationParams.Resolution.Y];
}
return deformationParams.Resolution;
}
get { return deformationParams.Resolution; }
set { SetResolution(value); }
}
@@ -202,6 +195,15 @@ namespace Barotrauma.SpriteDeformations
public static Vector2[,] GetDeformation(IEnumerable<SpriteDeformation> animations, Vector2 scale)
{
foreach (SpriteDeformation animation in animations)
{
if (animation.deformationParams.Resolution.X != animation.Deformation.GetLength(0) ||
animation.deformationParams.Resolution.Y != animation.Deformation.GetLength(1))
{
animation.Deformation = new Vector2[animation.deformationParams.Resolution.X, animation.deformationParams.Resolution.Y];
}
}
Point resolution = animations.First().Resolution;
if (animations.Any(a => a.Resolution != resolution))
{
@@ -211,7 +213,6 @@ namespace Barotrauma.SpriteDeformations
}
Vector2[,] deformation = new Vector2[resolution.X, resolution.Y];
foreach (SpriteDeformation animation in animations)
{
animation.GetDeformation(out Vector2[,] animDeformation, out float multiplier);

View File

@@ -62,7 +62,7 @@ namespace Barotrauma
{
foreach (RoundSound sound in sounds)
{
soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull);
soundChannel = SoundPlayer.PlaySound(sound.Sound, entity.WorldPosition, sound.Volume, sound.Range, hull);
if (soundChannel != null) soundChannel.Looping = loopSound;
}
}
@@ -82,7 +82,7 @@ namespace Barotrauma
selectedSoundIndex = Rand.Int(sounds.Count);
}
var selectedSound = sounds[selectedSoundIndex];
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull);
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, entity.WorldPosition, selectedSound.Volume, selectedSound.Range, hull);
if (soundChannel != null) soundChannel.Looping = loopSound;
}
}

View File

@@ -151,6 +151,7 @@ namespace Barotrauma
for (int i = traitStart + NPCPersonalityTrait.List.Count; i < csvContent.Length; i++) // Conversations
{
string[] presplit = csvContent[i].Split(','); // Handling speaker index fetching, somehow doesn't work with the regex
string[] split = SplitCSV(csvContent[i]);
int emptyFields = 0;
@@ -172,20 +173,20 @@ namespace Barotrauma
continue;
}
string speaker = split[1];
int depthIndex = int.Parse(split[2]);
string speaker = presplit[1];
int depthIndex = int.Parse(presplit[2]);
// 3 = original line
string line = split[4].Replace("\"", "");
string flags = split[5].Replace("\"", "");
string allowedJobs = split[6].Replace("\"", "");
string speakerTags = split[7].Replace("\"", "");
string minIntensity = split[8].Replace("\"", "");
string maxIntensity = split[9].Replace("\"", "");
string minIntensity = split[8].Replace("\"", "").Replace(",", ".");
string maxIntensity = split[9].Replace("\"", "").Replace(",", ".");
string element =
$"{GetIndenting(depthIndex)}" +
$"<Conversation line=\"{line}\" " +
$"{GetVariable("speaker" ,speaker)}" +
$"{GetVariable("speaker", speaker)}" +
$"{GetVariable("flags", flags)}" +
$"{GetVariable("allowedjobs", allowedJobs)}" +
$"{GetVariable("speakertags", speakerTags)}" +

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More