(d9829ac) v0.9.4.0

This commit is contained in:
Regalis
2019-10-24 18:05:42 +02:00
parent 9aa12bcac2
commit b39922a074
319 changed files with 12516 additions and 6815 deletions

View File

@@ -36,6 +36,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\CombatMission.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\Mission.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\MissionMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\MissionPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Fonts\ScalableFont.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameMain.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\CrewManager.cs" />
@@ -193,7 +194,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\BlurEffect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CampaignSetupUI.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CampaignUI.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CharacterEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CharacterEditor\CharacterEditorScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CharacterEditor\Wizard.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\CreditsPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\GameScreen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Screens\LevelEditorScreen.cs" />
@@ -217,6 +219,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\SoundPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\VideoSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sounds\VoipSound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DecorativeSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformableSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\CustomDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\Inflate.cs" />
@@ -227,9 +230,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\Sprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\SpriteSheet.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\StatusEffects\StatusEffect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Traitors\TraitorMissionPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\CrossThread.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\LocalizationCSVtoXML.cs">
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\LocalizationCSVtoXML.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\MathUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\OpenFileDialog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\TextureLoader.cs" />

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.9.3.2")]
[assembly: AssemblyFileVersion("0.9.3.2")]
[assembly: AssemblyVersion("0.9.4.0")]
[assembly: AssemblyFileVersion("0.9.4.0")]

View File

@@ -45,9 +45,6 @@ namespace Barotrauma
case AIState.Eat:
stateColor = Color.Brown;
break;
case AIState.GoTo:
stateColor = Color.Magenta;
break;
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);

View File

@@ -10,7 +10,7 @@ namespace Barotrauma
{
/*if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
{
CurrentOrder = Order.PrefabList.Find(o => o.AITag == "dismissed");
CurrentOrder = Order.GetPrefab("dismissed");
objectiveManager.SetOrder(CurrentOrder, "", null);
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder, null, null);
}*/

View File

@@ -369,12 +369,12 @@ namespace Barotrauma
LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime));
foreach (var deformation in SpriteDeformations)
{
if (character.IsDead && deformation.DeformationParams.StopWhenHostIsDead) { continue; }
if (deformation.DeformationParams.UseMovementSine)
if (character.IsDead && deformation.Params.StopWhenHostIsDead) { continue; }
if (deformation.Params.UseMovementSine)
{
if (this is AnimController animator)
{
deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.DeformationParams.Frequency + MathHelper.Pi * deformation.DeformationParams.SineOffset);
deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.Params.Frequency + MathHelper.Pi * deformation.Params.SineOffset);
}
}
else

View File

@@ -7,10 +7,8 @@ namespace Barotrauma
{
partial class Attack
{
public string StructureSoundType
{
get; private set;
}
[Serialize("StructureBlunt", true), Editable()]
public string StructureSoundType { get; private set; }
private RoundSound sound;
@@ -23,8 +21,6 @@ namespace Barotrauma
DebugConsole.ThrowError("Error in attack ("+element+") - sounds should be defined as child elements, not as attributes.");
return;
}
StructureSoundType = element.GetAttributeString("structuresoundtype", "StructureBlunt");
foreach (XElement subElement in element.Elements())
{

View File

@@ -86,11 +86,7 @@ namespace Barotrauma
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
public string BloodDecalName
{
get;
private set;
}
public string BloodDecalName => Params.BloodDecal;
private List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> BloodEmitters
@@ -137,22 +133,18 @@ namespace Barotrauma
get { return activeObjectiveEntities; }
}
partial void InitProjSpecific(XDocument doc)
partial void InitProjSpecific(XElement mainElement)
{
soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f);
soundInterval = mainElement.GetAttributeFloat("soundinterval", 10.0f);
soundTimer = Rand.Range(0.0f, soundInterval);
BloodDecalName = doc.Root.GetAttributeString("blooddecal", "");
sounds = new List<CharacterSound>();
foreach (XElement subElement in doc.Root.Elements())
Params.Sounds.ForEach(s => sounds.Add(new CharacterSound(s)));
foreach (XElement subElement in mainElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sound":
var characterSound = new CharacterSound(subElement);
if (characterSound.Sound != null) { sounds.Add(characterSound); }
break;
case "damageemitter":
damageEmitters.Add(new ParticleEmitter(subElement));
break;
@@ -216,7 +208,7 @@ namespace Barotrauma
float targetOffsetAmount = 0.0f;
if (moveCam)
{
if (needsAir &&
if (NeedsAir &&
pressureProtection < 80.0f &&
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 0.0f))
{
@@ -351,7 +343,7 @@ namespace Barotrauma
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult)
{
if (attackResult.Damage <= 0) { return; }
if (attackResult.Damage <= 1.0f) { return; }
if (soundTimer < soundInterval * 0.5f)
{
PlaySound(CharacterSound.SoundType.Damage);
@@ -542,7 +534,7 @@ namespace Barotrauma
{
switch (AIController.State)
{
case AIController.AIState.Attack:
case AIState.Attack:
PlaySound(CharacterSound.SoundType.Attack);
break;
default:
@@ -577,6 +569,7 @@ namespace Barotrauma
}
}
CharacterHealth.UpdateClientSpecific(deltaTime);
if (controlled == this)
{
CharacterHealth.UpdateHUD(deltaTime);
@@ -612,7 +605,7 @@ namespace Barotrauma
CharacterHUD.Draw(spriteBatch, this, cam);
if (drawHealth) CharacterHealth.DrawHUD(spriteBatch);
}
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) return;
@@ -713,12 +706,14 @@ namespace Barotrauma
if (IsDead) return;
if (Vitality < MaxVitality * 0.98f && hudInfoVisible)
if (CharacterHealth.DisplayedVitality < MaxVitality * 0.98f && hudInfoVisible)
{
hudInfoAlpha = Math.Max(hudInfoAlpha, Math.Min(CharacterHealth.DamageOverlayTimer, 1.0f));
Vector2 healthBarPos = new Vector2(pos.X - 50, -pos.Y);
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
Vitality / MaxVitality,
Color.Lerp(Color.Red, Color.Green, Vitality / MaxVitality) * 0.8f * hudInfoAlpha,
CharacterHealth.DisplayedVitality / MaxVitality,
Color.Lerp(Color.Red, Color.Green, CharacterHealth.DisplayedVitality / MaxVitality) * 0.8f * hudInfoAlpha,
new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
}
}

View File

@@ -220,7 +220,7 @@ namespace Barotrauma
}
public static CharacterInfo ClientRead(string configPath, IReadMessage inc)
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc)
{
ushort infoID = inc.ReadUInt16();
string newName = inc.ReadString();
@@ -238,7 +238,7 @@ namespace Barotrauma
Dictionary<string, float> skillLevels = new Dictionary<string, float>();
if (!string.IsNullOrEmpty(jobIdentifier))
{
jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier);
jobPrefab = JobPrefab.Get(jobIdentifier);
byte skillCount = inc.ReadByte();
for (int i = 0; i < skillCount; i++)
{
@@ -249,7 +249,7 @@ namespace Barotrauma
}
// TODO: animations
CharacterInfo ch = new CharacterInfo(configPath, newName, jobPrefab, ragdollFile)
CharacterInfo ch = new CharacterInfo(speciesName, newName, jobPrefab, ragdollFile)
{
ID = infoID,
};

View File

@@ -20,13 +20,13 @@ namespace Barotrauma
return;
}
//freeze AI characters if more than 1 seconds have passed since last update from the server
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 1.0f)
//freeze AI characters if more than x seconds have passed since last update from the server
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - NetConfig.FreezeCharacterIfPositionDataMissingDelay)
{
AnimController.Frozen = true;
memState.Clear();
//hide after 2 seconds
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 2.0f)
//hide after y seconds
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - NetConfig.DisableCharacterIfPositionDataMissingDelay)
{
Enabled = false;
return;
@@ -74,7 +74,7 @@ namespace Barotrauma
states = newInput,
intAim = intAngle
};
if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
(!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health)))
{
newMem.interact = focusedItem.ID;
@@ -133,9 +133,9 @@ namespace Barotrauma
{
msg.WriteRangedInteger((int)memInput[i].states, 0, (int)InputNetFlags.MaxVal);
msg.Write(memInput[i].intAim);
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
memInput[i].states.HasFlag(InputNetFlags.Deselect) ||
memInput[i].states.HasFlag(InputNetFlags.Use) ||
memInput[i].states.HasFlag(InputNetFlags.Use) ||
memInput[i].states.HasFlag(InputNetFlags.Health) ||
memInput[i].states.HasFlag(InputNetFlags.Grab))
{
@@ -187,11 +187,11 @@ namespace Barotrauma
bool attackInput = msg.ReadBoolean();
keys[(int)InputType.Attack].Held = attackInput;
keys[(int)InputType.Attack].SetState(false, attackInput);
double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI;
cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f;
TransformCursorPos();
bool ragdollInput = msg.ReadBoolean();
keys[(int)InputType.Ragdoll].Held = ragdollInput;
keys[(int)InputType.Ragdoll].SetState(false, ragdollInput);
@@ -225,7 +225,7 @@ namespace Barotrauma
msg.ReadSingle());
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
Vector2 linearVelocity = new Vector2(
msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12);
@@ -252,9 +252,9 @@ namespace Barotrauma
if (GameMain.Client.Character == this && AllowInput)
{
var posInfo = new CharacterStateInfo(
pos, rotation,
networkUpdateID,
facingRight ? Direction.Right : Direction.Left,
pos, rotation,
networkUpdateID,
facingRight ? Direction.Right : Direction.Left,
selectedCharacter, selectedItem, animation);
while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
@@ -264,11 +264,11 @@ namespace Barotrauma
else
{
var posInfo = new CharacterStateInfo(
pos, rotation,
linearVelocity, angularVelocity,
sendingTime, facingRight ? Direction.Right : Direction.Left,
pos, rotation,
linearVelocity, angularVelocity,
sendingTime, facingRight ? Direction.Right : Direction.Left,
selectedCharacter, selectedItem, animation);
while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
index++;
memState.Insert(index, posInfo);
@@ -359,18 +359,12 @@ namespace Barotrauma
DebugConsole.Log("Received spawn data for " + speciesName);
string configPath = GetConfigFile(speciesName);
if (string.IsNullOrEmpty(configPath))
{
throw new Exception("Error in character spawn data - could not find a config file for the character \"" + configPath + "\"!");
}
Character character = null;
if (noInfo)
{
if (!spawn) return null;
character = Create(configPath, position, seed, null, true);
character = Create(speciesName, position, seed, null, true);
character.ID = id;
}
else
@@ -383,19 +377,13 @@ namespace Barotrauma
if (!spawn) return null;
string infoConfigPath = GetConfigFile(infoSpeciesName);
if (string.IsNullOrEmpty(infoConfigPath))
{
throw new Exception("Error in character spawn data - could not find a config file for the character info \"" + configPath + "\"!");
}
CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);
CharacterInfo info = CharacterInfo.ClientRead(infoConfigPath, inc);
character = Create(configPath, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
character = Create(infoSpeciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
character.ID = id;
character.TeamID = (TeamType)teamID;
if (configPath == HumanConfigFile && character.TeamID != TeamType.FriendlyNPC)
if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC)
{
CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
@@ -421,15 +409,6 @@ namespace Barotrauma
return character;
}
private void ReadTraitorStatus(IReadMessage msg)
{
IsTraitor = msg.ReadBoolean();
if (IsTraitor)
{
TraitorCurrentObjective = msg.ReadString();
}
}
private void ReadStatus(IReadMessage msg)
{
bool isDead = msg.ReadBoolean();

View File

@@ -1,6 +1,4 @@
using System;
using System.Xml.Linq;
using Barotrauma.Sounds;
using Barotrauma.Sounds;
namespace Barotrauma
{
@@ -12,29 +10,18 @@ namespace Barotrauma
}
private readonly RoundSound roundSound;
public readonly CharacterParams.SoundParams Params;
public readonly SoundType Type;
public SoundType Type => Params.State;
public Gender Gender => Params.Gender;
public float Volume => roundSound.Volume;
public float Range => roundSound.Range;
public Sound Sound => roundSound?.Sound;
public float Volume
public CharacterSound(CharacterParams.SoundParams soundParams)
{
get { return roundSound.Volume; }
}
public float Range
{
get { return roundSound.Range; }
}
public Sound Sound
{
get { return roundSound?.Sound; }
}
public readonly Gender Gender;
public CharacterSound(XElement element)
{
roundSound = Submarine.LoadRoundSound(element);
Enum.TryParse(element.GetAttributeString("state", "Idle"), true, out Type);
Enum.TryParse(element.GetAttributeString("gender", "None"), true, out Gender);
Params = soundParams;
roundSound = Submarine.LoadRoundSound(soundParams.Element);
}
}
}

View File

@@ -95,6 +95,8 @@ namespace Barotrauma
private const float UpdateDisplayedAfflictionsInterval = 0.5f;
private List<Affliction> currentDisplayedAfflictions = new List<Affliction>();
public float DisplayedVitality, DisplayVitalityDelay;
public bool MouseOnElement
{
get { return highlightedLimbIndex > -1 || GUI.MouseOn == dropItemArea; }
@@ -159,6 +161,8 @@ namespace Barotrauma
partial void InitProjSpecific(XElement element, Character character)
{
DisplayedVitality = MaxVitality;
if (strengthTexts == null)
{
strengthTexts = new string[]
@@ -349,15 +353,17 @@ namespace Barotrauma
private void OnAttacked(Character attacker, AttackResult attackResult)
{
if (Math.Abs(attackResult.Damage) < 0.01f && attackResult.Afflictions.Count == 0) return;
if (Math.Abs(attackResult.Damage) < 0.01f && attackResult.Afflictions.Count == 0) { return; }
DamageOverlayTimer = MathHelper.Clamp(attackResult.Damage / MaxVitality, DamageOverlayTimer, 1.0f);
if (healthShadowDelay <= 0.0f) healthShadowDelay = 1.0f;
if (healthShadowDelay <= 0.0f) { healthShadowDelay = 1.0f; }
if (healthBarPulsateTimer <= 0.0f) healthBarPulsatePhase = 0.0f;
if (healthBarPulsateTimer <= 0.0f) { healthBarPulsatePhase = 0.0f; }
healthBarPulsateTimer = 1.0f;
float additionalIntensity = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, 0.1f, attackResult.Damage / MaxVitality));
damageIntensity = MathHelper.Clamp(damageIntensity + additionalIntensity, 0, 1);
DisplayVitalityDelay = 0.5f;
}
private void UpdateAlignment()
@@ -435,6 +441,35 @@ namespace Barotrauma
uiScale = GUI.Scale;
}
public void UpdateClientSpecific(float deltaTime)
{
if (GameMain.NetworkMember == null)
{
DisplayedVitality = Vitality;
}
else
{
DisplayVitalityDelay -= deltaTime;
if (DisplayVitalityDelay <= 0.0f)
{
DisplayedVitality = Vitality;
}
}
if (damageIntensity > 0)
{
damageIntensity -= deltaTime * damageIntensityDropdownRate;
if (damageIntensity < 0)
{
damageIntensity = 0;
}
}
if (DamageOverlayTimer > 0.0f)
{
DamageOverlayTimer -= deltaTime;
}
}
partial void UpdateOxygenProjSpecific(float prevOxygen)
{
if (prevOxygen > 0.0f && OxygenAmount <= 0.0f &&
@@ -492,20 +527,7 @@ namespace Barotrauma
});
updateDisplayedAfflictionsTimer = UpdateDisplayedAfflictionsInterval;
}
if (DamageOverlayTimer > 0.0f)
{
DamageOverlayTimer -= deltaTime;
}
if (damageIntensity > 0)
{
damageIntensity -= deltaTime * damageIntensityDropdownRate;
if (damageIntensity < 0)
{
damageIntensity = 0;
}
}
if (healthShadowDelay > 0.0f)
{
healthShadowDelay -= deltaTime;
@@ -639,12 +661,12 @@ namespace Barotrauma
}
else
{
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(Vitality / MaxVitality, Color.Red, Color.Orange, Color.Green);
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, Color.Red, Color.Orange, Color.Green);
healthBar.HoverColor = healthWindowHealthBar.HoverColor = healthBar.Color * 2.0f;
healthBar.BarSize = healthWindowHealthBar.BarSize =
(Vitality > 0.0f) ?
(MaxVitality > 0.0f ? Vitality / MaxVitality : 0.0f) :
(Math.Abs(MinVitality) > 0.0f ? 1.0f - Vitality / MinVitality : 0.0f);
(DisplayedVitality > 0.0f) ?
(MaxVitality > 0.0f ? DisplayedVitality / MaxVitality : 0.0f) :
(Math.Abs(MinVitality) > 0.0f ? 1.0f - DisplayedVitality / MinVitality : 0.0f);
if (healthBarPulsateTimer > 0.0f)
{
@@ -1446,6 +1468,9 @@ namespace Barotrauma
}
}
}
CalculateVitality();
DisplayedVitality = Vitality;
}
partial void UpdateLimbAfflictionOverlays()

View File

@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework;
using System.Linq;
namespace Barotrauma
{
@@ -29,13 +30,18 @@ namespace Barotrauma
}
var itemContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.5f), paddedFrame.RectTransform, Anchor.TopRight)
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) });
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) })
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
TextManager.Get("Items", fallBackTag: "mapentitycategory.equipment"), font: GUI.LargeFont);
foreach (string itemName in ItemNames)
foreach (string itemName in ItemNames.Distinct())
{
int count = ItemNames.Count(i => i == itemName);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
" - " + itemName, font: GUI.SmallFont);
" - " + (count == 1 ? itemName : itemName + " x" + count),
font: GUI.SmallFont);
}
return backFrame;

View File

@@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -18,8 +20,9 @@ namespace Barotrauma
{
public void UpdateDeformations(float deltaTime)
{
float jointMidAngle = (LowerLimit + UpperLimit) / 2.0f;
float jointAngle = this.JointAngle - jointMidAngle;
float diff = Math.Abs(UpperLimit - LowerLimit);
float strength = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, MathHelper.Pi, diff));
float jointAngle = this.JointAngle * strength;
JointBendDeformation limbADeformation = LimbA.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
JointBendDeformation limbBDeformation = LimbB.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
@@ -28,7 +31,6 @@ namespace Barotrauma
{
UpdateBend(LimbA, limbADeformation, this.LocalAnchorA, -jointAngle);
UpdateBend(LimbB, limbBDeformation, this.LocalAnchorB, jointAngle);
}
void UpdateBend(Limb limb, JointBendDeformation deformation, Vector2 localAnchor, float angle)
@@ -74,6 +76,14 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch)
{
// TODO: move this into the character editor
//var mouthPos = ragdoll.GetMouthPosition();
//if (mouthPos != null)
//{
// var pos = ConvertUnits.ToDisplayUnits(mouthPos.Value);
// pos.Y = -pos.Y;
// ShapeExtensions.DrawPoint(spriteBatch, pos, Color.Red, size: 5);
//}
return;
// A debug visualisation on the bezier curve between limbs.
var start = LimbA.WorldPosition;
@@ -110,6 +120,9 @@ namespace Barotrauma
public Sprite Sprite { get; protected set; }
public DeformableSprite DeformSprite { get; protected set; }
public List<DecorativeSprite> DecorativeSprites { get; private set; } = new List<DecorativeSprite>();
public Sprite ActiveSprite
{
get
@@ -130,32 +143,23 @@ namespace Barotrauma
public WearableSprite HuskSprite { get; private set; }
public WearableSprite HerpesSprite { get; private set; }
public void LoadHuskSprite()
{
var info = character.Info;
if (info == null) { return; }
var element = info.FilterByTypeAndHeadID(character.Info.FilterElementsByGenderAndRace(character.Info.Wearables), WearableType.Husk).FirstOrDefault();
if (element != null)
{
HuskSprite = new WearableSprite(element.Element("sprite"), WearableType.Husk);
}
}
public void LoadHerpesSprite()
{
var info = character.Info;
if (info == null) { return; }
var element = info.FilterByTypeAndHeadID(character.Info.FilterElementsByGenderAndRace(character.Info.Wearables), WearableType.Herpes).FirstOrDefault();
if (element != null)
{
HerpesSprite = new WearableSprite(element.Element("sprite"), WearableType.Herpes);
}
}
public void LoadHuskSprite() => HuskSprite = GetWearableSprite(WearableType.Husk);
public void LoadHerpesSprite() => HerpesSprite = GetWearableSprite(WearableType.Herpes);
public float TextureScale => limbParams.Ragdoll.TextureScale;
public float TextureScale => Params.Ragdoll.TextureScale;
public Sprite DamagedSprite { get; private set; }
public List<ConditionalSprite> ConditionalSprites { get; private set; } = new List<ConditionalSprite>();
private Dictionary<DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<DecorativeSprite, SpriteState>();
private Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
class SpriteState
{
public float RotationState;
public float OffsetState;
public bool IsActive = true;
}
public Color InitialLightSourceColor
{
@@ -183,25 +187,38 @@ namespace Barotrauma
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
public string HitSoundTag { get; private set; }
public string HitSoundTag => Params?.Sound?.Tag;
partial void InitProjSpecific(XElement element)
{
for (int i = 0; i < Params.decorativeSpriteParams.Count; i++)
{
var param = Params.decorativeSpriteParams[i];
var decorativeSprite = new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param));
DecorativeSprites.Add(decorativeSprite);
int groupID = decorativeSprite.RandomGroupID;
if (!DecorativeSpriteGroups.ContainsKey(groupID))
{
DecorativeSpriteGroups.Add(groupID, new List<DecorativeSprite>());
}
DecorativeSpriteGroups[groupID].Add(decorativeSprite);
spriteAnimState.Add(decorativeSprite, new SpriteState());
}
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sprite":
Sprite = new Sprite(subElement, "", GetSpritePath(subElement));
Sprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.normalSpriteParams));
break;
case "damagedsprite":
DamagedSprite = new Sprite(subElement, "", GetSpritePath(subElement));
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
break;
case "conditionalsprite":
ConditionalSprites.Add(new ConditionalSprite(subElement, character, file: GetSpritePath(subElement)));
ConditionalSprites.Add(new ConditionalSprite(subElement, character, file: GetSpritePath(subElement, null)));
break;
case "deformablesprite":
DeformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement));
DeformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams));
foreach (XElement animationElement in subElement.Elements())
{
int sync = animationElement.GetAttributeInt("sync", -1);
@@ -231,32 +248,63 @@ namespace Barotrauma
LightSource = new LightSource(subElement);
InitialLightSourceColor = LightSource.Color;
break;
case "sound":
HitSoundTag = subElement.GetAttributeString("tag", "");
if (string.IsNullOrWhiteSpace(HitSoundTag))
{
//legacy support
HitSoundTag = subElement.GetAttributeString("file", "");
}
break;
}
}
}
public void RecreateSprite()
public void RecreateSprites()
{
if (Sprite == null) { return; }
Sprite.Remove();
var source = Sprite.SourceElement;
Sprite = new Sprite(source, file: GetSpritePath(source));
if (Sprite != null)
{
Sprite.Remove();
var source = Sprite.SourceElement;
Sprite = new Sprite(source, file: GetSpritePath(source, Params.normalSpriteParams));
}
if (DeformSprite != null)
{
DeformSprite.Remove();
var source = DeformSprite.Sprite.SourceElement;
DeformSprite = new DeformableSprite(source, filePath: GetSpritePath(source, Params.deformSpriteParams));
}
if (DamagedSprite != null)
{
DamagedSprite.Remove();
var source = DamagedSprite.SourceElement;
DamagedSprite = new Sprite(source, file: GetSpritePath(source, Params.damagedSpriteParams));
}
for (int i = 0; i < ConditionalSprites.Count; i++)
{
var conditionalSprite = ConditionalSprites[i];
conditionalSprite.Remove();
var source = conditionalSprite.SourceElement;
// TODO: lazy load?
ConditionalSprites[i] = new ConditionalSprite(source, character, file: GetSpritePath(source, null));
}
for (int i = 0; i < DecorativeSprites.Count; i++)
{
var decorativeSprite = DecorativeSprites[i];
decorativeSprite.Remove();
var source = decorativeSprite.Sprite.SourceElement;
DecorativeSprites[i] = new DecorativeSprite(source, file: GetSpritePath(source, Params.decorativeSpriteParams[i]));
}
}
private string GetSpritePath(XElement element, SpriteParams spriteParams)
{
string texturePath = element.GetAttributeString("texture", null);
if (string.IsNullOrWhiteSpace(texturePath) && spriteParams != null)
{
texturePath = spriteParams.Ragdoll.Texture;
}
return GetSpritePath(texturePath);
}
/// <summary>
/// Get the full path of a limb sprite, taking into account tags, gender and head id
/// </summary>
private string GetSpritePath(XElement element)
private string GetSpritePath(string texturePath)
{
string spritePath = element.Attribute("texture")?.Value ?? "";
string spritePath = texturePath;
string spritePathWithTags = spritePath;
if (character.Info != null && character.IsHumanoid)
{
@@ -274,16 +322,19 @@ namespace Barotrauma
Path.GetFileNameWithoutExtension(spritePath) + tags + Path.GetExtension(spritePath));
}
}
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
}
partial void LoadParamsProjSpecific()
{
bool isFlipped = dir == Direction.Left;
Sprite?.LoadParams(limbParams.normalSpriteParams, isFlipped);
DamagedSprite?.LoadParams(limbParams.damagedSpriteParams, isFlipped);
DeformSprite?.Sprite.LoadParams(limbParams.deformSpriteParams, isFlipped);
Sprite?.LoadParams(Params.normalSpriteParams, isFlipped);
DamagedSprite?.LoadParams(Params.damagedSpriteParams, isFlipped);
DeformSprite?.Sprite.LoadParams(Params.deformSpriteParams, isFlipped);
for (int i = 0; i < DecorativeSprites.Count; i++)
{
DecorativeSprites[i].Sprite?.LoadParams(Params.decorativeSpriteParams[i], isFlipped);
}
}
partial void AddDamageProjSpecific(Vector2 simPosition, List<Affliction> afflictions, bool playSound, List<DamageModifier> appliedDamageModifiers)
@@ -378,6 +429,8 @@ namespace Barotrauma
LightSource.ParentSub = body.Submarine;
LightSource.Rotation = (dir == Direction.Right) ? body.Rotation : body.Rotation - MathHelper.Pi;
}
UpdateSpriteStates(deltaTime);
}
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
@@ -401,7 +454,14 @@ namespace Barotrauma
body.Dir = Dir;
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
bool enableHuskSprite = character.IsHusk || character.CharacterHealth.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
bool hideLimb = Params.Hide ||
enableHuskSprite && HuskSprite != null && HuskSprite.HideLimb ||
OtherWearables.Any(w => w.HideLimb) ||
wearingItems.Any(w => w != null && w.HideLimb);
// TODO: there's now two calls to this, because body.Draw() method calls this too -> is this an issue?
body.UpdateDrawPosition();
if (!hideLimb)
@@ -418,44 +478,68 @@ namespace Barotrauma
{
DeformSprite.Reset();
}
body.Draw(DeformSprite, cam, Vector2.One * Scale * TextureScale, color);
body.Draw(DeformSprite, cam, Vector2.One * Scale * TextureScale, color, Params.MirrorHorizontally);
}
else
{
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale);
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
}
}
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (LightSource != null)
{
LightSource.Position = body.DrawPosition;
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
}
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
{
DamagedSprite.Draw(spriteBatch,
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
color * Math.Min(damageOverlayStrength, 1.0f), ActiveSprite.Origin,
-body.DrawRotation,
Scale, spriteEffect, ActiveSprite.Depth - 0.0000015f);
}
foreach (var decorativeSprite in DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
var ca = (float)Math.Cos(-body.Rotation);
var sa = (float)Math.Sin(-body.Rotation);
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), color,
-body.Rotation + rotation, Scale, spriteEffect,
depth: decorativeSprite.Sprite.Depth);
}
float depthStep = 0.000001f;
float step = depthStep;
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (Params.MirrorHorizontally)
{
spriteEffect = spriteEffect == SpriteEffects.None ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
if (Params.MirrorVertically)
{
spriteEffect |= SpriteEffects.FlipVertically;
}
if (onlyDrawable == null)
{
if (HerpesSprite != null)
{
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
if (herpesStrength > 0.0f)
{
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
depthStep += 0.000001f;
}
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
depthStep += step;
}
if (HuskSprite != null && (character.SpeciesName == "Humanhusk" || (character.SpeciesName == "Human" &&
character.CharacterHealth.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active)))
if (HuskSprite != null && enableHuskSprite)
{
DrawWearable(HuskSprite, depthStep, spriteBatch, color, spriteEffect);
depthStep += 0.000001f;
depthStep += step;
}
foreach (WearableSprite wearable in OtherWearables)
{
if (wearable.Type == WearableType.Beard && enableHuskSprite && HuskSprite != null) { continue; }
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += 0.000001f;
depthStep += step;
}
}
foreach (WearableSprite wearable in WearingItems)
@@ -463,18 +547,7 @@ namespace Barotrauma
if (onlyDrawable != null && onlyDrawable != wearable) continue;
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += 0.000001f;
}
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
{
float depth = ActiveSprite.Depth - 0.0000015f;
DamagedSprite.Draw(spriteBatch,
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
color * Math.Min(damageOverlayStrength, 1.0f), ActiveSprite.Origin,
-body.DrawRotation,
1.0f, spriteEffect, depth);
depthStep += step;
}
if (GameMain.DebugDraw)
@@ -492,7 +565,7 @@ namespace Barotrauma
from.Y = -from.Y;
Vector2 to = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorB);
to.Y = -to.Y;
var localFront = body.GetLocalFront(MathHelper.ToRadians(limbParams.Ragdoll.SpritesheetOrientation));
var localFront = body.GetLocalFront(Params.GetSpriteOrientation());
var front = ConvertUnits.ToDisplayUnits(body.FarseerBody.GetWorldPoint(localFront));
front.Y = -front.Y;
GUI.DrawLine(spriteBatch, bodyDrawPos, front, Color.Yellow, width: 2);
@@ -503,25 +576,89 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 10, 10), Color.Red, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)front.X, (int)front.Y, 10, 10), Color.Yellow, true);
//Vector2 mainLimbFront = ConvertUnits.ToDisplayUnits(ragdoll.MainLimb.body.FarseerBody.GetWorldPoint(ragdoll.MainLimb.body.GetFrontLocal(MathHelper.ToRadians(ragdoll.RagdollParams.SpritesheetOrientation))));
//Vector2 mainLimbFront = ConvertUnits.ToDisplayUnits(ragdoll.MainLimb.body.FarseerBody.GetWorldPoint(ragdoll.MainLimb.body.GetFrontLocal(MathHelper.ToRadians(limbParams.Orientation))));
//mainLimbFront.Y = -mainLimbFront.Y;
//var mainLimbDrawPos = ragdoll.MainLimb.body.DrawPosition;
//mainLimbDrawPos.Y = -mainLimbDrawPos.Y;
//GUI.DrawLine(spriteBatch, mainLimbDrawPos, mainLimbFront, Color.White, width: 5);
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)mainLimbFront.X, (int)mainLimbFront.Y, 10, 10), Color.Yellow, true);
}
foreach (var modifier in damageModifiers)
DrawDamageModifiers(spriteBatch, cam, bodyDrawPos, isScreenSpace: false);
}
}
private void UpdateSpriteStates(float deltaTime)
{
foreach (int spriteGroup in DecorativeSpriteGroups.Keys)
{
for (int i = 0; i < DecorativeSpriteGroups[spriteGroup].Count; i++)
{
float rotation = -body.TransformedRotation + GetArmorSectorRotationOffset(modifier.ArmorSector) * Dir;
Vector2 forward = VectorExtensions.Forward(rotation);
float size = ConvertUnits.ToDisplayUnits(body.GetSize().Length() / 2);
color = modifier.DamageMultiplier > 1 ? Color.Red : Color.GreenYellow;
GUI.DrawLine(spriteBatch, bodyDrawPos, bodyDrawPos + Vector2.Normalize(forward) * size, color, width: (int)Math.Round(4 / cam.Zoom));
ShapeExtensions.DrawSector(spriteBatch, bodyDrawPos, size, GetArmorSectorSize(modifier.ArmorSector) * Dir, 40, color, rotation + MathHelper.Pi, thickness: 2 / cam.Zoom);
var decorativeSprite = DecorativeSpriteGroups[spriteGroup][i];
if (decorativeSprite == null) { continue; }
if (spriteGroup > 0)
{
// TODO
//int activeSpriteIndex = ID % DecorativeSpriteGroups[spriteGroup].Count;
//if (i != activeSpriteIndex)
//{
// spriteAnimState[decorativeSprite].IsActive = false;
// continue;
//}
}
//check if the sprite is active (whether it should be drawn or not)
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = true;
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
{
if (!conditional.Matches(this))
{
spriteState.IsActive = false;
break;
}
}
if (!spriteState.IsActive) { continue; }
//check if the sprite should be animated
bool animate = true;
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
{
if (!conditional.Matches(this)) { animate = false; break; }
}
if (!animate) { continue; }
spriteState.OffsetState += deltaTime;
spriteState.RotationState += deltaTime;
}
}
}
public void DrawDamageModifiers(SpriteBatch spriteBatch, Camera cam, Vector2 startPos, bool isScreenSpace)
{
foreach (var modifier in damageModifiers)
{
float rotation = -body.TransformedRotation + GetArmorSectorRotationOffset(modifier.ArmorSectorInRadians) * Dir;
Vector2 forward = VectorExtensions.Forward(rotation);
float size = ConvertUnits.ToDisplayUnits(body.GetSize().Length() / 2);
if (isScreenSpace)
{
size *= cam.Zoom;
}
Color color = modifier.DamageMultiplier > 1 ? Color.Red : Color.GreenYellow;
int width = 4;
if (!isScreenSpace)
{
width = (int)Math.Round(width / cam.Zoom);
}
GUI.DrawLine(spriteBatch, startPos, startPos + Vector2.Normalize(forward) * size, color, width: width);
int thickness = 2;
if (!isScreenSpace)
{
thickness = (int)Math.Round(thickness / cam.Zoom);
}
ShapeExtensions.DrawSector(spriteBatch, startPos, size, GetArmorSectorSize(modifier.ArmorSectorInRadians) * Dir, 40, color, rotation + MathHelper.Pi, thickness);
}
}
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, SpriteEffects spriteEffect)
{
if (wearable.InheritSourceRect)
@@ -584,6 +721,26 @@ namespace Barotrauma
Scale * textureScale, spriteEffect, depth);
}
private WearableSprite GetWearableSprite(WearableType type, bool random = false)
{
var info = character.Info;
if (info == null) { return null; }
XElement element;
if (random)
{
element = info.FilterByTypeAndHeadID(character.Info.FilterElementsByGenderAndRace(character.Info.Wearables), type)?.FirstOrDefault();
}
else
{
element = info.FilterByTypeAndHeadID(character.Info.FilterElementsByGenderAndRace(character.Info.Wearables), type)?.GetRandom(Rand.RandSync.ClientOnly);
}
if (element != null)
{
return new WearableSprite(element.Element("sprite"), type);
}
return null;
}
partial void RemoveProjSpecific()
{
Sprite?.Remove();
@@ -595,6 +752,9 @@ namespace Barotrauma
DeformSprite?.Sprite?.Remove();
DeformSprite = null;
DecorativeSprites.ForEach(s => s.Remove());
ConditionalSprites.Clear();
ConditionalSprites.ForEach(s => s.Remove());
ConditionalSprites.Clear();

View File

@@ -49,6 +49,7 @@ namespace Barotrauma
private static bool isOpen;
public static bool IsOpen => isOpen;
public static bool Paused = false;
private static GUITextBlock activeQuestionText;
@@ -773,9 +774,15 @@ namespace Barotrauma
}
}, isCheat: true));
commands.Add(new Command("messagebox", "", (string[] args) =>
commands.Add(new Command("messagebox|guimessagebox", "messagebox [header] [msg] [default/ingame]: Creates a message box.", (string[] args) =>
{
new GUIMessageBox("", string.Join(" ", args));
var msgBox = new GUIMessageBox(
args.Length > 0 ? args[0] : "",
args.Length > 1 ? args[1] : "",
buttons: new string[] { "OK" },
type: args.Length < 3 || args[2] == "default" ? GUIMessageBox.Type.Default : GUIMessageBox.Type.InGame);
msgBox.Buttons[0].OnClicked = msgBox.Close;
}));
AssignOnExecute("debugdraw", (string[] args) =>
@@ -1121,7 +1128,7 @@ namespace Barotrauma
{
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.xml";
var doc = XMLExtensions.TryLoadXml(filePath);
if (doc?.Root == null) return;
if (doc == null) { return; }
List<string> lines = new List<string>();
foreach (XElement element in doc.Root.Elements())
{
@@ -1154,6 +1161,7 @@ namespace Barotrauma
return;
}
var doc = XMLExtensions.TryLoadXml(destinationPath);
if (doc == null) { return; }
int i = 0;
foreach (XElement element in doc.Root.Elements())
{
@@ -1186,6 +1194,8 @@ namespace Barotrauma
var sourceDoc = XMLExtensions.TryLoadXml(sourcePath);
var destinationDoc = XMLExtensions.TryLoadXml(destinationPath);
if (sourceDoc == null || destinationDoc == null) { return; }
XElement destinationElement = destinationDoc.Root.Elements().First();
foreach (XElement element in sourceDoc.Root.Elements())
{
@@ -1221,6 +1231,76 @@ namespace Barotrauma
}
File.WriteAllLines(filePath, lines);
}));
commands.Add(new Command("itemcomponentdocumentation", "", (string[] args) =>
{
Dictionary<string, string> typeNames = new Dictionary<string, string>
{
{ "Single", "float"},
{ "Int32", "integer"},
{ "Boolean", "true/false"},
{ "String", "text"},
};
var itemComponentTypes = typeof(ItemComponent).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ItemComponent)));
string filePath = args.Length > 0 ? args[0] : "ItemComponentDocumentation.txt";
List<string> lines = new List<string>();
foreach (Type t in itemComponentTypes)
{
lines.Add($"[b]{t.Name}[/b]");
lines.Add("");
var properties = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);//.Cast<System.ComponentModel.PropertyDescriptor>();
Dictionary<string, SerializableProperty> dictionary = new Dictionary<string, SerializableProperty>();
foreach (var property in properties)
{
object[] attributes = property.GetCustomAttributes(true);
Serialize serialize = attributes.FirstOrDefault(a => a is Serialize) as Serialize;
if (serialize == null) { continue; }
string propertyTypeName = property.PropertyType.Name;
if (typeNames.ContainsKey(propertyTypeName))
{
propertyTypeName = typeNames[propertyTypeName];
}
else if (property.PropertyType.IsEnum)
{
List<string> valueNames = new List<string>();
foreach (object enumValue in Enum.GetValues(property.PropertyType))
{
valueNames.Add(enumValue.ToString());
}
propertyTypeName = string.Join("/", valueNames);
}
lines.Add($"{property.Name} ({propertyTypeName})");
if (!string.IsNullOrEmpty(serialize.Description))
{
lines.Add(serialize.Description);
}
Editable editable = attributes.FirstOrDefault(a => a is Editable) as Editable;
if (editable != null)
{
if (editable.MinValueFloat > float.MinValue || editable.MaxValueFloat < float.MaxValue)
{
lines.Add("Range: " + editable.MinValueFloat+"-"+editable.MaxValueFloat);
}
else if (editable.MinValueInt > int.MinValue || editable.MaxValueInt < int.MaxValue)
{
lines.Add("Range: " + editable.MinValueInt + "-" + editable.MaxValueInt);
}
}
lines.Add("Default value: " + serialize.defaultValue);
lines.Add("");
}
lines.Add("");
}
File.WriteAllLines(filePath, lines);
System.Diagnostics.Process.Start(Path.GetFullPath(filePath));
}));
#if DEBUG
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
{
@@ -1239,12 +1319,6 @@ namespace Barotrauma
if (args.Length == 0) return;
LocalizationCSVtoXML.Convert(args[0]);
}));
commands.Add(new Command("guimessagebox", "guimessagebox [msg] -> Creates a message box with the parameter as a message.", (string[] args) =>
{
if (args.Length == 0) return;
var dialog = new GUIMessageBox("Message box", args[0]);
}));
#endif
commands.Add(new Command("cleanbuild", "", (string[] args) =>
@@ -1257,7 +1331,7 @@ namespace Barotrauma
GameMain.Config.GraphicsWidth = 0;
GameMain.Config.GraphicsHeight = 0;
GameMain.Config.WindowMode = WindowMode.Fullscreen;
GameMain.Config.WindowMode = WindowMode.BorderlessWindowed;
NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
NewMessage("Fullscreen enabled", Color.Green);
@@ -1652,7 +1726,7 @@ namespace Barotrauma
ThrowError("Not controlling any character!");
return;
}
character.AnimController.ResetRagdoll();
character.AnimController.ResetRagdoll(forceReload: true);
}, isCheat: true));
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 =>
@@ -1762,7 +1836,7 @@ namespace Barotrauma
{
if (limb.type != LimbType.Head)
{
limb.RecreateSprite();
limb.RecreateSprites();
}
foreach (var wearable in limb.WearingItems)
{
@@ -1846,6 +1920,19 @@ namespace Barotrauma
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace);
}
}, isCheat: true));
commands.Add(new Command("pause", "Toggles the pause state when playing offline", (string[] args) =>
{
if (GameMain.NetworkMember == null)
{
Paused = !Paused;
DebugConsole.NewMessage("Game paused: " + Paused);
}
else
{
DebugConsole.NewMessage("Cannot pause when a multiplayer session is active.");
}
}));
}
private static void ReloadWearables(Character character, int variant = 0)

View File

@@ -1,17 +1,18 @@
using Barotrauma.Networking;
namespace Barotrauma
namespace Barotrauma
{
partial class Mission
{
partial void ShowMessageProjSpecific(int index)
{
if (index >= Headers.Count && index >= Messages.Count) return;
if (index >= Headers.Count && index >= Messages.Count) { return; }
string header = index < Headers.Count ? Headers[index] : "";
string message = index < Messages.Count ? Messages[index] : "";
new GUIMessageBox(header, message);
new GUIMessageBox(header, message, buttons: new string[0], type: GUIMessageBox.Type.InGame, icon: Prefab.Icon)
{
IconColor = Prefab.IconColor
};
}
}
}

View File

@@ -9,8 +9,9 @@ namespace Barotrauma
{
if (mission == null) return;
new GUIMessageBox(mission.Name, mission.Description, new Vector2(0.25f, 0.0f), new Point(400, 200))
new GUIMessageBox(mission.Name, mission.Description, new string[0], type: GUIMessageBox.Type.InGame, icon: mission.Prefab.Icon)
{
IconColor = mission.Prefab.IconColor,
UserData = "missionstartmessage"
};
}

View File

@@ -0,0 +1,33 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma
{
partial class MissionPrefab
{
public Sprite Icon
{
get;
private set;
}
public Color IconColor
{
get;
private set;
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "icon") { continue; }
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
}
}
}
}

View File

@@ -251,7 +251,7 @@ namespace Barotrauma
{
this.texDims = texDims;
this.baseChar = baseChar;
face.SetPixelSizes(0, size);
lock (mutex) { face.SetPixelSizes(0, size); }
face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
baseHeight = face.Glyph.Metrics.Height.ToInt32();
CrossThread.RequestExecutionOnMainThread(() =>
@@ -263,6 +263,7 @@ namespace Barotrauma
uint glyphIndex = face.GetCharIndex(character);
if (glyphIndex == 0) { return; }
lock (mutex) { face.SetPixelSizes(0, size); }
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
{

View File

@@ -1,3 +1,4 @@
using Barotrauma.CharacterEditor;
using Barotrauma.Extensions;
using Barotrauma.Sounds;
using Barotrauma.Tutorials;
@@ -8,6 +9,7 @@ using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -154,19 +156,38 @@ namespace Barotrauma
public static void Init(GameWindow window, IEnumerable<ContentPackage> selectedContentPackages, GraphicsDevice graphicsDevice)
{
GUI.graphicsDevice = graphicsDevice;
var uiStyles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle).ToList();
if (uiStyles.Count == 0)
var files = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle);
XElement selectedStyle = null;
foreach (var file in files)
{
XDocument doc = XMLExtensions.TryLoadXml(file);
if (doc == null) { continue; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
mainElement = doc.Root.FirstElement();
if (selectedStyle != null)
{
DebugConsole.NewMessage($"Overriding the ui styles with '{file}'", Color.Yellow);
}
}
else if (selectedStyle != null)
{
DebugConsole.ThrowError("Another ui style already loaded! Use <override></override> tags to override it.");
break;
}
selectedStyle = mainElement;
}
if (selectedStyle == null)
{
DebugConsole.ThrowError("No UI styles defined in the selected content package!");
return;
}
else if (uiStyles.Count > 1)
else
{
DebugConsole.ThrowError("Multiple UI styles defined in the selected content package! Selecting the first one.");
Style = new GUIStyle(selectedStyle, graphicsDevice);
}
Style = new GUIStyle(uiStyles[0], graphicsDevice);
if (CJKFont == null)
{
CJKFont = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
@@ -407,6 +428,10 @@ namespace Barotrauma
{
debugDrawEvents = !debugDrawEvents;
}
if (MouseOn != null)
{
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 500, 20), $"Selected UI Element: {MouseOn.GetType().ToString()}", Color.LightGreen, Color.Black * 0.5f, 0, SmallFont);
}
}
if (HUDLayoutSettings.DebugDraw) HUDLayoutSettings.Draw(spriteBatch);
@@ -601,10 +626,7 @@ namespace Barotrauma
private static void HandlePersistingElements(float deltaTime)
{
if (GUIMessageBox.VisibleBox != null && GUIMessageBox.VisibleBox.UserData as string != "verificationprompt" && GUIMessageBox.VisibleBox.UserData as string != "bugreporter")
{
GUIMessageBox.VisibleBox.AddToGUIUpdateList();
}
GUIMessageBox.AddActiveToGUIUpdateList();
if (pauseMenuOpen)
{
@@ -1570,7 +1592,7 @@ namespace Barotrauma
button.OnClicked += (btn, userData) =>
{
var quitButton = button;
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen charEditScreen || Screen.Selected is SubEditorScreen subEditScreen))
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen))
{
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
var msgBox = new GUIMessageBox("", TextManager.Get(text), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })

View File

@@ -163,6 +163,12 @@ namespace Barotrauma
{
TextColor = this.style == null ? Color.Black : this.style.textColor
};
if (rectT.Rect.Height == 0 && !string.IsNullOrEmpty(text))
{
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(textBlock.Text).Y));
RectTransform.MinSize = textBlock.RectTransform.MinSize = new Point(0, Rect.Height);
TextBlock.SetTextPos();
}
GUI.Style.Apply(textBlock, "", this);
Enabled = true;
}

View File

@@ -4,6 +4,10 @@ using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
using System;
using System.Xml.Linq;
using System.IO;
using RestSharp;
using System.Net;
namespace Barotrauma
{
@@ -596,5 +600,340 @@ namespace Barotrauma
this.style = style;
}
public static GUIComponent FromXML(XElement element, RectTransform parent)
{
GUIComponent component = null;
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional" &&
!CheckConditional(subElement))
{
return null;
}
}
switch (element.Name.ToString().ToLowerInvariant())
{
case "text":
case "guitextblock":
component = LoadGUITextBlock(element, parent);
break;
case "link":
component = LoadLink(element, parent);
break;
case "frame":
case "guiframe":
case "spacing":
component = LoadGUIFrame(element, parent);
break;
case "button":
case "guibutton":
component = LoadGUIButton(element, parent);
break;
case "listbox":
case "guilistbox":
component = LoadGUIListBox(element, parent);
break;
case "guilayoutgroup":
case "layoutgroup":
component = LoadGUILayoutGroup(element, parent);
break;
case "image":
case "guiimage":
component = LoadGUIImage(element, parent);
break;
case "accordion":
return LoadAccordion(element, parent);
case "gridtext":
LoadGridText(element, parent);
return null;
default:
throw new NotImplementedException("Loading GUI component \""+element.Name+"\" from XML is not implemented.");
}
if (component != null)
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional") { continue; }
FromXML(subElement, component is GUIListBox listBox ? listBox.Content.RectTransform : component.RectTransform);
}
if (element.GetAttributeBool("resizetofitchildren", false))
{
Vector2 relativeResizeScale = element.GetAttributeVector2("relativeresizescale", Vector2.One);
if (component is GUILayoutGroup layoutGroup)
{
layoutGroup.RectTransform.NonScaledSize =
layoutGroup.IsHorizontal ?
new Point(layoutGroup.Children.Sum(c => c.Rect.Width), layoutGroup.Rect.Height) :
component.RectTransform.MinSize = new Point(layoutGroup.Rect.Width, layoutGroup.Children.Sum(c => c.Rect.Height));
if (layoutGroup.CountChildren > 0)
{
layoutGroup.RectTransform.NonScaledSize +=
layoutGroup.IsHorizontal ?
new Point((int)((layoutGroup.CountChildren - 1) * (layoutGroup.AbsoluteSpacing + layoutGroup.Rect.Width * layoutGroup.RelativeSpacing)), 0) :
new Point(0, (int)((layoutGroup.CountChildren - 1) * (layoutGroup.AbsoluteSpacing + layoutGroup.Rect.Height * layoutGroup.RelativeSpacing)));
}
}
else if (component is GUIListBox listBox)
{
listBox.RectTransform.NonScaledSize =
listBox.ScrollBar.IsHorizontal ?
new Point(listBox.Children.Sum(c => c.Rect.Width + listBox.Spacing), listBox.Rect.Height) :
component.RectTransform.MinSize = new Point(listBox.Rect.Width, listBox.Children.Sum(c => c.Rect.Height + listBox.Spacing));
}
else
{
component.RectTransform.NonScaledSize =
new Point(
component.Children.Max(c => c.Rect.Right) - component.Children.Min(c => c.Rect.X),
component.Children.Max(c => c.Rect.Bottom) - component.Children.Min(c => c.Rect.Y));
}
component.RectTransform.NonScaledSize =
component.RectTransform.NonScaledSize.Multiply(relativeResizeScale);
}
}
return component;
}
private static bool CheckConditional(XElement element)
{
foreach (XAttribute attribute in element.Attributes())
{
switch (attribute.Name.ToString().ToLowerInvariant())
{
case "language":
string[] languages = element.GetAttributeStringArray(attribute.Name.ToString(), new string[0]);
if (!languages.Any(l => GameMain.Config.Language.ToLower() == l.ToLower())) { return false; }
break;
case "gameversion":
var version = new Version(attribute.Value);
if (GameMain.Version != version) { return false; }
break;
case "mingameversion":
var minVersion = new Version(attribute.Value);
if (GameMain.Version < minVersion) { return false; }
break;
case "maxgameversion":
var maxVersion = new Version(attribute.Value);
if (GameMain.Version > maxVersion) { return false; }
break;
}
}
return true;
}
private static GUITextBlock LoadGUITextBlock(XElement element, RectTransform parent, string overrideText = null, Anchor? anchor = null)
{
string text = element.Attribute("text") == null ?
element.ElementInnerText() :
element.GetAttributeString("text", "");
text = text.Replace(@"\n", "\n");
string style = element.GetAttributeString("style", "");
if (style == "null") { style = null; }
Color? color = null;
if (element.Attribute("color") != null) { color = element.GetAttributeColor("color", Color.White); }
float scale = element.GetAttributeFloat("scale", 1.0f);
bool wrap = element.GetAttributeBool("wrap", true);
Alignment alignment = Alignment.Center;
Enum.TryParse(element.GetAttributeString("alignment", "Center"), out alignment);
ScalableFont font = GUI.Font;
switch (element.GetAttributeString("font", "Font").ToLowerInvariant())
{
case "font":
font = GUI.Font;
break;
case "smallfont":
font = GUI.SmallFont;
break;
case "largefont":
font = GUI.LargeFont;
break;
case "videotitlefont":
font = GUI.VideoTitleFont;
break;
case "objectivetitlefont":
font = GUI.ObjectiveTitleFont;
break;
case "objectivenamefont":
font = GUI.ObjectiveNameFont;
break;
}
var textBlock = new GUITextBlock(RectTransform.Load(element, parent),
text, color, font, alignment, wrap: wrap, style: style)
{
TextScale = scale
};
if (anchor.HasValue) { textBlock.RectTransform.SetPosition(anchor.Value); }
textBlock.RectTransform.IsFixedSize = true;
textBlock.RectTransform.NonScaledSize = new Point(textBlock.Rect.Width, textBlock.Rect.Height);
return textBlock;
}
private static GUIButton LoadLink(XElement element, RectTransform parent)
{
var button = LoadGUIButton(element, parent);
string url = element.GetAttributeString("url", "");
button.OnClicked = (btn, userdata) =>
{
try
{
System.Diagnostics.Process.Start(url);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to open url \""+url+"\".", e);
}
return true;
};
return button;
}
private static void LoadGridText(XElement element, RectTransform parent)
{
string text = element.Attribute("text") == null ?
element.ElementInnerText() :
element.GetAttributeString("text", "");
text = text.Replace(@"\n", "\n");
string[] elements = text.Split(',');
RectTransform lineContainer = null;
for (int i = 0; i < elements.Length; i++)
{
switch (i % 3)
{
case 0:
lineContainer = LoadGUITextBlock(element, parent, elements[i], Anchor.CenterLeft).RectTransform;
lineContainer.Anchor = Anchor.TopCenter;
lineContainer.Pivot = Pivot.TopCenter;
lineContainer.NonScaledSize = new Point((int)(parent.NonScaledSize.X * 0.7f), lineContainer.NonScaledSize.Y);
break;
case 1:
LoadGUITextBlock(element, lineContainer, elements[i], Anchor.Center).TextAlignment = Alignment.Center;
break;
case 2:
LoadGUITextBlock(element, lineContainer, elements[i], Anchor.CenterRight).TextAlignment = Alignment.CenterRight;
break;
}
}
}
private static GUIFrame LoadGUIFrame(XElement element, RectTransform parent)
{
string style = element.GetAttributeString("style", element.Name.ToString().ToLowerInvariant() == "spacing" ? null : "");
if (style == "null") { style = null; }
return new GUIFrame(RectTransform.Load(element, parent), style: style);
}
private static GUIButton LoadGUIButton(XElement element, RectTransform parent)
{
string style = element.GetAttributeString("style", "");
if (style == "null") { style = null; }
Alignment textAlignment = Alignment.Center;
Enum.TryParse(element.GetAttributeString("textalignment", "Center"), out textAlignment);
string text = element.Attribute("text") == null ?
element.ElementInnerText() :
element.GetAttributeString("text", "");
text = text.Replace(@"\n", "\n");
return new GUIButton(RectTransform.Load(element, parent),
text: text,
textAlignment: textAlignment,
style: style);
}
private static GUIListBox LoadGUIListBox(XElement element, RectTransform parent)
{
string style = element.GetAttributeString("style", "");
if (style == "null") { style = null; }
bool isHorizontal = element.GetAttributeBool("ishorizontal", !element.GetAttributeBool("isvertical", true));
return new GUIListBox(RectTransform.Load(element, parent), isHorizontal, style: style);
}
private static GUILayoutGroup LoadGUILayoutGroup(XElement element, RectTransform parent)
{
bool isHorizontal = element.GetAttributeBool("ishorizontal", !element.GetAttributeBool("isvertical", true));
Enum.TryParse(element.GetAttributeString("childanchor", "TopLeft"), out Anchor childAnchor);
return new GUILayoutGroup(RectTransform.Load(element, parent), isHorizontal, childAnchor)
{
Stretch = element.GetAttributeBool("stretch", false),
RelativeSpacing = element.GetAttributeFloat("relativespacing", 0.0f),
AbsoluteSpacing = element.GetAttributeInt("absolutespacing", 0),
};
}
private static GUIImage LoadGUIImage(XElement element, RectTransform parent)
{
Sprite sprite = null;
string url = element.GetAttributeString("url", "");
if (!string.IsNullOrEmpty(url))
{
string localFileName = Path.GetFileNameWithoutExtension(url.Replace("/", "").Replace(":", "").Replace("https", "").Replace("http", ""))
.Replace(".", "");
localFileName += Path.GetExtension(url);
string localFilePath = Path.Combine("Downloads", localFileName);
if (!File.Exists(localFilePath))
{
Uri baseAddress = new Uri(url);
Uri remoteDirectory = new Uri(baseAddress, ".");
string remoteFileName = Path.GetFileName(baseAddress.LocalPath);
IRestClient client = new RestClient(remoteDirectory);
var response = client.Execute(new RestRequest(remoteFileName, Method.GET));
if (response.ResponseStatus != ResponseStatus.Completed) { return null; }
if (response.StatusCode != HttpStatusCode.OK) { return null; }
if (!Directory.Exists("Downloads")) { Directory.CreateDirectory("Downloads"); }
File.WriteAllBytes(localFilePath, response.RawBytes);
}
sprite = new Sprite(element, "Downloads", localFileName);
}
else
{
sprite = new Sprite(element);
}
return new GUIImage(RectTransform.Load(element, parent), sprite, scaleToFit: true);
}
private static GUIButton LoadAccordion(XElement element, RectTransform parent)
{
var button = LoadGUIButton(element, parent);
List<GUIComponent> content = new List<GUIComponent>();
foreach (XElement subElement in element.Elements())
{
var contentElement = FromXML(subElement, parent);
if (contentElement != null)
{
contentElement.Visible = false;
contentElement.IgnoreLayoutGroups = true;
content.Add(contentElement);
}
}
button.OnClicked = (btn, userdata) =>
{
bool visible = content.FirstOrDefault()?.Visible ?? true;
foreach (GUIComponent contentElement in content)
{
contentElement.Visible = !visible;
contentElement.IgnoreLayoutGroups = !contentElement.Visible;
}
if (button.Parent is GUILayoutGroup layoutGroup)
{
layoutGroup.Recalculate();
}
return true;
};
return button;
}
}
}

View File

@@ -14,6 +14,12 @@ namespace Barotrauma
get { return Math.Max(400, 400 * (GameMain.GraphicsWidth / 1920)); }
}
public enum Type
{
Default,
InGame
}
public List<GUIButton> Buttons { get; private set; } = new List<GUIButton>();
//public GUIFrame BackgroundFrame { get; private set; }
public GUILayoutGroup Content { get; private set; }
@@ -22,6 +28,29 @@ namespace Barotrauma
public GUITextBlock Text { get; private set; }
public string Tag { get; private set; }
public GUIImage Icon
{
get;
private set;
}
public Color IconColor
{
get { return Icon == null ? Color.White : Icon.Color; }
set
{
if (Icon == null) { return; }
Icon.Color = value;
}
}
private bool alwaysVisible;
private float openState;
private bool closing;
private Type type;
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
public GUIMessageBox(string headerText, string text, Vector2? relativeSize = null, Point? minSize = null)
@@ -29,12 +58,11 @@ namespace Barotrauma
{
this.Buttons[0].OnClicked = Close;
}
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, string tag = "")
: base(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "")
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, Type type = Type.Default, string tag = "", Sprite icon = null)
: base(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: GUI.Style.GetComponentStyle("GUIMessageBox." + type) != null ? "GUIMessageBox." + type : "GUIMessageBox")
{
//int width = (int)(DefaultWidth * GUI.Scale), height = 0;
int width = DefaultWidth, height = 0;
int width = (int)(DefaultWidth * (type == Type.Default ? 1.0f : 1.5f)), height = 0;
if (relativeSize.HasValue)
{
width = (int)(GameMain.GraphicsWidth * relativeSize.Value.X);
@@ -49,137 +77,198 @@ namespace Barotrauma
}
}
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, Anchor.Center) { IsFixedSize = false }, style: null);
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, type == Type.InGame ? Anchor.TopCenter : 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 };
this.type = type;
Tag = tag;
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
headerText, textAlignment: Alignment.Center, wrap: true);
GUI.Style.Apply(Header, "", this);
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
if (!string.IsNullOrWhiteSpace(text))
if (type == Type.Default)
{
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;
}
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
headerText, textAlignment: Alignment.Center, wrap: true);
GUI.Style.Apply(Header, "", this);
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter, maxSize: new Point(1000, 50)),
isHorizontal: true, childAnchor: buttons.Length > 1 ? Anchor.BottomLeft : Anchor.Center)
{
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;
if (minSize.HasValue)
if (!string.IsNullOrWhiteSpace(text))
{
height = Math.Max(height, minSize.Value.Y);
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;
}
InnerFrame.RectTransform.NonScaledSize =
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + (int)(50 * GUI.yScale)));
Content.RectTransform.NonScaledSize =
new Point(Content.Rect.Width, height);
}
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter, maxSize: new Point(1000, 50)),
isHorizontal: true, childAnchor: buttons.Length > 1 ? Anchor.BottomLeft : Anchor.Center)
{
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;
Buttons = new List<GUIButton>(buttons.Length);
for (int i = 0; i < buttons.Length; i++)
if (height == 0)
{
height += Header.Rect.Height + Content.AbsoluteSpacing;
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
height += buttonContainer.Rect.Height;
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
InnerFrame.RectTransform.NonScaledSize =
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + (int)(50 * GUI.yScale)));
Content.RectTransform.NonScaledSize =
new Point(Content.Rect.Width, height);
}
Buttons = new List<GUIButton>(buttons.Length);
for (int i = 0; i < buttons.Length; i++)
{
var button = new GUIButton(new RectTransform(new Vector2(Math.Min(0.9f / buttons.Length, 0.5f), 1.0f), buttonContainer.RectTransform), buttons[i], style: "GUIButtonLarge");
Buttons.Add(button);
}
}
else if (type == Type.InGame)
{
var button = new GUIButton(new RectTransform(new Vector2(Math.Min(0.9f / buttons.Length, 0.5f), 1.0f), buttonContainer.RectTransform), buttons[i], style: "GUIButtonLarge");
Buttons.Add(button);
}
InnerFrame.RectTransform.AbsoluteOffset = new Point(0, GameMain.GraphicsHeight);
alwaysVisible = true;
CanBeFocused = false;
GUI.Style.Apply(InnerFrame, "", this);
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), InnerFrame.RectTransform, Anchor.Center),
isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
RelativeSpacing = 0.02f
};
if (icon != null)
{
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), icon, scaleToFit: true);
}
Content = new GUILayoutGroup(new RectTransform(new Vector2(icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(0.15f, 1.0f), horizontalLayoutGroup.RectTransform), style: null);
Buttons = new List<GUIButton>(1)
{
new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
style: GUI.Style.GetComponentStyle("GUIButtonSolidHorizontalArrow") != null ? "GUIButtonSolidHorizontalArrow" : "GUIButtonHorizontalArrow")
{
OnClicked = Close
}
};
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true);
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);
/*Content.Recalculate();
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
new Point(Text.Rect.Width, Text.Rect.Height);
Text.RectTransform.IsFixedSize = true;*/
}
if (height == 0)
{
height += Header.Rect.Height + Content.AbsoluteSpacing;
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
InnerFrame.RectTransform.NonScaledSize =
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + (int)(50 * GUI.yScale)));
Content.RectTransform.NonScaledSize =
new Point(Content.Rect.Width, height);
}
Buttons[0].RectTransform.MaxSize = new Point(Math.Min(Buttons[0].Rect.Width, Buttons[0].Rect.Height));
}
MessageBoxes.Add(this);
}
///// <summary>
///// This is the new constructor.
///// TODO: for some reason the background does not prohibit input on the elements that are behind the box
///// TODO: allow providing buttons in the constructor
///// </summary>
/*public GUIMessageBox(RectTransform rectT, string headerText, string text, Alignment textAlignment = Alignment.TopCenter)
: base(rectT, "")
public static void AddActiveToGUIUpdateList()
{
//BackgroundFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), rectT, Anchor.Center), null, Color.Black * 0.5f);
float headerHeight = 0.2f;
float margin = 0.05f;
InnerFrame = new GUIFrame(rectT);
GUI.Style.Apply(InnerFrame, "", this);
Header = null;
if (!string.IsNullOrWhiteSpace(headerText))
for (int i = 0; i < MessageBoxes.Count; i++)
{
Header = new GUITextBlock(new RectTransform(new Vector2(1, headerHeight), InnerFrame.RectTransform, Anchor.TopCenter)
if (MessageBoxes[i] is GUIMessageBox alwaysVisibleMsgBox && alwaysVisibleMsgBox.alwaysVisible)
{
RelativeOffset = new Vector2(0, margin)
}, headerText, textAlignment: Alignment.Center);
GUI.Style.Apply(Header, "", this);
alwaysVisibleMsgBox.AddToGUIUpdateList();
break;
}
}
if (!string.IsNullOrWhiteSpace(text))
for (int i = MessageBoxes.Count - 1; i >= 0; i--)
{
float offset = headerHeight + margin;
var size = Header == null ? Vector2.One : new Vector2(1 - margin * 2, 1 - offset + margin);
Text = new GUITextBlock(new RectTransform(size, InnerFrame.RectTransform, Anchor.TopCenter)
if (MessageBoxes[i].UserData as string == "verificationprompt" ||
MessageBoxes[i].UserData as string == "bugreporter")
{
RelativeOffset = new Vector2(0, offset)
}, text, textAlignment: textAlignment, wrap: true);
GUI.Style.Apply(Text, "", this);
continue;
}
if (!(MessageBoxes[i] is GUIMessageBox msgBox) || !msgBox.alwaysVisible)
{
MessageBoxes[i].AddToGUIUpdateList();
break;
}
}
MessageBoxes.Add(this);
}*/
}
protected override void Update(float deltaTime)
{
if (type == Type.InGame)
{
Vector2 initialPos = new Vector2(0.0f, GameMain.GraphicsHeight);
Vector2 defaultPos = new Vector2(0.0f, HUDLayoutSettings.InventoryAreaLower.Y - InnerFrame.Rect.Height - 20 * GUI.Scale);
Vector2 endPos = new Vector2(GameMain.GraphicsWidth, defaultPos.Y);
/*for (int i = MessageBoxes.IndexOf(this); i >= 0; i--)
{
if (MessageBoxes[i] is GUIMessageBox otherMsgBox && otherMsgBox != this && otherMsgBox.type == type && !otherMsgBox.closing)
{
defaultPos = new Vector2(
Math.Max(otherMsgBox.InnerFrame.RectTransform.AbsoluteOffset.X + 10 * GUI.Scale, defaultPos.X),
Math.Max(otherMsgBox.InnerFrame.RectTransform.AbsoluteOffset.Y + 10 * GUI.Scale, defaultPos.Y));
}
}*/
if (!closing)
{
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
}
else
{
openState += deltaTime * 2.0f;
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
if (openState >= 2.0f)
{
if (Parent != null) { Parent.RemoveChild(this); }
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
}
}
}
}
//public override void AddToGUIUpdateList(bool ignoreChildren = false, bool updateLast = false)
//{
// base.AddToGUIUpdateList(ignoreChildren, updateLast);
//}
//public override void Draw(SpriteBatch spriteBatch, bool drawChildren = true)
//{
// if (RectTransform == null)
// {
// base.Draw(spriteBatch, drawChildren);
// }
// else
// {
// // Custom draw order so that the background is rendered behind the parent.
// if (drawChildren)
// {
// BackgroundFrame?.Draw(spriteBatch);
// }
// base.Draw(spriteBatch, false);
// if (drawChildren)
// {
// InnerFrame?.Draw(spriteBatch);
// Header?.Draw(spriteBatch);
// Text?.Draw(spriteBatch);
// Buttons.ForEach(b => b.Draw(spriteBatch));
// }
// }
//}
public void Close()
{
if (Parent != null) Parent.RemoveChild(this);
if (MessageBoxes.Contains(this)) MessageBoxes.Remove(this);
if (type == Type.InGame)
{
closing = true;
}
else
{
if (Parent != null) { Parent.RemoveChild(this); }
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
}
}
public bool Close(GUIButton button, object obj)
{
Close();
Close();
return true;
}

View File

@@ -30,27 +30,12 @@ namespace Barotrauma
public SpriteSheet FocusIndicator { get; private set; }
public GUIStyle(string file, GraphicsDevice graphicsDevice)
public GUIStyle(XElement element, GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
componentStyles = new Dictionary<string, GUIComponentStyle>();
XDocument doc;
try
{
ToolBox.IsProperFilenameCase(file);
doc = XDocument.Load(file, LoadOptions.SetBaseUri);
if (doc == null) { throw new Exception("doc is null"); }
if (doc.Root == null) { throw new Exception("doc.Root is null"); }
if (doc.Root.Elements() == null) { throw new Exception("doc.Root.Elements() is null"); }
}
catch (Exception e)
{
DebugConsole.ThrowError("Loading style \"" + file + "\" failed", e);
return;
}
configElement = doc.Root;
foreach (XElement subElement in doc.Root.Elements())
configElement = element;
foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{

View File

@@ -40,6 +40,8 @@ namespace Barotrauma
private float textDepth;
private ScalableFont originalFont;
public Vector2 TextOffset { get; set; }
private Vector4 padding;
@@ -62,7 +64,7 @@ namespace Barotrauma
set
{
if (base.Font == value) return;
base.Font = value;
base.Font = originalFont = value;
SetTextPos();
}
}
@@ -74,13 +76,23 @@ namespace Barotrauma
{
string newText = forceUpperCase ? value?.ToUpper() : value;
if (Text == newText) return;
if (Text == newText) { return; }
//reset scale, it gets recalculated in SetTextPos
if (autoScale) textScale = 1.0f;
if (autoScale) { textScale = 1.0f; }
text = newText;
wrappedText = newText;
if (TextManager.IsCJK(text))
{
//switch to fallback CJK font
if (!Font.IsCJK) { base.Font = GUI.CJKFont; }
}
else
{
if (Font == GUI.CJKFont) { base.Font = originalFont; }
}
SetTextPos();
}
}
@@ -208,8 +220,11 @@ namespace Barotrauma
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
//use the default CJK font as a fallback
var selectedFont = font ?? GUI.Font;
if (TextManager.IsCJK(text) && !selectedFont.IsCJK) { selectedFont = GUI.CJKFont; }
var selectedFont = originalFont = font ?? GUI.Font;
if (TextManager.IsCJK(text) && !selectedFont.IsCJK)
{
selectedFont = GUI.CJKFont;
}
this.Font = selectedFont;
this.textAlignment = textAlignment;
this.Wrap = wrap;

View File

@@ -162,10 +162,11 @@ namespace Barotrauma
public override ScalableFont Font
{
get { return textBlock?.Font ?? base.Font; }
set
{
base.Font = value;
if (textBlock == null) return;
if (textBlock == null) { return; }
textBlock.Font = value;
}
}

View File

@@ -32,7 +32,7 @@ namespace Barotrauma
{
rectT = rectT ?? new RectTransform(new Vector2(0.25f, 1f), GUI.Canvas) { MinSize = new Point(340, GameMain.GraphicsHeight) };
rectT.SetPosition(Anchor.TopRight);
Parent = new GUIFrame(rectT, null, new Color(20, 20, 20, 255));
Parent = new GUIFrame(rectT, null, Color);
EditorBox = new GUIListBox(new RectTransform(Vector2.One * 0.98f, rectT, Anchor.Center), color: Color.Black, style: null)
{
Spacing = 10
@@ -49,5 +49,7 @@ namespace Barotrauma
{
EditorBox = CreateEditorBox();
}
public static Color Color = new Color(20, 20, 20, 255);
}
}

View File

@@ -358,9 +358,9 @@ namespace Barotrauma
parent?.ChildrenChanged?.Invoke(this);
}
public static RectTransform Load(XElement element, RectTransform parent)
public static RectTransform Load(XElement element, RectTransform parent, Anchor defaultAnchor = Anchor.TopLeft)
{
Enum.TryParse(element.GetAttributeString("anchor", "Center"), out Anchor anchor);
Enum.TryParse(element.GetAttributeString("anchor", defaultAnchor.ToString()), out Anchor anchor);
Enum.TryParse(element.GetAttributeString("pivot", anchor.ToString()), out Pivot pivot);
Point? minSize = null, maxSize = null;
@@ -368,11 +368,7 @@ namespace Barotrauma
//if (element.Attribute("maxsize") != null) maxSize = element.GetAttributePoint("maxsize", new Point(1000, 1000));
RectTransform rectTransform;
if (element.Attribute("relativesize") != null)
{
rectTransform = new RectTransform(element.GetAttributeVector2("relativesize", Vector2.One), parent, anchor, pivot, minSize, maxSize);
}
else
if (element.Attribute("absolutesize") != null)
{
rectTransform = new RectTransform(element.GetAttributePoint("absolutesize", new Point(1000, 1000)), parent, anchor, pivot)
{
@@ -380,6 +376,10 @@ namespace Barotrauma
maxSize = maxSize
};
}
else
{
rectTransform = new RectTransform(element.GetAttributeVector2("relativesize", Vector2.One), parent, anchor, pivot, minSize, maxSize);
}
rectTransform.RelativeOffset = element.GetAttributeVector2("relativeoffset", Vector2.Zero);
rectTransform.AbsoluteOffset = element.GetAttributePoint("absoluteoffset", Point.Zero);
return rectTransform;

View File

@@ -16,6 +16,7 @@ using System.IO;
using System.Threading;
using Barotrauma.Tutorials;
using Barotrauma.Media;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -44,7 +45,7 @@ namespace Barotrauma
public static ParticleEditorScreen ParticleEditorScreen;
public static LevelEditorScreen LevelEditorScreen;
public static SpriteEditorScreen SpriteEditorScreen;
public static CharacterEditorScreen CharacterEditorScreen;
public static CharacterEditor.CharacterEditorScreen CharacterEditorScreen;
public static Lights.LightManager LightManager;
@@ -52,7 +53,7 @@ namespace Barotrauma
public static Thread MainThread { get; private set; }
public static HashSet<ContentPackage> SelectedPackages
public static IEnumerable<ContentPackage> SelectedPackages
{
get { return Config?.SelectedContentPackages; }
}
@@ -171,6 +172,9 @@ namespace Barotrauma
GraphicsDeviceManager = new GraphicsDeviceManager(this);
GraphicsDeviceManager.IsFullScreen = false;
GraphicsDeviceManager.ApplyChanges();
Window.Title = "Barotrauma";
Instance = this;
@@ -405,7 +409,7 @@ namespace Barotrauma
}
}
if (SelectedPackages.Count == 0)
if (SelectedPackages.None())
{
DebugConsole.Log("No content packages selected");
}
@@ -452,7 +456,9 @@ namespace Barotrauma
yield return CoroutineStatus.Running;
Character.LoadAllConfigFiles();
MissionPrefab.Init();
TraitorMissionPrefab.Init();
MapEntityPrefab.Init();
Tutorials.Tutorial.Init();
MapGenerationParams.Init();
@@ -472,9 +478,9 @@ namespace Barotrauma
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
// Add any missing jobs from the prefab into Config.JobNamePreferences.
foreach (JobPrefab job in JobPrefab.List)
foreach (string job in JobPrefab.List.Keys)
{
if (!Config.JobPreferences.Contains(job.Identifier)) { Config.JobPreferences.Add(job.Identifier); }
if (!Config.JobPreferences.Contains(job)) { Config.JobPreferences.Add(job); }
}
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
@@ -523,7 +529,7 @@ namespace Barotrauma
LevelEditorScreen = new LevelEditorScreen();
SpriteEditorScreen = new SpriteEditorScreen();
CharacterEditorScreen = new CharacterEditorScreen();
CharacterEditorScreen = new CharacterEditor.CharacterEditorScreen();
yield return CoroutineStatus.Running;
@@ -726,7 +732,7 @@ namespace Barotrauma
GameMain.MainMenuScreen.Select();
}
UInt64 serverSteamId = SteamManager.SteamIDStringToUInt64(ConnectEndpoint);
Client = new GameClient(SteamManager.GetUsername(),
Client = new GameClient(Config.PlayerName,
serverSteamId != 0 ? null : ConnectEndpoint,
serverSteamId,
string.IsNullOrWhiteSpace(ConnectName) ? ConnectEndpoint : ConnectName);
@@ -762,8 +768,11 @@ namespace Barotrauma
{
GUI.TogglePauseMenu();
}
else if ((Character.Controlled?.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null)
//open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC
else if (Character.Controlled == null ||
((Character.Controlled.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
//TODO: do we need to check Inventory.SelectedSlot?
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null))
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
@@ -771,7 +780,7 @@ namespace Barotrauma
}
GUI.ClearUpdateList();
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning) &&
paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning || DebugConsole.Paused) &&
(NetworkMember == null || !NetworkMember.GameStarted);
#if !DEBUG
@@ -802,6 +811,17 @@ namespace Barotrauma
{
(GameSession.GameMode as TutorialMode).Update((float)Timing.Step);
}
else if (DebugConsole.Paused)
{
if (Screen.Selected.Cam == null)
{
DebugConsole.Paused = false;
}
else
{
Screen.Selected.Cam.MoveCamera((float)Timing.Step);
}
}
if (NetworkMember != null)
{
@@ -908,7 +928,7 @@ namespace Barotrauma
UserData = link.Second,
OnClicked = (btn, userdata) =>
{
Process.Start(userdata as string);
ShowOpenUrlInWebBrowserPrompt(userdata as string);
return true;
}
};
@@ -920,7 +940,6 @@ namespace Barotrauma
Config.SaveNewPlayerConfig();
}
// ToDo: Move texts/links to localization, when possible.
public void ShowBugReporter()
{
var msgBox = new GUIMessageBox(TextManager.Get("bugreportbutton"), "");
@@ -928,24 +947,27 @@ namespace Barotrauma
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), 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("bugreportfeedbackform"),"https://barotraumagame.com/feedback"),
new Pair<string, string>(TextManager.Get("bugreportgithubform"),"https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md")
};
foreach (var link in links)
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportfeedbackform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), link.First, style: "MainMenuGUIButton", textAlignment: Alignment.Left)
UserData = "https://steamcommunity.com/app/602960/discussions/1/",
OnClicked = (btn, userdata) =>
{
UserData = link.Second,
OnClicked = (btn, userdata) =>
{
Process.Start(userdata as string);
msgBox.Close();
return true;
}
};
}
SteamManager.OverlayCustomURL(userdata as string);
msgBox.Close();
return true;
}
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportgithubform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
{
UserData = "https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md",
OnClicked = (btn, userdata) =>
{
ShowOpenUrlInWebBrowserPrompt(userdata as string);
msgBox.Close();
return true;
}
};
msgBox.InnerFrame.RectTransform.MinSize = new Point(0,
msgBox.InnerFrame.Rect.Height + linkHolder.Rect.Height + msgBox.Content.AbsoluteSpacing * 2 + (int)(50 * GUI.Scale));
@@ -968,5 +990,24 @@ namespace Barotrauma
if (GameSettings.SaveDebugConsoleLogs) DebugConsole.SaveLogs();
base.OnExiting(sender, args);
}
public void ShowOpenUrlInWebBrowserPrompt(string url)
{
if (string.IsNullOrEmpty(url)) { return; }
if (GUIMessageBox.VisibleBox?.UserData as string == "verificationprompt") { return; }
var msgBox = new GUIMessageBox("", TextManager.GetWithVariable("openlinkinbrowserprompt", "[link]", url),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
{
Process.Start(url);
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = msgBox.Close;
}
}
}

View File

@@ -172,6 +172,11 @@ namespace Barotrauma
}
var reports = Order.PrefabList.FindAll(o => o.TargetAllCharacters && o.SymbolSprite != null);
if (reports.None())
{
DebugConsole.ThrowError("No valid orders for report buttons found! Cannot create report buttons. The orders for the report buttons must have 'targetallcharacters' attribute enabled and a valid 'symbolsprite' defined.");
return;
}
reportButtonFrame = new GUILayoutGroup(new RectTransform(
new Point((HUDLayoutSettings.CrewArea.Height - (int)((reports.Count - 1) * 5 * GUI.Scale)) / reports.Count, HUDLayoutSettings.CrewArea.Height), guiFrame.RectTransform))
{
@@ -322,7 +327,7 @@ namespace Barotrauma
/// </summary>
private GUIComponent CreateCharacterFrame(Character character, GUIComponent parent)
{
int correctOrderCount = 0, neutralOrderCount = 0, wrongOrderCount = 0;
int genericOrderCount = 0, correctOrderCount = 0, wrongOrderCount = 0;
//sort the orders
// 1. generic orders (follow, wait, etc)
// 2. orders appropriate for the character's job (captain -> steer, etc)
@@ -331,15 +336,16 @@ namespace Barotrauma
foreach (Order order in Order.PrefabList)
{
if (order.TargetAllCharacters || order.SymbolSprite == null) continue;
if (order.AppropriateJobs == null || order.AppropriateJobs.Length == 0)
if (!JobPrefab.List.Values.Any(jp => jp.AppropriateOrders.Contains(order.Identifier)) &&
(order.AppropriateJobs == null || !order.AppropriateJobs.Any()))
{
orders.Insert(0, order);
correctOrderCount++;
genericOrderCount++;
}
else if (order.HasAppropriateJob(character))
{
orders.Add(order);
neutralOrderCount++;
correctOrderCount++;
}
}
foreach (Order order in Order.PrefabList)
@@ -481,7 +487,7 @@ namespace Barotrauma
var order = orders[i];
if (order.TargetAllCharacters) continue;
RectTransform btnParent = (i >= correctOrderCount + neutralOrderCount) ?
RectTransform btnParent = (i >= genericOrderCount + correctOrderCount) ?
wrongOrderList.Content.RectTransform :
orderButtonFrame.RectTransform;
@@ -516,7 +522,7 @@ namespace Barotrauma
if (btn.GetChildByUserData("selected").Visible)
{
SetCharacterOrder(character, Order.PrefabList.Find(o => o.AITag == "dismissed"), null, Character.Controlled);
SetCharacterOrder(character, Order.GetPrefab("dismissed"), null, Character.Controlled);
}
else
{
@@ -535,7 +541,7 @@ namespace Barotrauma
btn.ToolTip = order.Name;
//divider between different groups of orders
if (i == correctOrderCount - 1 || i == correctOrderCount + neutralOrderCount - 1)
if (i == genericOrderCount - 1 || i == genericOrderCount + correctOrderCount - 1)
{
//TODO: divider sprite
new GUIFrame(new RectTransform(new Point(8, iconSize), orderButtonFrame.RectTransform), style: "GUIButton");
@@ -999,14 +1005,15 @@ 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)
public void HighlightOrderButton(Character character, string orderIdentifier, Color color, Vector2? flashRectInflate = null)
{
var order = Order.PrefabList.Find(o => o.AITag == orderAiTag);
var order = Order.GetPrefab(orderIdentifier);
if (order == null)
{
DebugConsole.ThrowError("Could not find an order with the AI tag \"" + orderAiTag + "\".\n" + Environment.StackTrace);
DebugConsole.ThrowError("Could not find an order with the AI tag \"" + orderIdentifier + "\".\n" + Environment.StackTrace);
return;
}
ToggleCrewAreaOpen = true;
var characterElement = characterListBox.Content.FindChild(character);
GUIButton orderBtn = characterElement.FindChild(order, recursive: true) as GUIButton;
if (orderBtn.Frame.FlashTimer <= 0)
@@ -1417,14 +1424,14 @@ namespace Barotrauma
// return true;
//}
private void ToggleReportButton(string orderAiTag, bool enabled)
private void ToggleReportButton(string orderIdentifier, bool enabled)
{
Order order = Order.PrefabList.Find(o => o.AITag == orderAiTag);
Order order = Order.GetPrefab(orderIdentifier);
//already reported, disable the button
/*if (GameMain.GameSession.CrewManager.ActiveOrders.Any(o =>
o.First.TargetEntity == Character.Controlled.CurrentHull &&
o.First.AITag == orderAiTag))
o.First.Identifier == orderIdentifier))
{
enabled = false;
}*/

View File

@@ -9,8 +9,9 @@ namespace Barotrauma
{
if (Mission == null) return;
new GUIMessageBox(Mission.Name, Mission.Description, new Vector2(0.25f, 0.0f), new Point(400, 200))
new GUIMessageBox(Mission.Name, Mission.Description, new string[0], type: GUIMessageBox.Type.InGame, icon: Mission.Prefab.Icon)
{
IconColor = Mission.Prefab.IconColor,
UserData = "missionstartmessage"
};
}

View File

@@ -138,6 +138,7 @@ namespace Barotrauma
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
msg.Write(PurchasedHullRepairs);
msg.Write(PurchasedItemRepairs);
msg.Write(PurchasedLostShuttles);
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
@@ -164,6 +165,7 @@ namespace Barotrauma
int money = msg.ReadInt32();
bool purchasedHullRepairs = msg.ReadBoolean();
bool purchasedItemRepairs = msg.ReadBoolean();
bool purchasedLostShuttles = msg.ReadBoolean();
UInt16 purchasedItemCount = msg.ReadUInt16();
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
@@ -178,7 +180,7 @@ namespace Barotrauma
CharacterInfo myCharacterInfo = null;
if (hasCharacterData)
{
myCharacterInfo = CharacterInfo.ClientRead(Character.HumanConfigFile, msg);
myCharacterInfo = CharacterInfo.ClientRead(Character.HumanSpeciesName, msg);
}
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
@@ -226,6 +228,7 @@ namespace Barotrauma
campaign.Money = money;
campaign.PurchasedHullRepairs = purchasedHullRepairs;
campaign.PurchasedItemRepairs = purchasedItemRepairs;
campaign.PurchasedLostShuttles = purchasedLostShuttles;
campaign.CargoManager.SetPurchasedItems(purchasedItems);
if (myCharacterInfo != null)
@@ -239,7 +242,6 @@ namespace Barotrauma
}
campaign.lastUpdateID = updateID;
campaign.SuppressStateSending = false;
}
}

View File

@@ -32,11 +32,11 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { TryEndRound(GetLeavingSub()); return true; }
};
foreach (JobPrefab jobPrefab in JobPrefab.List)
foreach (JobPrefab jobPrefab in JobPrefab.List.Values)
{
for (int i = 0; i < jobPrefab.InitialCount; i++)
{
CrewManager.AddCharacterInfo(new CharacterInfo(Character.HumanConfigFile, "", jobPrefab));
CrewManager.AddCharacterInfo(new CharacterInfo(Character.HumanSpeciesName, "", jobPrefab));
}
}
}
@@ -175,6 +175,11 @@ namespace Barotrauma
protected override void WatchmanInteract(Character watchman, Character interactor)
{
if (interactor != null)
{
interactor.FocusedCharacter = null;
}
Submarine leavingSub = GetLeavingSub();
if (leavingSub == null)
{
@@ -182,7 +187,6 @@ namespace Barotrauma
return;
}
CreateDialog(new List<Character> { watchman }, "WatchmanInteract", 1.0f);
if (GUIMessageBox.MessageBoxes.Any(mbox => mbox.UserData as string == "watchmanprompt"))
@@ -295,7 +299,7 @@ namespace Barotrauma
{
GameMain.GameSession.LoadPrevious();
GameMain.LobbyScreen.Select();
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
GUIMessageBox.MessageBoxes.RemoveAll(c => c?.UserData as string == "roundsummary");
return true;
}
};
@@ -303,7 +307,11 @@ namespace Barotrauma
var quitButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform),
TextManager.Get("QuitButton"));
quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu;
quitButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; };
quitButton.OnClicked += (GUIButton button, object obj) =>
{
GUIMessageBox.MessageBoxes.RemoveAll(c => c?.UserData as string == "roundsummary");
return true;
};
}
}

View File

@@ -295,9 +295,7 @@ namespace Barotrauma.Tutorials
}
yield return new WaitForSeconds(1.0f);
var moloch = Character.Create(
"Content/Characters/Moloch/moloch.xml",
steering.Item.WorldPosition + new Vector2(3000.0f, -500.0f), "");
var moloch = Character.Create("moloch", steering.Item.WorldPosition + new Vector2(3000.0f, -500.0f), "");
moloch.PlaySound(CharacterSound.SoundType.Attack);
@@ -663,7 +661,7 @@ namespace Barotrauma.Tutorials
//TODO: reimplement
//enemy.Health = 50.0f;
enemy.AIController.State = AIController.AIState.Idle;
enemy.AIController.State = AIState.Idle;
Vector2 targetPos = Character.Controlled.WorldPosition + new Vector2(0.0f, 3000.0f);

View File

@@ -68,7 +68,7 @@ namespace Barotrauma.Tutorials
captainsuniform.Unequip(captain);
captain.Inventory.RemoveItem(captainsuniform);
var steerOrder = Order.PrefabList.Find(order => order.AITag == "steer");
var steerOrder = Order.GetPrefab("steer");
captain_steerIcon = steerOrder.SymbolSprite;
captain_steerIconColor = steerOrder.Color;
@@ -85,7 +85,7 @@ namespace Barotrauma.Tutorials
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"));
var medicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("medicaldoctor"));
captain_medic = Character.Create(medicInfo, captain_medicSpawnPos, "medicaldoctor");
captain_medic.GiveJobItems(null);
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
@@ -107,15 +107,15 @@ namespace Barotrauma.Tutorials
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"));
var mechanicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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"));
var securityInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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"));
var engineerInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer"));
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "engineer");
captain_engineer.GiveJobItems();

View File

@@ -48,7 +48,7 @@ namespace Barotrauma.Tutorials
{
base.Start();
var firstAidOrder = Order.PrefabList.Find(order => order.AITag == "requestfirstaid");
var firstAidOrder = Order.GetPrefab("requestfirstaid");
doctor_firstAidIcon = firstAidOrder.SymbolSprite;
doctor_firstAidIconColor = firstAidOrder.Color;
@@ -63,30 +63,30 @@ namespace Barotrauma.Tutorials
var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
var assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant"));
var assistantInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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"));
assistantInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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 mechanicInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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 securityInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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 engineerInfo = new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("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);
@@ -240,7 +240,7 @@ namespace Barotrauma.Tutorials
// treat patient --------------------------------------------------------------------------------------------
//patient 1 requests first aid
var newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), patient1.CurrentHull, null, orderGiver: patient1);
var newOrder = new Order(Order.GetPrefab("requestfirstaid"), patient1.CurrentHull, null, orderGiver: patient1);
doctor.AddActiveObjectiveEntity(patient1, doctor_firstAidIcon, doctor_firstAidIconColor);
//GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(patient1.Name, newOrder.GetChatMessage("", patient1.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order, null);
@@ -263,7 +263,7 @@ namespace Barotrauma.Tutorials
doctor.RemoveActiveObjectiveEntity(patient1);
TriggerTutorialSegment(3); // Get the patient to medbay
while (patient1.CurrentOrder == null || patient1.CurrentOrder.AITag != "follow")
while (patient1.CurrentOrder == null || patient1.CurrentOrder.Identifier != "follow")
{
GameMain.GameSession.CrewManager.HighlightOrderButton(patient1, "follow", highlightColor, new Vector2(5, 5));
yield return null;
@@ -329,7 +329,7 @@ namespace Barotrauma.Tutorials
//patient calls for help
//patient2.CanSpeak = true;
yield return new WaitForSeconds(2.0f, false);
newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), patient2.CurrentHull, null, orderGiver: patient2);
newOrder = new Order(Order.GetPrefab("requestfirstaid"), patient2.CurrentHull, null, orderGiver: patient2);
doctor.AddActiveObjectiveEntity(patient2, doctor_firstAidIcon, doctor_firstAidIconColor);
//GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(patient2.Name, newOrder.GetChatMessage("", patient1.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order, null);
@@ -396,7 +396,7 @@ namespace Barotrauma.Tutorials
if (!patientCalledHelp[i] && Timing.TotalTime > subEnterTime + 60 * (i + 1))
{
doctor.AddActiveObjectiveEntity(subPatients[i], doctor_firstAidIcon, doctor_firstAidIconColor);
newOrder = new Order(Order.PrefabList.Find(o => o.AITag == "requestfirstaid"), subPatients[i].CurrentHull, null, orderGiver: subPatients[i]);
newOrder = new Order(Order.GetPrefab("requestfirstaid"), subPatients[i].CurrentHull, null, orderGiver: subPatients[i]);
string message = newOrder.GetChatMessage("", subPatients[i].CurrentHull?.DisplayName, givingOrderToSelf: false);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(subPatients[i].Name, message, ChatMessageType.Order, null);
patientCalledHelp[i] = true;

View File

@@ -91,11 +91,11 @@ namespace Barotrauma.Tutorials
toolbox.Unequip(engineer);
engineer.Inventory.RemoveItem(toolbox);
var repairOrder = Order.PrefabList.Find(order => order.AITag == "repairsystems");
var repairOrder = Order.GetPrefab("repairsystems");
engineer_repairIcon = repairOrder.SymbolSprite;
engineer_repairIconColor = repairOrder.Color;
var reactorOrder = Order.PrefabList.Find(order => order.AITag == "operatereactor");
var reactorOrder = Order.GetPrefab("operatereactor");
engineer_reactorIcon = reactorOrder.SymbolSprite;
engineer_reactorIconColor = reactorOrder.Color;

View File

@@ -95,7 +95,7 @@ namespace Barotrauma.Tutorials
crowbar.Unequip(mechanic);
mechanic.Inventory.RemoveItem(crowbar);
var repairOrder = Order.PrefabList.Find(order => order.AITag == "repairsystems");
var repairOrder = Order.GetPrefab("repairsystems");
mechanic_repairIcon = repairOrder.SymbolSprite;
mechanic_repairIconColor = repairOrder.Color;
mechanic_weldIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(1, 256, 127, 127), new Vector2(0.5f, 0.5f));

View File

@@ -74,18 +74,12 @@ namespace Barotrauma.Tutorials
// 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()
@@ -111,7 +105,7 @@ namespace Barotrauma.Tutorials
bodyarmor.Unequip(officer);
officer.Inventory.RemoveItem(bodyarmor);
var gunOrder = Order.PrefabList.Find(order => order.AITag == "operateweapons");
var gunOrder = Order.GetPrefab("operateweapons");
officer_gunIcon = gunOrder.SymbolSprite;
officer_gunIconColor = gunOrder.Color;
@@ -267,7 +261,7 @@ namespace Barotrauma.Tutorials
// Room 3
do { yield return null; } while (!officer_crawlerSensor.MotionDetected);
TriggerTutorialSegment(2);
officer_crawler = SpawnMonster(crawlerCharacterFile, officer_crawlerSpawnPos);
officer_crawler = SpawnMonster("crawler", officer_crawlerSpawnPos);
do { yield return null; } while (!officer_crawler.IsDead);
RemoveCompletedObjective(segments[2]);
Heal(officer);
@@ -298,7 +292,7 @@ namespace Barotrauma.Tutorials
RemoveCompletedObjective(segments[3]);
yield return new WaitForSeconds(2f, false);
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 = SpawnMonster("hammerhead", officer_hammerheadSpawnPos);
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
SetHighlight(officer_coilgunPeriscope, true);
float originalDistance = Vector2.Distance(officer_coilgunPeriscope.WorldPosition, officer_hammerheadSpawnPos);
@@ -314,8 +308,8 @@ namespace Barotrauma.Tutorials
{
// Ensure that the Hammerhead targets the player
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
var ai = officer_hammerhead.AIController as EnemyAIController;
ai.sight = 2.0f;
/*var ai = officer_hammerhead.AIController as EnemyAIController;
ai.sight = 2.0f;*/
}
yield return null;
}
@@ -381,7 +375,7 @@ namespace Barotrauma.Tutorials
// Room 6
do { yield return null; } while (!officer_mudraptorObjectiveSensor.MotionDetected);
TriggerTutorialSegment(6);
officer_mudraptor = SpawnMonster(mudraptorCharacterFile, officer_mudraptorSpawnPos);
officer_mudraptor = SpawnMonster("mudraptor", officer_mudraptorSpawnPos);
do { yield return null; } while (!officer_mudraptor.IsDead);
Heal(officer);
RemoveCompletedObjective(segments[6]);
@@ -447,9 +441,9 @@ namespace Barotrauma.Tutorials
return officer?.SelectedConstruction == item;
}
private Character SpawnMonster(string characterFile, Vector2 pos)
private Character SpawnMonster(string speciesName, Vector2 pos)
{
var character = Character.Create(characterFile, pos, ToolBox.RandomSeed(8));
var character = Character.Create(speciesName, pos, ToolBox.RandomSeed(8));
var ai = character.AIController as EnemyAIController;
ai.TargetOutposts = true;
character.CharacterHealth.SetVitality(character.Health / 2);

View File

@@ -102,7 +102,7 @@ namespace Barotrauma.Tutorials
Submarine.MainSub.GodMode = true;
CharacterInfo charInfo = configElement.Element("Character") == null ?
new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer")) :
new CharacterInfo(Character.HumanSpeciesName, "", JobPrefab.Get("engineer")) :
new CharacterInfo(configElement.Element("Character"));
WayPoint wayPoint = GetSpawnPoint(charInfo);
@@ -176,9 +176,9 @@ namespace Barotrauma.Tutorials
return WayPoint.GetRandom(spawnPointType, charInfo.Job, spawnSub);
}
protected bool HasOrder(Character character, string aiTag, string option = null)
protected bool HasOrder(Character character, string identifier, string option = null)
{
if (character.CurrentOrder?.AITag == aiTag)
if (character.CurrentOrder?.Identifier == identifier)
{
if (option == null)
{

View File

@@ -32,7 +32,10 @@ namespace Barotrauma
SoundPlayer.OverrideMusicDuration = 18.0f;
}
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
{
UserData = "roundsummary"
};
int width = 760, height = 500;
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.5f), frame.RectTransform, Anchor.Center, minSize: new Point(width, height)));

View File

@@ -22,6 +22,8 @@ namespace Barotrauma
private readonly Point MinSupportedResolution = new Point(1024, 540);
private bool contentPackageSelectionDirty;
private GUIFrame settingsFrame;
private GUIButton applyButton;
@@ -122,18 +124,28 @@ namespace Barotrauma
}
if (!contentPackage.IsCompatible())
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
tickBox.TextColor = Color.Red * 0.6f;
tickBox.ToolTip = tickBox.TextBlock.ToolTip =
TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { contentPackage.Name, contentPackage.GameVersion.ToString(), GameMain.Version.ToString() });
}
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
tickBox.TextColor = Color.Red * 0.6f;
tickBox.ToolTip = tickBox.TextBlock.ToolTip =
TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
new string[2] { contentPackage.Name, string.Join(", ", missingContentTypes) }, new bool[2] { false, true });
}
else if (contentPackage.Invalid)
{
tickBox.Enabled = false;
tickBox.TextColor = Color.Red * 0.6f;
tickBox.ToolTip = tickBox.TextBlock.ToolTip =
TextManager.GetWithVariable("InvalidContentPackage", "[packagename]", contentPackage.Name) +
"\n" + string.Join("\n", contentPackage.ErrorMessages);
}
}
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.045f), generalLayoutGroup.RectTransform), TextManager.Get("Language"));
@@ -147,12 +159,28 @@ namespace Barotrauma
languageDD.OnSelected = (guiComponent, obj) =>
{
string newLanguage = obj as string;
if (newLanguage == Language) return true;
if (newLanguage == Language) { return true; }
string prevLanguage = Language;
Language = newLanguage;
UnsavedSettings = true;
var msgBox = new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
var msgBox = new GUIMessageBox(
TextManager.Get("RestartRequiredLabel"),
TextManager.Get("RestartRequiredLanguage"),
buttons: new string[] { TextManager.Get("Cancel"), TextManager.Get("OK") });
msgBox.Buttons[0].OnClicked += (btn, userdata) =>
{
Language = prevLanguage;
languageDD.SelectItem(Language);
msgBox.Close();
return true;
}; msgBox.Buttons[1].OnClicked += (btn, userdata) =>
{
ApplySettings();
GameMain.Instance.Exit();
return true;
};
return true;
};
@@ -586,7 +614,7 @@ namespace Barotrauma
BarScroll = (float)Math.Sqrt(MathUtils.InverseLerp(0.2f, 5.0f, MicrophoneVolume)),
OnMoved = (scrollBar, scroll) =>
{
MicrophoneVolume = MathHelper.Lerp(0.2f, 5.0f, scroll * scroll);
MicrophoneVolume = MathHelper.Lerp(0.2f, 10.0f, scroll * scroll);
MicrophoneVolume = (float)Math.Round(MicrophoneVolume, 1);
ChangeSliderText(scrollBar, MicrophoneVolume);
scrollBar.Step = 0.05f;
@@ -630,7 +658,7 @@ namespace Barotrauma
noiseGateSlider.Frame.Visible = false;
noiseGateSlider.Step = 0.01f;
noiseGateSlider.Range = new Vector2(-100.0f, 0.0f);
noiseGateSlider.BarScroll = MathUtils.InverseLerp(-1.0f, 0.0f, NoiseGateThreshold);
noiseGateSlider.BarScroll = MathUtils.InverseLerp(-100.0f, 0.0f, NoiseGateThreshold);
noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
noiseGateSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
@@ -976,14 +1004,15 @@ namespace Barotrauma
private bool SelectContentPackage(GUITickBox tickBox)
{
contentPackageSelectionDirty = true;
var contentPackage = tickBox.UserData as ContentPackage;
if (contentPackage.CorePackage)
{
if (tickBox.Selected)
{
//make sure no other core packages are selected
SelectedContentPackages.RemoveWhere(cp => cp.CorePackage && cp != contentPackage);
SelectedContentPackages.Add(contentPackage);
SelectedContentPackages.RemoveAll(cp => cp.CorePackage && cp != contentPackage);
SelectContentPackage(contentPackage);
foreach (GUITickBox otherTickBox in tickBox.Parent.Children)
{
ContentPackage otherContentPackage = otherTickBox.UserData as ContentPackage;
@@ -1003,11 +1032,11 @@ namespace Barotrauma
{
if (tickBox.Selected)
{
SelectedContentPackages.Add(contentPackage);
SelectContentPackage(contentPackage);
}
else
{
SelectedContentPackages.Remove(contentPackage);
DeselectContentPackage(contentPackage);
}
}
if (contentPackage.GetFilesOfType(ContentType.Submarine).Any()) { Submarine.RefreshSavedSubs(); }
@@ -1128,7 +1157,10 @@ namespace Barotrauma
{
ApplySettings();
if (Screen.Selected != GameMain.MainMenuScreen) GUI.SettingsMenuOpen = false;
if (contentPackageSelectionDirty)
{
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredGeneric"));
}
return true;
}
}

View File

@@ -113,7 +113,13 @@ namespace Barotrauma
if (item == null) return null;
var container = item.GetComponent<ItemContainer>();
if (container == null || !container.KeepOpenWhenEquipped || !character.HasEquippedItem(container.Item)) return null;
if (container == null ||
!character.CanAccessInventory(container.Inventory) ||
!container.KeepOpenWhenEquipped ||
!character.HasEquippedItem(container.Item))
{
return null;
}
return container.Inventory;
}
@@ -133,7 +139,7 @@ namespace Barotrauma
public override void CreateSlots()
{
if (slots == null) slots = new InventorySlot[capacity];
if (slots == null) { slots = new InventorySlot[capacity]; }
for (int i = 0; i < capacity; i++)
{
@@ -179,9 +185,11 @@ namespace Barotrauma
highlightedSubInventorySlots.RemoveWhere(s => s.Inventory.OpenState <= 0.0f);
foreach (var subSlot in highlightedSubInventorySlots)
{
subSlot.Slot = slots[subSlot.SlotIndex];
if (subSlot.ParentInventory == this && subSlot.SlotIndex > 0 && subSlot.SlotIndex < slots.Length)
{
subSlot.Slot = slots[subSlot.SlotIndex];
}
}
//highlightedSubInventorySlots.Clear();
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
CalculateBackgroundFrame();
@@ -475,7 +483,9 @@ namespace Barotrauma
}
List<SlotReference> hideSubInventories = new List<SlotReference>();
highlightedSubInventorySlots.RemoveWhere(s => s.SlotIndex < 0 || s.SlotIndex >= Items.Length || Items[s.SlotIndex] == null);
highlightedSubInventorySlots.RemoveWhere(s =>
s.ParentInventory == this &&
((s.SlotIndex < 0 || s.SlotIndex >= Items.Length || Items[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
{
if (highlightedSubInventorySlot.ParentInventory == this)
@@ -522,6 +532,9 @@ namespace Barotrauma
if (character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
{
//remove the highlighted slots of other characters' inventories when not grabbing anyone
highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory != this && s.ParentInventory?.Owner is Character);
for (int i = 0; i < capacity; i++)
{
var item = Items[i];
@@ -531,7 +544,10 @@ namespace Barotrauma
if (character.HasEquippedItem(item)) // Keep a subinventory display open permanently when the container is equipped
{
var itemContainer = item.GetComponent<ItemContainer>();
if (itemContainer != null && itemContainer.KeepOpenWhenEquipped && !highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory))
if (itemContainer != null &&
itemContainer.KeepOpenWhenEquipped &&
character.CanAccessInventory(itemContainer.Inventory) &&
!highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory))
{
ShowSubInventory(new SlotReference(this, slots[i], i, false, itemContainer.Inventory), deltaTime, cam, hideSubInventories, true);
}

View File

@@ -15,7 +15,7 @@ namespace Barotrauma.Items.Components
//openState when the vertices of the convex hull were last calculated
private float lastConvexHullState;
[Serialize("1,1", false)]
[Serialize("1,1", false, description: "The scale of the shadow-casting area of the door (relative to the actual size of the door).")]
public Vector2 ShadowScale
{
get;
@@ -102,7 +102,7 @@ namespace Barotrauma.Items.Components
}
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
Color color = item.SpriteColor;
if (brokenSprite == null)
@@ -115,7 +115,7 @@ namespace Barotrauma.Items.Components
if (stuck > 0.0f && weldedSprite != null)
{
Vector2 weldSpritePos = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2.0f);
if (item.Submarine != null) weldSpritePos += item.Submarine.Position;
if (item.Submarine != null) weldSpritePos += item.Submarine.DrawPosition;
weldSpritePos.Y = -weldSpritePos.Y;
weldedSprite.Draw(spriteBatch,

View File

@@ -400,7 +400,7 @@ namespace Barotrauma.Items.Components
string style = subElement.Attribute("style") == null ?
null : subElement.GetAttributeString("style", "");
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas), style, color);
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas, Anchor.Center), style, color);
DefaultLayout = GUILayoutSettings.Load(subElement);
break;
case "alternativelayout":

View File

@@ -33,49 +33,49 @@ namespace Barotrauma.Items.Components
}
#if DEBUG
[Serialize("0.0,0.0", false), Editable]
#else
[Serialize("0.0,0.0", false)]
[Editable]
#endif
[Serialize("0.0,0.0", false, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")]
public Vector2 ItemPos { get; set; }
#if DEBUG
[Serialize("0.0,0.0", false), Editable]
#else
[Serialize("0.0,0.0", false)]
[Editable]
#endif
[Serialize("0.0,0.0", false, description: "The interval at which the contained items are spaced apart from each other (in pixels).")]
public Vector2 ItemInterval { get; set; }
[Serialize(100, false)]
[Serialize(100, false, description: "How many items are placed in a row before starting a new row.")]
public int ItemsPerRow { get; set; }
/// <summary>
/// Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.
/// </summary>
[Serialize(-1.0f, false)]
[Serialize(-1.0f, false, description: "Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.")]
public float ContainedSpriteDepth { get; set; }
private float itemRotation;
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "The rotation in which the contained sprites are drawn (in degrees).")]
public float ItemRotation
{
get { return MathHelper.ToDegrees(itemRotation); }
set { itemRotation = MathHelper.ToRadians(value); }
}
[Serialize(null, false)]
[Serialize(null, false, description: "An optional text displayed above the item's inventory.")]
public string UILabel { get; set; }
[Serialize(false, false)]
[Serialize(false, false, description: "If enabled, the condition of this item is displayed in the indicator that would normally show the state of the contained items." +
" May be useful for items such as ammo boxes and magazines that spawn projectiles as needed," +
" and use the condition to determine how many projectiles can be spawned in total.")]
public bool ShowConditionInContainedStateIndicator
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
public bool KeepOpenWhenEquipped { get; set; }
[Serialize(false, false)]
[Serialize(false, false, description: "Can the inventory of this item be moved around on the screen by the player.")]
public bool MovableFrame { get; set; }
public Vector2 DrawSize
@@ -132,13 +132,13 @@ namespace Barotrauma.Items.Components
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
DrawContainedItems(spriteBatch);
DrawContainedItems(spriteBatch, itemDepth);
}
public void DrawContainedItems(SpriteBatch spriteBatch)
public void DrawContainedItems(SpriteBatch spriteBatch, float itemDepth)
{
Vector2 transformedItemPos = ItemPos * item.Scale;
Vector2 transformedItemInterval = ItemInterval * item.Scale;
@@ -199,20 +199,28 @@ namespace Barotrauma.Items.Components
{
containedItem.body.SetTransformIgnoreContacts(containedItem.body.SimPosition, currentRotation);
}
Vector2 origin = containedItem.Sprite.Origin;
if (item.FlippedX) { origin.X = containedItem.Sprite.SourceRect.Width - origin.X; }
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth;
containedSpriteDepth = itemDepth + (containedSpriteDepth - item.SpriteDepth) / 10000.0f;
containedItem.Sprite.Draw(
spriteBatch,
new Vector2(currentItemPos.X, -currentItemPos.Y),
containedItem.GetSpriteColor(),
-currentRotation,
origin,
- currentRotation,
containedItem.Scale,
spriteEffects,
depth: ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth);
depth: containedSpriteDepth);
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())
{
if (ic.hideItems) continue;
ic.DrawContainedItems(spriteBatch);
ic.DrawContainedItems(spriteBatch, containedSpriteDepth);
}
i++;

View File

@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
private float[] charWidths;
[Serialize("0,0,0,0", true)]
[Serialize("0,0,0,0", true, description: "The amount of padding around the text in pixels (left,top,right,bottom). ")]
public Vector4 Padding
{
get { return TextBlock.Padding; }
@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
}
private string text;
[Serialize("", true, translationTextTag: "Label."), Editable(100)]
[Serialize("", true, translationTextTag: "Label.", description: "The text displayed in the label."), Editable(100)]
public string Text
{
get { return text; }
@@ -54,7 +54,7 @@ namespace Barotrauma.Items.Components
private set;
}
[Editable, Serialize("0.0,0.0,0.0,1.0", true)]
[Editable, Serialize("0,0,0,255", true, description: "The color of the text displayed on the label (R,G,B,A).")]
public Color TextColor
{
get { return textColor; }
@@ -65,7 +65,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable(0.0f, 10.0f), Serialize(1.0f, true)]
[Editable(0.0f, 10.0f), Serialize(1.0f, true, description: "The scale of the text displayed on the label.")]
public float TextScale
{
get { return textBlock == null ? 1.0f : textBlock.TextScale; }
@@ -76,7 +76,7 @@ namespace Barotrauma.Items.Components
}
private bool scrollable;
[Serialize(false, true)]
[Serialize(false, true, description: "Should the text scroll horizontally across the item if it's too long to be displayed all at once.")]
public bool Scrollable
{
get { return scrollable; }
@@ -89,7 +89,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(20.0f, true)]
[Serialize(20.0f, true, description: "How fast the text scrolls across the item (only valid if Scrollable is set to true).")]
public float ScrollSpeed
{
get;
@@ -202,7 +202,7 @@ namespace Barotrauma.Items.Components
TextBlock.Text = sb.ToString();
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
var drawPos = new Vector2(
item.DrawPosition.X - item.Rect.Width / 2.0f,

View File

@@ -18,7 +18,7 @@ namespace Barotrauma.Items.Components
get { return light; }
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f)
{
@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
public override void FlipX(bool relativeToSub)
{
if (light?.LightSprite != null)
if (light?.LightSprite != null && item.Prefab.CanSpriteFlipX)
{
light.LightSpriteEffect = light.LightSpriteEffect == SpriteEffects.None ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;

View File

@@ -113,7 +113,7 @@ namespace Barotrauma.Items.Components
if (spriteIndex >= propellerSprite.FrameCount) spriteIndex = 0.0f;
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (propellerSprite != null)
{

View File

@@ -271,11 +271,14 @@ namespace Barotrauma.Items.Components
Rectangle slotRect = outputContainer.Inventory.slots[0].Rect;
GUI.DrawRectangle(spriteBatch,
new Rectangle(
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - progressState)),
slotRect.Width, (int)(slotRect.Height * progressState)),
Color.Green * 0.5f, isFilled: true);
if (fabricatedItem != null)
{
GUI.DrawRectangle(spriteBatch,
new Rectangle(
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - progressState)),
slotRect.Width, (int)(slotRect.Height * progressState)),
Color.Green * 0.5f, isFilled: true);
}
itemIcon.Draw(
spriteBatch,

View File

@@ -79,6 +79,11 @@ namespace Barotrauma.Items.Components
displayedSubs.AddRange(item.Submarine.DockedTo);
}
public override void FlipX(bool relativeToSub)
{
CreateHUD();
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
//recreate HUD if the subs we should display have changed

View File

@@ -137,7 +137,7 @@ namespace Barotrauma.Items.Components
var btnText = warningBtn.GetChild<GUITextBlock>();
btnText.Font = GUI.Font;
btnText.Wrap = true;
btnText.Wrap = false;
btnText.SetTextPos();
warningButtons.Add(warningTexts[i], warningBtn);
}

View File

@@ -27,12 +27,16 @@ namespace Barotrauma.Items.Components
private GUITickBox directionalTickBox;
private GUIScrollBar directionalSlider;
private Vector2? pingDragDirection = null;
private GUILayoutGroup activeControlsContainer;
private GUIFrame controlContainer;
private GUICustomComponent sonarView;
private Sprite directionalPingBackground;
private Sprite[] directionalPingButton;
private float displayBorderSize;
private List<SonarBlip> sonarBlips;
@@ -149,14 +153,10 @@ namespace Barotrauma.Items.Components
{
showDirectionalIndicatorTimer = 1.0f;
float pingAngle = MathHelper.Lerp(0.0f, MathHelper.TwoPi, scroll);
pingDirection = new Vector2((float)Math.Cos(pingAngle), (float)Math.Sin(pingAngle));
if (GameMain.Client != null)
{
unsentChanges = true;
correctionTimer = CorrectionDelay;
}
SetPingDirection(new Vector2((float)Math.Cos(pingAngle), (float)Math.Sin(pingAngle)));
return true;
}
},
Range = new Vector2(0,MathHelper.TwoPi)
};
signalWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedControlContainer.RectTransform), "", Color.Orange, textAlignment: Alignment.Center);
@@ -178,6 +178,14 @@ namespace Barotrauma.Items.Components
case "directionalpingcircle":
directionalPingCircle = new Sprite(subElement);
break;
case "directionalpingbackground":
directionalPingBackground = new Sprite(subElement);
break;
case "directionalpingbutton":
if (directionalPingButton == null) { directionalPingButton = new Sprite[3]; }
int index = subElement.GetAttributeInt("index", 0);
directionalPingButton[index] = new Sprite(subElement);
break;
case "screenoverlay":
screenOverlay = new Sprite(subElement);
break;
@@ -206,6 +214,16 @@ namespace Barotrauma.Items.Components
controlContainer.RectTransform.AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0);
}
private void SetPingDirection(Vector2 direction)
{
pingDirection = direction;
if (GameMain.Client != null)
{
unsentChanges = true;
correctionTimer = CorrectionDelay;
}
}
public override void OnItemLoaded()
{
zoomSlider.BarScroll = MathUtils.InverseLerp(MinZoom, MaxZoom, zoom);
@@ -352,6 +370,43 @@ namespace Barotrauma.Items.Components
prevDockingDist = float.MaxValue;
}
if (steering != null && directionalPingButton != null)
{
steering.SteerRadius = useDirectionalPing && pingDragDirection != null ?
-1.0f :
PlayerInput.LeftButtonDown() || !PlayerInput.LeftButtonHeld() ?
(float?)((sonarView.Rect.Width / 2) - (directionalPingButton[0].size.X * sonarView.Rect.Width / screenBackground.size.X)) :
null;
}
if (useDirectionalPing && PlayerInput.LeftButtonHeld())
{
if ((MouseInDirectionalPingRing(sonarView.Rect, false) && PlayerInput.LeftButtonDown()) || pingDragDirection != null)
{
Vector2 newDragDir = Vector2.Normalize(PlayerInput.MousePosition - sonarView.Rect.Center.ToVector2());
if (pingDragDirection == null && !MouseInDirectionalPingRing(sonarView.Rect, true))
{
directionalSlider.BarScrollValue = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(newDragDir));
directionalSlider.OnMoved(directionalSlider, directionalSlider.BarScroll);
}
else if (pingDragDirection != null)
{
float newAngle = MathUtils.VectorToAngle(newDragDir);
float oldAngle = MathUtils.VectorToAngle(pingDragDirection.Value);
float pingAngle = MathUtils.VectorToAngle(pingDirection);
pingAngle = MathUtils.WrapAngleTwoPi(pingAngle + MathUtils.GetShortestAngle(oldAngle, newAngle));
directionalSlider.BarScrollValue = pingAngle;
directionalSlider.OnMoved(directionalSlider, directionalSlider.BarScroll);
}
pingDragDirection = newDragDir;
}
}
else
{
pingDragDirection = null;
}
for (var pingIndex = 0; pingIndex < activePingsCount; ++pingIndex)
{
var activePing = activePings[pingIndex];
@@ -391,6 +446,28 @@ namespace Barotrauma.Items.Components
prevPassivePingRadius = passivePingRadius;
}
private bool MouseInDirectionalPingRing(Rectangle rect, bool onButton)
{
if (!useDirectionalPing || directionalPingButton == null) { return false; }
float endRadius = rect.Width / 2.0f;
float startRadius = endRadius - directionalPingButton[0].size.X * rect.Width / screenBackground.size.X;
Vector2 center = rect.Center.ToVector2();
float dist = Vector2.DistanceSquared(PlayerInput.MousePosition,center);
bool retVal = (dist >= startRadius*startRadius) && (dist < endRadius*endRadius);
if (onButton)
{
float pingAngle = MathUtils.VectorToAngle(pingDirection);
float mouseAngle = MathUtils.VectorToAngle(Vector2.Normalize(PlayerInput.MousePosition - center));
retVal &= Math.Abs(MathUtils.GetShortestAngle(mouseAngle, pingAngle)) < MathHelper.ToRadians(DirectionalPingSector * 0.5f);
}
return retVal;
}
private void DrawSonar(SpriteBatch spriteBatch, Rectangle rect)
{
displayBorderSize = 0.2f;
@@ -403,6 +480,24 @@ namespace Barotrauma.Items.Components
screenBackground.Draw(spriteBatch, center, 0.0f, rect.Width / screenBackground.size.X);
}
if (useDirectionalPing)
{
directionalPingBackground?.Draw(spriteBatch, center, 0.0f, rect.Width / directionalPingBackground.size.X);
if (directionalPingButton != null)
{
int buttonSprIndex = 0;
if (pingDragDirection != null)
{
buttonSprIndex = 2;
}
else if (MouseInDirectionalPingRing(rect, true))
{
buttonSprIndex = 1;
}
directionalPingButton[buttonSprIndex]?.Draw(spriteBatch, center, MathUtils.VectorToAngle(pingDirection), rect.Width / directionalPingBackground.size.X);
}
}
if (currentMode == Mode.Active && currentPingIndex != -1)
{
var activePing = activePings[currentPingIndex];

View File

@@ -47,6 +47,10 @@ namespace Barotrauma.Items.Components
private Sprite maintainPosIndicator, maintainPosOriginIndicator;
private Sprite steeringIndicator;
private List<DockingPort> connectedPorts = new List<DockingPort>();
private float checkConnectedPortsTimer;
private const float CheckConnectedPortsInterval = 1.0f;
private Vector2 keyboardInput = Vector2.Zero;
private float inputCumulation;
@@ -86,6 +90,19 @@ namespace Barotrauma.Items.Components
set;
} = true;
private float steerRadius;
public float? SteerRadius
{
get
{
return steerRadius;
}
set
{
steerRadius = value ?? (steerArea.Rect.Width / 2);
}
}
public List<DockingPort> DockingSources = new List<DockingPort>();
public DockingPort ActiveDockingSource, DockingTarget;
@@ -317,7 +334,7 @@ namespace Barotrauma.Items.Components
{
if (GameMain.Client == null)
{
item.SendSignal(0, "1", "toggle_docking", sender: Character.Controlled);
item.SendSignal(0, "1", "toggle_docking", sender: null);
}
else
{
@@ -384,6 +401,8 @@ namespace Barotrauma.Items.Components
statusContainer.RectTransform.AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0);
steerArea.RectTransform.NonScaledSize = new Point(viewSize);
dockingContainer.RectTransform.AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0);
steerRadius = steerArea.Rect.Width / 2;
}
private void FindConnectedDockingPort()
@@ -661,7 +680,7 @@ namespace Barotrauma.Items.Components
pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.5f;
if (Vector2.Distance(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerArea.Rect.Width / 2)
if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
{
if (PlayerInput.LeftButtonHeld())
{
@@ -735,10 +754,21 @@ namespace Barotrauma.Items.Components
}
if (!UseAutoDocking) { return; }
if (checkConnectedPortsTimer <= 0.0f)
{
Connection dockingConnection = item.Connections?.FirstOrDefault(c => c.Name == "toggle_docking");
if (dockingConnection != null)
{
connectedPorts = item.GetConnectedComponentsRecursive<DockingPort>(dockingConnection);
}
checkConnectedPortsTimer = CheckConnectedPortsInterval;
}
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
DockingModeEnabled = false;
foreach (DockingPort sourcePort in DockingPort.List)
foreach (DockingPort sourcePort in connectedPorts)
{
if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; }
if (sourcePort.Item.Submarine != controlledSub) { continue; }
@@ -826,6 +856,7 @@ namespace Barotrauma.Items.Components
int msgStartPos = msg.BitPosition;
bool autoPilot = msg.ReadBoolean();
bool dockingButtonClicked = msg.ReadBoolean();
Vector2 newSteeringInput = steeringInput;
Vector2 newTargetVelocity = targetVelocity;
float newSteeringAdjustSpeed = steeringAdjustSpeed;
@@ -833,6 +864,11 @@ namespace Barotrauma.Items.Components
Vector2? newPosToMaintain = null;
bool headingToStart = false;
if (dockingButtonClicked)
{
item.SendSignal(0, "1", "toggle_docking", sender: null);
}
if (autoPilot)
{
maintainPos = msg.ReadBoolean();

View File

@@ -92,7 +92,7 @@ namespace Barotrauma.Items.Components
chargeIndicator.Color = ToolBox.GradientLerp(chargeRatio, Color.Red, Color.Orange, Color.Green);
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (indicatorSize.X <= 1.0f || indicatorSize.Y <= 1.0f) return;
@@ -143,7 +143,10 @@ namespace Barotrauma.Items.Components
float rechargeRate = msg.ReadRangedInteger(0, 10) / 10.0f;
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
rechargeSpeedSlider.BarScroll = rechargeRate;
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = rechargeRate;
}
#endif
Charge = msg.ReadRangedSingle(0.0f, 1.0f, 8) * capacity;
}

View File

@@ -16,21 +16,17 @@ namespace Barotrauma.Items.Components
: IDrawableComponent
#endif
{
public ParticleEmitter ParticleEmitter
{
get;
private set;
}
#if DEBUG
public Vector2 DrawSize
{
get { return GameMain.DebugDraw ? Vector2.One * Range : Vector2.Zero; }
}
}
#endif
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
private List<Pair<RelatedItem, ParticleEmitter>> ParticleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
private List<ParticleEmitter> particleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> particleEmitterHitCharacter = new List<ParticleEmitter>();
private List<Pair<RelatedItem, ParticleEmitter>> particleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
private float prevProgressBarState;
@@ -41,7 +37,7 @@ namespace Barotrauma.Items.Components
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "particleemitter":
ParticleEmitter = new ParticleEmitter(subElement);
particleEmitters.Add(new ParticleEmitter(subElement));
break;
case "particleemitterhititem":
string[] identifiers = subElement.GetAttributeStringArray("identifiers", new string[0]);
@@ -49,16 +45,16 @@ namespace Barotrauma.Items.Components
string[] excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifiers", new string[0]);
if (excludedIdentifiers.Length == 0) excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifier", new string[0]);
ParticleEmitterHitItem.Add(
particleEmitterHitItem.Add(
new Pair<RelatedItem, ParticleEmitter>(
new RelatedItem(identifiers, excludedIdentifiers),
new ParticleEmitter(subElement)));
break;
case "particleemitterhitstructure":
ParticleEmitterHitStructure.Add(new ParticleEmitter(subElement));
particleEmitterHitStructure.Add(new ParticleEmitter(subElement));
break;
case "particleemitterhitcharacter":
ParticleEmitterHitCharacter.Add(new ParticleEmitter(subElement));
particleEmitterHitCharacter.Add(new ParticleEmitter(subElement));
break;
}
}
@@ -67,12 +63,12 @@ namespace Barotrauma.Items.Components
partial void UseProjSpecific(float deltaTime, Vector2 raystart)
{
if (ParticleEmitter != null)
foreach (ParticleEmitter particleEmitter in particleEmitters)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
ParticleEmitter.Emit(
particleEmitter.Emit(
deltaTime, ConvertUnits.ToDisplayUnits(raystart),
item.CurrentHull, particleAngle, ParticleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
item.CurrentHull, particleAngle, particleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
}
}
@@ -94,7 +90,7 @@ namespace Barotrauma.Items.Components
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetStructure.Submarine != null) particlePos += targetStructure.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitStructure)
foreach (var emitter in particleEmitterHitStructure)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
@@ -105,7 +101,7 @@ namespace Barotrauma.Items.Components
{
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetCharacter.Submarine != null) particlePos += targetCharacter.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitCharacter)
foreach (var emitter in particleEmitterHitCharacter)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
@@ -133,7 +129,7 @@ namespace Barotrauma.Items.Components
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitItem)
foreach (var emitter in particleEmitterHitItem)
{
if (!emitter.First.MatchesItem(targetItem)) continue;
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
@@ -141,7 +137,7 @@ namespace Barotrauma.Items.Components
}
}
#if DEBUG
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (GameMain.DebugDraw && IsActive)
{

View File

@@ -10,16 +10,10 @@ namespace Barotrauma.Items.Components
{
partial class Repairable : ItemComponent, IDrawableComponent
{
public GUIButton RepairButton
{
get { return repairButton; }
}
private GUIButton repairButton;
public GUIButton SabotageButton
{
get { return sabotageButton; }
}
private GUIButton sabotageButton;
public GUIButton RepairButton { get; private set; }
public GUIButton SabotageButton { get; private set; }
private GUIProgressBar progressBar;
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
@@ -33,7 +27,7 @@ namespace Barotrauma.Items.Components
private FixActions requestStartFixAction;
[Serialize("", false)]
[Serialize("", false, description: "An optional description of the needed repairs displayed in the repair interface.")]
public string Description
{
get;
@@ -83,7 +77,7 @@ namespace Barotrauma.Items.Components
repairButtonText = TextManager.Get("RepairButton");
repairingText = TextManager.Get("Repairing");
repairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter), repairButtonText)
RepairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter), repairButtonText)
{
OnClicked = (btn, obj) =>
{
@@ -94,7 +88,7 @@ namespace Barotrauma.Items.Components
};
sabotageButtonText = TextManager.Get("SabotageButton");
sabotagingText = TextManager.Get("Sabotaging");
sabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText)
SabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText)
{
OnClicked = (btn, obj) =>
{
@@ -165,14 +159,14 @@ namespace Barotrauma.Items.Components
progressBar.BarSize = item.Condition / item.MaxCondition;
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, Color.Red, Color.Orange, Color.Green);
repairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && item.ConditionPercentage <= ShowRepairUIThreshold;
repairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && item.ConditionPercentage <= ShowRepairUIThreshold;
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
repairButtonText :
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
sabotageButton.Visible = character.IsTraitor;
sabotageButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Sabotage)) && character.IsTraitor && item.ConditionPercentage > MinSabotageCondition;
sabotageButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Sabotage || !character.IsTraitor) ?
SabotageButton.Visible = character.IsTraitor;
SabotageButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Sabotage)) && character.IsTraitor && item.ConditionPercentage > MinSabotageCondition;
SabotageButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Sabotage || !character.IsTraitor) ?
sabotageButtonText :
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
@@ -193,7 +187,7 @@ namespace Barotrauma.Items.Components
}
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (GameMain.DebugDraw && Character.Controlled?.FocusedItem == item)
{

View File

@@ -10,7 +10,7 @@ namespace Barotrauma.Items.Components
get { return new Vector2(rangeX, rangeY) * 2.0f; }
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (!editing || !MapEntity.SelectedList.Contains(item)) return;

View File

@@ -10,7 +10,7 @@ namespace Barotrauma.Items.Components
get { return new Vector2(range * 2); }
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (!editing || !MapEntity.SelectedList.Contains(item)) return;

View File

@@ -48,7 +48,7 @@ namespace Barotrauma.Items.Components
get { return sectionExtents; }
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (sections.Count == 0 && !IsActive || Hidden)
{
@@ -154,6 +154,18 @@ namespace Barotrauma.Items.Components
public static void UpdateEditing(List<Wire> wires)
{
Wire equippedWire =
Character.Controlled?.SelectedItems[0]?.GetComponent<Wire>() ??
Character.Controlled?.SelectedItems[1]?.GetComponent<Wire>();
if (equippedWire != null)
{
if (PlayerInput.LeftButtonClicked() && Character.Controlled.SelectedConstruction == null)
{
equippedWire.Use(1.0f, Character.Controlled);
}
return;
}
//dragging a node of some wire
if (draggingWire != null)
{

View File

@@ -33,14 +33,14 @@ namespace Barotrauma.Items.Components
TextManager.Get("NotBreathing")
};
[Serialize(500.0f, false)]
[Serialize(500.0f, false, description: "How close to a target the user must be to see their health data (in pixels).")]
public float Range
{
get;
private set;
}
[Serialize(50.0f, false)]
[Serialize(50.0f, false, description: "The range within which the health info texts fades out.")]
public float FadeOutRange
{
get;

View File

@@ -25,7 +25,7 @@ namespace Barotrauma.Items.Components
private Vector2 crosshairPos, crosshairPointerPos;
private Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
private readonly Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
private float prevAngle;
private bool flashLowPower;
@@ -33,30 +33,30 @@ namespace Barotrauma.Items.Components
private float flashTimer;
private float flashLength = 1;
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
[Editable, Serialize("0.0,0.0,0.0,0.0", true)]
[Editable, Serialize("0,0,0,0", true, description: "Optional screen tint color when the item is being operated (R,G,B,A).")]
public Color HudTint
{
get;
private set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the charge of the connected batteries/supercapacitors be shown at the top of the screen when operating the item.")]
public bool ShowChargeIndicator
{
get;
private set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the available ammunition be shown at the top of the screen when operating the item.")]
public bool ShowProjectileIndicator
{
get;
private set;
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "How far the barrel \"recoils back\" when the turret is fired (in pixels).")]
public float RecoilDistance
{
get;
@@ -240,7 +240,7 @@ namespace Barotrauma.Items.Components
crosshairPointerPos = PlayerInput.MousePosition;
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
if (item.Submarine != null) drawPos += item.Submarine.DrawPosition;

View File

@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
get { return Vector2.Zero; }
}
public void Draw(SpriteBatch spriteBatch, bool editing)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (dockingState == 0.0f) return;
@@ -105,5 +105,56 @@ namespace Barotrauma.Items.Components
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool isDocked = msg.ReadBoolean();
for (int i = 0; i < 2; i++)
{
if (hulls[i] == null) continue;
item.linkedTo.Remove(hulls[i]);
hulls[i].Remove();
hulls[i] = null;
}
if (gap != null)
{
item.linkedTo.Remove(gap);
gap.Remove();
gap = null;
}
if (isDocked)
{
ushort dockingTargetID = msg.ReadUInt16();
bool isLocked = msg.ReadBoolean();
Entity targetEntity = Entity.FindEntityByID(dockingTargetID);
if (targetEntity == null || !(targetEntity is Item))
{
DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + targetEntity?.ToString() ?? "null" + ")");
return;
}
DockingTarget = (targetEntity as Item).GetComponent<DockingPort>();
if (DockingTarget == null)
{
DebugConsole.ThrowError("Invalid docking port network event (" + targetEntity + " doesn't have a docking port component)");
return;
}
Dock(DockingTarget);
if (isLocked)
{
Lock(isNetworkMessage: true, forcePosition: true);
}
}
else
{
Undock();
}
}
}
}

View File

@@ -209,7 +209,14 @@ namespace Barotrauma
public static SlotReference SelectedSlot
{
get { return selectedSlot; }
get
{
if (selectedSlot?.ParentInventory?.Owner == null || selectedSlot.ParentInventory.Owner.Removed)
{
return null;
}
return selectedSlot;
}
}
public virtual void CreateSlots()
@@ -430,6 +437,8 @@ namespace Barotrauma
if (canMove)
{
subInventory.HideTimer = 1.0f;
subInventory.OpenState = 1.0f;
if (subInventory.movableFrameRect.Contains(PlayerInput.MousePosition) && PlayerInput.RightButtonClicked())
{
container.Inventory.savedPosition = container.Inventory.originalPos;

View File

@@ -26,6 +26,9 @@ namespace Barotrauma
public float LastImpactSoundTime;
public const float ImpactSoundInterval = 0.2f;
private bool editingHUDRefreshPending;
private float editingHUDRefreshTimer;
class SpriteState
{
public float RotationState;
@@ -33,7 +36,7 @@ namespace Barotrauma
public bool IsActive = true;
}
private Dictionary<ItemPrefab.DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<ItemPrefab.DecorativeSprite, SpriteState>();
private Dictionary<DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<DecorativeSprite, SpriteState>();
private Sprite activeSprite;
public override Sprite Sprite
@@ -128,11 +131,13 @@ namespace Barotrauma
}
}
foreach (BrokenItemSprite brokenSprite in Prefab.BrokenSprites)
for (int i = 0; i < Prefab.BrokenSprites.Count;i++)
{
if (condition <= brokenSprite.MaxCondition)
float minCondition = i > 0 ? Prefab.BrokenSprites[i - i].MaxCondition : 0.0f;
if (condition <= minCondition ||
condition <= Prefab.BrokenSprites[i].MaxCondition && !Prefab.BrokenSprites[i].FadeIn)
{
activeSprite = brokenSprite.Sprite;
activeSprite = Prefab.BrokenSprites[i].Sprite;
break;
}
}
@@ -211,18 +216,18 @@ namespace Barotrauma
}
}
float depth = GetDrawDepth();
if (activeSprite != null)
{
SpriteEffects oldEffects = activeSprite.effects;
activeSprite.effects ^= SpriteEffects;
SpriteEffects oldBrokenSpriteEffects = SpriteEffects.None;
if (fadeInBrokenSprite != null)
if (fadeInBrokenSprite != null && fadeInBrokenSprite.Sprite != activeSprite)
{
oldBrokenSpriteEffects = fadeInBrokenSprite.Sprite.effects;
fadeInBrokenSprite.Sprite.effects ^= SpriteEffects;
}
float depth = GetDrawDepth();
if (body == null)
{
bool flipHorizontal = (SpriteEffects & SpriteEffects.FlipHorizontally) != 0;
@@ -304,9 +309,9 @@ namespace Barotrauma
}
activeSprite.effects = oldEffects;
if (fadeInBrokenSprite != null)
if (fadeInBrokenSprite != null && fadeInBrokenSprite.Sprite != activeSprite)
{
fadeInBrokenSprite.Sprite.effects = oldEffects;
fadeInBrokenSprite.Sprite.effects = oldBrokenSpriteEffects;
}
}
@@ -314,7 +319,7 @@ namespace Barotrauma
//causing them to be removed from the list
for (int i = drawableComponents.Count - 1; i >= 0; i--)
{
drawableComponents[i].Draw(spriteBatch, editing);
drawableComponents[i].Draw(spriteBatch, editing, depth);
}
if (GameMain.DebugDraw)
@@ -437,21 +442,23 @@ namespace Barotrauma
public override void UpdateEditing(Camera cam)
{
if (editingHUD == null || editingHUD.UserData as Item != this)
if (editingHUD == null || editingHUD.UserData as Item != this ||
(editingHUDRefreshPending && editingHUDRefreshTimer <= 0.0f))
{
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
editingHUDRefreshTimer = 1.0f;
}
if (Screen.Selected != GameMain.SubEditorScreen) return;
if (Screen.Selected != GameMain.SubEditorScreen) { return; }
if (Character.Controlled == null) activeHUDs.Clear();
if (Character.Controlled == null) { activeHUDs.Clear(); }
if (!Linkable) return;
if (!Linkable) { return; }
if (!PlayerInput.KeyDown(Keys.Space)) return;
if (!PlayerInput.KeyDown(Keys.Space)) { return; }
bool lClick = PlayerInput.LeftButtonClicked();
bool rClick = PlayerInput.RightButtonClicked();
if (!lClick && !rClick) return;
if (!lClick && !rClick) { return; }
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
var otherEntity = mapEntityList.FirstOrDefault(e => e != this && e.IsHighlighted && e.IsMouseOn(position));
@@ -472,6 +479,8 @@ namespace Barotrauma
public GUIComponent CreateEditingHUD(bool inGame = false)
{
editingHUDRefreshPending = false;
int heightScaled = (int)(20 * GUI.Scale);
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)
@@ -672,6 +681,13 @@ namespace Barotrauma
editingHUDCreated = editingHUD != null && editingHUD != prevEditingHUD;
}
if (editingHUD == null ||
!(GUI.KeyboardDispatcher.Subscriber is GUITextBox textBox) ||
!editingHUD.IsParentOf(textBox))
{
editingHUDRefreshTimer -= deltaTime;
}
List<ItemComponent> prevActiveHUDs = new List<ItemComponent>(activeHUDs);
List<ItemComponent> activeComponents = new List<ItemComponent>(components);
foreach (MapEntity entity in linkedTo)
@@ -916,6 +932,7 @@ namespace Barotrauma
break;
case NetEntityEvent.Type.ChangeProperty:
ReadPropertyChange(msg, false);
editingHUDRefreshPending = true;
break;
case NetEntityEvent.Type.Invalid:
break;
@@ -954,6 +971,7 @@ namespace Barotrauma
break;
case NetEntityEvent.Type.ChangeProperty:
WritePropertyChange(msg, extraData, true);
editingHUDRefreshTimer = 1.0f;
break;
case NetEntityEvent.Type.Combine:
UInt16 combineTargetID = (UInt16)extraData[1];
@@ -969,6 +987,7 @@ namespace Barotrauma
if (parentInventory != null || body == null || !body.Enabled || Removed)
{
positionBuffer.Clear();
return;
}

View File

@@ -47,138 +47,6 @@ namespace Barotrauma
partial class ItemPrefab : MapEntityPrefab
{
public class DecorativeSprite
{
public Sprite Sprite { get; private set; }
public enum AnimationType
{
None,
Sine,
Noise
}
[Serialize("0,0", false)]
public Vector2 Offset { get; private set; }
[Serialize(AnimationType.None, false)]
public AnimationType OffsetAnim { get; private set; }
[Serialize(0.0f, false)]
public float OffsetAnimSpeed { get; private set; }
private float rotationSpeedRadians;
[Serialize(0.0f, false)]
public float RotationSpeed
{
get
{
return MathHelper.ToDegrees(rotationSpeedRadians);
}
private set
{
rotationSpeedRadians = MathHelper.ToRadians(value);
}
}
[Serialize(0.0f, false)]
public float Rotation { get; private set; }
[Serialize(AnimationType.None, false)]
public AnimationType RotationAnim { get; private set; }
/// <summary>
/// If > 0, only one sprite of the same group is used (chosen randomly)
/// </summary>
[Serialize(0, false)]
public int RandomGroupID { get; private set; }
/// <summary>
/// The sprite is only drawn if these conditions are fulfilled
/// </summary>
public List<PropertyConditional> IsActiveConditionals { get; private set; } = new List<PropertyConditional>();
/// <summary>
/// The sprite is only animated if these conditions are fulfilled
/// </summary>
public List<PropertyConditional> AnimationConditionals { get; private set; } = new List<PropertyConditional>();
public DecorativeSprite(XElement element, string path = "", bool lazyLoad = false)
{
Sprite = new Sprite(element, path, lazyLoad: lazyLoad);
SerializableProperty.DeserializeProperties(this, element);
foreach (XElement subElement in element.Elements())
{
List<PropertyConditional> conditionalList = null;
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "conditional":
case "isactiveconditional":
conditionalList = IsActiveConditionals;
break;
case "animationconditional":
conditionalList = AnimationConditionals;
break;
default:
continue;
}
foreach (XAttribute attribute in subElement.Attributes())
{
if (attribute.Name.ToString().ToLowerInvariant() == "targetitemcomponent") { continue; }
conditionalList.Add(new PropertyConditional(attribute));
}
}
}
public Vector2 GetOffset(ref float offsetState)
{
if (OffsetAnimSpeed <= 0.0f)
{
return Offset;
}
switch (OffsetAnim)
{
case AnimationType.Sine:
offsetState = offsetState % (MathHelper.TwoPi / OffsetAnimSpeed);
return Offset * (float)Math.Sin(offsetState * OffsetAnimSpeed);
case AnimationType.Noise:
offsetState = offsetState % (1.0f / (OffsetAnimSpeed * 0.1f));
float t = offsetState * 0.1f * OffsetAnimSpeed;
return new Vector2(
Offset.X * (PerlinNoise.GetPerlin(t, t) - 0.5f),
Offset.Y * (PerlinNoise.GetPerlin(t + 0.5f, t + 0.5f) - 0.5f));
default:
return Offset;
}
}
public float GetRotation(ref float rotationState)
{
if (rotationSpeedRadians <= 0.0f)
{
return Rotation;
}
switch (OffsetAnim)
{
case AnimationType.Sine:
rotationState = rotationState % (MathHelper.TwoPi / rotationSpeedRadians);
return Rotation * (float)Math.Sin(rotationState * rotationSpeedRadians);
case AnimationType.Noise:
rotationState = rotationState % (1.0f / rotationSpeedRadians);
return Rotation * PerlinNoise.GetPerlin(rotationState * rotationSpeedRadians, rotationState * rotationSpeedRadians);
default:
return rotationState * rotationSpeedRadians;
}
}
public void Remove()
{
Sprite?.Remove();
Sprite = null;
}
}
public List<BrokenItemSprite> BrokenSprites = new List<BrokenItemSprite>();
public List<DecorativeSprite> DecorativeSprites = new List<DecorativeSprite>();
public List<ContainedItemSprite> ContainedSprites = new List<ContainedItemSprite>();

View File

@@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components
get { return Vector2.Zero; }
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (!IsActive) return;

View File

@@ -22,6 +22,7 @@ namespace Barotrauma
{
LoadConfig(configPath);
}
public BackgroundCreatureManager(IEnumerable<string> files)
{
foreach(var file in files)
@@ -29,14 +30,26 @@ namespace Barotrauma
LoadConfig(file);
}
}
private void LoadConfig(string configPath)
{
try
{
XDocument doc = XMLExtensions.TryLoadXml(configPath);
if (doc == null || doc.Root == null) return;
if (doc == null) { return; }
var mainElement = doc.Root;
if (mainElement.IsOverride())
{
mainElement = doc.Root.FirstElement();
prefabs.Clear();
DebugConsole.NewMessage($"Overriding all background creatures with '{configPath}'", Color.Yellow);
}
else if (prefabs.Any())
{
DebugConsole.NewMessage($"Loading additional background creatures from file '{configPath}'");
}
foreach (XElement element in doc.Root.Elements())
foreach (XElement element in mainElement.Elements())
{
prefabs.Add(new BackgroundCreaturePrefab(element));
};
@@ -46,6 +59,7 @@ namespace Barotrauma
DebugConsole.ThrowError(String.Format("Failed to load BackgroundCreatures from {0}", configPath), e);
}
}
public void SpawnSprites(int count, Vector2? position = null)
{
activeSprites.Clear();

View File

@@ -41,7 +41,7 @@ namespace Barotrauma
{
if (subElement.Name.ToString().ToLowerInvariant() != "sprite") continue;
Sprite = new Sprite(subElement);
Sprite = new Sprite(subElement, lazyLoad: true);
break;
}
}

View File

@@ -132,7 +132,7 @@ namespace Barotrauma
var newDeformation = SpriteDeformation.Load(animationElement, Prefab.Name);
if (newDeformation != null)
{
newDeformation.DeformationParams = Prefab.SpriteDeformations[j].DeformationParams;
newDeformation.Params = Prefab.SpriteDeformations[j].Params;
spriteDeformations.Add(newDeformation);
j++;
}

View File

@@ -72,6 +72,11 @@ namespace Barotrauma.Lights
private float ambientLightUpdateTimer;
public IEnumerable<LightSource> Lights
{
get { return lights; }
}
public LightManager(GraphicsDevice graphics, ContentManager content)
{
lights = new List<LightSource>();

View File

@@ -10,15 +10,11 @@ namespace Barotrauma.Lights
{
class LightSourceParams : ISerializableEntity
{
public string Name => "LightSource";
public string Name => "Light Source";
public bool Persistent;
public Dictionary<string, SerializableProperty> SerializableProperties
{
get;
private set;
} = new Dictionary<string, SerializableProperty>();
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; } = new Dictionary<string, SerializableProperty>();
[Serialize("1.0,1.0,1.0,1.0", true), Editable]
public Color Color
@@ -28,6 +24,7 @@ namespace Barotrauma.Lights
}
private float range;
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
public float Range
{
@@ -64,7 +61,7 @@ namespace Barotrauma.Lights
public LightSourceParams(XElement element)
{
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
Deserialize(element);
foreach (XElement subElement in element.Elements())
{
@@ -103,6 +100,17 @@ namespace Barotrauma.Lights
Range = range;
Color = color;
}
public bool Deserialize(XElement element)
{
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
return SerializableProperties != null;
}
public void Serialize(XElement element)
{
SerializableProperty.SerializeProperties(this, element, true);
}
}
class LightSource
@@ -893,13 +901,21 @@ namespace Barotrauma.Lights
if (GameMain.DebugDraw)
{
Vector2 drawPos = position;
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
drawPos.Y = -drawPos.Y;
if (CastShadows && Screen.Selected == GameMain.SubEditorScreen)
{
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 20, Vector2.One * 40, Color.Orange, isFilled: false);
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * 20, drawPos + Vector2.One * 20, Color.Orange);
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * 20, drawPos + new Vector2(1.0f, -1.0f) * 20, Color.Orange);
}
//visualize light recalculations
float timeSinceRecalculation = (float)Timing.TotalTime - lastRecalculationTime;
if (timeSinceRecalculation < 0.1f)
{
Vector2 drawPos = position;
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
drawPos.Y = -drawPos.Y;
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, Color.Red * (1.0f - timeSinceRecalculation * 10.0f), isFilled: true);
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * Range, drawPos + Vector2.One * Range, Color);
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * Range, drawPos + new Vector2(1.0f, -1.0f) * Range, Color);

View File

@@ -92,7 +92,7 @@ namespace Barotrauma
public virtual void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) { }
public virtual void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect) { }
public virtual void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect, bool editing) { }
/// <summary>
/// Update the selection logic in submarine editor

View File

@@ -170,9 +170,9 @@ namespace Barotrauma
Draw(spriteBatch, editing, back, null);
}
public override void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect)
public override void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect, bool editing)
{
Draw(spriteBatch, false, false, damageEffect);
Draw(spriteBatch, editing, false, damageEffect);
}
private void Draw(SpriteBatch spriteBatch, bool editing, bool back = true, Effect damageEffect = null)
@@ -265,7 +265,7 @@ namespace Barotrauma
}
}
if (back == depth > 0.5f || editing)
if (back == depth > 0.5f)
{
SpriteEffects oldEffects = prefab.sprite.effects;
prefab.sprite.effects ^= SpriteEffects;

View File

@@ -235,7 +235,7 @@ namespace Barotrauma
foreach (MapEntity e in entitiesToRender)
{
if (e.DrawDamageEffect)
e.DrawDamage(spriteBatch, damageEffect);
e.DrawDamage(spriteBatch, damageEffect, editing);
}
if (damageEffect != null)
{

View File

@@ -301,7 +301,7 @@ namespace Barotrauma
}
};
jobDropDown.AddItem(TextManager.Get("Any"), null);
foreach (JobPrefab jobPrefab in JobPrefab.List)
foreach (JobPrefab jobPrefab in JobPrefab.List.Values)
{
jobDropDown.AddItem(jobPrefab.Name, jobPrefab);
}

View File

@@ -9,6 +9,7 @@ namespace Barotrauma.Networking
struct TempClient
{
public string Name;
public UInt16 NameID;
public UInt64 SteamID;
public byte ID;
public UInt16 CharacterID;

View File

@@ -18,6 +18,22 @@ namespace Barotrauma.Networking
get { return true; }
}
private string name;
private UInt16 nameId = 0;
public string Name
{
get { return name; }
}
public void SetName(string value)
{
if (string.IsNullOrEmpty(value)) { return; }
name = value.Replace(":", "").Replace(";", "");
nameId++;
}
private ClientPeer clientPeer;
public ClientPeer ClientPeer { get { return clientPeer; } }
@@ -213,7 +229,7 @@ namespace Barotrauma.Networking
Hull.EditFire = false;
Hull.EditWater = false;
Name = newName;
SetName(newName);
entityEventManager = new ClientEntityEventManager(this);
@@ -221,7 +237,7 @@ namespace Barotrauma.Networking
fileReceiver.OnFinished += OnFileReceived;
fileReceiver.OnTransferFailed += OnTransferFailed;
characterInfo = new CharacterInfo(Character.HumanConfigFile, name, null)
characterInfo = new CharacterInfo(Character.HumanSpeciesName, name, null)
{
Job = null
};
@@ -311,6 +327,7 @@ namespace Barotrauma.Networking
translatedEndpoint = endpoint;
}
clientPeer.OnDisconnect = OnDisconnect;
clientPeer.OnDisconnectMessageReceived = HandleDisconnectMessage;
clientPeer.OnInitializationComplete = () =>
{
if (SteamManager.IsInitialized)
@@ -323,6 +340,8 @@ namespace Barotrauma.Networking
canStart = true;
connected = true;
VoipClient = new VoipClient(this, clientPeer);
if (Screen.Selected != GameMain.GameScreen)
{
GameMain.NetLobbyScreen.Select();
@@ -591,13 +610,17 @@ namespace Barotrauma.Networking
respawnManager.Update(deltaTime);
}
if (updateTimer > DateTime.Now) { return; }
SendIngameUpdate();
if (updateTimer <= DateTime.Now)
{
SendIngameUpdate();
}
}
else
{
if (updateTimer > DateTime.Now) { return; }
SendLobbyUpdate();
if (updateTimer <= DateTime.Now)
{
SendLobbyUpdate();
}
}
if (serverSettings.VoiceChatEnabled)
@@ -615,8 +638,11 @@ namespace Barotrauma.Networking
}
}
// Update current time
updateTimer = DateTime.Now + updateInterval;
if (updateTimer <= DateTime.Now)
{
// Update current time
updateTimer = DateTime.Now + updateInterval;
}
}
private CoroutineHandle startGameCoroutine;
@@ -641,6 +667,9 @@ namespace Barotrauma.Networking
{
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
}
#if DEBUG
DebugConsole.ThrowError("Error while reading an ingame update message from server.", e);
#endif
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
throw;
}
@@ -671,10 +700,21 @@ namespace Barotrauma.Networking
IWriteMessage readyToStartMsg = new WriteOnlyMessage();
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
MultiPlayerCampaign campaign = GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset ?
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
GameMain.NetLobbyScreen.UsingShuttle = usingShuttle;
bool readyToStart =
GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList) &&
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
bool readyToStart;
if (campaign == null)
{
readyToStart = GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList) &&
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
}
else
{
readyToStart = !fileReceiver.ActiveTransfers.Any(c => c.FileType == FileTransferType.CampaignSave) &&
(campaign.LastSaveID == campaign.PendingSaveID);
}
readyToStartMsg.Write(readyToStart);
WriteCharacterInfo(readyToStartMsg);
@@ -741,18 +781,16 @@ namespace Barotrauma.Networking
}
}
private void OnDisconnect(string disconnectMsg)
{
HandleDisconnectMessage(disconnectMsg);
}
private void HandleDisconnectMessage(string disconnectMsg)
private void OnDisconnect()
{
if (SteamManager.IsInitialized)
{
SteamManager.Instance.User.ClearRichPresence();
}
}
private void HandleDisconnectMessage(string disconnectMsg)
{
disconnectMsg = disconnectMsg ?? "";
string[] splitMsg = disconnectMsg.Split('/');
@@ -910,9 +948,13 @@ namespace Barotrauma.Networking
private void ReadTraitorMessage(IReadMessage inc)
{
TraitorMessageType messageType = (TraitorMessageType)inc.ReadByte();
string missionIdentifier = inc.ReadString();
string message = inc.ReadString();
message = TextManager.GetServerMessage(message);
var missionPrefab = TraitorMissionPrefab.List.Find(t => t.Identifier == missionIdentifier);
Sprite icon = missionPrefab?.Icon;
switch(messageType) {
case TraitorMessageType.Objective:
var isTraitor = !string.IsNullOrEmpty(message);
@@ -932,7 +974,11 @@ namespace Barotrauma.Networking
DebugConsole.NewMessage(message);
break;
case TraitorMessageType.ServerMessageBox:
new GUIMessageBox("", message);
var msgBox = new GUIMessageBox("", message, new string[0], type: GUIMessageBox.Type.InGame, icon: icon);
if (msgBox.Icon != null)
{
msgBox.IconColor = missionPrefab.IconColor;
}
break;
case TraitorMessageType.Server:
default:
@@ -1137,6 +1183,12 @@ namespace Barotrauma.Networking
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
}
if (GameMain.GameSession.Submarine.IsFileCorrupted)
{
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Name}\".");
yield return CoroutineStatus.Failure;
}
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (!loadSecondSub && i > 0) { break; }
@@ -1221,7 +1273,6 @@ namespace Barotrauma.Networking
private void ReadInitialUpdate(IReadMessage inc)
{
myID = inc.ReadByte();
VoipClient = new VoipClient(this, clientPeer);
UInt16 subListCount = inc.ReadUInt16();
serverSubmarines.Clear();
@@ -1229,16 +1280,14 @@ namespace Barotrauma.Networking
{
string subName = inc.ReadString();
string subHash = inc.ReadString();
bool requiredContentPackagesInstalled = inc.ReadBoolean();
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
if (matchingSub != null)
{
serverSubmarines.Add(matchingSub);
}
else
{
serverSubmarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false));
}
var matchingSub =
Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false);
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
serverSubmarines.Add(matchingSub);
}
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, serverSubmarines);
@@ -1265,6 +1314,7 @@ namespace Barotrauma.Networking
{
byte id = inc.ReadByte();
UInt64 steamId = inc.ReadUInt64();
UInt16 nameId = inc.ReadUInt16();
string name = inc.ReadString();
UInt16 characterID = inc.ReadUInt16();
bool muted = inc.ReadBoolean();
@@ -1274,6 +1324,7 @@ namespace Barotrauma.Networking
tempClients.Add(new TempClient
{
ID = id,
NameID = nameId,
SteamID = steamId,
Name = name,
CharacterID = characterID,
@@ -1301,6 +1352,7 @@ namespace Barotrauma.Networking
ConnectedClients.Add(existingClient);
GameMain.NetLobbyScreen.AddPlayer(existingClient);
}
existingClient.NameID = tc.NameID;
existingClient.Character = null;
existingClient.Muted = tc.Muted;
existingClient.AllowKicking = tc.AllowKicking;
@@ -1315,7 +1367,11 @@ namespace Barotrauma.Networking
if (existingClient.ID == myID)
{
existingClient.SetPermissions(permissions, permittedConsoleCommands);
name = tc.Name;
if (!NetIdUtils.IdMoreRecent(nameId, tc.NameID))
{
name = tc.Name;
nameId = tc.NameID;
}
if (GameMain.NetLobbyScreen.CharacterNameBox != null &&
!GameMain.NetLobbyScreen.CharacterNameBox.Selected)
{
@@ -1591,6 +1647,7 @@ namespace Barotrauma.Networking
outmsg.Write(GameMain.NetLobbyScreen.LastUpdateID);
outmsg.Write(ChatMessage.LastID);
outmsg.Write(LastClientListUpdateID);
outmsg.Write(nameId);
outmsg.Write(name);
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
@@ -1795,6 +1852,7 @@ namespace Barotrauma.Networking
}
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
campaign.LastSaveID = campaign.PendingSaveID;
DebugConsole.Log("Campaign save received, save ID " + campaign.LastSaveID);
@@ -2123,7 +2181,15 @@ namespace Barotrauma.Networking
public bool SpectateClicked(GUIButton button, object userData)
{
if (button != null) button.Enabled = false;
MultiPlayerCampaign campaign =
GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset ?
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
if (campaign != null && campaign.LastSaveID < campaign.PendingSaveID)
{
new GUIMessageBox("", TextManager.Get("campaignfiletransferinprogress"));
return false;
}
if (button != null) { button.Enabled = false; }
IWriteMessage readyToStartMsg = new WriteOnlyMessage();
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);

View File

@@ -7,12 +7,14 @@ namespace Barotrauma.Networking
abstract class ClientPeer
{
public delegate void MessageCallback(IReadMessage message);
public delegate void DisconnectCallback(string msg);
public delegate void DisconnectCallback();
public delegate void DisconnectMessageCallback(string message);
public delegate void PasswordCallback(int salt, int retries);
public delegate void InitializationCompleteCallback();
public MessageCallback OnMessageReceived;
public DisconnectCallback OnDisconnect;
public DisconnectMessageCallback OnDisconnectMessageReceived;
public PasswordCallback OnRequestPassword;
public InitializationCompleteCallback OnInitializationComplete;

View File

@@ -136,6 +136,7 @@ namespace Barotrauma.Networking
case NetConnectionStatus.Disconnected:
string disconnectMsg = inc.ReadString();
Close(disconnectMsg);
OnDisconnectMessageReceived?.Invoke(disconnectMsg);
break;
}
}
@@ -227,7 +228,7 @@ namespace Barotrauma.Networking
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
netClient = null;
steamAuthTicket?.Cancel(); steamAuthTicket = null;
OnDisconnect?.Invoke(msg);
OnDisconnect?.Invoke();
}
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
@@ -248,6 +249,13 @@ namespace Barotrauma.Networking
break;
}
#if DEBUG
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Client.SimulatedDuplicatesChance;
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Client.SimulatedMinimumLatency;
netPeerConfiguration.SimulatedRandomLatency = GameMain.Client.SimulatedRandomLatency;
netPeerConfiguration.SimulatedLoss = GameMain.Client.SimulatedLoss;
#endif
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
byte[] msgData = new byte[msg.LengthBytes];
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);

View File

@@ -116,6 +116,7 @@ namespace Barotrauma.Networking
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
string msg = inc.ReadString();
Close(msg);
OnDisconnectMessageReceived?.Invoke(msg);
}
else
{
@@ -270,8 +271,27 @@ namespace Barotrauma.Networking
}
heartbeatTimer = 5.0;
bool successSend = SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, buf, length + 4, sendType);
#if DEBUG
CoroutineManager.InvokeAfter(() =>
{
if (Rand.Range(0.0f, 1.0f) < GameMain.Client.SimulatedLoss && sendType != Facepunch.Steamworks.Networking.SendType.Reliable) { return; }
int count = Rand.Range(0.0f, 1.0f) < GameMain.Client.SimulatedDuplicatesChance ? 2 : 1;
for (int i = 0; i < count; i++)
{
Send(buf, length + 4, sendType);
}
},
GameMain.Client.SimulatedMinimumLatency + Rand.Range(0.0f, GameMain.Client.SimulatedRandomLatency));
#else
Send(buf, length + 4, sendType);
#endif
}
private void Send(byte[] buf, int length, Facepunch.Steamworks.Networking.SendType sendType)
{
bool successSend = SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, buf, length + 4, sendType);
if (!successSend)
{
if (sendType != Facepunch.Steamworks.Networking.SendType.Reliable)
@@ -332,7 +352,7 @@ namespace Barotrauma.Networking
steamAuthTicket?.Cancel(); steamAuthTicket = null;
hostSteamId = 0;
OnDisconnect?.Invoke(msg);
OnDisconnect?.Invoke();
}
}
}

View File

@@ -414,6 +414,7 @@ namespace Barotrauma.Networking
case NetConnectionStatus.Disconnected:
string disconnectMsg = inc.ReadString();
Close(disconnectMsg);
OnDisconnectMessageReceived?.Invoke(disconnectMsg);
break;
}
}
@@ -429,7 +430,7 @@ namespace Barotrauma.Networking
isActive = false;
for (int i=remotePeers.Count-1;i>=0;i--)
for (int i = remotePeers.Count - 1; i >= 0; i--)
{
DisconnectPeer(remotePeers[i], msg ?? DisconnectReason.ServerShutdown.ToString());
}
@@ -444,7 +445,7 @@ namespace Barotrauma.Networking
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
netClient = null;
OnDisconnect?.Invoke(msg);
OnDisconnect?.Invoke();
Steam.SteamManager.Instance.Networking.OnIncomingConnection = null;
Steam.SteamManager.Instance.Networking.OnP2PData = null;
@@ -478,6 +479,12 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
#if DEBUG
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Client.SimulatedDuplicatesChance;
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Client.SimulatedMinimumLatency;
netPeerConfiguration.SimulatedRandomLatency = GameMain.Client.SimulatedRandomLatency;
netPeerConfiguration.SimulatedLoss = GameMain.Client.SimulatedLoss;
#endif
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{

View File

@@ -758,8 +758,14 @@ namespace Barotrauma.Networking
karmaSettingsBlocker = new GUIFrame(new RectTransform(Vector2.One, karmaSettingsContainer.RectTransform, Anchor.CenterLeft) { MaxSize = new Point(karmaSettingsList.Content.Rect.Width, int.MaxValue) },
style: "InnerFrame");
karmaPresetDD.SelectItem(KarmaPreset);
karmaSettingsBlocker.Visible = !karmaBox.Selected || KarmaPreset != "custom";
GameMain.NetworkMember.KarmaManager.CreateSettingsFrame(karmaSettingsList.Content);
karmaPresetDD.OnSelected = (selected, obj) =>
{
string newKarmaPreset = obj as string;
if (newKarmaPreset == KarmaPreset) { return true; }
List<NetPropertyData> properties = netProperties.Values.ToList();
List<object> prevValues = new List<object>();
foreach (NetPropertyData prop in netProperties.Values)
@@ -772,7 +778,7 @@ namespace Barotrauma.Networking
GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
GameMain.NetworkMember?.KarmaManager?.Save();
}
KarmaPreset = obj as string;
KarmaPreset = newKarmaPreset;
GameMain.NetworkMember.KarmaManager.SelectPreset(KarmaPreset);
karmaSettingsList.Content.ClearChildren();
karmaSettingsBlocker.Visible = !karmaBox.Selected || KarmaPreset != "custom";
@@ -783,7 +789,6 @@ namespace Barotrauma.Networking
}
return true;
};
karmaPresetDD.SelectItem(KarmaPreset);
AssignGUIComponent("KarmaPreset", karmaPresetDD);
karmaBox.OnSelected = (tb) =>
{
@@ -836,16 +841,16 @@ namespace Barotrauma.Networking
public bool ToggleSettingsFrame(GUIButton button, object obj)
{
if (settingsFrame == null)
{
CreateSettingsFrame();
}
else
{
if (KarmaPreset == "custom")
{
GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
GameMain.NetworkMember?.KarmaManager?.Save();
}
CreateSettingsFrame();
}
else
{
ClientAdminWrite(NetFlags.Properties);
foreach (NetPropertyData prop in netProperties.Values)
{

View File

@@ -736,14 +736,14 @@ namespace Barotrauma.Steam
/// <summary>
/// Creates a copy of the specified workshop item in the staging folder and an editor that can be used to edit and update the item
/// </summary>
public static void CreateWorkshopItemStaging(Workshop.Item existingItem, out Workshop.Editor itemEditor, out ContentPackage contentPackage)
public static bool CreateWorkshopItemStaging(Workshop.Item existingItem, out Workshop.Editor itemEditor, out ContentPackage contentPackage)
{
if (!existingItem.Installed)
{
itemEditor = null;
contentPackage = null;
DebugConsole.ThrowError("Cannot edit the workshop item \"" + existingItem.Title + "\" because it has not been installed.");
return;
return false;
}
itemEditor = instance.client.Workshop.EditItem(existingItem.Id);
@@ -763,7 +763,7 @@ namespace Barotrauma.Steam
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { existingItem.Title, errorMsg }));
itemEditor = null;
contentPackage = null;
return;
return false;
}
}
@@ -773,7 +773,7 @@ namespace Barotrauma.Steam
if (contentPackage == null && tempContentPackage.GameVersion <= new Version(0, 9, 1, 0))
{
//try finding the content package in the lega
//try finding the content package from the non-legacy path
installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage, legacy: false));
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
}
@@ -792,8 +792,11 @@ namespace Barotrauma.Steam
contentPackage.Path = newPath;
itemEditor.Folder = newDir;
if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); }
if (File.Exists(newPath)) { File.Delete(newPath); }
File.Move(installedContentPackagePath, newPath);
if (Path.GetFullPath(newPath) != installedContentPackagePath)
{
if (File.Exists(newPath)) { File.Delete(newPath); }
File.Move(installedContentPackagePath, newPath);
}
//move all files inside the Mods folder
foreach (ContentFile cf in contentPackage.Files)
{
@@ -815,7 +818,7 @@ namespace Barotrauma.Steam
string errorMsg = TextManager.GetWithVariable("WorkshopErrorOnEnable", "[itemname]", TextManager.EnsureUTF8(existingItem.Title));
new GUIMessageBox(TextManager.Get("Error"), errorMsg);
DebugConsole.ThrowError(errorMsg, e);
return;
return false;
}
}
@@ -846,6 +849,7 @@ namespace Barotrauma.Steam
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CreateWorkshopItemStaging:WriteAllBytesFailed" + previewImagePath,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
}
return true;
}
public static void StartPublishItem(ContentPackage contentPackage, Workshop.Editor item)
@@ -865,11 +869,9 @@ namespace Barotrauma.Steam
contentPackage.GameVersion = GameMain.Version;
contentPackage.Save(contentPackage.Path);
if (File.Exists(PreviewImageName)) { File.Delete(PreviewImageName); }
//move the preview image out of the staging folder, it does not need to be included in the folder sent to Workshop
File.Move(Path.GetFullPath(Path.Combine(item.Folder, PreviewImageName)), PreviewImageName);
item.PreviewImage = Path.GetFullPath(PreviewImageName);
string previewImagePath = Path.GetFullPath(Path.Combine(item.Folder, PreviewImageName));
item.PreviewImage = File.Exists(previewImagePath) ? previewImagePath : null;
CoroutineManager.StartCoroutine(PublishItem(item));
}
@@ -904,7 +906,7 @@ namespace Barotrauma.Steam
/// <summary>
/// Enables a workshop item by moving it to the game folder.
/// </summary>
public static bool EnableWorkShopItem(Workshop.Item item, bool allowFileOverwrite, out string errorMsg)
public static bool EnableWorkShopItem(Workshop.Item item, bool allowFileOverwrite, out string errorMsg, bool selectContentPackage = true)
{
if (!item.Installed)
{
@@ -959,19 +961,24 @@ namespace Barotrauma.Steam
}
newPackage.Save(newContentPackagePath);
ContentPackage.List.Add(newPackage);
if (newPackage.CorePackage)
if (selectContentPackage)
{
//if enabling a core package, disable all other core packages
GameMain.Config.SelectedContentPackages.RemoveWhere(cp => cp.CorePackage);
if (newPackage.CorePackage)
{
//if enabling a core package, disable all other core packages
GameMain.Config.SelectedContentPackages.RemoveAll(cp => cp.CorePackage);
}
GameMain.Config.SelectContentPackage(newPackage);
GameMain.Config.SaveNewPlayerConfig();
foreach (ContentFile cf in newPackage.Files)
{
if (cf.Type == ContentType.Submarine)
{
Submarine.RefreshSavedSub(cf.Path);
}
}
}
GameMain.Config.SelectedContentPackages.Add(newPackage);
GameMain.Config.SaveNewPlayerConfig();
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
{
Submarine.RefreshSavedSubs();
}
errorMsg = "";
return true;
}
@@ -1166,7 +1173,8 @@ namespace Barotrauma.Steam
}
ContentPackage.List.RemoveAll(cp => System.IO.Path.GetFullPath(cp.Path) == System.IO.Path.GetFullPath(installedContentPackagePath));
GameMain.Config.SelectedContentPackages.RemoveWhere(cp => !ContentPackage.List.Contains(cp));
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
ContentPackage.SortContentPackages();
GameMain.Config.SaveNewPlayerConfig();
}
catch (Exception e)
@@ -1218,7 +1226,7 @@ namespace Barotrauma.Steam
{
metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
}
catch (ArgumentException e)
catch (ArgumentException)
{
string errorMessage = "Metadata file for the Workshop item \"" + item.Title +
"\" not found. Could not combine path (" + (item.Directory.FullName ?? "directory name empty") + ").";
@@ -1255,7 +1263,7 @@ namespace Barotrauma.Steam
public static bool CheckWorkshopItemUpToDate(Workshop.Item item)
{
if (!item.Installed) return false;
if (!item.Installed) { return false; }
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
if (!File.Exists(metaDataPath))
@@ -1274,6 +1282,22 @@ namespace Barotrauma.Steam
return item.Modified <= myPackage.InstallTime.Value;
}
public static bool CheckWorkshopItemSelected(Workshop.Item item)
{
if (!item.Installed) { return false; }
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
if (!File.Exists(metaDataPath))
{
DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
return false;
}
ContentPackage steamPackage = new ContentPackage(metaDataPath);
return GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == steamPackage.Name);
}
public static bool AutoUpdateWorkshopItems()
{
if (instance == null || !instance.isInitialized) { return false; }
@@ -1290,8 +1314,9 @@ namespace Barotrauma.Steam
itemsUpdated = false;
foreach (var item in q.Items)
{
if (item.Installed && CheckWorkshopItemEnabled(item) && !CheckWorkshopItemUpToDate(item))
try
{
if (!item.Installed || !CheckWorkshopItemEnabled(item) || CheckWorkshopItemUpToDate(item)) { continue; }
if (!UpdateWorkshopItem(item, out string errorMsg))
{
DebugConsole.ThrowError(errorMsg);
@@ -1305,6 +1330,16 @@ namespace Barotrauma.Steam
itemsUpdated = true;
}
}
catch (Exception e)
{
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }));
GameAnalyticsManager.AddErrorEventOnce(
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
}
}
};
@@ -1328,8 +1363,9 @@ namespace Barotrauma.Steam
{
errorMsg = "";
if (!item.Installed) { return false; }
bool wasSelected = CheckWorkshopItemSelected(item);
if (!DisableWorkShopItem(item, out errorMsg)) { return false; }
if (!EnableWorkShopItem(item, allowFileOverwrite: false, errorMsg: out errorMsg)) { return false; }
if (!EnableWorkShopItem(item, allowFileOverwrite: false, errorMsg: out errorMsg, selectContentPackage: wasSelected)) { return false; }
return true;
}

View File

@@ -1,6 +1,7 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;
namespace Barotrauma.Particles
{
@@ -10,21 +11,47 @@ namespace Barotrauma.Particles
public DecalManager()
{
prefabs = new Dictionary<string, DecalPrefab>();
var decalElements = new Dictionary<string, XElement>();
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.Decals))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
foreach (XElement element in doc.Root.Elements())
bool allowOverriding = false;
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
if (prefabs.ContainsKey(element.Name.ToString()))
{
DebugConsole.ThrowError("Error in " + configFile + "! Each decal prefab must have a unique name.");
continue;
}
prefabs.Add(element.Name.ToString(), new DecalPrefab(element));
mainElement = doc.Root.FirstElement();
allowOverriding = true;
}
foreach (XElement sourceElement in mainElement.Elements())
{
var element = sourceElement.IsOverride() ? sourceElement.FirstElement() : sourceElement;
string name = element.Name.ToString().ToLowerInvariant();
if (decalElements.ContainsKey(name))
{
if (allowOverriding || sourceElement.IsOverride())
{
DebugConsole.NewMessage($"Overriding the existing decal prefab '{name}' using the file '{configFile}'", Color.Yellow);
decalElements.Remove(name);
}
else
{
DebugConsole.ThrowError($"Error in '{configFile}': Duplicate decal prefab '{name}' found in '{configFile}'! Each decal prefab must have a unique name. " +
"Use <override></override> tags to override prefabs.");
continue;
}
}
decalElements.Add(name, element);
}
}
//prefabs = decalElements.ToDictionary(d => d.Key, d => new DecalPrefab(d.Value));
prefabs = new Dictionary<string, DecalPrefab>();
foreach (var kvp in decalElements)
{
prefabs.Add(kvp.Key, new DecalPrefab(kvp.Value));
}
}

View File

@@ -63,22 +63,48 @@ namespace Barotrauma.Particles
public void LoadPrefabs()
{
prefabs = new Dictionary<string, ParticlePrefab>();
var particleElements = new Dictionary<string, XElement>();
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.Particles))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
foreach (XElement element in doc.Root.Elements())
bool allowOverriding = false;
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
if (prefabs.ContainsKey(element.Name.ToString()))
{
DebugConsole.ThrowError("Error in " + configFile + "! Each particle prefab must have a unique name.");
continue;
}
prefabs.Add(element.Name.ToString(), new ParticlePrefab(element));
mainElement = doc.Root.FirstElement();
allowOverriding = true;
}
}
foreach (XElement sourceElement in mainElement.Elements())
{
var element = sourceElement.IsOverride() ? sourceElement.FirstElement() : sourceElement;
string name = element.Name.ToString().ToLowerInvariant();
if (particleElements.ContainsKey(name))
{
if (allowOverriding || sourceElement.IsOverride())
{
DebugConsole.NewMessage($"Overriding the existing particle prefab '{name}' using the file '{configFile}'", Color.Yellow);
particleElements.Remove(name);
}
else
{
DebugConsole.ThrowError($"Error in '{configFile}': Duplicate particle prefab '{name}' found in '{configFile}'! Each particle prefab must have a unique name. " +
"Use <override></override> tags to override prefabs.");
continue;
}
}
particleElements.Add(name, element);
}
}
//prefabs = particleElements.ToDictionary(p => p.Key, p => new ParticlePrefab(p.Value));
prefabs = new Dictionary<string, ParticlePrefab>();
foreach (var kvp in particleElements)
{
prefabs.Add(kvp.Key, new ParticlePrefab(kvp.Value));
}
}
public Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess = null)

View File

@@ -17,12 +17,12 @@ namespace Barotrauma.Particles
private set;
}
[Editable(0.0f, float.MaxValue, ToolTip = "How many seconds the particle remains alive."), Serialize(5.0f, false)]
[Editable(0.0f, float.MaxValue), Serialize(5.0f, false, description: "How many seconds the particle remains alive.")]
public float LifeTime { get; private set; }
[Editable(ToolTip = "How long it takes for the particle to appear after spawning it."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
public float StartDelayMin { get; private set; }
[Editable(ToolTip = "How long it takes for the particle to appear after spawning it."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
public float StartDelayMax { get; private set; }
//movement -----------------------------------------
@@ -57,7 +57,7 @@ namespace Barotrauma.Particles
private float startRotationMin;
public float StartRotationMinRad { get; private set; }
[Editable(ToolTip = "The minimum initial rotation of the particle (in degrees)."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "The minimum initial rotation of the particle (in degrees).")]
public float StartRotationMin
{
get { return startRotationMin; }
@@ -71,7 +71,7 @@ namespace Barotrauma.Particles
private float startRotationMax;
public float StartRotationMaxRad { get; private set; }
[Editable(ToolTip = "The maximum initial rotation of the particle (in degrees)."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "The maximum initial rotation of the particle (in degrees).")]
public float StartRotationMax
{
get { return startRotationMax; }
@@ -82,19 +82,19 @@ namespace Barotrauma.Particles
}
}
[Editable(ToolTip = "Should the particle face the direction it's moving towards."), Serialize(false, false)]
[Editable, Serialize(false, false, description: "Should the particle face the direction it's moving towards.")]
public bool RotateToDirection { get; private set; }
[Editable(ToolTip = "Drag applied to the particle when it's moving through air."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through air.")]
public float Drag { get; private set; }
[Editable(ToolTip = "Drag applied to the particle when it's moving through water."), Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through water.")]
public float WaterDrag { get; private set; }
private Vector2 velocityChange;
public Vector2 VelocityChangeDisplay { get; private set; }
[Editable(ToolTip = "How much the velocity of the particle changes per second."), Serialize("0.0,0.0", false)]
[Editable, Serialize("0.0,0.0", false, description: "How much the velocity of the particle changes per second.")]
public Vector2 VelocityChange
{
get { return velocityChange; }
@@ -108,7 +108,7 @@ namespace Barotrauma.Particles
private Vector2 velocityChangeWater;
public Vector2 VelocityChangeWaterDisplay { get; private set; }
[Editable(ToolTip = "How much the velocity of the particle changes per second when in water."), Serialize("0.0,0.0", false)]
[Editable, Serialize("0.0,0.0", false, description: "How much the velocity of the particle changes per second when in water.")]
public Vector2 VelocityChangeWater
{
get { return velocityChangeWater; }
@@ -119,62 +119,62 @@ namespace Barotrauma.Particles
}
}
[Editable(0.0f, 10000.0f, ToolTip = "Drag applied to the particle when it's moving through water."), Serialize(0.0f, false)]
[Editable(0.0f, 10000.0f), Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through water.")]
public float CollisionRadius { get; private set; }
[Editable(ToolTip = "Does the particle collide with the walls of the submarine and the level."), Serialize(false, false)]
[Editable, Serialize(false, false, description: "Does the particle collide with the walls of the submarine and the level.")]
public bool UseCollision { get; private set; }
[Editable(ToolTip = "Does the particle disappear when it collides with something."), Serialize(false, false)]
[Editable, Serialize(false, false, description: "Does the particle disappear when it collides with something.")]
public bool DeleteOnCollision { get; private set; }
[Editable(0.0f, 1.0f, ToolTip = "The friction coefficient of the particle, i.e. how much it slows down when it's sliding against a surface."), Serialize(0.5f, false)]
[Editable(0.0f, 1.0f), Serialize(0.5f, false, description: "The friction coefficient of the particle, i.e. how much it slows down when it's sliding against a surface.")]
public float Friction { get; private set; }
[Editable(0.0f, 1.0f, ToolTip = "How much of the particle's velocity is conserved when it collides with something, i.e. the \"bounciness\" of the particle. (1.0 = the particle stops completely).")]
[Serialize(0.5f, false)]
[Editable(0.0f, 1.0f)]
[Serialize(0.5f, false, description: "How much of the particle's velocity is conserved when it collides with something, i.e. the \"bounciness\" of the particle. (1.0 = the particle stops completely).")]
public float Restitution { get; private set; }
//size -----------------------------------------
[Editable(ToolTip = "The minimum initial size of the particle."), Serialize("1.0,1.0", false)]
[Editable, Serialize("1.0,1.0", false, description: "The minimum initial size of the particle.")]
public Vector2 StartSizeMin { get; private set; }
[Editable(ToolTip = "The maximum initial size of the particle."), Serialize("1.0,1.0", false)]
[Editable, Serialize("1.0,1.0", false, description: "The maximum initial size of the particle.")]
public Vector2 StartSizeMax { get; private set; }
[Editable(ToolTip = "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
[Serialize("0.0,0.0", false)]
[Editable]
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
public Vector2 SizeChangeMin { get; private set; }
[Editable(ToolTip = "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
[Serialize("0.0,0.0", false)]
[Editable]
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
public Vector2 SizeChangeMax { get; private set; }
[Editable(ToolTip = "How many seconds it takes for the particle to grow to it's initial size.")]
[Serialize(0.0f, false)]
[Editable]
[Serialize(0.0f, false, description: "How many seconds it takes for the particle to grow to it's initial size.")]
public float GrowTime { get; private set; }
//rendering -----------------------------------------
[Editable(ToolTip = "The initial color of the particle."), Serialize("1.0,1.0,1.0,1.0", false)]
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The initial color of the particle.")]
public Color StartColor { get; private set; }
[Editable(ToolTip = "The color of the particle at the end of its lifetime."), Serialize("1.0,1.0,1.0,1.0", false)]
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The color of the particle at the end of its lifetime.")]
public Color EndColor { get; private set; }
[Editable(ToolTip = "Should the particle be rendered in air, water or both."), Serialize(DrawTargetType.Air, false)]
[Editable, Serialize(DrawTargetType.Air, false, description: "Should the particle be rendered in air, water or both.")]
public DrawTargetType DrawTarget { get; private set; }
[Editable(ToolTip = "The type of blending to use when rendering the particle."), Serialize(ParticleBlendState.AlphaBlend, false)]
[Editable, Serialize(ParticleBlendState.AlphaBlend, false, description: "The type of blending to use when rendering the particle.")]
public ParticleBlendState BlendState { get; private set; }
//animation -----------------------------------------
[Editable(0.0f, float.MaxValue, ToolTip = "The duration of the particle's animation cycle (if it's animated)."), Serialize(1.0f, false)]
[Editable(0.0f, float.MaxValue), Serialize(1.0f, false, description: "The duration of the particle's animation cycle (if it's animated).")]
public float AnimDuration { get; private set; }
[Editable(ToolTip = "Should the sprite animation be looped, or stay at the last frame when the animation finishes."), Serialize(true, false)]
[Editable, Serialize(true, false, description: "Should the sprite animation be looped, or stay at the last frame when the animation finishes.")]
public bool LoopAnim { get; private set; }
//----------------------------------------------------

View File

@@ -17,7 +17,7 @@ namespace Barotrauma
get { return bodyShapeTexture; }
}
public void Draw(DeformableSprite deformSprite, Camera cam, Vector2 scale, Color color)
public void Draw(DeformableSprite deformSprite, Camera cam, Vector2 scale, Color color, bool mirror = false)
{
if (!Enabled) return;
UpdateDrawPosition();
@@ -25,17 +25,23 @@ namespace Barotrauma
new Vector3(DrawPosition, MathHelper.Clamp(deformSprite.Sprite.Depth, 0, 1)),
deformSprite.Origin,
-DrawRotation,
scale,
color,
flip: Dir < 0);
scale, color, Dir < 0, mirror);
}
public void Draw(SpriteBatch spriteBatch, Sprite sprite, Color color, float? depth = null, float scale = 1.0f)
public void Draw(SpriteBatch spriteBatch, Sprite sprite, Color color, float? depth = null, float scale = 1.0f, bool mirrorX = false, bool mirrorY = false)
{
if (!Enabled) return;
UpdateDrawPosition();
if (sprite == null) return;
SpriteEffects spriteEffect = (Dir == 1.0f) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (mirrorX)
{
spriteEffect = spriteEffect == SpriteEffects.None ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
if (mirrorY)
{
spriteEffect |= SpriteEffects.FlipVertically;
}
sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y), color, -drawRotation, scale, spriteEffect, depth);
}
@@ -134,14 +140,17 @@ namespace Barotrauma
rot -= MathHelper.PiOver2;
}
spriteBatch.Draw(
bodyShapeTexture,
new Vector2(DrawPosition.X, -DrawPosition.Y),
null,
color,
rot,
new Vector2(bodyShapeTexture.Width / 2, bodyShapeTexture.Height / 2),
1.0f / bodyShapeTextureScale, SpriteEffects.None, 0.0f);
if (bodyShapeTexture != null)
{
spriteBatch.Draw(
bodyShapeTexture,
new Vector2(DrawPosition.X, -DrawPosition.Y),
null,
color,
rot,
new Vector2(bodyShapeTexture.Width / 2, bodyShapeTexture.Height / 2),
1.0f / bodyShapeTextureScale, SpriteEffects.None, 0.0f);
}
}
public PosInfo ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime, string parentDebugName)

View File

@@ -9,8 +9,7 @@ using Barotrauma.Steam;
using System.Diagnostics;
#if WINDOWS
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
using SharpDX;
#endif
#endregion
@@ -31,135 +30,41 @@ namespace Barotrauma
[STAThread]
static void Main(string[] args)
{
SteamManager.Initialize();
GameMain game = null;
#if !DEBUG
try
{
#endif
SteamManager.Initialize();
game = new GameMain(args);
#if !DEBUG
}
catch (Exception e)
{
if (game != null) game.Dispose();
CrashDump(null, "crashreport.log", e);
return;
}
#endif
#if DEBUG
game.Run();
#else
bool attemptRestart = false;
do
{
try
{
game.Run();
attemptRestart = false;
}
catch (Exception e)
{
if (restartAttempts < 5 && CheckException(game, e))
{
attemptRestart = true;
restartAttempts++;
}
else
{
CrashDump(game, "crashreport.log", e);
attemptRestart = false;
}
}
} while (attemptRestart);
#endif
#if !DEBUG
try
{
#endif
game.Run();
game.Dispose();
#if !DEBUG
}
catch (Exception e)
{
CrashDump(null, "crashreport.log", e);
}
#endif
}
private static bool CheckException(GameMain game, Exception e)
{
#if WINDOWS
if (e is SharpDX.SharpDXException sharpDxException)
{
DebugConsole.NewMessage("SharpDX exception caught. ("
+ e.Message + ", " + sharpDxException.ResultCode.Code.ToString("X") + "). Attempting to fix...", Microsoft.Xna.Framework.Color.Red);
switch ((UInt32)sharpDxException.ResultCode.Code)
try
{
case 0x887A0022: //DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
switch (restartAttempts)
{
case 0:
//just wait and try again
DebugConsole.NewMessage("Retrying after 100 ms...", Microsoft.Xna.Framework.Color.Red);
System.Threading.Thread.Sleep(100);
return true;
case 1:
//force focus to this window
DebugConsole.NewMessage("Forcing focus to the window and retrying...", Microsoft.Xna.Framework.Color.Red);
var myForm = (Form)Control.FromHandle(game.Window.Handle);
myForm.Focus();
return true;
case 2:
//try disabling hardware mode switch
if (GameMain.Config.WindowMode == WindowMode.Fullscreen)
{
DebugConsole.NewMessage("Failed to set fullscreen mode, switching configuration to borderless windowed.", Microsoft.Xna.Framework.Color.Red);
GameMain.Config.WindowMode = WindowMode.BorderlessWindowed;
GameMain.Config.SaveNewPlayerConfig();
}
return false;
default:
DebugConsole.NewMessage("Failed to resolve the DXGI_ERROR_NOT_CURRENTLY_AVAILABLE exception. Give up and let it crash :(", Microsoft.Xna.Framework.Color.Red);
return false;
}
case 0x80070057: //E_INVALIDARG/Invalid Arguments
DebugConsole.NewMessage("Invalid graphics settings, attempting to fix...", Microsoft.Xna.Framework.Color.Red);
GameMain.Config.GraphicsWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
GameMain.Config.GraphicsHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
DebugConsole.NewMessage("Display size set to " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight, Microsoft.Xna.Framework.Color.Red);
game.ApplyGraphicsSettings();
return true;
default:
DebugConsole.NewMessage("Unknown SharpDX exception code (" + sharpDxException.ResultCode.Code.ToString("X") + ")", Microsoft.Xna.Framework.Color.Red);
return false;
CrashDump(game, "crashreport.log", e);
}
catch (Exception e2)
{
CrashMessageBox("Barotrauma seems to have crashed, and failed to generate a crash report: "
+ e2.Message + "\n" + e2.StackTrace.ToString(),
null);
}
game?.Dispose();
return;
}
#endif
return false;
}
public static void CrashMessageBox(string message, string filePath)
{
#if WINDOWS
MessageBox.Show(message, "Oops! Barotrauma just crashed.", MessageBoxButtons.OK, MessageBoxIcon.Error);
#endif
Microsoft.Xna.Framework.MessageBox.ShowWrapped(Microsoft.Xna.Framework.MessageBox.Flags.Error, "Oops! Barotrauma just crashed.", message);
// Open the crash log.
Process.Start(filePath);
if (!string.IsNullOrWhiteSpace(filePath)) { Process.Start(filePath); }
}
static void CrashDump(GameMain game, string filePath, Exception exception)
@@ -259,10 +164,18 @@ namespace Barotrauma
sb.AppendLine("\n");
sb.AppendLine("Exception: " + exception.Message);
#if WINDOWS
if (exception is SharpDXException sharpDxException && ((uint)sharpDxException.HResult) == 0x887A0005)
{
var dxDevice = (SharpDX.Direct3D11.Device)game.GraphicsDevice.Handle;
sb.AppendLine("Device removed reason: " + dxDevice.DeviceRemovedReason.ToString());
}
#endif
if (exception.TargetSite != null)
{
sb.AppendLine("Target site: " + exception.TargetSite.ToString());
}
sb.AppendLine("Stack trace: ");
sb.AppendLine(exception.StackTrace);
sb.AppendLine("\n");

View File

@@ -114,7 +114,7 @@ namespace Barotrauma
}
string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
bool hasRequiredContentPackages = selectedSub.RequiredContentPackages.All(cp => GameMain.SelectedPackages.Any(cp2 => cp2.Name == cp));
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
{

View File

@@ -27,7 +27,7 @@ namespace Barotrauma
private GUIComponent selectedLocationInfo;
private GUIListBox selectedMissionInfo;
private GUIButton repairHullsButton, repairItemsButton;
private GUIButton repairHullsButton, replaceShuttlesButton, repairItemsButton;
private GUIFrame characterPreviewFrame;
@@ -281,6 +281,8 @@ namespace Barotrauma
TextGetter = GetMoney
};
// repair hulls -----------------------------------------------
var repairHullsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
@@ -295,7 +297,7 @@ namespace Barotrauma
{
ForceUpperCase = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairHullsHolder.RectTransform), "500", textAlignment: Alignment.Right, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairHullsHolder.RectTransform), CampaignMode.HullRepairCost.ToString(), 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) =>
@@ -324,6 +326,8 @@ namespace Barotrauma
CanBeFocused = false
};
// repair items -------------------------------------------
var repairItemsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
@@ -338,7 +342,7 @@ namespace Barotrauma
{
ForceUpperCase = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairItemsHolder.RectTransform), "500", textAlignment: Alignment.Right, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairItemsHolder.RectTransform), CampaignMode.ItemRepairCost.ToString(), 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) =>
@@ -367,6 +371,59 @@ namespace Barotrauma
CanBeFocused = false
};
// replace lost shuttles -------------------------------------------
var replaceShuttlesHolder = 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), replaceShuttlesHolder.RectTransform, Anchor.CenterLeft), "ReplaceShuttlesButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), replaceShuttlesHolder.RectTransform), TextManager.Get("ReplaceLostShuttles"), textAlignment: Alignment.Right, font: GUI.LargeFont)
{
ForceUpperCase = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), replaceShuttlesHolder.RectTransform), CampaignMode.ShuttleReplaceCost.ToString(), textAlignment: Alignment.Right, font: GUI.LargeFont);
replaceShuttlesButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), replaceShuttlesHolder.RectTransform), TextManager.Get("ReplaceShuttles"), style: "GUIButtonLarge")
{
OnClicked = (btn, userdata) =>
{
if (GameMain.GameSession?.Submarine != null &&
GameMain.GameSession.Submarine.LeftBehindSubDockingPortOccupied)
{
new GUIMessageBox("", TextManager.Get("ReplaceShuttleDockingPortOccupied"));
return true;
}
if (campaign.PurchasedLostShuttles)
{
campaign.Money += CampaignMode.ShuttleReplaceCost;
campaign.PurchasedLostShuttles = false;
}
else
{
if (campaign.Money >= CampaignMode.ShuttleReplaceCost)
{
campaign.Money -= CampaignMode.ShuttleReplaceCost;
campaign.PurchasedLostShuttles = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = campaign.PurchasedLostShuttles;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), replaceShuttlesButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
// mission info -------------------------------------------------------------------------
missionPanel = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.5f), container.RectTransform, Anchor.TopRight)
@@ -853,6 +910,19 @@ namespace Barotrauma
(Campaign.PurchasedItemRepairs || Campaign.Money >= CampaignMode.ItemRepairCost) &&
(GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
repairItemsButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedItemRepairs;
if (GameMain.GameSession?.Submarine == null || !GameMain.GameSession.Submarine.SubsLeftBehind)
{
replaceShuttlesButton.Enabled = false;
replaceShuttlesButton.GetChild<GUITickBox>().Selected = false;
}
else
{
replaceShuttlesButton.Enabled =
(Campaign.PurchasedLostShuttles || Campaign.Money >= CampaignMode.ShuttleReplaceCost) &&
(GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
replaceShuttlesButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedLostShuttles;
}
break;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@ namespace Barotrauma
GameMain.Instance.OnResolutionChanged += () => { ClearChildren(); Load(); };
var doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null) { return; }
configElement = doc.Root;
Load();
@@ -34,126 +35,17 @@ namespace Barotrauma
foreach (XElement subElement in configElement.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "text":
AddTextElement(subElement, listBox.Content.RectTransform);
break;
case "gridtext":
AddGridTextElement(subElement, listBox.Content.RectTransform);
break;
case "spacing":
AddSpacingElement(subElement, listBox.Content.RectTransform);
break;
case "image":
AddImageElement(subElement, listBox.Content.RectTransform);
break;
}
GUIComponent.FromXML(subElement, listBox.Content.RectTransform);
}
foreach (GUIComponent child in listBox.Children)
{
child.CanBeFocused = false;
}
listBox.RecalculateChildren();
listBox.UpdateScrollBarSize();
}
private GUIComponent AddTextElement(XElement element, RectTransform parent, string overrideText = null, Anchor anchor = Anchor.Center)
{
var text = overrideText ?? element.ElementInnerText().Replace(@"\n", "\n");
Color color = element.GetAttributeColor("color", Color.White);
float scale = element.GetAttributeFloat("scale", 1.0f);
Alignment alignment = Alignment.Center;
Enum.TryParse(element.GetAttributeString("alignment", "Center"), out alignment);
ScalableFont font = GUI.Font;
switch (element.GetAttributeString("font", "Font").ToLowerInvariant())
{
case "font":
font = GUI.Font;
break;
case "smallfont":
font = GUI.SmallFont;
break;
case "largefont":
font = GUI.LargeFont;
break;
case "videotitlefont":
font = GUI.VideoTitleFont;
break;
case "objectivetitlefont":
font = GUI.ObjectiveTitleFont;
break;
case "objectivenamefont":
font = GUI.ObjectiveNameFont;
break;
}
var textHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), parent), style: null);
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), textHolder.RectTransform, anchor),
text,
color,
font,
alignment,
wrap: true)
{
TextScale = scale
};
textBlock.RectTransform.IsFixedSize = textHolder.RectTransform.IsFixedSize = true;
textBlock.RectTransform.NonScaledSize = new Point(textBlock.Rect.Width, textBlock.Rect.Height);
textHolder.RectTransform.NonScaledSize = new Point(textHolder.Rect.Width, textBlock.Rect.Height);
return textHolder;
}
private void AddGridTextElement(XElement element, RectTransform parent)
{
var text = element.ElementInnerText().Replace(@"\n", "\n");
string[] elements = text.Split(',');
RectTransform lineContainer = null;
for (int i = 0; i < elements.Length; i++)
{
switch (i % 3)
{
case 0:
lineContainer = AddTextElement(element, parent, elements[i], Anchor.CenterLeft).RectTransform;
lineContainer.Anchor = Anchor.TopCenter;
lineContainer.Pivot = Pivot.TopCenter;
lineContainer.NonScaledSize = new Point((int)(parent.NonScaledSize.X * 0.7f), lineContainer.NonScaledSize.Y);
break;
case 1:
AddTextElement(element, lineContainer, elements[i], Anchor.Center).GetChild<GUITextBlock>().TextAlignment = Alignment.Center;
break;
case 2:
AddTextElement(element, lineContainer, elements[i], Anchor.CenterRight).GetChild<GUITextBlock>().TextAlignment = Alignment.CenterRight;
break;
}
}
}
private void AddSpacingElement(XElement element, RectTransform parent)
{
if (element.Attribute("absoluteheight") != null)
{
int absoluteHeight = element.GetAttributeInt("absoluteheight", 10);
var textHolder = new GUIFrame(new RectTransform(new Point(parent.NonScaledSize.X, absoluteHeight), parent), style: null);
}
else
{
float relativeHeight = element.GetAttributeFloat("relativeheight", 0.0f);
var textHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, relativeHeight), parent), style: null);
}
}
private void AddImageElement(XElement element, RectTransform parent)
{
Sprite sprite = new Sprite(element);
if (element.Attribute("absoluteheight") != null)
{
int absoluteHeight = element.GetAttributeInt("absoluteheight", 10);
new GUIImage(new RectTransform(new Point(parent.NonScaledSize.X, absoluteHeight), parent), sprite, scaleToFit: true);
}
else
{
float relativeHeight = element.GetAttributeFloat("relativeheight", 0.0f);
new GUIImage(new RectTransform(new Vector2(1.0f, relativeHeight), parent), sprite, scaleToFit: true);
}
}
public void Restart()
{
listBox.BarScroll = 0.0f;

View File

@@ -501,7 +501,7 @@ namespace Barotrauma
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelGenerationParameters))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams)
{
@@ -523,7 +523,7 @@ namespace Barotrauma
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
foreach (LevelObjectPrefab levelObjPrefab in LevelObjectPrefab.List)
{
@@ -549,7 +549,7 @@ namespace Barotrauma
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelGenerationParameters))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
bool elementFound = false;
foreach (XElement element in doc.Root.Elements())
@@ -664,7 +664,7 @@ namespace Barotrauma
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc?.Root == null) continue;
if (doc == null) { continue; }
var newElement = new XElement(newPrefab.Name);
newPrefab.Save(newElement);
newElement.Add(new XElement("Sprite",

View File

@@ -4,10 +4,12 @@ using Barotrauma.Tutorials;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RestSharp;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Xml.Linq;
@@ -68,6 +70,16 @@ namespace Barotrauma
RelativeSpacing = 0.02f
};
FetchRemoteContent(Frame.RectTransform);
/*var doc = XMLExtensions.TryLoadXml("Content/UI/MenuTextTest.xml");
if (doc?.Root != null)
{
foreach (XElement subElement in doc?.Root.Elements())
{
GUIComponent.FromXML(subElement, Frame.RectTransform);
}
}*/
// === 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);
@@ -360,6 +372,7 @@ namespace Barotrauma
{
OnClicked = SelectTab
};
}
#endregion
@@ -506,7 +519,8 @@ namespace Barotrauma
}
}
else
{
{
titleText.Visible = true;
selectedTab = 0;
}
@@ -575,7 +589,7 @@ namespace Barotrauma
//(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8));
gamesession.StartRound(ToolBox.RandomSeed(8));
GameMain.GameScreen.Select();
// TODO: modding support
string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic" };
for (int i = 0; i < 3; i++)
{
@@ -587,14 +601,14 @@ namespace Barotrauma
return;
}
var characterInfo = new CharacterInfo(
Character.HumanConfigFile,
jobPrefab: JobPrefab.List.Find(j => j.Identifier == jobIdentifiers[i]));
Character.HumanSpeciesName,
jobPrefab: JobPrefab.Get(jobIdentifiers[i]));
if (characterInfo.Job == null)
{
DebugConsole.ThrowError("Failed to find the job \"" + jobIdentifiers[i] + "\"!");
}
var newCharacter = Character.Create(Character.HumanConfigFile, spawnPoint.WorldPosition, ToolBox.RandomSeed(8), characterInfo);
var newCharacter = Character.Create(Character.HumanSpeciesName, spawnPoint.WorldPosition, ToolBox.RandomSeed(8), characterInfo);
newCharacter.GiveJobItems(spawnPoint);
gamesession.CrewManager.AddCharacter(newCharacter);
Character.Controlled = newCharacter;
@@ -872,7 +886,7 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch, textPos, textPos - Vector2.UnitX * textSize.X, mouseOn ? Color.White : Color.White * 0.7f);
if (mouseOn && PlayerInput.LeftButtonClicked())
{
Process.Start("http://privacypolicy.daedalic.com");
GameMain.Instance.ShowOpenUrlInWebBrowserPrompt("http://privacypolicy.daedalic.com");
}
}
textPos.Y -= textSize.Y;
@@ -955,7 +969,7 @@ namespace Barotrauma
if (File.Exists(ServerSettings.SettingsFile))
{
XDocument settingsDoc = XMLExtensions.TryLoadXml(ServerSettings.SettingsFile);
if (settingsDoc?.Root != null)
if (settingsDoc != null)
{
port = settingsDoc.Root.GetAttributeInt("port", port);
queryPort = settingsDoc.Root.GetAttributeInt("queryport", queryPort);
@@ -1050,7 +1064,47 @@ namespace Barotrauma
OnClicked = HostServerClicked
};
}
#endregion
#endregion
private void FetchRemoteContent(RectTransform parent)
{
if (string.IsNullOrEmpty(GameMain.Config.RemoteContentUrl)) { return; }
try
{
var client = new RestClient(GameMain.Config.RemoteContentUrl);
var request = new RestRequest("MenuContent.xml", Method.GET);
IRestResponse response = client.Execute(request);
if (response.ResponseStatus != ResponseStatus.Completed)
{
return;
}
if (response.StatusCode != HttpStatusCode.OK)
{
return;
}
string xml = response.Content;
int index = xml.IndexOf('<');
if (index > 0) { xml = xml.Substring(index, xml.Length - index); }
if (string.IsNullOrWhiteSpace(xml)) { return; }
XElement element = XDocument.Parse(xml)?.Root;
foreach (XElement subElement in element.Elements())
{
GUIComponent.FromXML(subElement, parent);
}
}
catch (Exception e)
{
#if DEBUG
DebugConsole.ThrowError("Fetching remote content to the main menu failed.", e);
#endif
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.FetchRemoteContent:Exception", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Fetching remote content to the main menu failed. " + e.Message);
return;
}
}
}
}

View File

@@ -449,11 +449,7 @@ namespace Barotrauma
{
UserData = mode
};
//TODO: translate mission descriptions
if (TextManager.Language == "English")
{
textBlock.ToolTip = mode.Description;
}
textBlock.ToolTip = mode.Description;
}
//mission type ------------------------------------------------------------------
@@ -731,7 +727,7 @@ namespace Barotrauma
ReadyToStartBox.Selected = false;
if (campaignUI != null)
{
//SelectTab(Tab.Map);
campaignUI.SelectTab(CampaignUI.Tab.Map);
if (campaignUI.StartButton != null)
{
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
@@ -909,7 +905,7 @@ namespace Barotrauma
{
if (characterInfo == null)
{
characterInfo = new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, null);
characterInfo = new CharacterInfo(Character.HumanSpeciesName, GameMain.Client.Name, null);
characterInfo.RecreateHead(
GameMain.Config.CharacterHeadIndex,
GameMain.Config.CharacterRace,
@@ -930,7 +926,7 @@ namespace Barotrauma
UserData = characterInfo
};
CharacterNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), infoContainer.RectTransform), characterInfo.Name, font: GUI.LargeFont, textAlignment: Alignment.Center)
CharacterNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), infoContainer.RectTransform), characterInfo.Name, textAlignment: Alignment.Center)
{
MaxTextLength = Client.MaxNameLength,
OverflowClip = true
@@ -947,7 +943,7 @@ namespace Barotrauma
else
{
ReadyToStartBox.Selected = false;
GameMain.Client.Name = tb.Text;
GameMain.Client.SetName(tb.Text);
};
};
@@ -1011,7 +1007,7 @@ namespace Barotrauma
int i = 1;
foreach (string jobIdentifier in GameMain.Config.JobPreferences)
{
JobPrefab job = JobPrefab.List.Find(j => j.Identifier == jobIdentifier);
if (!JobPrefab.List.TryGetValue(jobIdentifier, out JobPrefab job)) { continue; }
if (job == null || job.MaxNumber <= 0) continue;
var jobFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), jobList.Content.RectTransform) { MinSize = new Point(0, 20) }, style: "ListBoxElement")
@@ -1247,6 +1243,12 @@ namespace Barotrauma
};
}
if (!sub.RequiredContentPackagesInstalled)
{
subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.ToolTip;
}
if (sub.HasTag(SubmarineTag.Shuttle))
{
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { RelativeOffset = new Vector2(0.1f, 0.0f) },
@@ -1270,14 +1272,32 @@ namespace Barotrauma
public bool VotableClicked(GUIComponent component, object userData)
{
if (GameMain.Client == null) return false;
if (GameMain.Client == null) { return false; }
VoteType voteType;
if (component.Parent == GameMain.NetLobbyScreen.SubList.Content)
{
if (!GameMain.Client.ServerSettings.Voting.AllowSubVoting)
{
if (GameMain.Client.HasPermission(ClientPermissions.SelectSub))
var selectedSub = component.UserData as Submarine;
if (!selectedSub.RequiredContentPackagesInstalled)
{
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
selectedSub.RequiredContentPackages.Any() ?
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)) :
TextManager.Get("ContentPackageMismatchWarningGeneric"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = msgBox.Close;
msgBox.Buttons[0].OnClicked += (button, obj) =>
{
GameMain.Client.RequestSelectSub(component.Parent.GetChildIndex(component), isShuttle: false);
return true;
};
msgBox.Buttons[1].OnClicked = msgBox.Close;
return false;
}
else if (GameMain.Client.HasPermission(ClientPermissions.SelectSub))
{
GameMain.Client.RequestSelectSub(component.Parent.GetChildIndex(component), isShuttle: false);
return true;
@@ -1714,16 +1734,6 @@ namespace Barotrauma
jobInfoFrame?.AddToGUIUpdateList();
}
public List<Submarine> GetSubList()
{
List<Submarine> subs = new List<Submarine>();
foreach (GUIComponent component in subList.Content.Children)
{
if (component.UserData is Submarine) subs.Add((Submarine)component.UserData);
}
return subs;
}
public override void Update(double deltaTime)
{
@@ -2057,7 +2067,7 @@ namespace Barotrauma
.UserData as Submarine;
//matching sub found and already selected, all good
if (sub != null && subList.SelectedData is Submarine selectedSub && selectedSub.MD5Hash?.Hash == md5Hash)
if (sub != null && subList.SelectedData is Submarine selectedSub && selectedSub.MD5Hash?.Hash == md5Hash && System.IO.File.Exists(sub.FilePath))
{
return true;
}
@@ -2090,12 +2100,12 @@ namespace Barotrauma
FailedSelectedShuttle = null;
//hashes match, all good
if (sub.MD5Hash?.Hash == md5Hash)
if (sub.MD5Hash?.Hash == md5Hash && Submarine.SavedSubmarines.Contains(sub))
{
return true;
}
}
//-------------------------------------------------------------------------------------
//if we get to this point, a matching sub was not found or it has an incorrect MD5 hash
@@ -2105,14 +2115,15 @@ namespace Barotrauma
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
string errorMsg = "";
if (sub == null)
if (sub == null || !Submarine.SavedSubmarines.Contains(sub))
{
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
}
else if (sub.MD5Hash?.Hash == null)
{
errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
subList.Content.GetChildByUserData(sub).GetChild<GUITextBox>().TextColor = Color.Red;
GUITextBlock textBlock = subList.Content.GetChildByUserData(sub)?.GetChild<GUITextBlock>();
if (textBlock != null) { textBlock.TextColor = Color.Red; }
}
else
{

View File

@@ -186,7 +186,7 @@ namespace Barotrauma
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.Particles))
{
XDocument doc = XMLExtensions.TryLoadXml(configFile);
if (doc == null || doc.Root == null) continue;
if (doc == null) { continue; }
var prefabList = GameMain.ParticleManager.GetPrefabList();
foreach (ParticlePrefab prefab in prefabList)

View File

@@ -85,7 +85,7 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), clientNameHolder.RectTransform), TextManager.Get("YourName"));
clientNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.5f), clientNameHolder.RectTransform), "")
{
Text = GameMain.Config.DefaultPlayerName,
Text = GameMain.Config.PlayerName,
MaxTextLength = Client.MaxNameLength,
OverflowClip = true
};
@@ -822,11 +822,20 @@ namespace Barotrauma
private void ServerQueryFinished()
{
if (serverList.Content.Children.All(c => !c.Visible))
if (!serverList.Content.Children.Any())
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("NoMatchingServers"))
new GUITextBlock(new RectTransform(Vector2.One, serverList.Content.RectTransform),
TextManager.Get("NoServers"), textAlignment: Alignment.Center)
{
CanBeFocused = false
};
}
else if (serverList.Content.Children.All(c => !c.Visible))
{
new GUITextBlock(new RectTransform(Vector2.One, serverList.Content.RectTransform),
TextManager.Get("NoMatchingServers"), textAlignment: Alignment.Center)
{
CanBeFocused = false,
UserData = "noresults"
};
}
@@ -918,7 +927,7 @@ namespace Barotrauma
return false;
}
GameMain.Config.DefaultPlayerName = clientNameBox.Text;
GameMain.Config.PlayerName = clientNameBox.Text;
GameMain.Config.SaveNewPlayerConfig();
CoroutineManager.StartCoroutine(ConnectToServer(ip, serverName));

View File

@@ -301,7 +301,7 @@ namespace Barotrauma
if (file.Path.EndsWith(".xml"))
{
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc != null && doc.Root != null)
if (doc != null)
{
LoadSprites(doc.Root);
}

View File

@@ -164,8 +164,7 @@ namespace Barotrauma
if (userdata is Facepunch.Steamworks.Workshop.Item item)
{
if (!item.Installed) { return false; }
CreateWorkshopItem(item);
ShowCreateItemFrame();
if (CreateWorkshopItem(item)) { ShowCreateItemFrame(); }
}
return true;
}
@@ -310,7 +309,7 @@ namespace Barotrauma
CreateMyItemFrame(contentPackage, myItemList);
}
}
private void OnItemsReceived(IList<Facepunch.Steamworks.Workshop.Item> itemDetails, GUIListBox listBox)
{
listBox.ClearChildren();
@@ -525,6 +524,9 @@ namespace Barotrauma
OnClicked = DownloadItem
};
}
innerFrame.Recalculate();
listBox.RecalculateChildren();
}
private void RemoveItemFromLists(ulong itemID)
@@ -651,6 +653,9 @@ namespace Barotrauma
{
if (!(tickBox.UserData is Facepunch.Steamworks.Workshop.Item item)) { return false; }
//currently editing the item, don't allow enabling/disabling it
if (itemEditor?.Id == item.Id) { tickBox.Selected = true; return false; }
var updateButton = tickBox.Parent.FindChild("updatebutton");
string errorMsg = "";
@@ -724,23 +729,30 @@ namespace Barotrauma
}
};
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform)) { Color = Color.Black };
var centerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.01f,
Color = Color.Black * 0.9f
};
if (itemPreviewSprites.ContainsKey(item.PreviewImageUrl))
{
new GUIImage(new RectTransform(Vector2.One, headerArea.RectTransform), itemPreviewSprites[item.PreviewImageUrl], scaleToFit: true);
new GUIImage(new RectTransform(new Vector2(0.5f, 1.0f), centerArea.RectTransform), itemPreviewSprites[item.PreviewImageUrl], scaleToFit: true);
}
else
{
new GUIImage(new RectTransform(Vector2.One, headerArea.RectTransform), SteamManager.Instance.DefaultPreviewImage, scaleToFit: true);
new GUIImage(new RectTransform(new Vector2(0.5f, 0.0f), centerArea.RectTransform), SteamManager.Instance.DefaultPreviewImage, scaleToFit: true);
}
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform)) { ScrollBarVisible = true };
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), centerArea.RectTransform)) { ScrollBarVisible = true };
//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), TextManager.EnsureUTF8(item.Description), wrap: true)
string description = TextManager.EnsureUTF8(item.Description);
description = ToolBox.RemoveBBCodeTags(description);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), descriptionContainer.Content.RectTransform), description, wrap: true)
{
CanBeFocused = false
};
@@ -799,12 +811,24 @@ namespace Barotrauma
var modificationDate = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), content.RectTransform), TextManager.Get("WorkshopItemModificationDate"));
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), modificationDate.RectTransform, Anchor.CenterRight), item.Modified.ToString("dd.MM.yyyy"), textAlignment: Alignment.TopRight);
}
/*private void CreateWorkshopItem()
{
SteamManager.CreateWorkshopItemStaging("ModName", out itemEditor, out itemContentPackage);
}*/
if (item.Subscribed)
{
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), content.RectTransform) { MinSize = new Point(0, 25) }, isHorizontal: true);
new GUIButton(new RectTransform(new Vector2(0.5f, 0.95f), buttonContainer.RectTransform), TextManager.Get("WorkshopItemUnsubscribe"))
{
UserData = item,
OnClicked = (btn, userdata) =>
{
item.UnSubscribe();
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
itemPreviewFrame.ClearChildren();
return true;
}
};
}
}
private void CreateWorkshopItem(Submarine sub)
{
string destinationFolder = Path.Combine("Mods", sub.Name);
@@ -826,7 +850,7 @@ namespace Barotrauma
itemContentPackage.Name = sub.Name;
itemContentPackage.Save(itemContentPackage.Path);
ContentPackage.List.Add(itemContentPackage);
GameMain.Config.SelectedContentPackages.Add(itemContentPackage);
GameMain.Config.SelectContentPackage(itemContentPackage);
itemEditor.Title = sub.Name;
itemEditor.Tags.Add("Submarine");
@@ -886,15 +910,21 @@ namespace Barotrauma
}*/
}
private void CreateWorkshopItem(Facepunch.Steamworks.Workshop.Item item)
private bool CreateWorkshopItem(Facepunch.Steamworks.Workshop.Item item)
{
if (!item.Installed)
{
new GUIMessageBox(TextManager.Get("Error"),
new GUIMessageBox(TextManager.Get("Error"),
TextManager.GetWithVariable("WorkshopErrorInstallRequiredToEdit", "[itemname]", TextManager.EnsureUTF8(item.Title)));
return;
return false;
}
SteamManager.CreateWorkshopItemStaging(item, out itemEditor, out itemContentPackage);
if (!SteamManager.CreateWorkshopItemStaging(item, out itemEditor, out itemContentPackage))
{
return false;
}
var tickBox = publishedItemList.Content.GetChildByUserData(item)?.GetAnyChild<GUITickBox>();
if (tickBox != null) { tickBox.Selected = true; }
return true;
}
private void ShowCreateItemFrame()
@@ -1256,6 +1286,14 @@ namespace Barotrauma
createItemFileList.Flash(Color.Red);
}
if (!itemContentPackage.CheckValidity(out List<string> errorMessages))
{
new GUIMessageBox(
TextManager.GetWithVariable("workshopitempublishfailed", "[itemname]", itemEditor.Title),
string.Join("\n", errorMessages));
return false;
}
PublishWorkshopItem();
return true;
}

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