(5a377a8ee) Unstable v0.9.1000.0

This commit is contained in:
Juan Pablo Arce
2020-05-13 12:55:42 -03:00
parent b143329701
commit a1ca41aa5d
426 changed files with 14384 additions and 5708 deletions

3
.gitignore vendored
View File

@@ -37,5 +37,8 @@ Libraries/webm_mem_playback/opus_x64_linux/
# Mac
*.DS_Store
# Win
desktop.ini
#Merge script
temp.txt

View File

@@ -200,7 +200,7 @@ namespace Barotrauma
worldView = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
viewMatrix = Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0));
globalZoomScale = (float)Math.Pow(new Vector2(resolution.X, resolution.Y).Length() / new Vector2(1920, 1080).Length(), 2);
globalZoomScale = (float)Math.Pow(new Vector2(GUI.UIWidth, resolution.Y).Length() / GUI.ReferenceResolution.Length(), 2);
}
public void UpdateTransform(bool interpolate = true)

View File

@@ -35,7 +35,7 @@ namespace Barotrauma
}
targetPos.Y = -targetPos.Y;
GUI.DrawLine(spriteBatch, pos, targetPos, GUI.Style.Red * 0.5f, 0, 4);
if (wallTarget != null)
if (wallTarget != null && (State == AIState.Attack || State == AIState.Aggressive || State == AIState.PassiveAggressive))
{
Vector2 wallTargetPos = wallTarget.Position;
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }

View File

@@ -0,0 +1,50 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using Barotrauma.Networking;
namespace Barotrauma
{
partial class WreckAI : IServerSerializable
{
private CoroutineHandle fadeOutRoutine;
partial void FadeOutColors()
{
if (fadeOutRoutine != null)
{
CoroutineManager.StopCoroutines(fadeOutRoutine);
}
fadeOutRoutine = CoroutineManager.StartCoroutine(FadeOutColors(Config.DeadEntityColorFadeOutTime));
}
private IEnumerable<object> FadeOutColors(float time)
{
float timer = 0;
while (timer < time)
{
timer += CoroutineManager.DeltaTime;
float m = MathHelper.Lerp(1, Config.DeadEntityColorMultiplier, MathUtils.InverseLerp(0, time, timer));
foreach (var item in thalamusItems)
{
if (item.Prefab.BrokenSprites.None())
{
Color c = item.prefab.SpriteColor;
item.SpriteColor = new Color(c.R / 255f * m, c.G / 255f * m, c.B / 255f * m, c.A / 255f);
}
}
foreach (var structure in thalamusStructures)
{
Color c = structure.prefab.SpriteColor;
structure.SpriteColor = new Color(c.R / 255f * m, c.G / 255f * m, c.B / 255f * m, c.A / 255f);
}
yield return CoroutineStatus.Running;
}
yield return CoroutineStatus.Success;
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
IsAlive = msg.ReadBoolean();
}
}
}

View File

@@ -389,7 +389,7 @@ namespace Barotrauma
{
foreach (Limb limb in Limbs)
{
if (limb == null || limb.IsSevered || limb.ActiveSprite == null) continue;
if (limb == null || limb.IsSevered || limb.ActiveSprite == null) { continue; }
Vector2 spriteOrigin = limb.ActiveSprite.Origin;
spriteOrigin.X = limb.ActiveSprite.SourceRect.Width - spriteOrigin.X;
@@ -404,8 +404,8 @@ namespace Barotrauma
float gibParticleAmount = MathHelper.Clamp(limb.Mass / character.AnimController.Mass, 0.1f, 1.0f);
foreach (ParticleEmitter emitter in character.GibEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
emitter.Emit(1.0f, limb.WorldPosition, character.CurrentHull, amountMultiplier: gibParticleAmount);
}
@@ -418,7 +418,8 @@ namespace Barotrauma
if (playSound)
{
SoundPlayer.PlayDamageSound("Gore", 1.0f, limbJoint.LimbA.body);
var damageSound = character.GetSound(s => s.Type == CharacterSound.SoundType.Damage);
SoundPlayer.PlayDamageSound(limbJoint.Params.BreakSound, 1.0f, limbJoint.LimbA.body.DrawPosition, range: damageSound != null ? damageSound.Range : 800);
}
}
@@ -446,9 +447,10 @@ namespace Barotrauma
float depthOffset = GetDepthOffset();
for (int i = 0; i < limbs.Length; i++)
{
if (depthOffset != 0.0f) { inversedLimbDrawOrder[i].ActiveSprite.Depth += depthOffset; }
inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color);
if (depthOffset != 0.0f) { inversedLimbDrawOrder[i].ActiveSprite.Depth -= depthOffset; }
var limb = inversedLimbDrawOrder[i];
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth += depthOffset; }
limb.Draw(spriteBatch, cam, color);
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth -= depthOffset; }
}
LimbJoints.ForEach(j => j.Draw(spriteBatch));
}
@@ -489,8 +491,8 @@ namespace Barotrauma
public void DebugDraw(SpriteBatch spriteBatch)
{
if (!GameMain.DebugDraw || !character.Enabled) return;
if (simplePhysicsEnabled) return;
if (!GameMain.DebugDraw || !character.Enabled) { return; }
if (simplePhysicsEnabled) { return; }
foreach (Limb limb in Limbs)
{
@@ -522,7 +524,10 @@ namespace Barotrauma
if (limb.body.TargetPosition != null)
{
Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition);
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null)
{
pos += currentHull.Submarine.DrawPosition;
}
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 10, (int)pos.Y - 10, 20, 20), Color.Cyan, false, 0.01f);
@@ -541,13 +546,19 @@ namespace Barotrauma
if (character.MemState.Count > 1)
{
Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position);
if (currentHull?.Submarine != null) prevPos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null)
{
prevPos += currentHull.Submarine.DrawPosition;
}
prevPos.Y = -prevPos.Y;
for (int i = 1; i < character.MemState.Count; i++)
{
Vector2 currPos = ConvertUnits.ToDisplayUnits(character.MemState[i].Position);
if (currentHull?.Submarine != null) currPos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null)
{
currPos += currentHull.Submarine.DrawPosition;
}
currPos.Y = -currPos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 3, (int)currPos.Y - 3, 6, 6), Color.Cyan * 0.6f, true, 0.01f);

View File

@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -233,7 +234,7 @@ namespace Barotrauma
pressureParticleTimer += pressure * deltaTime;
if (pressureParticleTimer > 10.0f)
{
Particle p = GameMain.ParticleManager.CreateParticle("waterblood", WorldPosition + Rand.Vector(5.0f), Rand.Vector(10.0f));
GameMain.ParticleManager.CreateParticle(Params.BleedParticleWater, WorldPosition + Rand.Vector(5.0f), Rand.Vector(10.0f));
pressureParticleTimer = 0.0f;
}
}
@@ -355,7 +356,7 @@ namespace Barotrauma
}
}
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult)
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
{
if (attackResult.Damage <= 1.0f || IsDead) { return; }
if (soundTimer < soundInterval * 0.5f)
@@ -444,6 +445,7 @@ namespace Barotrauma
if (item.body != null && !item.body.Enabled) continue;
if (item.ParentInventory != null) continue;
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
if (Screen.Selected is SubEditorScreen editor && editor.WiringMode && item.GetComponent<ConnectionPanel>() == null) { continue; }
if (draggingItemToWorld)
{
@@ -812,19 +814,23 @@ namespace Barotrauma
return progressBar;
}
private readonly List<CharacterSound> matchingSounds = new List<CharacterSound>();
private SoundChannel soundChannel;
public void PlaySound(CharacterSound.SoundType soundType)
{
if (sounds == null || sounds.Count == 0) { return; }
if (soundChannel != null && soundChannel.IsPlaying) { return; }
var matchingSounds = sounds.Where(s =>
s.Type == soundType &&
(s.Gender == Gender.None || (info != null && info.Gender == s.Gender)));
if (!matchingSounds.Any()) { return; }
var matchingSoundsList = matchingSounds.ToList();
var selectedSound = matchingSoundsList[Rand.Int(matchingSoundsList.Count)];
if (GameMain.SoundManager?.Disabled ?? true) { return; }
matchingSounds.Clear();
foreach (var s in sounds)
{
if (s.Type == soundType && (s.Gender == Gender.None || (info != null && info.Gender == s.Gender)))
{
matchingSounds.Add(s);
}
}
var selectedSound = matchingSounds.GetRandom();
if (selectedSound?.Sound == null) { return; }
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, CurrentHull);
soundTimer = soundInterval;
}
@@ -843,6 +849,11 @@ namespace Barotrauma
activeObjectiveEntities.Remove(found);
}
/// <summary>
/// Note that when a predicate is provided, the random option uses Linq.Where() extension method, which creates a new collection.
/// </summary>
public CharacterSound GetSound(Func<CharacterSound, bool> predicate = null, bool random = false) => random ? sounds.GetRandom(predicate) : sounds.FirstOrDefault(predicate);
partial void ImplodeFX()
{
Vector2 centerOfMass = AnimController.GetCenterOfMass();

View File

@@ -2,6 +2,7 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -28,7 +29,7 @@ namespace Barotrauma
{
if (hudFrame == null)
{
hudFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
hudFrame = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas), style: null)
{
CanBeFocused = false
};
@@ -37,6 +38,9 @@ namespace Barotrauma
}
}
private static bool shouldRecreateHudTexts = true;
private static bool heldDownShiftWhenGotHudTexts;
private static bool ShouldDrawInventory(Character character)
{
return
@@ -140,7 +144,11 @@ namespace Barotrauma
else
{
focusedItemOverlayTimer = Math.Max(focusedItemOverlayTimer - deltaTime, 0.0f);
if (focusedItemOverlayTimer <= 0.0f) focusedItem = null;
if (focusedItemOverlayTimer <= 0.0f)
{
focusedItem = null;
shouldRecreateHudTexts = true;
}
}
}
@@ -194,6 +202,7 @@ namespace Barotrauma
foreach (Item brokenItem in brokenItems)
{
if (brokenItem.NonInteractable) { continue; }
float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition);
Vector2 drawPos = brokenItem.DrawPosition;
float alpha = Math.Min((1000.0f - dist) / 1000.0f * 2.0f, 1.0f);
@@ -209,20 +218,20 @@ namespace Barotrauma
DrawCharacterHoverTexts(spriteBatch, cam, character);
}
float circleSize;
if (character.FocusedItem != null)
{
if (focusedItem != character.FocusedItem)
{
focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer);
shouldRecreateHudTexts = true;
}
focusedItem = character.FocusedItem;
focusedItem = character.FocusedItem;
}
if (focusedItem != null && focusedItemOverlayTimer > ItemOverlayDelay)
{
Vector2 circlePos = cam.WorldToScreen(focusedItem.DrawPosition);
circleSize = Math.Max(focusedItem.Rect.Width, focusedItem.Rect.Height) * 1.5f;
float circleSize = Math.Max(focusedItem.Rect.Width, focusedItem.Rect.Height) * 1.5f;
circleSize = MathHelper.Clamp(circleSize, 45.0f, 100.0f) * Math.Min((focusedItemOverlayTimer - 1.0f) * 5.0f, 1.0f);
if (circleSize > 0.0f)
{
@@ -238,7 +247,14 @@ namespace Barotrauma
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
{
var hudTexts = focusedItem.GetHUDTexts(character);
bool shiftDown = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
if(shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
{
shouldRecreateHudTexts = true;
heldDownShiftWhenGotHudTexts = shiftDown;
}
var hudTexts = focusedItem.GetHUDTexts(character, shouldRecreateHudTexts);
shouldRecreateHudTexts = false;
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
@@ -358,7 +374,7 @@ namespace Barotrauma
{
GUIComponent.DrawToolTip(
spriteBatch,
character.Info?.Job == null ? character.DisplayName : character.Name + " (" + character.Info.Job.Name + ")",
character.Info?.Job == null ? character.DisplayName : character.DisplayName + " (" + character.Info.Job.Name + ")",
HUDLayoutSettings.PortraitArea);
}
}
@@ -378,10 +394,6 @@ namespace Barotrauma
startPos = cam.WorldToScreen(startPos);
string focusName = character.FocusedCharacter.DisplayName;
if (character.FocusedCharacter.Info != null)
{
focusName = character.FocusedCharacter.Info.DisplayName;
}
Vector2 textPos = startPos;
Vector2 textSize = GUI.Font.MeasureString(focusName);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusName);

View File

@@ -19,75 +19,107 @@ namespace Barotrauma
}
public GUIFrame CreateInfoFrame(GUIFrame frame)
public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null)
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) })
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) })
{
Stretch = true,
RelativeSpacing = 0.03f
RelativeSpacing = 0.05f
//Stretch = true
};
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), paddedFrame.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal: true);
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1.0f), headerArea.RectTransform),
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
new GUICustomComponent(new RectTransform(new Vector2(0.425f, 1.0f), headerArea.RectTransform),
onDraw: (sb, component) => DrawInfoFrameCharacterIcon(sb, component.Rect));
ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), headerArea.RectTransform))
var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.575f, 1.0f), headerArea.RectTransform))
{
RelativeSpacing = 0.05f,
RelativeSpacing = 0.02f,
Stretch = true
};
Color? nameColor = null;
if (Job != null) { nameColor = Job.Prefab.UIColor; }
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
Name, textColor: nameColor, font: GUI.LargeFont)
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), ToolBox.LimitString(Name, GUI.Font, headerTextArea.Rect.Width), textColor: nameColor, font: GUI.Font)
{
Padding = Vector4.Zero,
AutoScaleHorizontal = true
ForceUpperCase = true,
Padding = Vector4.Zero
};
if (Job != null)
if (permissionIcon != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
Job.Name, textColor: Job.Prefab.UIColor, font: font);
Point iconSize = permissionIcon.SourceRect.Size;
int iconWidth = (int)((float)characterNameBlock.Rect.Height / iconSize.Y * iconSize.X);
new GUIImage(new RectTransform(new Point(iconWidth, characterNameBlock.Rect.Height), characterNameBlock.RectTransform) { AbsoluteOffset = new Point(-iconWidth - 2, 0) }, permissionIcon) { IgnoreLayoutGroups = true };
}
if (Job != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), Job.Name, textColor: Job.Prefab.UIColor, font: font)
{
Padding = Vector4.Zero
};
}
if (personalityTrait != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + personalityTrait.Name.Replace(" ", ""))), font: font);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + personalityTrait.Name.Replace(" ", ""))), font: font)
{
Padding = Vector4.Zero
};
}
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), style: null);
if (Job != null)
if (Job != null && (Character == null || !Character.IsDead))
{
var skillsArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter))
{
Stretch = true
};
var skills = Job.Skills;
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
TextManager.Get("Skills") + ":", font: font);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("skills"), string.Empty), font: font) { Padding = Vector4.Zero };
foreach (Skill skill in skills)
{
Color textColor = Color.White * (0.5f + skill.Level / 200.0f);
var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform),
((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font) { Padding = Vector4.Zero };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform), ((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
}
}
else if (Character != null && Character.IsDead)
{
var deadArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter))
{
Stretch = true
};
return frame;
string deadDescription = TextManager.AddPunctuation(':', TextManager.Get("deceased") + "\n" + Character.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
TextManager.AddPunctuation(':', TextManager.Get("CauseOfDeath"), TextManager.Get("CauseOfDeath." + Character.CauseOfDeath.Type.ToString())));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), deadArea.RectTransform), deadDescription, textColor: GUI.Style.Red, font: font, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
}
if (returnParent)
{
return frame;
}
else
{
return paddedFrame;
}
}
private void DrawInfoFrameCharacterIcon(SpriteBatch sb, Rectangle componentRect)
{
Vector2 targetAreaSize = componentRect.Size.ToVector2();
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
DrawIcon(sb, componentRect.Location.ToVector2() + headSprite.size / 2 * scale, targetAreaSize);
}
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)

View File

@@ -278,7 +278,7 @@ namespace Barotrauma
break;
case ServerNetObject.ENTITY_EVENT:
int eventType = msg.ReadRangedInteger(0, 3);
int eventType = msg.ReadRangedInteger(0, 4);
switch (eventType)
{
case 0:
@@ -338,6 +338,40 @@ namespace Barotrauma
info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
}
break;
case 4:
int attackLimbIndex = msg.ReadByte();
UInt16 targetEntityID = msg.ReadUInt16();
int targetLimbIndex = msg.ReadByte();
//255 = entity already removed, no need to do anything
if (attackLimbIndex == 255) { break; }
if (attackLimbIndex >= AnimController.Limbs.Length)
{
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds ({attackLimbIndex})");
break;
}
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
Limb targetLimb = null;
if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
{
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target entity not found (ID {targetEntityID})");
break;
}
if (targetEntity is Character targetCharacter)
{
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
{
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds ({targetLimbIndex})");
break;
}
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
}
if (attackLimb?.attack != null)
{
attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
}
break;
}
msg.ReadPadBits();
break;
@@ -397,8 +431,7 @@ namespace Barotrauma
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
{
var orderPrefab = Order.PrefabList[orderPrefabIndex];
if ((orderPrefab.ItemComponentType == null && orderPrefab.ItemIdentifiers.None()) ||
(targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
if (!orderPrefab.MustSetTarget || (targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
{
character.SetOrder(
new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
@@ -469,11 +502,9 @@ namespace Barotrauma
causeOfDeathAffliction = AfflictionPrefab.Prefabs[afflictionName];
}
}
byte severedLimbCount = msg.ReadByte();
if (!IsDead)
{
if (causeOfDeathType == CauseOfDeathType.Pressure)
if (causeOfDeathType == CauseOfDeathType.Pressure || causeOfDeathAffliction == AfflictionPrefab.Pressure)
{
Implode(true);
}
@@ -482,26 +513,26 @@ namespace Barotrauma
Kill(causeOfDeathType, causeOfDeathAffliction?.Instantiate(1.0f), true);
}
}
for (int i = 0; i < severedLimbCount; i++)
{
int severedJointIndex = msg.ReadByte();
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
else
{
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
}
}
}
else
{
if (IsDead) { Revive(); }
CharacterHealth.ClientRead(msg);
}
byte severedLimbCount = msg.ReadByte();
for (int i = 0; i < severedLimbCount; i++)
{
int severedJointIndex = msg.ReadByte();
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
else
{
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;

View File

@@ -1,4 +1,5 @@
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -20,9 +21,9 @@ namespace Barotrauma
}
const int MaxFakeFireSources = 10;
private float minFakeFireSourceInterval = 10.0f, maxFakeFireSourceInterval = 200.0f;
const float MinFakeFireSourceInterval = 30.0f, MaxFakeFireSourceInterval = 240.0f;
private float createFireSourceTimer;
private List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
private readonly List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
enum FloodType
{
@@ -31,26 +32,30 @@ namespace Barotrauma
HideFlooding
}
private float minSoundInterval = 10.0f, maxSoundInterval = 60.0f;
const float MinSoundInterval = 10.0f, MaxSoundInterval = 180.0f;
private FloodType currentFloodType;
private float soundTimer;
private float minFloodInterval = 30.0f, maxFloodInterval = 180.0f;
const float MinFloodInterval = 60.0f, MaxFloodInterval = 240.0f;
private float createFloodTimer;
private float currentFloodState;
private float currentFloodDuration;
private float fakeBrokenInterval = 30.0f;
private float fakeBrokenTimer = 0.0f;
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
if (Character.Controlled != characterHealth.Character) return;
UpdateFloods(deltaTime);
UpdateSounds(characterHealth.Character, deltaTime);
UpdateFires(characterHealth.Character, deltaTime);
UpdateFires(characterHealth.Character, deltaTime);
UpdateFakeBroken(deltaTime);
}
private void UpdateSounds(Character character, float deltaTime)
{
if (soundTimer < MathHelper.Lerp(maxSoundInterval, minSoundInterval, Strength / 100.0f))
if (soundTimer < MathHelper.Lerp(MaxSoundInterval, MinSoundInterval, Strength / 100.0f))
{
soundTimer += deltaTime;
return;
@@ -97,7 +102,7 @@ namespace Barotrauma
return;
}
if (createFloodTimer < MathHelper.Lerp(maxFloodInterval, minFloodInterval, Strength / 100.0f))
if (createFloodTimer < MathHelper.Lerp(MaxFloodInterval, MinFloodInterval, Strength / 100.0f))
{
createFloodTimer += deltaTime;
return;
@@ -124,7 +129,7 @@ namespace Barotrauma
createFireSourceTimer += deltaTime;
if (fakeFireSources.Count < MaxFakeFireSources &&
character.Submarine != null &&
createFireSourceTimer > MathHelper.Lerp(maxFakeFireSourceInterval, minFakeFireSourceInterval, Strength / 100.0f))
createFireSourceTimer > MathHelper.Lerp(MaxFakeFireSourceInterval, MinFakeFireSourceInterval, Strength / 100.0f))
{
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
@@ -140,9 +145,9 @@ namespace Barotrauma
foreach (FakeFireSource fakeFireSource in fakeFireSources)
{
if (fakeFireSource.Hull.Surface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
if (fakeFireSource.Hull.DrawSurface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
{
fakeFireSource.LifeTime -= deltaTime * 10.0f;
fakeFireSource.LifeTime -= deltaTime * 100.0f;
}
fakeFireSource.LifeTime -= deltaTime;
@@ -162,5 +167,28 @@ namespace Barotrauma
fakeFireSources.RemoveAll(fs => fs.LifeTime <= 0.0f);
}
private void UpdateFakeBroken(float deltaTime)
{
fakeBrokenTimer -= deltaTime;
if (fakeBrokenTimer > 0.0f) { return; }
foreach (Item item in Item.ItemList)
{
var repairable = item.GetComponent<Repairable>();
if (repairable == null) { continue; }
if (ShouldFakeBrokenItem(item))
{
repairable.FakeBrokenTimer = 60.0f;
}
}
fakeBrokenTimer = fakeBrokenInterval;
}
private bool ShouldFakeBrokenItem(Item item)
{
return Rand.Range(0.0f, 1000.0f) < Strength;
}
}
}

View File

@@ -251,8 +251,7 @@ namespace Barotrauma
{
get
{
// 0.38775510204f = percentage of offset before reaching the healthbar portion of the graphic going from bottom upwards
return new Point(2, (int)(HUDLayoutSettings.HealthBarArea.Size.Y * 0.38775510204f));
return new Point(Math.Max(2, GUI.IntScaleCeiling(1.5f)), Math.Min(GUI.IntScaleFloor(18f), 19));
}
}
@@ -260,7 +259,7 @@ namespace Barotrauma
{
get
{
return new Point((int)Math.Ceiling(HUDLayoutSettings.HealthBarArea.Size.X - 45 * GUI.Scale), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2);
return new Point(healthBarHolder.Rect.Width - Math.Min(GUI.IntScale(45f), 47), GUI.IntScale(15f));
}
}
@@ -505,8 +504,6 @@ namespace Barotrauma
Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ?
AnimController.Animation.None : AnimController.Animation.CPR;
button.Selected = Character.Controlled.AnimController.Anim == AnimController.Animation.CPR;
selectedCharacter.AnimController.ResetPullJoints();
if (GameMain.Client != null)
@@ -599,12 +596,14 @@ namespace Barotrauma
switch (alignment)
{
case Alignment.Left:
healthInterfaceFrame.RectTransform.SetPosition(Anchor.CenterLeft);
healthInterfaceFrame.RectTransform.SetPosition(Anchor.BottomLeft);
break;
case Alignment.Right:
healthInterfaceFrame.RectTransform.SetPosition(Anchor.CenterRight);
healthInterfaceFrame.RectTransform.SetPosition(Anchor.BottomRight);
break;
}
healthInterfaceFrame.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
healthInterfaceFrame.RectTransform.RecalculateChildren(false);
}
@@ -651,10 +650,14 @@ namespace Barotrauma
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
if (bloodParticleTimer <= 0.0f)
{
bool inWater = Character.AnimController.InWater;
float bloodParticleSize = MathHelper.Lerp(0.5f, 1.0f, affliction.Strength / 100.0f);
if (!Character.AnimController.InWater) bloodParticleSize *= 2.0f;
if (!inWater)
{
bloodParticleSize *= 2.0f;
}
var blood = GameMain.ParticleManager.CreateParticle(
Character.AnimController.InWater ? "waterblood" : "blooddrop",
inWater ? Character.Params.BleedParticleWater : Character.Params.BleedParticleAir,
targetLimb.WorldPosition, Rand.Vector(affliction.Strength), 0.0f, Character.AnimController.CurrentHull);
if (blood != null)
@@ -765,7 +768,8 @@ namespace Barotrauma
{
OpenHealthWindow = null;
}
else if (Character.Controlled == Character && Character.Controlled.FocusedCharacter == null)
else if (Character.Controlled == Character &&
(Character.Controlled.FocusedCharacter?.CharacterHealth == null || !Character.Controlled.FocusedCharacter.CharacterHealth.UseHealthWindow))
{
OpenHealthWindow = this;
forceAfflictionContainerUpdate = true;
@@ -946,6 +950,10 @@ namespace Barotrauma
&& !Character.IsDead
&& openHealthWindow == this;
cprButton.IgnoreLayoutGroups = !cprButton.Visible;
cprButton.Selected =
Character.Controlled != null &&
Character == Character.Controlled.SelectedCharacter &&
Character.Controlled.AnimController.Anim == AnimController.Animation.CPR;
cprFrame.RectTransform.Resize(new Vector2(0.7f, 1.0f));
cprButton.RectTransform.Resize(new Vector2(1.0f, 1.0f));
@@ -1100,7 +1108,7 @@ namespace Barotrauma
float currHealth = healthBar.BarSize;
Color prevColor = healthBar.Color;
healthBarShadow.BarSize = healthShadowSize;
healthBarShadow.Color = GUI.Style.Red;
healthBarShadow.Color = Color.Lerp(GUI.Style.Red, Color.Black, 0.5f);
healthBarShadow.Visible = true;
healthBar.BarSize = currHealth;
healthBar.Color = prevColor;
@@ -1815,7 +1823,7 @@ namespace Barotrauma
Vector2 iconPos = highlightArea.Center.ToVector2();
//Affliction mostSevereAffliction = thisAfflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !thisAfflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? thisAfflictions.FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(thisAfflictions).FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(thisAfflictions, excludeBuffs: false).FirstOrDefault();
if (mostSevereAffliction != null) { DrawLimbAfflictionIcon(spriteBatch, mostSevereAffliction, iconScale, ref iconPos); }
if (thisAfflictions.Count() > 1)

View File

@@ -12,8 +12,10 @@ namespace Barotrauma
{
int width = 500, height = 400;
GUIButton backFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, height), backFrame.RectTransform, Anchor.Center));
GUIButton frameHolder = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, frameHolder.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, height), frameHolder.RectTransform, Anchor.Center));
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Name, font: GUI.LargeFont);
@@ -49,7 +51,7 @@ namespace Barotrauma
font: GUI.SmallFont);
}*/
return backFrame;
return frameHolder;
}

View File

@@ -8,7 +8,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
@@ -70,7 +70,6 @@ namespace Barotrauma
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
@@ -110,6 +109,7 @@ namespace Barotrauma
private float wetTimer;
private float dripParticleTimer;
private float deadTimer;
/// <summary>
/// Note that different limbs can share the same deformations.
@@ -125,7 +125,7 @@ namespace Barotrauma
{
get
{
var conditionalSprite = ConditionalSprites.FirstOrDefault(c => c.IsActive && c.DeformableSprite != null);
var conditionalSprite = ConditionalSprites.FirstOrDefault(c => c.Exclusive && c.IsActive && c.DeformableSprite != null);
if (conditionalSprite != null)
{
return conditionalSprite.DeformableSprite;
@@ -143,7 +143,7 @@ namespace Barotrauma
{
get
{
var conditionalSprite = ConditionalSprites.FirstOrDefault(c => c.IsActive && c.ActiveSprite != null);
var conditionalSprite = ConditionalSprites.FirstOrDefault(c => c.Exclusive && c.IsActive && c.ActiveSprite != null);
if (conditionalSprite != null)
{
return conditionalSprite.ActiveSprite;
@@ -165,6 +165,12 @@ namespace Barotrauma
public Sprite DamagedSprite { get; private set; }
public bool Hide
{
get => Params.Hide;
set => Params.Hide = value;
}
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>>();
@@ -273,7 +279,17 @@ namespace Barotrauma
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
break;
case "conditionalsprite":
var conditionalSprite = new ConditionalSprite(subElement, character, file: GetSpritePath(subElement, null));
ISerializableEntity targetEntity;
string target = subElement.GetAttributeString("target", null);
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
{
targetEntity = character;
}
else
{
targetEntity = this;
}
var conditionalSprite = new ConditionalSprite(subElement, targetEntity, file: GetSpritePath(subElement, null));
ConditionalSprites.Add(conditionalSprite);
if (conditionalSprite.DeformableSprite != null)
{
@@ -372,12 +388,16 @@ namespace Barotrauma
private string GetSpritePath(XElement element, SpriteParams spriteParams)
{
string texturePath = element.GetAttributeString("texture", null);
if (string.IsNullOrWhiteSpace(texturePath) && spriteParams != null)
if (spriteParams != null)
{
texturePath = spriteParams.Ragdoll.Texture;
return GetSpritePath(spriteParams.GetTexturePath());
}
else
{
string texturePath = element.GetAttributeString("texture", null);
texturePath = string.IsNullOrWhiteSpace(texturePath) ? ragdoll.RagdollParams.Texture : texturePath;
return GetSpritePath(texturePath);
}
return GetSpritePath(texturePath);
}
/// <summary>
@@ -418,19 +438,46 @@ namespace Barotrauma
}
}
partial void AddDamageProjSpecific(Vector2 simPosition, List<Affliction> afflictions, bool playSound, List<DamageModifier> appliedDamageModifiers)
partial void AddDamageProjSpecific(bool playSound, AttackResult result)
{
float bleedingDamage = character.CharacterHealth.DoesBleed ? afflictions.FindAll(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth)) : 0;
float damage = afflictions.FindAll(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
float damageMultiplier = 1;
foreach (DamageModifier damageModifier in appliedDamageModifiers)
float bleedingDamage = 0;
if (character.CharacterHealth.DoesBleed)
{
damageMultiplier *= damageModifier.DamageMultiplier;
foreach (var affliction in result.Afflictions)
{
if (affliction is AfflictionBleeding)
{
bleedingDamage += affliction.GetVitalityDecrease(character.CharacterHealth);
}
}
}
float damage = 0;
foreach (var affliction in result.Afflictions)
{
if (affliction.Prefab.AfflictionType == "damage")
{
damage += affliction.GetVitalityDecrease(character.CharacterHealth);
}
}
float damageMultiplier = 1;
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
{
foreach (var afflictionPrefab in AfflictionPrefab.List)
{
if (damageModifier.MatchesAffliction(afflictionPrefab.Identifier, afflictionPrefab.AfflictionType))
{
if (afflictionPrefab.Effects.Any(e => e.MaxVitalityDecrease > 0))
{
damageMultiplier *= damageModifier.DamageMultiplier;
break;
}
}
}
}
if (playSound)
{
string damageSoundType = (bleedingDamage > damage) ? "LimbSlash" : "LimbBlunt";
foreach (DamageModifier damageModifier in appliedDamageModifiers)
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
{
if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound))
{
@@ -447,9 +494,8 @@ namespace Barotrauma
{
foreach (ParticleEmitter emitter in character.DamageEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
}
}
@@ -461,9 +507,8 @@ namespace Barotrauma
foreach (ParticleEmitter emitter in character.BloodEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount);
}
@@ -471,19 +516,26 @@ namespace Barotrauma
{
character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
}
}
}
}
partial void UpdateProjSpecific(float deltaTime)
{
if (!body.Enabled) return;
if (!body.Enabled) { return; }
if (!character.IsDead)
if (!IsDead)
{
DamageOverlayStrength -= deltaTime;
BurnOverlayStrength -= deltaTime;
}
else
{
var spriteParams = Params.GetSprite();
if (spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
{
deadTimer += deltaTime;
}
}
if (inWater)
{
@@ -524,7 +576,14 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
{
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
Color color = new Color(brightness, brightness, brightness);
var spriteParams = Params.GetSprite();
if (spriteParams == null) { return; }
Color color = new Color(spriteParams.Color.R / 255f * brightness, spriteParams.Color.G / 255f * brightness, spriteParams.Color.B / 255f * brightness, spriteParams.Color.A / 255f);
if (deadTimer > 0)
{
color = Color.Lerp(color, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
}
color = overrideColor ?? color;
@@ -545,7 +604,7 @@ namespace Barotrauma
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
bool hideLimb = Params.Hide ||
bool hideLimb = Hide ||
OtherWearables.Any(w => w.HideLimb) ||
wearingItems.Any(w => w != null && w.HideLimb);
@@ -566,6 +625,7 @@ namespace Barotrauma
{
var deformation = SpriteDeformation.GetDeformation(Deformations, deformSprite.Size);
deformSprite.Deform(deformation);
LightSource?.DeformableLightSprite?.Deform(deformation);
}
else
{
@@ -577,6 +637,31 @@ namespace Barotrauma
{
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
}
// Handle non-exlusive, i.e. additional conditional sprites
foreach (var conditionalSprite in ConditionalSprites)
{
// Exclusive conditional sprites are handled in the Properties
if (conditionalSprite.Exclusive) { continue; }
if (!conditionalSprite.IsActive) { continue; }
if (conditionalSprite.DeformableSprite != null)
{
var defSprite = conditionalSprite.DeformableSprite;
if (Deformations != null && Deformations.Any())
{
var deformation = SpriteDeformation.GetDeformation(Deformations, defSprite.Size);
defSprite.Deform(deformation);
}
else
{
defSprite.Reset();
}
body.Draw(defSprite, cam, Vector2.One * Scale * TextureScale, color, Params.MirrorHorizontally);
}
else
{
body.Draw(spriteBatch, conditionalSprite.Sprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
}
}
}
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (LightSource != null)
@@ -594,13 +679,19 @@ namespace Barotrauma
foreach (var decorativeSprite in DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
Color c = new Color(decorativeSprite.Color.R / 255f * brightness, decorativeSprite.Color.G / 255f * brightness, decorativeSprite.Color.B / 255f * brightness, decorativeSprite.Color.A / 255f);
if (deadTimer > 0)
{
c = Color.Lerp(c, spriteParams.DeadColor, MathUtils.InverseLerp(0, Params.GetSprite().DeadColorTime, deadTimer));
}
c = overrideColor ?? c;
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,
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
-body.Rotation + rotation, decorativeSprite.Scale * Scale, spriteEffect,
depth: decorativeSprite.Sprite.Depth);
}
float depthStep = 0.000001f;

View File

@@ -5,13 +5,14 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
using FarseerPhysics;
using Barotrauma.Extensions;
using Barotrauma.Steam;
namespace Barotrauma
{
@@ -217,6 +218,8 @@ namespace Barotrauma
case "toggleupperhud":
case "togglecharacternames":
case "fpscounter":
case "dumptofile":
case "findentityids":
return true;
default:
return client.HasConsoleCommandPermission(command);
@@ -453,17 +456,10 @@ namespace Barotrauma
GameMain.CharacterEditorScreen.Select();
}));
commands.Add(new Command("money", "", args =>
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks debug logging.", (string[] args) =>
{
if (args.Length == 0) { return; }
if (GameMain.GameSession.GameMode is CampaignMode campaign)
{
if (int.TryParse(args[0], out int money))
{
campaign.Money += money;
}
}
}, isCheat: true));
SteamManager.NetworkingDebugLog = !SteamManager.NetworkingDebugLog;
}));
AssignRelayToServer("kick", false);
AssignRelayToServer("kickid", false);
@@ -476,6 +472,7 @@ namespace Barotrauma
AssignRelayToServer("help", false);
AssignRelayToServer("verboselogging", false);
AssignRelayToServer("freecam", false);
AssignRelayToServer("steamnetdebug", false);
#if DEBUG
AssignRelayToServer("crash", false);
AssignRelayToServer("simulatedlatency", false);
@@ -495,6 +492,7 @@ namespace Barotrauma
AssignRelayToServer("setpassword", true);
commands.Add(new Command("traitorlist", "", (string[] args) => { }));
AssignRelayToServer("traitorlist", true);
AssignRelayToServer("money", true);
AssignOnExecute("control", (string[] args) =>
{
@@ -515,13 +513,14 @@ namespace Barotrauma
AssignOnExecute("explosion", (string[] args) =>
{
Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
float range = 500, force = 10, damage = 50, structureDamage = 10, empStrength = 0.0f;
float range = 500, force = 10, damage = 50, structureDamage = 10, itemDamage = 100, empStrength = 0.0f;
if (args.Length > 0) float.TryParse(args[0], out range);
if (args.Length > 1) float.TryParse(args[1], out force);
if (args.Length > 2) float.TryParse(args[2], out damage);
if (args.Length > 3) float.TryParse(args[3], out structureDamage);
if (args.Length > 4) float.TryParse(args[4], out empStrength);
new Explosion(range, force, damage, structureDamage, empStrength).Explode(explosionPos, null);
if (args.Length > 4) float.TryParse(args[4], out itemDamage);
if (args.Length > 5) float.TryParse(args[5], out empStrength);
new Explosion(range, force, damage, structureDamage, itemDamage, empStrength).Explode(explosionPos, null);
});
AssignOnExecute("teleportcharacter|teleport", (string[] args) =>
@@ -836,7 +835,7 @@ namespace Barotrauma
return;
}
if (Submarine.MainSub.SaveAs(System.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
if (Submarine.MainSub.SaveAs(Barotrauma.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
{
NewMessage("Sub saved", Color.Green);
}
@@ -1028,8 +1027,7 @@ namespace Barotrauma
foreach (var deconstructItem in itemPrefab.DeconstructItems)
{
var targetItem = MapEntityPrefab.Find(null, deconstructItem.ItemIdentifier, showErrorMessages: false) as ItemPrefab;
if (targetItem == null)
if (!(MapEntityPrefab.Find(null, deconstructItem.ItemIdentifier, showErrorMessages: false) is ItemPrefab targetItem))
{
ThrowError("Error in item \"" + itemPrefab.Name + "\" - could not find deconstruct item \"" + deconstructItem.ItemIdentifier + "\"!");
continue;
@@ -1044,9 +1042,14 @@ namespace Barotrauma
if (fabricationRecipe != null)
{
if (!fabricationRecipe.RequiredItems.Any(r => r.ItemPrefab == targetItem))
var ingredient = fabricationRecipe.RequiredItems.Find(r => r.ItemPrefab == targetItem);
if (ingredient == null)
{
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Orange);
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Red);
}
else if (ingredient.UseCondition && ingredient.MinCondition < deconstructItem.OutCondition)
{
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {ingredient.ItemPrefab.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(deconstructItem.OutCondition * 100)}%)", Color.Red);
}
}
}
@@ -1430,7 +1433,7 @@ namespace Barotrauma
element.Value = lines[i];
i++;
}
doc.Save(destinationPath);
doc.SaveSafe(destinationPath);
},
() =>
{
@@ -1465,7 +1468,7 @@ namespace Barotrauma
while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode;
destinationElement = nextNode as XElement;
}
destinationDoc.Save(destinationPath);
destinationDoc.SaveSafe(destinationPath);
},
() =>
{
@@ -1720,69 +1723,69 @@ namespace Barotrauma
GameMain.Config.SaveNewPlayerConfig();
var saveFiles = System.IO.Directory.GetFiles(SaveUtil.SaveFolder);
var saveFiles = Barotrauma.IO.Directory.GetFiles(SaveUtil.SaveFolder);
foreach (string saveFile in saveFiles)
{
System.IO.File.Delete(saveFile);
Barotrauma.IO.File.Delete(saveFile);
NewMessage("Deleted " + saveFile, Color.Green);
}
if (System.IO.Directory.Exists(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp")))
if (Barotrauma.IO.Directory.Exists(Barotrauma.IO.Path.Combine(SaveUtil.SaveFolder, "temp")))
{
System.IO.Directory.Delete(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp"), true);
Barotrauma.IO.Directory.Delete(Barotrauma.IO.Path.Combine(SaveUtil.SaveFolder, "temp"), true);
NewMessage("Deleted temp save folder", Color.Green);
}
if (System.IO.Directory.Exists(ServerLog.SavePath))
if (Barotrauma.IO.Directory.Exists(ServerLog.SavePath))
{
var logFiles = System.IO.Directory.GetFiles(ServerLog.SavePath);
var logFiles = Barotrauma.IO.Directory.GetFiles(ServerLog.SavePath);
foreach (string logFile in logFiles)
{
System.IO.File.Delete(logFile);
Barotrauma.IO.File.Delete(logFile);
NewMessage("Deleted " + logFile, Color.Green);
}
}
if (System.IO.File.Exists("filelist.xml"))
if (Barotrauma.IO.File.Exists("filelist.xml"))
{
System.IO.File.Delete("filelist.xml");
Barotrauma.IO.File.Delete("filelist.xml");
NewMessage("Deleted filelist", Color.Green);
}
if (System.IO.File.Exists("Data/bannedplayers.txt"))
if (Barotrauma.IO.File.Exists("Data/bannedplayers.txt"))
{
System.IO.File.Delete("Data/bannedplayers.txt");
Barotrauma.IO.File.Delete("Data/bannedplayers.txt");
NewMessage("Deleted bannedplayers.txt", Color.Green);
}
if (System.IO.File.Exists("Submarines/TutorialSub.sub"))
if (Barotrauma.IO.File.Exists("Submarines/TutorialSub.sub"))
{
System.IO.File.Delete("Submarines/TutorialSub.sub");
Barotrauma.IO.File.Delete("Submarines/TutorialSub.sub");
NewMessage("Deleted TutorialSub from the submarine folder", Color.Green);
}
/*if (System.IO.File.Exists(GameServer.SettingsFile))
/*if (Barotrauma.IO.File.Exists(GameServer.SettingsFile))
{
System.IO.File.Delete(GameServer.SettingsFile);
Barotrauma.IO.File.Delete(GameServer.SettingsFile);
NewMessage("Deleted server settings", Color.Green);
}
if (System.IO.File.Exists(GameServer.ClientPermissionsFile))
if (Barotrauma.IO.File.Exists(GameServer.ClientPermissionsFile))
{
System.IO.File.Delete(GameServer.ClientPermissionsFile);
Barotrauma.IO.File.Delete(GameServer.ClientPermissionsFile);
NewMessage("Deleted client permission file", Color.Green);
}*/
if (System.IO.File.Exists("crashreport.log"))
if (Barotrauma.IO.File.Exists("crashreport.log"))
{
System.IO.File.Delete("crashreport.log");
Barotrauma.IO.File.Delete("crashreport.log");
NewMessage("Deleted crashreport.log", Color.Green);
}
if (!System.IO.File.Exists("Content/Map/TutorialSub.sub"))
if (!Barotrauma.IO.File.Exists("Content/Map/TutorialSub.sub"))
{
ThrowError("TutorialSub.sub not found!");
}
@@ -2196,7 +2199,7 @@ namespace Barotrauma
ThrowError("Cannot use the flipx command while playing online.");
return;
}
Submarine.MainSub?.FlipX();
if (Submarine.MainSub.SubBody != null) { Submarine.MainSub?.FlipX(); }
}, isCheat: true));
commands.Add(new Command("gender", "Set the gender of the controlled character. Allowed parameters: Male, Female, None.", args =>
@@ -2318,9 +2321,16 @@ namespace Barotrauma
}
try
{
SubmarineInfo subInfo = new SubmarineInfo(args[0]);
Submarine spawnedSub = Submarine.Load(subInfo, false);
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
var subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.DisplayName.Equals(args[0], StringComparison.OrdinalIgnoreCase));
if (subInfo == null)
{
ThrowError($"Could not find a submarine with the name \"{args[0]}\".");
}
else
{
Submarine spawnedSub = Submarine.Load(subInfo, false);
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
}
}
catch (Exception e)
{
@@ -2328,7 +2338,15 @@ namespace Barotrauma
ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace);
}
}, isCheat: true));
},
() =>
{
return new string[][]
{
SubmarineInfo.SavedSubmarines.Select(s => s.DisplayName).ToArray()
};
},
isCheat: true));
commands.Add(new Command("pause", "Toggles the pause state when playing offline", (string[] args) =>
{

View File

@@ -26,7 +26,19 @@ namespace Barotrauma
}
}
item.body.FarseerBody.BodyType = BodyType.Kinematic;
int executedEffectCount = msg.ReadByte();
for (int i = 0; i < executedEffectCount; i++)
{
int index1 = msg.ReadByte();
int index2 = msg.ReadByte();
var selectedEffect = statusEffects[index1][index2];
item.ApplyStatusEffect(selectedEffect, selectedEffect.type, deltaTime: 1.0f, worldPosition: item.Position);
}
if (item.body != null)
{
item.body.FarseerBody.BodyType = BodyType.Kinematic;
}
}
}
}

View File

@@ -7,76 +7,6 @@ using System.Xml.Linq;
namespace Barotrauma
{
public class ColorData
{
public int StartIndex, EndIndex;
public Color Color;
private const char colorDefinitionIndicator = '‖';
private const char lineChangeIndicator = '\n';
private const string colorDefinitionStartString = "‖color:";
private const string coloringEndDefinition = "‖color:end‖";
public static List<ColorData> GetColorData(string text, out string sanitizedText)
{
List<ColorData> textColors = null;
if (text != null && text.IndexOf(colorDefinitionIndicator) != -1 && text.Contains(colorDefinitionStartString))
{
textColors = new List<ColorData>();
List<int> lineChangeIndexes = null;
int currentIndex = text.IndexOf(lineChangeIndicator);
if (currentIndex != -1)
{
lineChangeIndexes = new List<int>();
lineChangeIndexes.Add(currentIndex);
int startIndex = currentIndex + 1;
while (true)
{
if (startIndex >= text.Length) break;
currentIndex = text.IndexOf(lineChangeIndicator, startIndex);
if (currentIndex == -1) break;
lineChangeIndexes.Add(currentIndex);
startIndex = currentIndex + 1;
}
}
while (text.IndexOf(colorDefinitionStartString) != -1)
{
ColorData colorData = new ColorData();
int colorDefinitionStartIndex = text.IndexOf(colorDefinitionStartString);
int colorDefinitionEndIndex = text.IndexOf(colorDefinitionIndicator, colorDefinitionStartIndex + 1);
string[] colorDefinition = text.Substring(colorDefinitionStartIndex + colorDefinitionStartString.Length, colorDefinitionEndIndex - colorDefinitionStartIndex - colorDefinitionStartString.Length).Split(',');
colorData.StartIndex = colorDefinitionStartIndex;
colorData.Color = new Color(int.Parse(colorDefinition[0]), int.Parse(colorDefinition[1]), int.Parse(colorDefinition[2]));
text = text.Remove(colorDefinitionStartIndex, colorDefinitionEndIndex - colorDefinitionStartIndex + 1);
colorData.EndIndex = text.IndexOf(coloringEndDefinition);
text = text.Remove(colorData.EndIndex, coloringEndDefinition.Length);
if (lineChangeIndexes != null)
{
for (int i = 0; i < lineChangeIndexes.Count; i++)
{
if (colorData.StartIndex > lineChangeIndexes[i])
{
colorData.StartIndex--;
colorData.EndIndex--;
}
}
}
textColors.Add(colorData);
}
}
sanitizedText = text;
return textColors;
}
}
public class ScalableFont : IDisposable
{
private static List<ScalableFont> FontList = new List<ScalableFont>();
@@ -492,12 +422,12 @@ namespace Barotrauma
}
}
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, List<ColorData> colorData)
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, List<RichTextData> richTextData)
{
DrawStringWithColors(sb, text, position, color, rotation, origin, new Vector2(scale), se, layerDepth, colorData);
DrawStringWithColors(sb, text, position, color, rotation, origin, new Vector2(scale), se, layerDepth, richTextData);
}
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth, List<ColorData> colorData)
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth, List<RichTextData> richTextData)
{
if (textures.Count == 0 && !DynamicLoading) { return; }
@@ -505,8 +435,8 @@ namespace Barotrauma
Vector2 currentPos = position;
Vector2 advanceUnit = rotation == 0.0f ? Vector2.UnitX : new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
int colorDataIndex = 0;
ColorData currentColorData = colorData[colorDataIndex];
int richTextDataIndex = 0;
RichTextData currentRichTextData = richTextData[richTextDataIndex];
for (int i = 0; i < text.Length; i++)
{
@@ -527,15 +457,19 @@ namespace Barotrauma
Color currentTextColor;
if (currentColorData != null && i > currentColorData.EndIndex + lineNum)
if (currentRichTextData != null && i > currentRichTextData.EndIndex + lineNum)
{
colorDataIndex++;
currentColorData = colorDataIndex < colorData.Count ? colorData[colorDataIndex] : null;
richTextDataIndex++;
currentRichTextData = richTextDataIndex < richTextData.Count ? richTextData[richTextDataIndex] : null;
}
if (currentColorData != null && currentColorData.StartIndex + lineNum <= i && i <= currentColorData.EndIndex + lineNum)
if (currentRichTextData != null && currentRichTextData.StartIndex + lineNum <= i && i <= currentRichTextData.EndIndex + lineNum)
{
currentTextColor = currentColorData.Color;
currentTextColor = currentRichTextData.Color ?? color;
if (!string.IsNullOrEmpty(currentRichTextData.Metadata))
{
currentTextColor = Color.Lerp(currentTextColor, Color.White, 0.5f);
}
}
else
{

View File

@@ -52,7 +52,20 @@ namespace Barotrauma
public GUITextBox InputBox { get; private set; }
public GUIButton ToggleButton;
private GUIButton toggleButton;
public GUIButton ToggleButton
{
get => toggleButton;
set
{
if (toggleButton != null)
{
toggleButton.RectTransform.Parent = null;
}
toggleButton = value;
}
}
private GUIButton showNewMessagesButton;
@@ -109,7 +122,7 @@ namespace Barotrauma
};
chatSendButton.RectTransform.AbsoluteOffset = new Point((int)(InputBox.Rect.Height * 0.15f), 0);
InputBox.TextBlock.RectTransform.MaxSize
= new Point((int)(InputBox.Rect.Width - chatSendButton.Rect.Width * 1.25f - InputBox.TextBlock.Padding.Z), int.MaxValue);
= new Point((int)(InputBox.Rect.Width - chatSendButton.Rect.Width * 1.25f - InputBox.TextBlock.Padding.X - chatSendButton.RectTransform.AbsoluteOffset.X), int.MaxValue);
showNewMessagesButton = new GUIButton(new RectTransform(new Vector2(1f, 0.075f), GUIFrame.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0.0f, 0.125f) }, TextManager.Get("chat.shownewmessages"));
showNewMessagesButton.OnClicked += (GUIButton btn, object userdata) =>
@@ -190,22 +203,49 @@ namespace Barotrauma
var msgHolder = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.0f), chatBox.Content.RectTransform, Anchor.TopCenter), style: null,
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f);
GUITextBlock senderNameBlock = new GUITextBlock(new RectTransform(new Vector2(0.98f, 0.0f), msgHolder.RectTransform) { AbsoluteOffset = new Point((int)(5 * GUI.Scale), 0) },
GUITextBlock senderNameTimestamp = new GUITextBlock(new RectTransform(new Vector2(0.98f, 0.0f), msgHolder.RectTransform) { AbsoluteOffset = new Point((int)(5 * GUI.Scale), 0) },
ChatMessage.GetTimeStamp(), textColor: Color.LightGray, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
{
CanBeFocused = true
};
if (!string.IsNullOrEmpty(senderName))
{
new GUITextBlock(new RectTransform(new Vector2(0.8f, 1.0f), senderNameBlock.RectTransform) { AbsoluteOffset = new Point((int)(senderNameBlock.TextSize.X), 0) },
senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
var senderNameBlock = new GUIButton(new RectTransform(new Vector2(0.8f, 1.0f), senderNameTimestamp.RectTransform) { AbsoluteOffset = new Point((int)(senderNameTimestamp.TextSize.X), 0) },
senderName, textAlignment: Alignment.TopLeft, style: null, color: Color.Transparent)
{
CanBeFocused = true
TextBlock =
{
Padding = Vector4.Zero
},
Font = GUI.SmallFont,
CanBeFocused = true,
ForceUpperCase = false,
UserData = message.SenderClient,
OnClicked = (_, o) =>
{
if (!(o is Client client)) { return false; }
GameMain.NetLobbyScreen?.SelectPlayer(client);
return true;
},
OnSecondaryClicked = (_, o) =>
{
if (!(o is Client client)) { return false; }
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
return true;
},
Text = senderName
};
senderNameBlock.RectTransform.NonScaledSize = senderNameBlock.TextBlock.TextSize.ToPoint();
senderNameBlock.TextBlock.OverrideTextColor(senderColor);
if (senderNameBlock.UserData != null)
{
senderNameBlock.TextBlock.HoverTextColor = Color.White;
}
}
var msgText =new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), msgHolder.RectTransform)
{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), senderNameBlock == null ? 0 : senderNameBlock.Rect.Height) },
{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), senderNameTimestamp == null ? 0 : senderNameTimestamp.Rect.Height) },
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null, wrap: true,
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f)
{
@@ -230,7 +270,7 @@ namespace Barotrauma
msgHolder.RectTransform.SizeChanged -= Recalculate;
//resize the holder to match the size of the message and add some spacing
msgText.RectTransform.MaxSize = new Point(msgHolder.Rect.Width - msgText.RectTransform.AbsoluteOffset.X, int.MaxValue);
senderNameBlock.RectTransform.MaxSize = new Point(msgHolder.Rect.Width - senderNameBlock.RectTransform.AbsoluteOffset.X, int.MaxValue);
senderNameTimestamp.RectTransform.MaxSize = new Point(msgHolder.Rect.Width - senderNameTimestamp.RectTransform.AbsoluteOffset.X, int.MaxValue);
msgHolder.Children.ForEach(c => (c as GUITextBlock)?.CalculateHeightFromText());
msgHolder.RectTransform.Resize(new Point(msgHolder.Rect.Width, msgHolder.Children.Sum(c => c.Rect.Height) + (int)(10 * GUI.Scale)), resizeChildren: false);
msgHolder.RectTransform.SizeChanged += Recalculate;
@@ -247,6 +287,11 @@ namespace Barotrauma
showNewMessagesButton.Visible = true;
}
if (message.Type == ChatMessageType.Server && message.ChangeType != PlayerConnectionChangeType.None)
{
TabMenu.StorePlayerConnectionChangeMessage(message);
}
if (!ToggleOpen)
{
var popupMsg = new GUIFrame(new RectTransform(Vector2.One, GUIFrame.RectTransform), style: "GUIToolTip")
@@ -339,17 +384,6 @@ namespace Barotrauma
prevUIScale = GUI.Scale;
}
//hide chatbox when accessing the inventory of another character to prevent overlaps
if (Character.Controlled?.SelectedCharacter?.Inventory != null &&
Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
{
SetVisibility(false);
}
else
{
SetVisibility(true);
}
if (showNewMessagesButton.Visible && chatBox.ScrollBar.BarScroll == 1f)
{
showNewMessagesButton.Visible = false;

View File

@@ -1,7 +1,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Text;
@@ -38,7 +38,7 @@ namespace Barotrauma
private static GUIDropDown fileTypeDropdown;
private static GUIButton openButton;
private static FileSystemWatcher fileSystemWatcher;
private static System.IO.FileSystemWatcher fileSystemWatcher;
private static string currentFileTypePattern;
@@ -78,10 +78,10 @@ namespace Barotrauma
currentDirectory += "/";
}
fileSystemWatcher?.Dispose();
fileSystemWatcher = new FileSystemWatcher(currentDirectory)
fileSystemWatcher = new System.IO.FileSystemWatcher(currentDirectory)
{
Filter = "*",
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
NotifyFilter = System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName
};
fileSystemWatcher.Created += OnFileSystemChanges;
fileSystemWatcher.Deleted += OnFileSystemChanges;
@@ -97,11 +97,11 @@ namespace Barotrauma
set;
}
private static void OnFileSystemChanges(object sender, FileSystemEventArgs e)
private static void OnFileSystemChanges(object sender, System.IO.FileSystemEventArgs e)
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Created:
case System.IO.WatcherChangeTypes.Created:
{
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), e.Name)
{
@@ -114,15 +114,15 @@ namespace Barotrauma
fileList.Content.RectTransform.SortChildren(SortFiles);
}
break;
case WatcherChangeTypes.Deleted:
case System.IO.WatcherChangeTypes.Deleted:
{
var itemFrame = fileList.Content.FindChild(c => (c is GUITextBlock tb) && (tb.Text == e.Name || tb.Text == e.Name + "/"));
if (itemFrame != null) { fileList.RemoveChild(itemFrame); }
}
break;
case WatcherChangeTypes.Renamed:
case System.IO.WatcherChangeTypes.Renamed:
{
RenamedEventArgs renameArgs = e as RenamedEventArgs;
System.IO.RenamedEventArgs renameArgs = e as System.IO.RenamedEventArgs;
var itemFrame = fileList.Content.FindChild(c => (c is GUITextBlock tb) && (tb.Text == renameArgs.OldName || tb.Text == renameArgs.OldName + "/")) as GUITextBlock;
itemFrame.UserData = (bool?)Directory.Exists(e.FullPath);
itemFrame.Text = renameArgs.Name;
@@ -156,7 +156,7 @@ namespace Barotrauma
public static void Init()
{
backgroundFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
backgroundFrame = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas), style: null)
{
Color = Color.Black * 0.5f,
HoverColor = Color.Black * 0.5f,
@@ -169,10 +169,10 @@ namespace Barotrauma
var horizontalLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.9f, window.RectTransform, Anchor.Center), true);
sidebar = new GUIListBox(new RectTransform(new Vector2(0.29f, 1.0f), horizontalLayout.RectTransform));
var drives = DriveInfo.GetDrives();
var drives = System.IO.DriveInfo.GetDrives();
foreach (var drive in drives)
{
if (drive.DriveType == DriveType.Ram) { continue; }
if (drive.DriveType == System.IO.DriveType.Ram) { continue; }
if (ignoredDrivePrefixes.Any(p => drive.Name.StartsWith(p))) { continue; }
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), sidebar.Content.RectTransform), drive.Name.Replace('\\','/'));
}
@@ -348,17 +348,24 @@ namespace Barotrauma
}
IEnumerable<string> files = null;
foreach (string pattern in currentFileTypePattern.Split(','))
if (currentFileTypePattern == null)
{
string patternTrimmed = pattern.Trim();
patternTrimmed = "*" + filterBox.Text + "*" + patternTrimmed;
if (files == null)
files = Directory.GetFiles(currentDirectory);
}
else
{
foreach (string pattern in currentFileTypePattern.Split(','))
{
files = Directory.EnumerateFiles(currentDirectory, patternTrimmed);
}
else
{
files = files.Concat(Directory.EnumerateFiles(currentDirectory, patternTrimmed));
string patternTrimmed = pattern.Trim();
patternTrimmed = "*" + filterBox.Text + "*" + patternTrimmed;
if (files == null)
{
files = Directory.EnumerateFiles(currentDirectory, patternTrimmed);
}
else
{
files = files.Concat(Directory.EnumerateFiles(currentDirectory, patternTrimmed));
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.CharacterEditor;
@@ -80,13 +80,33 @@ namespace Barotrauma
public static readonly string[] colorComponentLabels = { "R", "G", "B", "A" };
public static Vector2 ReferenceResolution => new Vector2(1920f, 1080f);
public static float Scale => (GameMain.GraphicsWidth / ReferenceResolution.X + GameMain.GraphicsHeight / ReferenceResolution.Y) / 2.0f * GameSettings.HUDScale;
public static float xScale => GameMain.GraphicsWidth / ReferenceResolution.X * GameSettings.HUDScale;
public static float Scale => (UIWidth / ReferenceResolution.X + GameMain.GraphicsHeight / ReferenceResolution.Y) / 2.0f * GameSettings.HUDScale;
public static float xScale => UIWidth / ReferenceResolution.X * GameSettings.HUDScale;
public static float yScale => GameMain.GraphicsHeight / ReferenceResolution.Y * GameSettings.HUDScale;
public static int IntScale(float f) => (int)(f * Scale);
public static int IntScaleFloor(float f) => (int)Math.Floor(f * Scale);
public static int IntScaleCeiling(float f) => (int) Math.Ceiling(f * Scale);
public static float HorizontalAspectRatio => GameMain.GraphicsWidth / (float)GameMain.GraphicsHeight;
public static float VerticalAspectRatio => GameMain.GraphicsHeight / (float)GameMain.GraphicsWidth;
public static float RelativeHorizontalAspectRatio => HorizontalAspectRatio / (ReferenceResolution.X / ReferenceResolution.Y);
public static float RelativeVerticalAspectRatio => VerticalAspectRatio / (ReferenceResolution.Y / ReferenceResolution.X);
public static bool IsUltrawide => HorizontalAspectRatio > 2.0f;
public static int UIWidth
{
get
{
// Ultrawide
if (IsUltrawide)
{
return (int)(GameMain.GraphicsHeight * ReferenceResolution.X / ReferenceResolution.Y);
}
else
{
return GameMain.GraphicsWidth;
}
}
}
public static float SlicedSpriteScale
{
@@ -496,9 +516,58 @@ namespace Barotrauma
if (MouseOn != null)
{
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 500, 20),
$"Selected UI Element: {MouseOn.GetType().Name} ({ (MouseOn.Style?.Element.Name.LocalName ?? "no style") }, {MouseOn.Rect})",
Color.LightGreen, Color.Black * 0.5f, 0, SmallFont);
RectTransform mouseOnRect = MouseOn.RectTransform;
bool isAbsoluteOffsetInUse = mouseOnRect.AbsoluteOffset != Point.Zero || mouseOnRect.RelativeOffset == Vector2.Zero;
string selectedString = $"Selected UI Element: {MouseOn.GetType().Name} ({ MouseOn.Style?.Element.Name.LocalName ?? "no style" }, {MouseOn.Rect}";
string offsetString = $"Relative Offset: {mouseOnRect.RelativeOffset} | Absolute Offset: {(isAbsoluteOffsetInUse ? mouseOnRect.AbsoluteOffset : mouseOnRect.ParentRect.MultiplySize(mouseOnRect.RelativeOffset))}{(isAbsoluteOffsetInUse ? "" : " (Calculated from RelativeOffset)")}";
string anchorPivotString = $"Anchor: {mouseOnRect.Anchor} | Pivot: {mouseOnRect.Pivot}";
Vector2 selectedStringSize = SmallFont.MeasureString(selectedString);
Vector2 offsetStringSize = SmallFont.MeasureString(offsetString);
Vector2 anchorPivotStringSize = SmallFont.MeasureString(anchorPivotString);
int padding = IntScale(10);
int yPos = padding;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)selectedStringSize.X - padding, yPos), selectedString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)selectedStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)offsetStringSize.X - padding, yPos), offsetString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)offsetStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)anchorPivotStringSize.X - padding, yPos), anchorPivotString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)anchorPivotStringSize.Y + padding / 2;
}
else
{
string guiScaleString = $"GUI.Scale: {Scale}";
string guixScaleString = $"GUI.xScale: {xScale}";
string guiyScaleString = $"GUI.yScale: {yScale}";
string relativeHorizontalAspectRatioString = $"RelativeHorizontalAspectRatio: {RelativeHorizontalAspectRatio}";
string relativeVerticalAspectRatioString = $"RelativeVerticalAspectRatio: {RelativeVerticalAspectRatio}";
Vector2 guiScaleStringSize = SmallFont.MeasureString(guiScaleString);
Vector2 guixScaleStringSize = SmallFont.MeasureString(guixScaleString);
Vector2 guiyScaleStringSize = SmallFont.MeasureString(guiyScaleString);
Vector2 relativeHorizontalAspectRatioStringSize = SmallFont.MeasureString(relativeHorizontalAspectRatioString);
Vector2 relativeVerticalAspectRatioStringSize = SmallFont.MeasureString(relativeVerticalAspectRatioString);
int padding = IntScale(10);
int yPos = padding;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)guiScaleStringSize.X - padding, yPos), guiScaleString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)guiScaleStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)guixScaleStringSize.X - padding, yPos), guixScaleString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)guixScaleStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)guiyScaleStringSize.X - padding, yPos), guiyScaleString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)guiyScaleStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)relativeHorizontalAspectRatioStringSize.X - padding, yPos), relativeHorizontalAspectRatioString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)relativeHorizontalAspectRatioStringSize.Y + padding / 2;
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - (int)relativeVerticalAspectRatioStringSize.X - padding, yPos), relativeVerticalAspectRatioString, Color.LightGreen, Color.Black, 0, SmallFont);
yPos += (int)relativeVerticalAspectRatioStringSize.Y + padding / 2;
}
}
@@ -521,6 +590,34 @@ namespace Barotrauma
MouseOn.DrawToolTip(spriteBatch);
}
if (SubEditorScreen.IsSubEditor())
{
// Draw our "infinite stack" on the cursor
switch (SubEditorScreen.DraggedItemPrefab)
{
case ItemPrefab itemPrefab:
{
var sprite = itemPrefab.InventoryIcon ?? itemPrefab.sprite;
sprite?.Draw(spriteBatch, PlayerInput.MousePosition, scale: Math.Min(64 / sprite.size.X, 64 / sprite.size.Y) * Scale);
break;
}
case ItemAssemblyPrefab iPrefab:
{
var (x, y) = PlayerInput.MousePosition;
foreach (var pair in iPrefab.DisplayEntities)
{
Rectangle dRect = pair.Second;
dRect = new Rectangle(x: (int)(dRect.X * iPrefab.Scale + x),
y: (int)(dRect.Y * iPrefab.Scale - y),
width: (int)(dRect.Width * iPrefab.Scale),
height: (int)(dRect.Height * iPrefab.Scale));
pair.First.DrawPlacing(spriteBatch, dRect, pair.First.Scale * iPrefab.Scale);
}
break;
}
}
}
if (GameMain.WindowActive && !HideCursor)
{
spriteBatch.End();
@@ -541,6 +638,10 @@ namespace Barotrauma
GameMain.GameScreen.PostProcessEffect.Parameters["blurDistance"].SetValue(0.001f * aberrationStrength);
GameMain.GameScreen.PostProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(new Vector3(-0.025f, -0.01f, -0.05f) *
(float)(PerlinNoise.CalculatePerlin(aberrationT, aberrationT, 0) + 0.5f) * aberrationStrength);
Matrix.CreateOrthographicOffCenter(0, GameMain.GraphicsWidth, GameMain.GraphicsHeight, 0, 0, -1, out Matrix projection);
GameMain.GameScreen.PostProcessEffect.Parameters["MatrixTransform"].SetValue(projection);
GameMain.GameScreen.PostProcessEffect.CurrentTechnique = GameMain.GameScreen.PostProcessEffect.Techniques["BlurChromaticAberration"];
GameMain.GameScreen.PostProcessEffect.CurrentTechnique.Passes[0].Apply();
@@ -780,6 +881,8 @@ namespace Barotrauma
if (MouseCursor == CursorState.Waiting) { return CursorState.Waiting; }
if (GUIScrollBar.DraggingBar != null) { return GUIScrollBar.DraggingBar.Bar.HoverCursor; }
if (SubEditorScreen.IsSubEditor() && SubEditorScreen.DraggedItemPrefab != null) { return CursorState.Hand; }
// Wire cursors
if (Character.Controlled != null)
{
@@ -816,8 +919,7 @@ namespace Barotrauma
case SubEditorScreen editor:
{
// Portrait area
if ((editor.CharacterMode || editor.WiringMode) &&
HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition))
if (editor.WiringMode && HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition))
{
return CursorState.Hand;
}
@@ -1137,7 +1239,7 @@ namespace Barotrauma
font.DrawString(sb, text, pos, color);
}
public static void DrawStringWithColors(SpriteBatch sb, Vector2 pos, string text, Color color, List<ColorData> colorData, Color? backgroundColor = null, int backgroundPadding = 0, ScalableFont font = null, float depth = 0.0f)
public static void DrawStringWithColors(SpriteBatch sb, Vector2 pos, string text, Color color, List<RichTextData> richTextData, Color? backgroundColor = null, int backgroundPadding = 0, ScalableFont font = null, float depth = 0.0f)
{
if (font == null) font = Font;
if (backgroundColor != null)
@@ -1146,7 +1248,7 @@ namespace Barotrauma
DrawRectangle(sb, pos - Vector2.One * backgroundPadding, textSize + Vector2.One * 2.0f * backgroundPadding, (Color)backgroundColor, true, depth, 5);
}
font.DrawStringWithColors(sb, text, pos, color, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, depth, colorData);
font.DrawStringWithColors(sb, text, pos, color, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, depth, richTextData);
}
public static void DrawRectangle(SpriteBatch sb, Vector2 start, Vector2 size, Color clr, bool isFilled = false, float depth = 0.0f, int thickness = 1)
@@ -1863,8 +1965,9 @@ namespace Barotrauma
Inventory.draggingItem = null;
Inventory.DraggingInventory = null;
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas), style: null, color: Color.Black * 0.5f);
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas, Anchor.Center), style: null);
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, PauseMenu.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.3f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(250, 300) });
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.6f), pauseMenuInner.RectTransform, Anchor.Center))

View File

@@ -8,7 +8,7 @@ namespace Barotrauma
{
public class GUICanvas : RectTransform
{
protected GUICanvas() : base(Vector2.One, parent: null) { }
protected GUICanvas() : base(size, parent: null) { }
private static GUICanvas _instance;
public static GUICanvas Instance
@@ -22,15 +22,63 @@ namespace Barotrauma
{
GameMain.Instance.OnResolutionChanged += RecalculateSize;
}
_instance.ItemComponentHolder = new GUIFrame(new RectTransform(Vector2.One, _instance, Anchor.Center)).RectTransform;
}
return _instance;
}
}
public RectTransform ItemComponentHolder;
private static Vector2 size => new Vector2(GameMain.GraphicsWidth / (float)GUI.UIWidth, 1f);
protected override Rectangle NonScaledUIRect => UIRect;
private enum ResizeAxis { Both = 0, X = 1, Y = 2 }
// Turn public, if there is a need to call this manually.
private static void RecalculateSize()
{
Instance.Resize(Vector2.One, resizeChildren: true);
Vector2 recalculatedSize = size;
// Scale children that are supposed to encompass the whole screen so that they are properly scaled on ultrawide as well
for (int i = 0; i < Instance.Children.Count(); i++)
{
RectTransform target = Instance.GetChild(i);
if (target == null || target.RelativeSize.X < 1 && target.RelativeSize.Y < 1) continue;
ResizeAxis axis;
if (target.RelativeSize.X >= 1 && target.RelativeSize.Y >= 1)
{
axis = ResizeAxis.Both;
}
else if (target.RelativeSize.X >= 1)
{
axis = ResizeAxis.X;
}
else
{
axis = ResizeAxis.Y;
}
switch (axis)
{
case ResizeAxis.Both:
target.RelativeSize = recalculatedSize;
break;
case ResizeAxis.X:
target.RelativeSize = new Vector2(recalculatedSize.X, target.RelativeSize.Y);
break;
case ResizeAxis.Y:
target.RelativeSize = new Vector2(target.RelativeSize.X, recalculatedSize.Y);
break;
}
}
Instance.Resize(size, resizeChildren: true);
Instance.GetAllChildren().Select(c => c.GUIComponent as GUITextBlock).ForEach(t => t?.SetTextPos());
}
}

View File

@@ -5,7 +5,7 @@ using System.Linq;
using Barotrauma.Extensions;
using System;
using System.Xml.Linq;
using System.IO;
using Barotrauma.IO;
using RestSharp;
using System.Net;
@@ -18,6 +18,9 @@ namespace Barotrauma
public CursorState HoverCursor = CursorState.Default;
public delegate bool SecondaryButtonDownHandler(GUIComponent component, object userData);
public SecondaryButtonDownHandler OnSecondaryClicked;
public IEnumerable<GUIComponent> Children => RectTransform.Children.Select(c => c.GUIComponent);
public T GetChild<T>() where T : GUIComponent
@@ -202,12 +205,12 @@ namespace Barotrauma
set
{
RawToolTip = value;
TooltipColorData = ColorData.GetColorData(value, out value);
TooltipRichTextData = RichTextData.GetRichTextData(value, out value);
toolTip = value;
}
}
public List<ColorData> TooltipColorData = null;
public List<RichTextData> TooltipRichTextData = null;
public GUIComponentStyle Style
{
@@ -451,6 +454,15 @@ namespace Barotrauma
protected virtual void Update(float deltaTime)
{
if (!Visible) return;
if (CanBeFocused && OnSecondaryClicked != null)
{
if (GUI.IsMouseOn(this) && PlayerInput.SecondaryMouseButtonClicked())
{
OnSecondaryClicked?.Invoke(this, userData);
}
}
if (flashTimer > 0.0f)
{
flashTimer -= deltaTime;
@@ -638,10 +650,10 @@ namespace Barotrauma
public void DrawToolTip(SpriteBatch spriteBatch)
{
if (!Visible) return;
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect, TooltipColorData);
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect, TooltipRichTextData);
}
public static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle targetElement, List<ColorData> colorData = null)
public static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle targetElement, List<RichTextData> richTextData = null)
{
if (Tutorials.Tutorial.ContentRunning) { return; }
@@ -651,7 +663,7 @@ namespace Barotrauma
if (toolTipBlock == null || (string)toolTipBlock.userData != toolTip)
{
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, height), null), colorData, toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, height), null), richTextData, toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
toolTipBlock.RectTransform.NonScaledSize = new Point(
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + padding.X + toolTipBlock.Padding.X + toolTipBlock.Padding.Z),
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).Y + padding.Y + toolTipBlock.Padding.Y + toolTipBlock.Padding.W));

View File

@@ -394,7 +394,7 @@ namespace Barotrauma
if (Dropped)
{
listBox.AddToGUIUpdateList(false, UpdateOrder);
listBox.AddToGUIUpdateList(false, 1);
}
}

View File

@@ -1,12 +1,27 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Barotrauma
{
public class GUIImage : GUIComponent
{
//paths of the textures that are being loaded asynchronously
private static readonly List<string> activeTextureLoads = new List<string>();
private static bool loadingTextures;
public static bool LoadingTextures
{
get
{
return loadingTextures;
}
}
public float Rotation;
private Sprite sprite;
@@ -15,8 +30,12 @@ namespace Barotrauma
private bool crop;
private bool scaleToFit;
private readonly bool scaleToFit;
private bool lazyLoaded, loading;
public bool LoadAsynchronously;
public bool Crop
{
get
@@ -75,7 +94,6 @@ namespace Barotrauma
private GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect, bool scaleToFit, string style) : base(style, rectT)
{
this.scaleToFit = scaleToFit;
sprite?.EnsureLazyLoaded();
Sprite = sprite;
if (sourceRect.HasValue)
{
@@ -95,18 +113,45 @@ namespace Barotrauma
}
else
{
rectT.SizeChanged += RecalculateScale;
if (Sprite != null && !Sprite.LazyLoad)
{
rectT.SizeChanged += RecalculateScale;
}
}
Enabled = true;
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) return;
if (!Visible || loading) { return; }
if (Parent != null) { State = Parent.State; }
if (OverrideState != null) { State = OverrideState.Value; }
if (Sprite != null && Sprite.LazyLoad && !lazyLoaded)
{
if (LoadAsynchronously)
{
loadingTextures = true;
loading = true;
TaskPool.Add(LoadTextureAsync(), (Task) =>
{
loading = false;
lazyLoaded = true;
RectTransform.SizeChanged += RecalculateScale;
RecalculateScale();
});
return;
}
else
{
Sprite.EnsureLazyLoaded();
RectTransform.SizeChanged += RecalculateScale;
RecalculateScale();
lazyLoaded = true;
}
}
Color currentColor = GetColor(State);
if (BlendState != null)
@@ -146,9 +191,53 @@ namespace Barotrauma
private void RecalculateScale()
{
if (sourceRect == Rectangle.Empty && sprite != null)
{
sourceRect = sprite.SourceRect;
}
Scale = sprite == null || sprite.SourceRect.Width == 0 || sprite.SourceRect.Height == 0 ?
1.0f :
Math.Min(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
}
private async Task<bool> LoadTextureAsync()
{
await Task.Yield();
bool wait = true;
{
//if another GUIImage is already loading the same texture, wait for it to finish
while (wait)
{
await Task.Delay(5);
lock (activeTextureLoads)
{
wait = activeTextureLoads.Contains(Sprite.FullPath);
}
}
}
try
{
lock (activeTextureLoads)
{
activeTextureLoads.Add(Sprite.FullPath);
}
Sprite.EnsureLazyLoaded();
}
finally
{
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
while (!Sprite.Loaded && DateTime.Now < timeOut)
{
await Task.Delay(5);
}
lock (activeTextureLoads)
{
activeTextureLoads.Remove(Sprite.FullPath);
loadingTextures = activeTextureLoads.Count > 0;
}
}
return true;
}
}
}

View File

@@ -77,7 +77,6 @@ namespace Barotrauma
public GUILayoutGroup(RectTransform rectT, bool isHorizontal = false, Anchor childAnchor = Anchor.TopLeft) : base(null, rectT)
{
CanBeFocused = false;
this.isHorizontal = isHorizontal;
this.childAnchor = childAnchor;
rectT.ChildrenChanged += (child) => needsToRecalculate = true;

View File

@@ -70,6 +70,11 @@ namespace Barotrauma
scrollBarNeedsRecalculation = true;
}
}
/// <summary>
/// true if mouse down should select elements instead of mouse up
/// </summary>
private bool useMouseDownToSelect = false;
private Vector4? overridePadding;
public Vector4 Padding
@@ -80,7 +85,11 @@ namespace Barotrauma
if (Style == null) { return Vector4.Zero; }
return Style.Padding;
}
set { overridePadding = value; }
set
{
dimensionsNeedsRecalculation = true;
overridePadding = value;
}
}
public GUIComponent SelectedComponent
@@ -182,10 +191,11 @@ namespace Barotrauma
public GUIComponent DraggedElement => draggedElement;
/// <param name="isScrollBarOnDefaultSide">For horizontal listbox, default side is on the bottom. For vertical, it's on the right.</param>
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true) : base(style, rectT)
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true, bool useMouseDownToSelect = false) : base(style, rectT)
{
CanBeFocused = true;
selected = new List<GUIComponent>();
this.useMouseDownToSelect = useMouseDownToSelect;
ContentBackground = new GUIFrame(new RectTransform(Vector2.One, rectT), style)
{
CanBeFocused = false
@@ -237,7 +247,7 @@ namespace Barotrauma
UpdateDimensions();
}
private void UpdateDimensions()
public void UpdateDimensions()
{
dimensionsNeedsRecalculation = false;
ContentBackground.RectTransform.Resize(Rect.Size);
@@ -403,7 +413,10 @@ namespace Barotrauma
if (Enabled && CanBeFocused && child.CanBeFocused && (GUI.IsMouseOn(child)) && child.Rect.Contains(PlayerInput.MousePosition))
{
child.State = ComponentState.Hover;
if (PlayerInput.PrimaryMouseButtonClicked())
var mouseDown = useMouseDownToSelect ? PlayerInput.PrimaryMouseButtonDown() : PlayerInput.PrimaryMouseButtonClicked();
if (mouseDown)
{
Select(i, autoScroll: false);
}
@@ -426,7 +439,7 @@ namespace Barotrauma
}
else
{
child.State = ComponentState.None;
child.State = !child.ExternalHighlight ? ComponentState.None : ComponentState.Hover;
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Barotrauma
public static List<GUIComponent> MessageBoxes = new List<GUIComponent>();
private static int DefaultWidth
{
get { return Math.Max(400, 400 * (GameMain.GraphicsWidth / 1920)); }
get { return Math.Max(400, (int)(400 * (GameMain.GraphicsWidth / GUI.ReferenceResolution.X))); }
}
private float inGameCloseTimer = 0.0f;
@@ -63,7 +63,7 @@ namespace Barotrauma
}
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")
: base(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: GUI.Style.GetComponentStyle("GUIMessageBox." + type) != null ? "GUIMessageBox." + type : "GUIMessageBox")
{
int width = (int)(DefaultWidth * (type == Type.Default ? 1.0f : 1.5f)), height = 0;
if (relativeSize.HasValue)
@@ -249,7 +249,10 @@ namespace Barotrauma
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
inGameCloseTimer += deltaTime;
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn))
{
inGameCloseTimer += deltaTime;
}
if (inGameCloseTimer >= inGameCloseTime)
{

View File

@@ -59,6 +59,11 @@ namespace Barotrauma
/// </summary>
public Color Blue { get; private set; } = Color.Blue;
/// <summary>
/// General yellow color used for elements whose colors are set from code
/// </summary>
public Color Yellow { get; private set; } = Color.Yellow;
public Color ColorInventoryEmpty { get; private set; } = Color.Red;
public Color ColorInventoryHalf { get; private set; } = Color.Orange;
public Color ColorInventoryFull { get; private set; } = Color.LightGreen;
@@ -128,6 +133,9 @@ namespace Barotrauma
case "blue":
Blue = subElement.GetAttributeColor("color", Blue);
break;
case "yellow":
Yellow = subElement.GetAttributeColor("color", Yellow);
break;
case "colorinventoryempty":
ColorInventoryEmpty = subElement.GetAttributeColor("color", ColorInventoryEmpty);
break;

View File

@@ -238,9 +238,40 @@ namespace Barotrauma
get { return censoredText; }
}
private List<ColorData> colorData = null;
private bool hasColorHighlight = false;
public class StrikethroughSettings
{
private Color color = GUI.Style.Red;
private int thickness;
private int expand;
public StrikethroughSettings(Color? color = null, int thickness = 1, int expand = 0)
{
if (color != null) this.color = color.Value;
this.thickness = thickness;
this.expand = expand;
}
public void Draw(SpriteBatch spriteBatch, float textSizeHalf, float xPos, float yPos)
{
ShapeExtensions.DrawLine(spriteBatch, new Vector2(xPos - textSizeHalf - expand, yPos), new Vector2(xPos + textSizeHalf + expand, yPos), color, thickness);
}
}
public StrikethroughSettings Strikethrough = null;
private readonly List<RichTextData> richTextData = null;
private readonly bool hasColorHighlight = false;
public struct ClickableArea
{
public RichTextData Data;
public delegate void OnClickDelegate(GUITextBlock textBlock, ClickableArea area);
public OnClickDelegate OnClick;
}
public List<ClickableArea> ClickableAreas { get; private set; } = new List<ClickableArea>();
/// <summary>
/// This is the new constructor.
/// If the rectT height is set 0, the height is calculated from the text.
@@ -282,11 +313,11 @@ namespace Barotrauma
Enabled = true;
Censor = false;
}
public GUITextBlock(RectTransform rectT, List<ColorData> colorData, string text, Color? textColor = null, ScalableFont font = null, Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool playerInput = false)
public GUITextBlock(RectTransform rectT, List<RichTextData> richTextData, string text, Color? textColor = null, ScalableFont font = null, Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool playerInput = false)
: this(rectT, text, textColor, font, textAlignment, wrap, style, color, playerInput)
{
this.colorData = colorData;
hasColorHighlight = colorData != null;
this.richTextData = richTextData;
hasColorHighlight = richTextData != null;
}
public void CalculateHeightFromText(int padding = 0)
@@ -427,6 +458,131 @@ namespace Barotrauma
disabledTextColor = color;
}
protected List<Tuple<Vector2, int>> GetAllPositions()
{
float halfHeight = Font.MeasureString("T").Y * 0.5f;
string textDrawn = Censor ? CensoredText : WrappedText;
var positions = new List<Tuple<Vector2, int>>();
if (textDrawn.Contains("\n"))
{
string[] lines = textDrawn.Split('\n');
int index = 0;
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
totalIndex += line.Length;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y;
for (int j = 0; j <= line.Length; j++)
{
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j));
Vector2 indexPos = new Vector2(lineTextSize.X + Padding.X, totalTextHeight + Padding.Y - halfHeight);
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
}
index = totalIndex;
}
}
else
{
textDrawn = Censor ? CensoredText : Text;
for (int i = 0; i <= Text.Length; i++)
{
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i));
Vector2 indexPos = new Vector2(textSize.X + Padding.X, textSize.Y + Padding.Y - halfHeight) + TextPos - Origin;
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
positions.Add(new Tuple<Vector2, int>(indexPos, i));
}
}
return positions;
}
public int GetCaretIndexFromScreenPos(Vector2 pos)
{
return GetCaretIndexFromLocalPos(pos - Rect.Location.ToVector2());
}
public int GetCaretIndexFromLocalPos(Vector2 pos)
{
var positions = GetAllPositions();
if (positions.Count == 0) { return 0; }
float halfHeight = Font.MeasureString("T").Y * 0.5f;
var currPosition = positions[0];
float topY = positions.Min(p => p.Item1.Y);
for (int i = 1; i < positions.Count; i++)
{
var p1 = positions[i];
var p2 = currPosition;
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
if (diffY < -3.0f)
{
currPosition = p1; continue;
}
else if (diffY > 3.0f)
{
continue;
}
else
{
diffY = Math.Abs(p1.Item1.Y - pos.Y);
if (diffY < halfHeight || (p1.Item1.Y == topY && pos.Y < topY))
{
//we are on this line, select the nearest character
float diffX = Math.Abs(p1.Item1.X - pos.X) - Math.Abs(p2.Item1.X - pos.X);
if (diffX < -1.0f)
{
currPosition = p1; continue;
}
else
{
continue;
}
}
else
{
//we are on a different line, preserve order
if (p1.Item2 < p2.Item2)
{
if (p1.Item1.Y > pos.Y) { currPosition = p1; }
}
else if (p1.Item2 > p2.Item2)
{
if (p1.Item1.Y < pos.Y) { currPosition = p1; }
}
continue;
}
}
}
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
return currPosition != null ? currPosition.Item2 : Text.Length;
}
protected override void Update(float deltaTime)
{
base.Update(deltaTime);
if (ClickableAreas.Any() && (GUI.MouseOn?.IsParentOf(this) ?? true) && Rect.Contains(PlayerInput.MousePosition))
{
int index = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
foreach (ClickableArea clickableArea in ClickableAreas)
{
if (clickableArea.Data.StartIndex <= index && index <= clickableArea.Data.EndIndex)
{
GUI.MouseCursor = CursorState.Hand;
if (PlayerInput.PrimaryMouseButtonClicked())
{
clickableArea.OnClick?.Invoke(this, clickableArea);
}
break;
}
}
}
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (!Visible) { return; }
@@ -480,7 +636,12 @@ namespace Barotrauma
else
{
Font.DrawStringWithColors(spriteBatch, Censor ? censoredText : (Wrap ? wrappedText : text), pos,
currentTextColor * (currentTextColor.A / 255.0f), 0.0f, origin, TextScale, SpriteEffects.None, textDepth, colorData);
currentTextColor * (currentTextColor.A / 255.0f), 0.0f, origin, TextScale, SpriteEffects.None, textDepth, richTextData);
}
if (Strikethrough != null)
{
Strikethrough.Draw(spriteBatch, (int)Math.Ceiling(TextSize.X / 2f), pos.X, ForceUpperCase ? pos.Y : pos.Y + GUI.Scale * 2f);
}
}

View File

@@ -67,7 +67,12 @@ namespace Barotrauma
private Vector2 selectionEndPos;
private Vector2 selectionRectSize;
private bool mouseHeldInside;
private readonly Memento<string> memento = new Memento<string>();
// Skip one update cycle, fixes Enter key instantly deselecting the chatbox
private bool skipUpdate;
public GUIFrame Frame
{
@@ -362,114 +367,14 @@ namespace Barotrauma
caretPosDirty = false;
}
protected List<Tuple<Vector2, int>> GetAllPositions()
{
float halfHeight = Font.MeasureString("T").Y * 0.5f;
string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText;
var positions = new List<Tuple<Vector2, int>>();
if (textDrawn.Contains("\n"))
{
string[] lines = textDrawn.Split('\n');
int index = 0;
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
totalIndex += line.Length;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y;
for (int j = 0; j <= line.Length; j++)
{
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j));
Vector2 indexPos = new Vector2(lineTextSize.X + textBlock.Padding.X, totalTextHeight + textBlock.Padding.Y - halfHeight);
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
}
index = totalIndex;
}
}
else
{
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
for (int i = 0; i <= textBlock.Text.Length; i++)
{
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i));
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y - halfHeight) + textBlock.TextPos - textBlock.Origin;
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
positions.Add(new Tuple<Vector2, int>(indexPos, i));
}
}
return positions;
}
public int GetCaretIndexFromScreenPos(Vector2 pos)
{
return GetCaretIndexFromLocalPos(pos - textBlock.Rect.Location.ToVector2());
}
public int GetCaretIndexFromLocalPos(Vector2 pos)
{
var positions = GetAllPositions();
if (positions.Count==0) { return 0; }
float halfHeight = Font.MeasureString("T").Y * 0.5f;
var currPosition = positions[0];
for (int i=1;i<positions.Count;i++)
{
var p1 = positions[i];
var p2 = currPosition;
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
if (diffY < -3.0f)
{
currPosition = p1; continue;
}
else if (diffY > 3.0f)
{
continue;
}
else
{
diffY = Math.Abs(p1.Item1.Y - pos.Y);
if (diffY < halfHeight)
{
//we are on this line, select the nearest character
float diffX = Math.Abs(p1.Item1.X - pos.X) - Math.Abs(p2.Item1.X - pos.X);
if (diffX < -1.0f)
{
currPosition = p1; continue;
}
else
{
continue;
}
}
else
{
//we are on a different line, preserve order
if (p1.Item2 < p2.Item2)
{
if (p1.Item1.Y > pos.Y) { currPosition = p1; }
}
else if (p1.Item2 > p2.Item2)
{
if (p1.Item1.Y < pos.Y) { currPosition = p1; }
}
continue;
}
}
}
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
return currPosition != null ? currPosition.Item2 : textBlock.Text.Length;
}
public void Select(int forcedCaretIndex = -1)
{
skipUpdate = true;
if (memento.Current == null)
{
memento.Store(Text);
}
CaretIndex = forcedCaretIndex == - 1 ? GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
ClearSelection();
selected = true;
GUI.KeyboardDispatcher.Subscriber = this;
@@ -499,11 +404,19 @@ namespace Barotrauma
if (flashTimer > 0.0f) flashTimer -= deltaTime;
if (!Enabled) { return; }
if (skipUpdate)
{
skipUpdate = false;
return;
}
if (MouseRect.Contains(PlayerInput.MousePosition) && (GUI.MouseOn == null || (!(GUI.MouseOn is GUIButton) && GUI.IsMouseOn(this))))
{
State = ComponentState.Hover;
if (PlayerInput.PrimaryMouseButtonDown())
{
mouseHeldInside = true;
Select();
}
else
@@ -518,7 +431,7 @@ namespace Barotrauma
{
if (!MathUtils.NearlyEqual(PlayerInput.MouseSpeed.X, 0))
{
CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
CaretIndex = textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
CalculateCaretPos();
CalculateSelection();
}
@@ -526,7 +439,11 @@ namespace Barotrauma
}
else
{
if ((PlayerInput.LeftButtonClicked() || PlayerInput.RightButtonClicked()) && selected) Deselect();
if ((PlayerInput.LeftButtonClicked() || PlayerInput.RightButtonClicked()) && selected)
{
if (!mouseHeldInside) { Deselect(); }
mouseHeldInside = false;
}
isSelecting = false;
State = ComponentState.None;
}
@@ -793,7 +710,7 @@ namespace Barotrauma
InitSelectionStart();
}
float lineHeight = Font.MeasureString("T").Y;
int newIndex = GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y-lineHeight));
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y-lineHeight));
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();
@@ -804,7 +721,7 @@ namespace Barotrauma
InitSelectionStart();
}
lineHeight = Font.MeasureString("T").Y;
newIndex = GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y+lineHeight));
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y+lineHeight));
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();

View File

@@ -50,10 +50,6 @@ namespace Barotrauma
get; private set;
}
/*public static Rectangle HealthBarAreaRight
{
get; private set;
}*/
public static Rectangle HealthBarArea
{
get; private set;
@@ -120,17 +116,11 @@ namespace Barotrauma
//horizontal slices at the corners of the screen for health bar and affliction icons
int afflictionAreaHeight = (int)(50 * GUI.Scale);
int healthBarWidth = BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing * 2 + CharacterInventory.HideButtonWidth;
int healthBarWidth = (int)(BottomRightInfoArea.Width * 1.58f);
int healthBarHeight = (int)(50f * GUI.Scale);
HealthBarArea = new Rectangle(BottomRightInfoArea.X - (healthBarWidth - BottomRightInfoArea.Width) + (int)(2 * GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + (int)(10 * GUI.Scale), healthBarWidth, healthBarHeight);
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
//HealthBarAreaRight = new Rectangle(Padding, GameMain.GraphicsHeight - healthBarHeight - Padding, healthBarWidth, healthBarHeight);
/*if (HealthBarAreaRight.Y + healthBarHeight * 0.75f < PortraitArea.Y)
{
HealthBarAreaRight = new Rectangle(GameMain.GraphicsWidth - Padding - healthBarWidth, HealthBarAreaRight.Y, HealthBarAreaRight.Width, HealthBarAreaRight.Height);
}*/
//AfflictionAreaRight = new Rectangle(HealthBarAreaRight.X, HealthBarAreaRight.Y + healthBarHeight + Padding, healthBarWidth, afflictionAreaHeight);
HealthBarArea = new Rectangle(BottomRightInfoArea.Right - healthBarWidth + (int)Math.Floor(1 / GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + GUI.IntScale(10), healthBarWidth, healthBarHeight);
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
int messageAreaWidth = GameMain.GraphicsWidth / 3;
MessageAreaTop = new Rectangle((GameMain.GraphicsWidth - messageAreaWidth) / 2, ButtonAreaTop.Bottom, messageAreaWidth, ButtonAreaTop.Height);
@@ -146,7 +136,7 @@ namespace Barotrauma
CrewArea = new Rectangle(Padding, Padding, (int)Math.Max(400 * GUI.Scale, 220), ObjectiveAnchor.Top - Padding * 2);
InventoryAreaLower = new Rectangle(Padding, inventoryTopY, GameMain.GraphicsWidth - Padding * 2, GameMain.GraphicsHeight - inventoryTopY);
InventoryAreaLower = new Rectangle(ChatBoxArea.Right + Padding * 7, inventoryTopY, GameMain.GraphicsWidth - Padding * 9 - ChatBoxArea.Width, GameMain.GraphicsHeight - inventoryTopY);
int healthWindowWidth = (int)(GameMain.GraphicsWidth * 0.5f);
int healthWindowHeight = (int)(GameMain.GraphicsWidth * 0.5f * 0.65f);

View File

@@ -338,6 +338,8 @@ namespace Barotrauma
PendingSplashScreens.Clear();
currSplashScreen = null;
}
if (currSplashScreen == null) { return; }
}
if (currSplashScreen.IsPlaying)

View File

@@ -253,11 +253,12 @@ namespace Barotrauma
return _rect;
}
}
public Rectangle ParentRect => Parent != null ? Parent.Rect : ScreenRect;
public Rectangle ParentRect => Parent != null ? Parent.Rect : UIRect;
protected Rectangle NonScaledRect => new Rectangle(NonScaledTopLeft, NonScaledSize);
protected Rectangle NonScaledParentRect => parent != null ? Parent.NonScaledRect : ScreenRect;
protected Rectangle ScreenRect => new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
protected virtual Rectangle NonScaledUIRect => NonScaledRect;
protected Rectangle NonScaledParentRect => parent != null ? Parent.NonScaledRect : UIRect;
protected Rectangle NonScaledParentUIRect => parent != null ? Parent.NonScaledUIRect : UIRect;
protected Rectangle UIRect => new Rectangle(0, 0, GUI.UIWidth, GameMain.GraphicsHeight);
private Pivot pivot;
/// <summary>
@@ -444,14 +445,14 @@ namespace Barotrauma
protected void RecalculateRelativeSize()
{
relativeSize = new Vector2(NonScaledSize.X, NonScaledSize.Y) / new Vector2(NonScaledParentRect.Width, NonScaledParentRect.Height);
relativeSize = new Vector2(NonScaledSize.X, NonScaledSize.Y) / new Vector2(NonScaledParentUIRect.Width, NonScaledParentUIRect.Height);
recalculateRect = true;
SizeChanged?.Invoke();
}
protected void RecalculateAbsoluteSize()
{
Point size = NonScaledParentRect.Size;
Point size = NonScaledParentUIRect.Size;
switch (ScaleBasis)
{
case ScaleBasis.BothWidth:
@@ -651,6 +652,13 @@ namespace Barotrauma
Parent.ChildrenChanged?.Invoke(this);
}
public void ReverseChildren()
{
children.Reverse();
RecalculateAll(false, false, true);
Parent.ChildrenChanged?.Invoke(this);
}
public void SetAsLastChild()
{
if (IsLastChild) { return; }

View File

@@ -0,0 +1,941 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Linq;
using Barotrauma.Networking;
namespace Barotrauma
{
class TabMenu
{
public static bool PendingChanges = false;
private static bool initialized = false;
private static UISprite spectateIcon, deadIcon, disconnectedIcon;
private static Sprite ownerIcon, moderatorIcon;
private enum InfoFrameTab { Crew, Mission, MyCharacter, Traitor };
private static InfoFrameTab selectedTab;
private GUIFrame infoFrame, contentFrame;
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
private GUIFrame infoFrameHolder;
private List<LinkedGUI> linkedGUIList;
private GUIListBox logList;
private GUIListBox[] crewListArray;
private float sizeMultiplier = 1f;
private IEnumerable<Character> crew;
private List<Character.TeamType> teamIDs;
private const string inLobbyString = "\u2022 \u2022 \u2022";
private static Color ownCharacterBGColor = Color.Gold * 0.7f;
private class LinkedGUI
{
private const ushort lowPingThreshold = 100;
private const ushort mediumPingThreshold = 200;
private ushort currentPing;
private Client client;
private Character character;
private bool hasCharacter;
private GUITextBlock textBlock;
private GUIFrame frame;
public LinkedGUI(Client client, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
{
this.client = client;
this.textBlock = textBlock;
this.frame = frame;
this.hasCharacter = hasCharacter;
}
public LinkedGUI(Character character, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
{
this.character = character;
this.textBlock = textBlock;
this.frame = frame;
this.hasCharacter = hasCharacter;
}
public bool HasMultiplayerCharacterChanged()
{
if (client == null) return false;
bool characterState = client.Character != null;
if (characterState && client.Character.IsDead) characterState = false;
return hasCharacter != characterState;
}
public bool HasMultiplayerCharacterDied()
{
if (client == null || !hasCharacter || client.Character == null) return false;
return client.Character.IsDead;
}
public bool HasAICharacterDied()
{
if (character == null) return false;
return character.IsDead;
}
public void TryPingRefresh()
{
if (client == null) return;
if (currentPing == client.Ping) return;
currentPing = client.Ping;
textBlock.Text = currentPing.ToString();
textBlock.TextColor = GetPingColor();
}
private Color GetPingColor()
{
if (currentPing < lowPingThreshold)
{
return GUI.Style.Green;
}
else if (currentPing < mediumPingThreshold)
{
return GUI.Style.Yellow;
}
else
{
return GUI.Style.Red;
}
}
public void Remove(GUIFrame parent)
{
parent.RemoveChild(frame);
}
}
public void Initialize()
{
spectateIcon = GUI.Style.GetComponentStyle("SpectateIcon").Sprites[GUIComponent.ComponentState.None][0];
deadIcon = GUI.Style.GetComponentStyle("DeadIcon").Sprites[GUIComponent.ComponentState.None][0];
disconnectedIcon = GUI.Style.GetComponentStyle("DisconnectedIcon").Sprites[GUIComponent.ComponentState.None][0];
ownerIcon = GUI.Style.GetComponentStyle("OwnerIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
moderatorIcon = GUI.Style.GetComponentStyle("ModeratorIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
initialized = true;
}
public TabMenu()
{
if (!initialized) Initialize();
CreateInfoFrame(selectedTab);
SelectInfoFrameTab(null, selectedTab);
}
public void Update()
{
if (selectedTab != InfoFrameTab.Crew) return;
if (linkedGUIList == null) return;
if (GameMain.IsMultiplayer)
{
for (int i = 0; i < linkedGUIList.Count; i++)
{
linkedGUIList[i].TryPingRefresh();
if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasMultiplayerCharacterDied() || linkedGUIList[i].HasAICharacterDied())
{
RemoveCurrentElements();
CreateMultiPlayerList(true);
return;
}
}
}
else
{
for (int i = 0; i < linkedGUIList.Count; i++)
{
if (linkedGUIList[i].HasAICharacterDied())
{
RemoveCurrentElements();
CreateSinglePlayerList(true);
}
}
}
}
public void AddToGUIUpdateList()
{
infoFrame?.AddToGUIUpdateList();
NetLobbyScreen.JobInfoFrame?.AddToGUIUpdateList();
}
public static void OnRoundEnded()
{
storedMessages.Clear();
PendingChanges = false;
}
private void CreateInfoFrame(InfoFrameTab selectedTab)
{
tabButtons.Clear();
infoFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, infoFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
switch (selectedTab)
{
case InfoFrameTab.Crew:
case InfoFrameTab.Mission:
case InfoFrameTab.Traitor:
default:
contentFrame = new GUIFrame(new RectTransform(new Vector2(0.33f, 0.667f), infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { /*MinSize = new Point(width, height),*/ RelativeOffset = new Vector2(0.025f, 0.12f) });
break;
case InfoFrameTab.MyCharacter:
contentFrame = new GUIFrame(new RectTransform(new Vector2(0.33f, 0.5f), infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { /*MinSize = new Point(width, height),*/ RelativeOffset = new Vector2(0.025f, 0.12f) });
break;
}
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.958f, 0.943f), contentFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(17.5f)) }, style: null);
var buttonArea = new GUILayoutGroup(new RectTransform(new Point(innerFrame.Rect.Width, GUI.IntScale(25f)), innerFrame.RectTransform) { AbsoluteOffset = new Point(2, 0) }, isHorizontal: true)
{
RelativeSpacing = 0.01f
};
infoFrameHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.926f), innerFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter), style: null);
var crewButton = new GUIButton(new RectTransform(new Vector2(0.245f, 1.0f), buttonArea.RectTransform), TextManager.Get("Crew"), style: "GUITabButton")
{
UserData = InfoFrameTab.Crew,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(crewButton);
var missionButton = new GUIButton(new RectTransform(new Vector2(0.245f, 1.0f), buttonArea.RectTransform), TextManager.Get("Mission"), style: "GUITabButton")
{
UserData = InfoFrameTab.Mission,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(missionButton);
bool isTraitor = GameMain.Client?.Character?.IsTraitor ?? false;
if (isTraitor && GameMain.Client.TraitorMission != null)
{
var traitorButton = new GUIButton(new RectTransform(new Vector2(0.245f, 1.0f), buttonArea.RectTransform), TextManager.Get("tabmenu.traitor"), style: "GUITabButton")
{
UserData = InfoFrameTab.Traitor,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(traitorButton);
}
if (GameMain.NetworkMember != null)
{
var myCharacterButton = new GUIButton(new RectTransform(new Vector2(0.245f, 1.0f), buttonArea.RectTransform), TextManager.Get("tabmenu.character"), style: "GUITabButton")
{
UserData = InfoFrameTab.MyCharacter,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(myCharacterButton);
}
}
private bool SelectInfoFrameTab(GUIButton button, object userData)
{
selectedTab = (InfoFrameTab)userData;
CreateInfoFrame(selectedTab);
tabButtons.ForEach(tb => tb.Selected = (InfoFrameTab)tb.UserData == selectedTab);
switch (selectedTab)
{
case InfoFrameTab.Crew:
CreateCrewListFrame(infoFrameHolder);
break;
case InfoFrameTab.Mission:
CreateMissionInfo(infoFrameHolder);
break;
case InfoFrameTab.Traitor:
TraitorMissionPrefab traitorMission = GameMain.Client.TraitorMission;
Character traitor = GameMain.Client.Character;
if (traitor == null || traitorMission == null) return false;
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
break;
case InfoFrameTab.MyCharacter:
if (GameMain.NetworkMember == null) { return false; }
GameMain.NetLobbyScreen.CreatePlayerFrame(infoFrameHolder);
break;
}
return true;
}
private const float jobColumnWidthPercentage = 0.138f;
private const float characterColumnWidthPercentage = 0.656f;
private const float pingColumnWidthPercentage = 0.206f;
private int jobColumnWidth, characterColumnWidth, pingColumnWidth;
private void CreateCrewListFrame(GUIFrame crewFrame)
{
crew = GameMain.GameSession.CrewManager.GetCharacters();
teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
// Show own team first when there's more than one team
if (teamIDs.Count > 1 && GameMain.Client.Character != null)
{
Character.TeamType ownTeam = GameMain.Client.Character.TeamID;
teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
}
if (!teamIDs.Any()) teamIDs.Add(Character.TeamType.None);
var content = new GUILayoutGroup(new RectTransform(Vector2.One, crewFrame.RectTransform));
crewListArray = new GUIListBox[teamIDs.Count];
GUILayoutGroup[] headerFrames = new GUILayoutGroup[teamIDs.Count];
float nameHeight = 0.075f;
Vector2 crewListSize = new Vector2(1f, 1f / teamIDs.Count - (teamIDs.Count > 1 ? nameHeight * 1.1f : 0f));
for (int i = 0; i < teamIDs.Count; i++)
{
if (teamIDs.Count > 1)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, nameHeight), content.RectTransform), CombatMission.GetTeamName(teamIDs[i]), textColor: i == 0 ? GUI.Style.Green : GUI.Style.Orange) { ForceUpperCase = true };
}
headerFrames[i] = new GUILayoutGroup(new RectTransform(Vector2.Zero, content.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(2, -1) }, isHorizontal: true)
{
AbsoluteSpacing = 2,
UserData = i
};
GUIListBox crewList = new GUIListBox(new RectTransform(crewListSize, content.RectTransform))
{
Padding = new Vector4(2, 5, 0, 0),
AutoHideScrollBar = false
};
crewList.UpdateDimensions();
if (teamIDs.Count > 1)
{
crewList.OnSelected = (component, obj) =>
{
for (int i = 0; i < crewListArray.Length; i++)
{
if (crewListArray[i] == crewList) continue;
crewListArray[i].Deselect();
}
SelectElement(component.UserData, crewList);
return true;
};
}
else
{
crewList.OnSelected = (component, obj) =>
{
SelectElement(component.UserData, crewList);
return true;
};
}
crewListArray[i] = crewList;
}
for (int i = 0; i < teamIDs.Count; i++)
{
headerFrames[i].RectTransform.RelativeSize = new Vector2(1f - crewListArray[i].ScrollBar.Rect.Width / (float)crewListArray[i].Rect.Width, GUI.HotkeyFont.Size / (float)crewFrame.RectTransform.Rect.Height * 1.5f);
if (!GameMain.IsMultiplayer)
{
CreateSinglePlayerListContentHolder(headerFrames[i]);
}
else
{
CreateMultiPlayerListContentHolder(headerFrames[i]);
}
}
crewFrame.RectTransform.AbsoluteOffset = new Point(0, (int)(headerFrames[0].Rect.Height * headerFrames.Length) - (teamIDs.Count > 1 ? GUI.IntScale(10f) : 0));
if (GameMain.IsMultiplayer)
{
CreateMultiPlayerList(false);
CreateMultiPlayerLogContent(crewFrame);
}
else
{
CreateSinglePlayerList(false);
}
}
private void CreateSinglePlayerListContentHolder(GUILayoutGroup headerFrame)
{
GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
characterButton.RectTransform.RelativeSize = new Vector2((1f - jobColumnWidthPercentage * sizeMultiplier) * sizeMultiplier, 1f);
jobButton.TextBlock.Font = characterButton.TextBlock.Font = GUI.HotkeyFont;
jobButton.CanBeFocused = characterButton.CanBeFocused = false;
jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase = true;
jobColumnWidth = jobButton.Rect.Width;
characterColumnWidth = characterButton.Rect.Width;
}
private void CreateSinglePlayerList(bool refresh)
{
if (refresh)
{
crew = GameMain.GameSession.CrewManager.GetCharacters();
}
linkedGUIList = new List<LinkedGUI>();
for (int i = 0; i < teamIDs.Count; i++)
{
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
{
CreateSinglePlayerCharacterElement(character, i);
}
}
}
private void CreateSinglePlayerCharacterElement(Character character, int i)
{
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
{
UserData = character,
Color = (Character.Controlled == character) ? ownCharacterBGColor : Color.Transparent
};
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
{
AbsoluteSpacing = 2
};
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
{
CanBeFocused = false,
HoverColor = Color.White,
SelectedColor = Color.White
};
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
ToolBox.LimitString(character.Info.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead, null));
}
private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
{
GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
GUIButton pingButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("serverlistping"), style: "GUIButtonSmallFreeScale");
sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
characterButton.RectTransform.RelativeSize = new Vector2(characterColumnWidthPercentage * sizeMultiplier, 1f);
pingButton.RectTransform.RelativeSize = new Vector2(pingColumnWidthPercentage * sizeMultiplier, 1f);
jobButton.TextBlock.Font = characterButton.TextBlock.Font = pingButton.TextBlock.Font = GUI.HotkeyFont;
jobButton.CanBeFocused = characterButton.CanBeFocused = pingButton.CanBeFocused = false;
jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase = pingButton.ForceUpperCase = true;
jobColumnWidth = jobButton.Rect.Width;
characterColumnWidth = characterButton.Rect.Width;
pingColumnWidth = pingButton.Rect.Width;
}
private void CreateMultiPlayerList(bool refresh)
{
if (refresh)
{
crew = GameMain.GameSession.CrewManager.GetCharacters();
}
linkedGUIList = new List<LinkedGUI>();
List<Client> connectedClients = GameMain.Client.ConnectedClients;
for (int i = 0; i < teamIDs.Count; i++)
{
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
{
if (!(character is AICharacter) && connectedClients.Find(c => c.Character == null && c.Name == character.Name) != null) continue;
CreateMultiPlayerCharacterElement(character, GameMain.Client.ConnectedClients.Find(c => c.Character == character), i);
}
}
for (int j = 0; j < connectedClients.Count; j++)
{
Client client = connectedClients[j];
if (!client.InGame || client.Character == null || client.Character.IsDead)
{
CreateMultiPlayerClientElement(client);
}
}
}
private void CreateMultiPlayerCharacterElement(Character character, Client client, int i)
{
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
{
UserData = character,
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? ownCharacterBGColor : Color.Transparent
};
frame.OnSecondaryClicked += (component, data) =>
{
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
return true;
};
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
{
AbsoluteSpacing = 2
};
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
{
CanBeFocused = false,
HoverColor = Color.White,
SelectedColor = Color.White
};
if (client != null)
{
CreateNameWithPermissionIcon(client, paddedFrame);
linkedGUIList.Add(new LinkedGUI(client, frame, true, new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center)));
}
else
{
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
ToolBox.LimitString(character.Info.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
if (character is AICharacter)
{
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead, new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = true }));
}
else
{
linkedGUIList.Add(new LinkedGUI(client: null, frame, true, null));
new GUICustomComponent(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
{
CanBeFocused = false,
HoverColor = Color.White,
SelectedColor = Color.White
};
}
}
}
private void CreateMultiPlayerClientElement(Client client)
{
int teamIndex = GetTeamIndex(client);
if (teamIndex == -1) teamIndex = 0;
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[teamIndex].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[teamIndex].Content.RectTransform), style: "ListBoxElement")
{
UserData = client,
Color = Color.Transparent
};
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
{
AbsoluteSpacing = 2
};
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client))
{
CanBeFocused = false,
HoverColor = Color.White,
SelectedColor = Color.White
};
CreateNameWithPermissionIcon(client, paddedFrame);
linkedGUIList.Add(new LinkedGUI(client, frame, false, new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center)));
}
private int GetTeamIndex(Client client)
{
if (teamIDs.Count <= 1) return 0;
if (client.Character != null)
{
return teamIDs.IndexOf(client.Character.TeamID);
}
if (client.CharacterID != 0)
{
foreach (Character c in crew)
{
if (client.CharacterID == c.ID)
{
return teamIDs.IndexOf(c.TeamID);
}
}
}
else
{
foreach (Character c in crew)
{
if (client.Name == c.Name)
{
return teamIDs.IndexOf(c.TeamID);
}
}
}
return 0;
}
private void CreateNameWithPermissionIcon(Client client, GUILayoutGroup paddedFrame)
{
GUITextBlock characterNameBlock;
Sprite permissionIcon = GetPermissionIcon(client);
JobPrefab prefab = client.Character?.Info?.Job?.Prefab;
Color nameColor = prefab != null ? prefab.UIColor : Color.White;
if (permissionIcon != null)
{
Point iconSize = permissionIcon.SourceRect.Size;
float characterNameWidthAdjustment = (iconSize.X + paddedFrame.AbsoluteSpacing) / characterColumnWidth;
characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
ToolBox.LimitString(client.Name, GUI.Font, (int)(characterColumnWidth - paddedFrame.Rect.Width * characterNameWidthAdjustment)), textAlignment: Alignment.Center, textColor: nameColor);
float iconWidth = iconSize.X / (float)characterColumnWidth;
int xOffset = (int)(jobColumnWidth + characterNameBlock.TextPos.X - GUI.Font.MeasureString(characterNameBlock.Text).X / 2f - paddedFrame.AbsoluteSpacing - iconWidth * paddedFrame.Rect.Width);
new GUIImage(new RectTransform(new Vector2(iconWidth, 1f), paddedFrame.RectTransform) { AbsoluteOffset = new Point(xOffset + 2, 0) }, permissionIcon) { IgnoreLayoutGroups = true };
}
else
{
characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
ToolBox.LimitString(client.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: nameColor);
}
if (client.Character != null && client.Character.IsDead)
{
characterNameBlock.Strikethrough = new GUITextBlock.StrikethroughSettings(null, GUI.IntScale(1f), GUI.IntScale(5f));
}
}
private Sprite GetPermissionIcon(Client client)
{
if (GameMain.NetworkMember == null || client == null || !client.HasPermissions) return null;
if (!client.AllowKicking) // Owner cannot be kicked
{
return ownerIcon;
}
else
{
return moderatorIcon;
}
}
private void DrawNotInGameIcon(SpriteBatch spriteBatch, Rectangle area, Client client)
{
if (client.Spectating)
{
spectateIcon.Draw(spriteBatch, area, Color.White);
}
else if (client.Character != null && client.Character.IsDead)
{
client.Character.Info.DrawJobIcon(spriteBatch, area);
}
else
{
Vector2 stringOffset = GUI.GlobalFont.MeasureString(inLobbyString) / 2f;
GUI.GlobalFont.DrawString(spriteBatch, inLobbyString, area.Center.ToVector2() - stringOffset, Color.White);
}
}
private void DrawDisconnectedIcon(SpriteBatch spriteBatch, Rectangle area)
{
disconnectedIcon.Draw(spriteBatch, area, GUI.Style.Red);
}
/// <summary>
/// Select an element from CrewListFrame
/// </summary>
private bool SelectElement(object userData, GUIComponent crewList)
{
Character character = userData as Character;
Client client = userData as Client;
GUIComponent existingPreview = infoFrameHolder.FindChild("SelectedCharacter");
if (existingPreview != null) infoFrameHolder.RemoveChild(existingPreview);
GUIFrame background = new GUIFrame(new RectTransform(new Vector2(0.543f, 0.717f), infoFrameHolder.RectTransform, Anchor.TopLeft, Pivot.TopRight) { RelativeOffset = new Vector2(-0.061f, 0) })
{
UserData = "SelectedCharacter"
};
if (character != null)
{
if (GameMain.NetworkMember == null)
{
GUIComponent preview = character.Info.CreateInfoFrame(background, false, null);
}
else
{
GUIComponent preview = character.Info.CreateInfoFrame(background, false, GetPermissionIcon(GameMain.Client.ConnectedClients.Find(c => c.Character == character)));
GameMain.Client.SelectCrewCharacter(character, preview);
}
}
else if (client != null)
{
GUIComponent preview = CreateClientInfoFrame(background, client, GetPermissionIcon(client));
if (GameMain.NetworkMember != null) GameMain.Client.SelectCrewClient(client, preview);
}
return true;
}
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
{
GUIComponent paddedFrame;
if (client.Character == null)
{
paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) })
{
RelativeSpacing = 0.05f
//Stretch = true
};
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal: true);
new GUICustomComponent(new RectTransform(new Vector2(0.425f, 1.0f), headerArea.RectTransform),
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client));
ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.575f, 1.0f), headerArea.RectTransform))
{
RelativeSpacing = 0.02f,
Stretch = true
};
GUITextBlock clientNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), ToolBox.LimitString(client.Name, GUI.Font, headerTextArea.Rect.Width), textColor: Color.White, font: GUI.Font)
{
ForceUpperCase = true,
Padding = Vector4.Zero
};
if (permissionIcon != null)
{
Point iconSize = permissionIcon.SourceRect.Size;
int iconWidth = (int)((float)clientNameBlock.Rect.Height / iconSize.Y * iconSize.X);
new GUIImage(new RectTransform(new Point(iconWidth, clientNameBlock.Rect.Height), clientNameBlock.RectTransform) { AbsoluteOffset = new Point(-iconWidth - 2, 0) }, permissionIcon) { IgnoreLayoutGroups = true };
}
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), client.Spectating ? TextManager.Get("playingasspectator") : TextManager.Get("tabmenu.inlobby"), textColor: Color.White, font: font, wrap: true)
{
Padding = Vector4.Zero
};
}
else
{
paddedFrame = client.Character.Info.CreateInfoFrame(frame, false, permissionIcon);
}
return paddedFrame;
}
private void CreateMultiPlayerLogContent(GUIFrame crewFrame)
{
var logContainer = new GUIFrame(new RectTransform(new Vector2(0.543f, 0.717f), crewFrame.RectTransform, Anchor.TopRight, Pivot.TopLeft) { RelativeOffset = new Vector2(-0.061f, 0) });
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.900f, 0.900f), logContainer.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0f, 0.0475f) }, style: null);
var content = new GUILayoutGroup(new RectTransform(Vector2.One, innerFrame.RectTransform))
{
Stretch = true
};
logList = new GUIListBox(new RectTransform(Vector2.One, content.RectTransform))
{
Padding = new Vector4(0, 10 * GUI.Scale, 0, 10 * GUI.Scale),
UserData = crewFrame,
AutoHideScrollBar = false,
Spacing = (int)(5 * GUI.Scale)
};
foreach (Pair<string, PlayerConnectionChangeType> pair in storedMessages)
{
AddLineToLog(pair.First, pair.Second);
}
logList.BarScroll = 1f;
}
private static readonly List<Pair<string, PlayerConnectionChangeType>> storedMessages = new List<Pair<string, PlayerConnectionChangeType>>();
public static void StorePlayerConnectionChangeMessage(ChatMessage message)
{
if (!GameMain.GameSession?.GameMode?.IsRunning ?? true) { return; }
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
if (GameSession.IsTabMenuOpen)
{
TabMenu instance = GameSession.TabMenuInstance;
instance.AddLineToLog(msg, message.ChangeType);
// Update crew
if (selectedTab == InfoFrameTab.Crew)
{
instance.RemoveCurrentElements();
instance.CreateMultiPlayerList(true);
}
}
}
private void RemoveCurrentElements()
{
for (int i = 0; i < crewListArray.Length; i++)
{
for (int j = 0; j < linkedGUIList.Count; j++)
{
linkedGUIList[j].Remove(crewListArray[i].Content);
}
}
linkedGUIList.Clear();
}
private void AddLineToLog(string line, PlayerConnectionChangeType type)
{
Color textColor = Color.White;
switch (type)
{
case PlayerConnectionChangeType.Joined:
textColor = GUI.Style.Green;
break;
case PlayerConnectionChangeType.Kicked:
textColor = GUI.Style.Orange;
break;
case PlayerConnectionChangeType.Disconnected:
textColor = GUI.Style.Yellow;
break;
case PlayerConnectionChangeType.Banned:
textColor = GUI.Style.Red;
break;
}
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), logList.Content.RectTransform), line, wrap: true, font: GUI.SmallFont)
{
TextColor = textColor,
CanBeFocused = false,
UserData = line
}.CalculateHeightFromText();
//if ((prevSize == 1.0f && listBox.BarScroll == 0.0f) || (prevSize < 1.0f && listBox.BarScroll == 1.0f)) listBox.BarScroll = 1.0f;
}
private void CreateMissionInfo(GUIFrame infoFrame)
{
infoFrame.ClearChildren();
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
int padding = (int)(0.0245f * missionFrame.Rect.Height);
Location endLocation = GameMain.GameSession.EndLocation;
Sprite portrait = endLocation.Type.GetPortrait(endLocation.PortraitId);
bool hasPortrait = portrait != null && portrait.SourceRect.Width > 0 && portrait.SourceRect.Height > 0;
int contentWidth = hasPortrait ? (int)(missionFrame.Rect.Width * 0.951f) : missionFrame.Rect.Width - padding * 2;
Vector2 locationNameSize = GUI.LargeFont.MeasureString(endLocation.Name);
Vector2 locationTypeSize = GUI.SubHeadingFont.MeasureString(endLocation.Name);
GUITextBlock locationNameText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationNameSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, endLocation.Name, font: GUI.LargeFont);
GUITextBlock locationTypeText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationTypeSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationNameText.Rect.Height + padding) }, endLocation.Type.Name, font: GUI.SubHeadingFont);
int locationInfoYOffset = locationNameText.Rect.Height + locationTypeText.Rect.Height + padding * 2;
GUIFrame missionDescriptionHolder;
if (hasPortrait)
{
GUIFrame missionImageHolder = new GUIFrame(new RectTransform(new Point(contentWidth, (int)(missionFrame.Rect.Height * 0.588f)), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationInfoYOffset) });
float portraitAspectRatio = portrait.SourceRect.Width / portrait.SourceRect.Height;
GUIImage portraitImage = new GUIImage(new RectTransform(new Vector2(1.0f, 1f), missionImageHolder.RectTransform), portrait, scaleToFit: true);
missionImageHolder.RectTransform.NonScaledSize = new Point(portraitImage.Rect.Size.X, (int)(portraitImage.Rect.Size.X / portraitAspectRatio));
missionDescriptionHolder = new GUIFrame(new RectTransform(new Point(contentWidth, 0), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, missionImageHolder.RectTransform.AbsoluteOffset.Y + missionImageHolder.Rect.Height + padding) }, style: null);
}
else
{
missionDescriptionHolder = new GUIFrame(new RectTransform(new Point(contentWidth, 0), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationInfoYOffset) }, style: null);
}
Mission mission = GameMain.GameSession?.Mission;
if (mission != null)
{
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.225f, 0f) }, false, childAnchor: Anchor.TopLeft);
string missionNameString = ToolBox.WrapText(mission.Name, missionTextGroup.Rect.Width, GUI.LargeFont);
string missionDescriptionString = ToolBox.WrapText(mission.Description, missionTextGroup.Rect.Width, GUI.Font);
string missionRewardString = ToolBox.WrapText(TextManager.GetWithVariable("MissionReward", "[reward]", mission.Reward.ToString()), missionTextGroup.Rect.Width, GUI.Font);
Vector2 missionNameSize = GUI.LargeFont.MeasureString(missionNameString);
Vector2 missionDescriptionSize = GUI.Font.MeasureString(missionDescriptionString);
Vector2 missionRewardSize = GUI.Font.MeasureString(missionRewardString);
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)(missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y));
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
float iconAspectRatio = mission.Prefab.Icon.SourceRect.Width / mission.Prefab.Icon.SourceRect.Height;
int iconWidth = (int)(0.225f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
Point iconSize = new Point(iconWidth, iconHeight);
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true) { Color = mission.Prefab.IconColor };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionNameString, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionRewardString);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionDescriptionString);
}
else
{
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft), false, childAnchor: Anchor.TopLeft);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), TextManager.Get("NoMission"), font: GUI.LargeFont);
}
}
private void CreateTraitorInfo(GUIFrame infoFrame, TraitorMissionPrefab traitorMission, Character traitor)
{
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
int padding = (int)(0.0245f * missionFrame.Rect.Height);
GUIFrame missionDescriptionHolder = new GUIFrame(new RectTransform(new Point(missionFrame.Rect.Width - padding * 2, 0), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, style: null);
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.65f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.319f, 0f) }, false, childAnchor: Anchor.TopLeft);
string missionNameString = ToolBox.WrapText(TextManager.Get("tabmenu.traitor"), missionTextGroup.Rect.Width, GUI.LargeFont);
string missionDescriptionString = ToolBox.WrapText(traitor.TraitorCurrentObjective, missionTextGroup.Rect.Width, GUI.Font);
Vector2 missionNameSize = GUI.LargeFont.MeasureString(missionNameString);
Vector2 missionDescriptionSize = GUI.Font.MeasureString(missionDescriptionString);
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)(missionNameSize.Y + missionDescriptionSize.Y));
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
float aspectRatio = traitorMission.Icon.SourceRect.Width / traitorMission.Icon.SourceRect.Height;
int iconWidth = (int)(0.319f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * aspectRatio));
Point iconSize = new Point(iconWidth, iconHeight);
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), traitorMission.Icon, null, true) { Color = traitorMission.IconColor };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionNameString, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionDescriptionString);
}
}
}

View File

@@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
using System;
using System.Xml.Linq;
using Barotrauma.Media;
using System.IO;
using Barotrauma.IO;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
@@ -56,7 +56,7 @@ namespace Barotrauma
public VideoPlayer() // GUI elements with size set to Point.Zero are resized based on content
{
int screenWidth = (int)(GameMain.GraphicsWidth * 0.55f);
int screenWidth = (int)(GameMain.GraphicsWidth * 0.65f);
scaledVideoResolution = new Point(screenWidth, (int)(screenWidth / 16f * 9f));
int width = scaledVideoResolution.X;
@@ -178,6 +178,7 @@ namespace Barotrauma
videoFrame.RectTransform.NonScaledSize = scaledVideoResolution + new Point(scaledBorderSize, scaledBorderSize);
videoView.RectTransform.NonScaledSize = scaledVideoResolution;
videoFrame.RectTransform.AbsoluteOffset = new Point(0, videoFrame.RectTransform.NonScaledSize.Y);
title.RectTransform.NonScaledSize = new Point(scaledTextWidth, scaledTitleHeight);
title.RectTransform.AbsoluteOffset = new Point((int)(5 * GUI.Scale), (int)(10 * GUI.Scale));
@@ -247,7 +248,7 @@ namespace Barotrauma
}
else
{
videoFrame.RectTransform.AbsoluteOffset = new Point(0, (int)(100 * GUI.Scale));
videoFrame.RectTransform.AbsoluteOffset = new Point(0, 0);
okButton = new GUIButton(new RectTransform(scaledButtonSize, videoFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("Back"))
{

View File

@@ -12,7 +12,7 @@ using System.Diagnostics;
using System.Linq;
using System.Reflection;
using GameAnalyticsSDK.Net;
using System.IO;
using Barotrauma.IO;
using System.Threading;
using Barotrauma.Tutorials;
using Barotrauma.Media;
@@ -112,6 +112,8 @@ namespace Barotrauma
public event Action OnResolutionChanged;
private bool exiting;
public static GameMain Instance
{
get;
@@ -144,7 +146,17 @@ namespace Barotrauma
public static bool WindowActive
{
get { return Instance == null || Instance.IsActive; }
get
{
try
{
return Instance != null && !Instance.exiting && Instance.IsActive;
}
catch (NullReferenceException)
{
return false;
}
}
}
public static GameClient Client;
@@ -179,10 +191,14 @@ namespace Barotrauma
{
Content.RootDirectory = "Content";
GraphicsDeviceManager = new GraphicsDeviceManager(this);
GraphicsDeviceManager.IsFullScreen = false;
GraphicsDeviceManager.GraphicsProfile = GfxProfile;
#if DEBUG && WINDOWS
GraphicsAdapter.UseDebugLayers = true;
#endif
GraphicsDeviceManager = new GraphicsDeviceManager(this)
{
IsFullScreen = false,
GraphicsProfile = GfxProfile
};
GraphicsDeviceManager.ApplyChanges();
Window.Title = "Barotrauma";
@@ -329,6 +345,8 @@ namespace Barotrauma
//do this here because we need it for the loading screen
WaterRenderer.Instance = new WaterRenderer(base.GraphicsDevice, Content);
Quad.Init(GraphicsDevice);
loadingScreenOpen = true;
TitleScreen = new LoadingScreen(GraphicsDevice)
{
@@ -409,7 +427,7 @@ namespace Barotrauma
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0);
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume, 0);
SoundManager.SetCategoryGainMultiplier("voip", Math.Min(Config.VoiceChatVolume, 1.0f), 0);
if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro"))
{
@@ -514,6 +532,8 @@ namespace Barotrauma
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
Order.Init();
EventManagerSettings.Init();
TitleScreen.LoadState = 50.0f;
yield return CoroutineStatus.Running;
@@ -829,6 +849,10 @@ namespace Barotrauma
{
(GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI();
}
else if (GameSession.IsTabMenuOpen)
{
gameSession.ToggleTabMenu();
}
else if (GUI.PauseMenuOpen)
{
GUI.TogglePauseMenu();
@@ -837,7 +861,8 @@ namespace Barotrauma
else if ((Character.Controlled == null || !itemHudActive())
//TODO: do we need to check Inventory.SelectedSlot?
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null
&& !CrewManager.IsCommandInterfaceOpen)
&& !CrewManager.IsCommandInterfaceOpen
&& !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null))
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
@@ -928,7 +953,7 @@ namespace Barotrauma
sw.Stop();
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks / (float)TimeSpan.TicksPerMillisecond);
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
PerformanceCounter.UpdateIterationsGraph.Update(updateIterations);
}
@@ -950,10 +975,13 @@ namespace Barotrauma
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds;
double step = 1.0 / Timing.FrameLimit;
while (!Config.VSyncEnabled && sw.Elapsed.TotalSeconds + deltaTime < step)
if (Timing.FrameLimit > 0)
{
Thread.Sleep(1);
double step = 1.0 / Timing.FrameLimit;
while (!Config.VSyncEnabled && sw.Elapsed.TotalSeconds + deltaTime < step)
{
Thread.Sleep(1);
}
}
PerformanceCounter.Update(sw.Elapsed.TotalSeconds + deltaTime);
@@ -978,7 +1006,7 @@ namespace Barotrauma
sw.Stop();
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks / (float)TimeSpan.TicksPerMillisecond);
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
}
@@ -1147,7 +1175,9 @@ namespace Barotrauma
protected override void OnExiting(object sender, EventArgs args)
{
if (NetworkMember != null) NetworkMember.Disconnect();
exiting = true;
DebugConsole.NewMessage("Exiting...");
NetworkMember?.Disconnect();
SteamManager.ShutDown();
try

View File

@@ -134,7 +134,7 @@ namespace Barotrauma
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write(pi.ItemPrefab.Identifier);
msg.Write((UInt16)pi.Quantity);
msg.WriteRangedInteger(pi.Quantity, 0, 100);
}
}
@@ -162,7 +162,7 @@ namespace Barotrauma
for (int i = 0; i < purchasedItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
UInt16 itemQuantity = msg.ReadUInt16();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
}

View File

@@ -25,7 +25,7 @@ namespace Barotrauma
: base(preset, param)
{
int buttonHeight = (int)(HUDLayoutSettings.ButtonAreaTop.Height * 0.7f);
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(HUDLayoutSettings.ButtonAreaTop.Right - 200, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonHeight / 2, 200, buttonHeight), GUICanvas.Instance),
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(HUDLayoutSettings.ButtonAreaTop.Right - GUI.IntScale(200), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonHeight / 2, GUI.IntScale(200), buttonHeight), GUICanvas.Instance),
TextManager.Get("EndRound"), textAlignment: Alignment.Center)
{
Font = GUI.SmallFont,
@@ -276,6 +276,7 @@ namespace Barotrauma
c.SaveInventory(c.Inventory, inventoryElement);
c.Info.InventoryData = inventoryElement;
c.Inventory?.DeleteAllItems();
c.ResetCurrentOrder();
}
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);

View File

@@ -246,7 +246,7 @@ namespace Barotrauma.Tutorials
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f, false);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Any());
} while (!Submarine.MainSub.AtEndPosition || !Submarine.MainSub.DockedTo.Any());
RemoveCompletedObjective(segments[6]);
yield return new WaitForSeconds(3f, false);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.GetWithVariable("Captain.Radio.Complete", "[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);
@@ -284,7 +284,9 @@ namespace Barotrauma.Tutorials
private bool IsSelectedItem(Item item)
{
return captain?.SelectedConstruction == item;
return
captain?.SelectedConstruction == item ||
(captain?.SelectedConstruction?.linkedTo?.Contains(item) ?? false);
}
}
}

View File

@@ -156,7 +156,7 @@ namespace Barotrauma.Tutorials
//yield return new WaitForSeconds(2.5f);
doctor.SetStun(1.5f);
var explosion = new Explosion(range: 100, force: 10, damage: 0, structureDamage: 0);
var explosion = new Explosion(range: 100, force: 10, damage: 0, structureDamage: 0, itemDamage: 0);
explosion.DisableParticles();
GameMain.GameScreen.Cam.Shake = shakeAmount;
explosion.Explode(Character.Controlled.WorldPosition - Vector2.UnitX * 25, null);

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Xml.Linq;
using System.Linq;
using Barotrauma.Items.Components;

View File

@@ -2,7 +2,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;

View File

@@ -515,7 +515,7 @@ namespace Barotrauma.Tutorials
height += (int)GUI.Font.MeasureString(title).Y + (int)(150 * GUI.Scale);
}
var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), style: null, Color.Black * 0.5f);
var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), style: "GUIBackgroundBlocker");
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), background.RectTransform, anchor));
infoBlock.Flash(GUI.Style.Green);
@@ -533,15 +533,15 @@ namespace Barotrauma.Tutorials
titleBlock.RectTransform.IsFixedSize = true;
}
List<ColorData> colorData = ColorData.GetColorData(text, out text);
List<RichTextData> richTextData = RichTextData.GetRichTextData(text, out text);
GUITextBlock textBlock;
if (colorData == null)
if (richTextData == null)
{
textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), " " + text, wrap: true);
}
else
{
textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), colorData, " " + text, wrap: true);
textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoContent.RectTransform), richTextData, " " + text, wrap: true);
}
textBlock.RectTransform.IsFixedSize = true;

View File

@@ -1,159 +1,41 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
partial class GameSession
{
private InfoFrameTab selectedTab;
private GUIFrame infoFrame;
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
private GUIFrame infoFrameContent;
public RoundSummary RoundSummary { get; private set; }
public static bool IsInfoFrameOpen => GameMain.GameSession?.infoFrame != null;
public static bool IsTabMenuOpen => GameMain.GameSession?.tabMenu != null;
public static TabMenu TabMenuInstance => GameMain.GameSession?.tabMenu;
private bool ToggleInfoFrame()
private TabMenu tabMenu;
public bool ToggleTabMenu()
{
if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
{
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
}
if (infoFrame == null)
if (tabMenu == null && GameMode is TutorialMode == false)
{
CreateInfoFrame();
SelectInfoFrameTab(null, selectedTab);
tabMenu = new TabMenu();
}
else
{
infoFrame = null;
tabMenu = null;
NetLobbyScreen.JobInfoFrame = null;
}
return true;
}
public void CreateInfoFrame()
{
int width = 600, height = 400;
tabButtons.Clear();
infoFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.35f), infoFrame.RectTransform, Anchor.Center) { MinSize = new Point(width, height), RelativeOffset = new Vector2(0.0f, 0.033f) });
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center), style: null);
var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedFrame.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.01f
};
infoFrameContent = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.85f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.08f) }, style: "InnerFrame");
var crewButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("Crew"), style: "GUITabButton")
{
UserData = InfoFrameTab.Crew,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(crewButton);
var missionButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("Mission"), style: "GUITabButton")
{
UserData = InfoFrameTab.Mission,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(missionButton);
if (GameMain.NetworkMember != null)
{
var myCharacterButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("MyCharacter"), style: "GUITabButton")
{
UserData = InfoFrameTab.MyCharacter,
OnClicked = SelectInfoFrameTab
};
tabButtons.Add(myCharacterButton);
}
/*TODO: fix
if (GameMain.Server != null)
{
var manageButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), TextManager.Get("ManagePlayers"))
{
UserData = InfoFrameTab.ManagePlayers,
OnClicked = SelectInfoFrameTab
};
}*/
}
private bool SelectInfoFrameTab(GUIButton button, object userData)
{
selectedTab = (InfoFrameTab)userData;
CreateInfoFrame();
tabButtons.ForEach(tb => tb.Selected = (InfoFrameTab)tb.UserData == selectedTab);
switch (selectedTab)
{
case InfoFrameTab.Crew:
CrewManager.CreateCrewListFrame(CrewManager.GetCharacters(), infoFrameContent);
break;
case InfoFrameTab.Mission:
CreateMissionInfo(infoFrameContent);
break;
case InfoFrameTab.MyCharacter:
if (GameMain.NetworkMember == null) { return false; }
GameMain.NetLobbyScreen.CreatePlayerFrame(infoFrameContent);
break;
case InfoFrameTab.ManagePlayers:
//TODO: fix
//GameMain.Server.ManagePlayersFrame(infoFrameContent);
break;
}
return true;
}
private void CreateMissionInfo(GUIFrame infoFrame)
{
infoFrameContent.ClearChildren();
var isTraitor = GameMain.Client?.Character?.IsTraitor ?? false;
var missionFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, isTraitor ? 0.95f : 0.45f), infoFrameContent.RectTransform))
{
RelativeSpacing = 0.05f
};
if (Mission != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), Mission.Name, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), TextManager.GetWithVariable("MissionReward", "[reward]", Mission.Reward.ToString()));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), Mission.Description, wrap: true);
}
else
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform, Anchor.TopCenter), TextManager.Get("NoMission"), font: GUI.LargeFont);
}
if (isTraitor)
{
var traitorFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.45f), infoFrameContent.RectTransform, Anchor.BottomLeft))
{
RelativeSpacing = 0.05f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorFrame.RectTransform), TextManager.Get("Traitors"), font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorFrame.RectTransform), GameMain.Client.Character.TraitorCurrentObjective, wrap: true);
}
}
public void AddToGUIUpdateList()
{
if (GUI.DisableHUD) return;
GameMode?.AddToGUIUpdateList();
infoFrame?.AddToGUIUpdateList();
tabMenu?.AddToGUIUpdateList();
if (GameMain.NetworkMember != null)
{
@@ -166,17 +48,31 @@ namespace Barotrauma
{
if (GUI.DisableHUD) return;
if (PlayerInput.KeyDown(InputType.InfoTab) &&
(GUI.KeyboardDispatcher.Subscriber == null || GUI.KeyboardDispatcher.Subscriber is GUIListBox))
if (GameMode.IsRunning)
{
if (infoFrame == null)
if (tabMenu == null)
{
ToggleInfoFrame();
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
{
ToggleTabMenu();
}
}
else
{
tabMenu.Update();
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
{
ToggleTabMenu();
}
}
}
else if (infoFrame != null)
else
{
ToggleInfoFrame();
if (tabMenu != null)
{
ToggleTabMenu();
}
}
if (GameMain.NetworkMember != null)
@@ -202,9 +98,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch)
{
if (GUI.DisableHUD) return;
GameMode?.Draw(spriteBatch);
//infoFrame?.DrawManually(spriteBatch);
}
}
}

View File

@@ -32,7 +32,9 @@ namespace Barotrauma
SoundPlayer.OverrideMusicDuration = 18.0f;
}
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
GUIFrame background = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, background.RectTransform, Anchor.Center), style: null)
{
UserData = "roundsummary"
};

View File

@@ -18,6 +18,7 @@ namespace Barotrauma
{
Graphics,
Audio,
VoiceChat,
Controls,
#if DEBUG
Debug
@@ -43,6 +44,8 @@ namespace Barotrauma
}
}
private const int inventoryHotkeyCount = 10;
public void SetDefaultBindings(XDocument doc = null, bool legacy = false)
{
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
@@ -60,6 +63,7 @@ namespace Barotrauma
keyMapping[(int)InputType.CrewOrders] = new KeyOrMouse(Keys.C);
keyMapping[(int)InputType.Voice] = new KeyOrMouse(Keys.V);
keyMapping[(int)InputType.LocalVoice] = new KeyOrMouse(Keys.B);
keyMapping[(int)InputType.Command] = new KeyOrMouse(MouseButton.MiddleMouse);
if (Language == "French")
@@ -98,6 +102,13 @@ namespace Barotrauma
keyMapping[(int)InputType.Select] = new KeyOrMouse(MouseButton.PrimaryMouse);
// shoot and deselect are handled in CheckBindings() so that we don't override the legacy settings.
}
inventoryKeyMapping = new KeyOrMouse[inventoryHotkeyCount];
for (int i = 0; i < inventoryKeyMapping.Length; i++)
{
inventoryKeyMapping[i] = new KeyOrMouse(Keys.D0 + (i + 1) % 10);
}
if (doc != null)
{
LoadControls(doc);
@@ -177,6 +188,26 @@ namespace Barotrauma
}
}
private void LoadInventoryKeybinds(XElement element)
{
for (int i = 0; i < inventoryKeyMapping.Length; i++)
{
XAttribute attribute = element.Attributes().ElementAt(i);
if (int.TryParse(attribute.Value.ToString(), out int mouseButtonInt))
{
inventoryKeyMapping[i] = new KeyOrMouse((MouseButton)mouseButtonInt);
}
else if (Enum.TryParse(attribute.Value.ToString(), true, out MouseButton mouseButton))
{
inventoryKeyMapping[i] = new KeyOrMouse(mouseButton);
}
else if (Enum.TryParse(attribute.Value.ToString(), true, out Keys key))
{
inventoryKeyMapping[i] = new KeyOrMouse(key);
}
}
}
private void LoadControls(XDocument doc)
{
XElement keyMapping = doc.Root.Element("keymapping");
@@ -184,6 +215,12 @@ namespace Barotrauma
{
LoadKeyBinds(keyMapping);
}
XElement inventoryKeyMapping = doc.Root.Element("inventorykeymapping");
if (inventoryKeyMapping != null)
{
LoadInventoryKeybinds(inventoryKeyMapping);
}
}
public KeyOrMouse KeyBind(InputType inputType)
@@ -193,25 +230,14 @@ namespace Barotrauma
public string KeyBindText(InputType inputType)
{
KeyOrMouse bind = keyMapping[(int)inputType];
if (bind.MouseButton != MouseButton.None)
{
switch (bind.MouseButton)
{
case MouseButton.PrimaryMouse:
return PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.rightmouse") : TextManager.Get("input.leftmouse");
case MouseButton.SecondaryMouse:
return PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.leftmouse") : TextManager.Get("input.rightmouse");
default:
return TextManager.Get("input." + bind.MouseButton.ToString().ToLowerInvariant());
}
}
return bind.ToString();
return keyMapping[(int)inputType].Name;
}
public KeyOrMouse InventoryKeyBind(int index)
{
return inventoryKeyMapping[index];
}
private GUIListBox contentPackageList;
private bool ChangeSliderText(GUIScrollBar scrollBar, float barScroll)
@@ -257,7 +283,8 @@ namespace Barotrauma
}
else
{
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null, color: Color.Black * 0.5f);
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, settingsFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
var settingsFrameContent = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), settingsFrame.RectTransform, Anchor.Center));
settingsHolder = settingsFrameContent.RectTransform;
}
@@ -290,6 +317,25 @@ namespace Barotrauma
ButtonEnabled = ContentPackage.List.Count(cp => cp.CorePackage) > 1
};
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform), isHorizontal: true)
{
Stretch = true
};
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) =>
{
foreach (GUIComponent child in contentPackageList.Content.Children)
{
if (!(child.UserData is ContentPackage cp)) { continue; }
child.Visible = string.IsNullOrEmpty(text) ? true : cp.Name.ToLower().Contains(text.ToLower());
}
return true;
};
contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.70f), leftPanel.RectTransform))
{
OnSelected = (gc, obj) => false,
@@ -443,11 +489,13 @@ namespace Barotrauma
UserData = tab
};
float tabWidth = 0.25f;
#if DEBUG
tabWidth = 0.2f;
if (tab != Tab.Debug)
{
#endif
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform),
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(tabWidth, 1.0f), tabButtonHolder.RectTransform),
TextManager.Get("SettingsTab." + tab.ToString()), style: "GUITabButton")
{
UserData = tab,
@@ -457,7 +505,7 @@ namespace Barotrauma
}
else
{
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tabButtonHolder.RectTransform), "Debug", style: "GUITabButton")
tabButtons[(int)tab] = new GUIButton(new RectTransform(new Vector2(tabWidth, 1.0f), tabButtonHolder.RectTransform), "Debug", style: "GUITabButton")
{
UserData = tab,
OnClicked = (bt, userdata) => { SelectTab((Tab)userdata); return true; }
@@ -547,6 +595,37 @@ namespace Barotrauma
};
GUITickBox textureCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale, leftColumn.RectTransform), TextManager.Get("EnableTextureCompression"))
{
ToolTip = TextManager.Get("EnableTextureCompressionToolTip"),
OnSelected = (GUITickBox box) =>
{
if (box.Selected == TextureCompressionEnabled) { return true; }
bool prevTextureCompressionEnabled = TextureCompressionEnabled;
TextureCompressionEnabled = box.Selected;
var msgBox = new GUIMessageBox(
TextManager.Get("RestartRequiredLabel"),
TextManager.Get("RestartRequiredGeneric"),
buttons: new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked += (btn, userdata) =>
{
ApplySettings();
GameMain.Instance.Exit();
return true;
}; msgBox.Buttons[1].OnClicked += (btn, userdata) =>
{
TextureCompressionEnabled = prevTextureCompressionEnabled;
box.Selected = prevTextureCompressionEnabled;
msgBox.Close();
return true;
};
return true;
},
Selected = TextureCompressionEnabled
};
GUITickBox pauseOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, leftColumn.RectTransform),
TextManager.Get("PauseOnFocusLost"))
{
@@ -608,7 +687,8 @@ namespace Barotrauma
{
ChangeSliderText(scrollBar, barScroll);
LightMapScale = MathHelper.Lerp(0.2f, 1.0f, barScroll);
UnsavedSettings = true; return true;
UnsavedSettings = true;
return true;
},
Step = 0.25f
};
@@ -677,10 +757,10 @@ namespace Barotrauma
var audioContent = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.97f), tabs[(int)Tab.Audio].RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
Stretch = false,
RelativeSpacing = 0.01f
};
GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(textBlockScale, audioContent.RectTransform), TextManager.Get("SoundVolume"), font: GUI.SubHeadingFont);
GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(textBlockScale, audioContent.RectTransform),
style: "GUISlider", barSize: 0.05f)
@@ -718,15 +798,16 @@ namespace Barotrauma
style: "GUISlider", barSize: 0.05f)
{
UserData = voiceChatVolumeText,
BarScroll = VoiceChatVolume,
OnMoved = (scrollBar, scroll) =>
{
ChangeSliderText(scrollBar, scroll);
VoiceChatVolume = scroll;
return true;
},
Range = new Vector2(0.0f, 2.0f),
Step = 0.05f
};
voiceChatScrollBar.BarScrollValue = VoiceChatVolume;
voiceChatScrollBar.OnMoved = (scrollBar, scroll) =>
{
ChangeSliderText(scrollBar, scrollBar.BarScrollValue);
VoiceChatVolume = scrollBar.BarScrollValue;
return true;
};
voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll);
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, audioContent.RectTransform), TextManager.Get("MuteOnFocusLost"))
@@ -765,7 +846,15 @@ namespace Barotrauma
}
};
new GUITextBlock(new RectTransform(textBlockScale, audioContent.RectTransform), TextManager.Get("VoiceChat"), font: GUI.SubHeadingFont);
/// Voice chat tab ----------------------------------------------------------------
var voiceChatContent = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.97f), tabs[(int)Tab.VoiceChat].RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = false,
RelativeSpacing = 0.01f
};
//new GUITextBlock(new RectTransform(textBlockScale, voiceChatContent.RectTransform), TextManager.Get("VoiceChat"), font: GUI.SubHeadingFont);
CaptureDeviceNames = Alc.GetStringList((IntPtr)null, Alc.CaptureDeviceSpecifier);
foreach (string name in CaptureDeviceNames)
@@ -773,7 +862,7 @@ namespace Barotrauma
DebugConsole.NewMessage(name + " " + name.Length.ToString(), Color.Lime);
}
GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(tickBoxScale, audioContent.RectTransform), TextManager.Get("DirectionalVoiceChat"))
GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(tickBoxScale, voiceChatContent.RectTransform), TextManager.Get("DirectionalVoiceChat"))
{
Selected = UseDirectionalVoiceChat,
ToolTip = TextManager.Get("DirectionalVoiceChatToolTip"),
@@ -794,7 +883,7 @@ namespace Barotrauma
VoiceSetting = VoiceMode.Disabled;
}
#if (!OSX)
var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), audioContent.RectTransform), TrimAudioDeviceName(VoiceCaptureDevice), CaptureDeviceNames.Count);
var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), voiceChatContent.RectTransform), TrimAudioDeviceName(VoiceCaptureDevice), CaptureDeviceNames.Count);
if (CaptureDeviceNames?.Count > 0)
{
foreach (string name in CaptureDeviceNames)
@@ -819,7 +908,7 @@ namespace Barotrauma
}
#else
var defaultDeviceGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.3f), audioContent.RectTransform), true, Anchor.CenterLeft);
var defaultDeviceGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.3f), voiceChatContent.RectTransform), true, Anchor.CenterLeft);
var currentDeviceTextBlock = new GUITextBlock(new RectTransform(new Vector2(.7f, 0.75f), null),
TextManager.AddPunctuation(':', TextManager.Get("CurrentDevice"), TrimAudioDeviceName(VoiceCaptureDevice)), font: GUI.SubHeadingFont)
{
@@ -857,15 +946,15 @@ namespace Barotrauma
#endif
var voiceModeCount = Enum.GetNames(typeof(VoiceMode)).Length;
var voiceModeDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), audioContent.RectTransform), elementCount: voiceModeCount);
var voiceModeDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), voiceChatContent.RectTransform), elementCount: voiceModeCount);
for (int i = 0; i < voiceModeCount; i++)
{
var voiceMode = "VoiceMode." + ((VoiceMode)i).ToString();
voiceModeDropDown.AddItem(TextManager.Get(voiceMode), userData: i, toolTip: TextManager.Get(voiceMode + "ToolTip"));
}
var micVolumeText = new GUITextBlock(new RectTransform(textBlockScale, audioContent.RectTransform), TextManager.Get("MicrophoneVolume"), font: GUI.SubHeadingFont);
var micVolumeSlider = new GUIScrollBar(new RectTransform(textBlockScale, audioContent.RectTransform),
var micVolumeText = new GUITextBlock(new RectTransform(textBlockScale, voiceChatContent.RectTransform), TextManager.Get("MicrophoneVolume"), font: GUI.SubHeadingFont);
var micVolumeSlider = new GUIScrollBar(new RectTransform(textBlockScale, voiceChatContent.RectTransform),
style: "GUISlider", barSize: 0.05f)
{
UserData = micVolumeText,
@@ -882,7 +971,7 @@ namespace Barotrauma
};
micVolumeSlider.OnMoved(micVolumeSlider, micVolumeSlider.BarScroll);
var extraVoiceSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), audioContent.RectTransform, Anchor.BottomCenter), style: null);
var extraVoiceSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), voiceChatContent.RectTransform, Anchor.BottomCenter), style: null);
var voiceActivityGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), extraVoiceSettingsContainer.RectTransform))
{
@@ -928,8 +1017,8 @@ namespace Barotrauma
return true;
};
var voiceInputContainer = new GUILayoutGroup(
new RectTransform(new Vector2(1.0f, 0.25f), extraVoiceSettingsContainer.RectTransform)
var voiceInputContainerHorizontal = new GUILayoutGroup(
new RectTransform(new Vector2(1.0f, 0.5f), extraVoiceSettingsContainer.RectTransform)
{
RelativeOffset = new Vector2(0.0f, voiceActivityGroup.RectTransform.RelativeSize.Y + 0.1f)
},
@@ -937,6 +1026,11 @@ namespace Barotrauma
{
Visible = VoiceSetting == VoiceMode.PushToTalk
};
var voiceInputContainer = new GUILayoutGroup(
new RectTransform(new Vector2(0.5f, 1.0f), voiceInputContainerHorizontal.RectTransform),
isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice"), font: GUI.SubHeadingFont);
var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.Voice))
{
@@ -945,6 +1039,39 @@ namespace Barotrauma
};
voiceKeyBox.OnSelected += KeyBoxSelected;
var localVoiceInputContainer = new GUILayoutGroup(
new RectTransform(new Vector2(0.5f, 1.0f), voiceInputContainerHorizontal.RectTransform),
isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), localVoiceInputContainer.RectTransform), TextManager.Get("InputType.LocalVoice"), font: GUI.SubHeadingFont);
var localVoiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), localVoiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.LocalVoice))
{
SelectedColor = Color.Gold * 0.3f,
UserData = InputType.LocalVoice
};
localVoiceKeyBox.OnSelected += KeyBoxSelected;
var cutoffPreventionText = new GUITextBlock(new RectTransform(textBlockScale, voiceChatContent.RectTransform), TextManager.Get("CutoffPrevention"), font: GUI.SubHeadingFont)
{
ToolTip = TextManager.Get("CutoffPreventionTooltip")
};
var cutoffPreventionSlider = new GUIScrollBar(new RectTransform(textBlockScale, voiceChatContent.RectTransform),
style: "GUISlider", barSize: 0.05f)
{
UserData = micVolumeText,
Range = new Vector2(0,540),
Step = 1.0f / 9.0f
};
cutoffPreventionSlider.BarScrollValue = VoiceChatCutoffPrevention;
cutoffPreventionSlider.OnMoved = (scrollBar, scroll) =>
{
VoiceChatCutoffPrevention = (int)scrollBar.BarScrollValue;
cutoffPreventionText.Text = TextManager.Get("CutoffPrevention") +
" " + TextManager.GetWithVariable("timeformatmilliseconds", "[milliseconds]", VoiceChatCutoffPrevention.ToString());
return true;
};
cutoffPreventionSlider.OnMoved(cutoffPreventionSlider, cutoffPreventionSlider.BarScrollValue);
voiceModeDropDown.OnSelected = (GUIComponent selected, object userData) =>
{
try
@@ -961,7 +1088,7 @@ namespace Barotrauma
{
VoiceSetting = vMode = VoiceMode.Disabled;
voiceActivityGroup.Visible = false;
voiceInputContainer.Visible = false;
voiceInputContainerHorizontal.Visible = false;
return true;
}
}
@@ -977,7 +1104,7 @@ namespace Barotrauma
noiseGateText.Visible = (vMode == VoiceMode.Activity);
noiseGateSlider.Visible = (vMode == VoiceMode.Activity);
voiceActivityGroup.Visible = (vMode != VoiceMode.Disabled);
voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk);
voiceInputContainerHorizontal.Visible = (vMode == VoiceMode.PushToTalk);
UnsavedSettings = true;
}
catch (Exception e)
@@ -1062,6 +1189,24 @@ namespace Barotrauma
keyBox.SelectedColor = Color.Gold * 0.3f;
}
for (int i = 0; i < inventoryHotkeyCount; i++)
{
var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), ((i + 1) <= inventoryHotkeyCount / 2 ? inputColumnLeft : inputColumnRight).RectTransform))
{ Stretch = true, IsHorizontal = true, RelativeSpacing = 0.01f, Color = new Color(12, 14, 15, 215) };
var inputName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(100, 0) },
TextManager.GetWithVariable("inventoryslotkeybind", "[slotnumber]", (i + 1).ToString()), font: GUI.SmallFont)
{ ForceUpperCase = true };
inputNameBlocks.Add(inputName);
var keyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), inputContainer.RectTransform),
text: inventoryKeyMapping[i].Name, font: GUI.SmallFont, style: "GUITextBoxNoIcon")
{
UserData = i
};
keyBox.Text = ToolBox.LimitString(keyBox.Text, keyBox.Font, (int)(keyBox.Rect.Width - keyBox.Padding.X - keyBox.Padding.Z));
keyBox.OnSelected += InventoryKeyBoxSelected;
keyBox.SelectedColor = Color.Gold * 0.3f;
}
GUITextBlock.AutoScaleAndNormalize(inputNameBlocks);
var resetControlsArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.07f), controlsLayoutGroup.RectTransform), style: null);
@@ -1302,7 +1447,7 @@ namespace Barotrauma
{
switch (tab)
{
case Tab.Audio:
case Tab.VoiceChat:
if (VoiceSetting != VoiceMode.Disabled)
{
if (GameMain.Client == null && VoipCapture.Instance == null)
@@ -1329,7 +1474,13 @@ namespace Barotrauma
private void KeyBoxSelected(GUITextBox textBox, Keys key)
{
textBox.Text = "";
CoroutineManager.StartCoroutine(WaitForKeyPress(textBox));
CoroutineManager.StartCoroutine(WaitForKeyPress(textBox, keyMapping));
}
private void InventoryKeyBoxSelected(GUITextBox textBox, Keys key)
{
textBox.Text = "";
CoroutineManager.StartCoroutine(WaitForKeyPress(textBox, inventoryKeyMapping));
}
private void ResetControls(bool legacy)
@@ -1425,7 +1576,7 @@ namespace Barotrauma
return true;
}
private IEnumerable<object> WaitForKeyPress(GUITextBox keyBox)
private IEnumerable<object> WaitForKeyPress(GUITextBox keyBox, KeyOrMouse[] keyArray)
{
yield return CoroutineStatus.Running;
@@ -1449,42 +1600,43 @@ namespace Barotrauma
if (PlayerInput.LeftButtonClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.LeftMouse);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.LeftMouse);
}
else if (PlayerInput.RightButtonClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.RightMouse);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.RightMouse);
}
else if (PlayerInput.MidButtonClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.MiddleMouse);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.MiddleMouse);
}
else if (PlayerInput.Mouse4ButtonClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.MouseButton4);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.MouseButton4);
}
else if (PlayerInput.Mouse5ButtonClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.MouseButton5);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.MouseButton5);
}
else if (PlayerInput.MouseWheelUpClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.MouseWheelUp);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.MouseWheelUp);
}
else if (PlayerInput.MouseWheelDownClicked())
{
keyMapping[keyIndex] = new KeyOrMouse(MouseButton.MouseWheelDown);
keyArray[keyIndex] = new KeyOrMouse(MouseButton.MouseWheelDown);
}
else if (PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0)
{
Keys key = PlayerInput.GetKeyboardState.GetPressedKeys()[0];
keyMapping[keyIndex] = new KeyOrMouse(key);
keyArray[keyIndex] = new KeyOrMouse(key);
}
else
{
yield return CoroutineStatus.Success;
}
keyBox.Text = KeyBindText((InputType)keyIndex);
keyBox.Text = keyArray[keyIndex].Name;
keyBox.Text = ToolBox.LimitString(keyBox.Text, keyBox.Font, keyBox.Rect.Width);
keyBox.Deselect();

View File

@@ -345,9 +345,7 @@ namespace Barotrauma
{
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
hideButton.RectTransform.NonScaledSize = new Point(HideButtonWidth, HUDLayoutSettings.BottomRightInfoArea.Height);
hideButton.RectTransform.AbsoluteOffset = new Point(
personalSlotArea.Right + Spacing * 2,
HUDLayoutSettings.BottomRightInfoArea.Y);
hideButton.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.BottomRightInfoArea.Left - HideButtonWidth + GUI.IntScaleCeiling(2f), HUDLayoutSettings.BottomRightInfoArea.Y + GUI.IntScaleCeiling(1f));
hideButton.Visible = true;
SetIndicatorSizes();
@@ -356,7 +354,6 @@ namespace Barotrauma
break;
case Layout.Right:
{
int extraOffset = 0;
int x = HUDLayoutSettings.InventoryAreaLower.Right;
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
for (int i = 0; i < slots.Length; i++)
@@ -373,17 +370,18 @@ namespace Barotrauma
}
int lowerX = x;
int personalSlotY = GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2 - (int)(!GUI.IsFourByThree() ? UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment : UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment * 2f);
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - extraOffset - Spacing * 2);
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
personalSlotX -= slots[i].Rect.Width + Spacing;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + Spacing;
}
}
@@ -393,7 +391,7 @@ namespace Barotrauma
{
if (!HideSlot(i)) continue;
x -= slots[i].Rect.Width + Spacing;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset - extraOffset);
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
}
}
break;
@@ -401,12 +399,14 @@ namespace Barotrauma
{
int x = HUDLayoutSettings.InventoryAreaLower.X;
int personalSlotX = x;
int personalSlotY = GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2 - (int)(!GUI.IsFourByThree() ? UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment : UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment * 2f);
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2);
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
personalSlotX += slots[i].Rect.Width + Spacing;
}
else
@@ -493,7 +493,7 @@ namespace Barotrauma
((selectedSlot != null && selectedSlot.IsSubSlot) || (draggingItem != null && (draggingSlot == null || !draggingSlot.MouseOn())));
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
if (layout == Layout.Default)
if (layout == Layout.Default && (Screen.Selected != GameMain.SubEditorScreen || Screen.Selected is SubEditorScreen editor && editor.WiringMode))
{
if (hideButton.Visible)
{
@@ -525,8 +525,7 @@ namespace Barotrauma
for (int i = 0; i < capacity; i++)
{
if (Items[i] != null && Items[i] != draggingItem && Character.Controlled?.Inventory == this &&
GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen &&
slots[i].QuickUseKey != Keys.None && PlayerInput.KeyHit(slots[i].QuickUseKey))
GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen && PlayerInput.InventoryKeyHit(slots[i].InventoryKeyIndex))
{
QuickUseItem(Items[i], true, false, true);
}
@@ -586,6 +585,19 @@ namespace Barotrauma
}
}
}
// In sub editor we cannot hover over the slot because they are not rendered so we override it here
if (Screen.Selected is SubEditorScreen subEditor && !subEditor.WiringMode)
{
for (int i = 0; i < slots.Length; i++)
{
var subInventory = GetSubInventory(i);
if (subInventory != null)
{
ShowSubInventory(new SlotReference(this, slots[i], i, false, Items[i].GetComponent<ItemContainer>().Inventory), deltaTime, cam, hideSubInventories, true);
}
}
}
foreach (var subInventorySlot in hideSubInventories)
{
@@ -771,21 +783,16 @@ namespace Barotrauma
}
}
private void AssignQuickUseNumKeys()
public void AssignQuickUseNumKeys()
{
int num = 1;
int keyBindIndex = 0;
for (int i = 0; i < slots.Length; i++)
{
if (HideSlot(i))
{
slots[i].QuickUseKey = Keys.None;
continue;
}
if (HideSlot(i)) continue;
if (SlotTypes[i] == InvSlotType.Any)
{
slots[i].QuickUseKey = Keys.D0 + num % 10;
num++;
slots[i].InventoryKeyIndex = keyBindIndex;
keyBindIndex++;
}
}
}
@@ -808,16 +815,21 @@ namespace Barotrauma
{
if (item.Container == null || character.Inventory.FindIndex(item.Container) == -1) // Not a subinventory in the character's inventory
{
return item.ParentInventory is CharacterInventory ?
QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)))
{
return QuickUseAction.PutToEquippedItem;
}
else
{
return item.ParentInventory is CharacterInventory ? QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
}
}
else
{
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
if (selectedContainer != null &&
selectedContainer.Inventory != null &&
!selectedContainer.Inventory.Locked &&
allowInventorySwap)
!selectedContainer.Inventory.Locked)
{
// Move the item from the subinventory to the selected container
return QuickUseAction.PutToContainer;
@@ -854,7 +866,7 @@ namespace Barotrauma
{
return QuickUseAction.TakeFromCharacter;
}
else if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)))
else if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)) && allowInventorySwap)
{
return QuickUseAction.PutToEquippedItem;
}
@@ -882,13 +894,40 @@ namespace Barotrauma
private void QuickUseItem(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
{
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && !Submarine.Unloading)
{
// Find the slot the item was contained in and flash it
if (item.ParentInventory?.slots != null)
{
var invSlots = item.ParentInventory.slots;
var invItems = item.ParentInventory.Items;
for (int i = 0; i < invSlots.Length; i++)
{
if (i < 0 || invSlots.Length <= i || i < 0 || invItems.Length <= i) { break; }
var slot = invSlots[i];
var slotItem = invItems[i];
if (slotItem == item)
{
slot.ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.4f);
GUI.PlayUISound(GUISoundType.PickItem);
break;
}
}
}
item.Remove();
return;
}
var quickUseAction = GetQuickUseAction(item, allowEquip, allowInventorySwap, allowApplyTreatment);
bool success = false;
switch (quickUseAction)
{
case QuickUseAction.Equip:
//attempt to put in a free slot first
for (int i = 0; i < capacity; i++)
for (int i = capacity - 1; i >= 0; i--)
{
if (Items[i] != null) continue;
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) continue;
@@ -898,11 +937,11 @@ namespace Barotrauma
if (!success)
{
for (int i = 0; i < capacity; i++)
for (int i = capacity - 1; i >= 0; i--)
{
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) continue;
//something else already equipped in the slot, attempt to unequip it
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any))
// something else already equipped in a hand slot, attempt to unequip it so items aren't unnecessarily swapped to it
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any) && SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand)
{
TryPutItem(Items[i], Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
}
@@ -1003,6 +1042,7 @@ namespace Barotrauma
prevUIScale != UIScale ||
prevHUDScale != GUI.Scale)
{
CreateSlots();
SetSlotPositions(layout);
prevUIScale = UIScale;
prevHUDScale = GUI.Scale;

View File

@@ -237,6 +237,7 @@ namespace Barotrauma.Items.Components
{
StopPicking(null);
PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse);
if (isOpen) { stuck = MathHelper.Clamp(stuck - StuckReductionOnOpen, 0.0f, 100.0f); }
}
}
}
@@ -245,7 +246,8 @@ namespace Barotrauma.Items.Components
{
base.ClientRead(type, msg, sendingTime);
bool open = msg.ReadBoolean();
bool open = msg.ReadBoolean();
bool broken = msg.ReadBoolean();
bool forcedOpen = msg.ReadBoolean();
SetState(open, isNetworkMessage: true, sendNetworkMessage: false, forcedOpen: forcedOpen);
Stuck = msg.ReadRangedSingle(0.0f, 100.0f, 8);
@@ -258,6 +260,7 @@ namespace Barotrauma.Items.Components
}
if (isStuck) { OpenState = 0.0f; }
IsBroken = broken;
PredictedState = null;
}
}

View File

@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
@@ -52,5 +53,13 @@ namespace Barotrauma.Items.Components
}
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
CurrPowerConsumption = powerConsumption;
charging = true;
timer = Duration;
IsActive = true;
}
}
}

View File

@@ -71,6 +71,8 @@ namespace Barotrauma.Items.Components
base.ClientRead(type, msg, sendingTime);
bool shouldBeAttached = msg.ReadBoolean();
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
UInt16 submarineID = msg.ReadUInt16();
Submarine sub = Entity.FindEntityByID(submarineID) as Submarine;
if (!attachable)
{
@@ -84,6 +86,7 @@ namespace Barotrauma.Items.Components
{
Drop(false, null);
item.SetTransform(simPosition, 0.0f);
item.Submarine = sub;
AttachToWall();
}
}

View File

@@ -4,7 +4,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Text;
using System.Xml.Linq;

View File

@@ -4,7 +4,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
@@ -436,8 +436,7 @@ namespace Barotrauma.Items.Components
if (subElement.Attribute("color") != null) color = subElement.GetAttributeColor("color", Color.White);
string style = subElement.Attribute("style") == null ?
null : subElement.GetAttributeString("style", "");
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas, Anchor.Center), style, color);
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas.ItemComponentHolder, Anchor.Center), style, color);
DefaultLayout = GUILayoutSettings.Load(subElement);
break;
case "alternativelayout":

View File

@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
}
private string text;
[Serialize("", true, translationTextTag: "Label.", description: "The text displayed in the label."), Editable(100)]
[Serialize("", true, translationTextTag: "Label.", description: "The text displayed in the label.", alwaysUseInstanceValues: true), Editable(100)]
public string Text
{
get { return text; }
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
private set;
}
[Editable, Serialize("0,0,0,255", true, description: "The color of the text displayed on the label (R,G,B,A).")]
[Editable, Serialize("0,0,0,255", true, description: "The color of the text displayed on the label (R,G,B,A).", alwaysUseInstanceValues: true)]
public Color TextColor
{
get { return textColor; }
@@ -69,7 +69,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable(0.0f, 10.0f), Serialize(1.0f, true, description: "The scale of the text displayed on the label.")]
[Editable(0.0f, 10.0f), Serialize(1.0f, true, description: "The scale of the text displayed on the label.", alwaysUseInstanceValues: true)]
public float TextScale
{
get { return textBlock == null ? 1.0f : textBlock.TextScale; }

View File

@@ -48,7 +48,10 @@ namespace Barotrauma.Items.Components
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
{
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, item.Scale, SpriteEffects.None, item.SpriteDepth - 0.0001f);
Vector2 origin = light.LightSprite.Origin;
if (light.LightSpriteEffect == SpriteEffects.FlipHorizontally) { origin.X = light.LightSprite.SourceRect.Width - origin.X; }
if (light.LightSpriteEffect == SpriteEffects.FlipVertically) { origin.Y = light.LightSprite.SourceRect.Height - origin.Y; }
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, origin, -light.Rotation, item.Scale, light.LightSpriteEffect, item.SpriteDepth - 0.0001f);
}
}

View File

@@ -76,7 +76,7 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
state = msg.ReadBoolean();
State = msg.ReadBoolean();
ushort userID = msg.ReadUInt16();
if (userID == 0)
{

View File

@@ -16,6 +16,10 @@ namespace Barotrauma.Items.Components
private GUIScrollBar forceSlider;
private GUITickBox autoControlIndicator;
private int particlesPerSec = 60;
private float particleTimer;
public float AnimSpeed
{
get;

View File

@@ -318,10 +318,10 @@ namespace Barotrauma.Items.Components
{
if (item.ParentInventory.slots[availableSlotIndex].HighlightTimer <= 0.0f)
{
item.ParentInventory.slots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f);
item.ParentInventory.slots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
{
inputContainer.Inventory.slots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f);
inputContainer.Inventory.slots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
}
}
}
@@ -337,10 +337,22 @@ namespace Barotrauma.Items.Components
slotRect.Center.ToVector2(),
color: requiredItem.ItemPrefab.InventoryIconColor * 0.3f,
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X, slotRect.Bottom - 8, slotRect.Width, 8), Color.Black * 0.8f, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(slotRect.X, slotRect.Bottom - 8, (int)(slotRect.Width * requiredItem.MinCondition), 8),
GUI.Style.Green * 0.8f, true);
}
if (slotRect.Contains(PlayerInput.MousePosition))
{
string toolTipText = requiredItem.ItemPrefab.Name;
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
{
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
}
if (!string.IsNullOrEmpty(requiredItem.ItemPrefab.Description))
{
toolTipText += '\n' + requiredItem.ItemPrefab.Description;

View File

@@ -91,6 +91,7 @@ namespace Barotrauma.Items.Components
if ((item.Submarine == null && displayedSubs.Count > 0) || //item not inside a sub anymore, but display is still showing subs
!displayedSubs.Contains(item.Submarine) || //current sub not displayer
item.Submarine.DockedTo.Any(s => !displayedSubs.Contains(s)) || //some of the docked subs not diplayed
!submarineContainer.Children.Any() || // We lack a GUI
displayedSubs.Any(s => s != item.Submarine && !item.Submarine.DockedTo.Contains(s))) //displaying a sub that shouldn't be displayed
{
CreateHUD();
@@ -116,15 +117,17 @@ namespace Barotrauma.Items.Components
private void DrawHUDFront(SpriteBatch spriteBatch, GUICustomComponent container)
{
if (Voltage < MinVoltage)
{
{
Vector2 textSize = GUI.Font.MeasureString(noPowerTip);
Vector2 textPos = GuiFrame.Rect.Center.ToVector2();
GUI.DrawString(spriteBatch, textPos - textSize / 2, noPowerTip,
GUI.Style.Orange * (float)Math.Abs(Math.Sin(Timing.TotalTime)), Color.Black * 0.8f, font: GUI.SubHeadingFont);
GUI.Style.Orange * (float)Math.Abs(Math.Sin(Timing.TotalTime)), Color.Black * 0.8f, font: GUI.SubHeadingFont);
return;
}
if (!submarineContainer.Children.Any()) { return; }
foreach (GUIComponent child in submarineContainer.Children.First().Children)
{
if (child.UserData is Hull hull)
@@ -151,7 +154,7 @@ namespace Barotrauma.Items.Components
foreach (Hull hull in Hull.hullList)
{
var hullFrame = submarineContainer.Children.First().FindChild(hull);
var hullFrame = submarineContainer.Children.FirstOrDefault()?.FindChild(hull);
if (hullFrame == null) { continue; }
if (GUI.MouseOn == hullFrame || hullFrame.IsParentOf(GUI.MouseOn))
@@ -175,7 +178,7 @@ namespace Barotrauma.Items.Components
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null) continue;
var hullFrame = submarineContainer.Children.First().FindChild(hull);
var hullFrame = submarineContainer.Children.FirstOrDefault()?.FindChild(hull);
if (hullFrame == null) continue;
hullDatas.TryGetValue(hull, out HullData hullData);

View File

@@ -163,7 +163,7 @@ namespace Barotrauma.Items.Components
{
pumpSpeedLockTimer -= deltaTime;
isActiveLockTimer -= deltaTime;
autoControlIndicator.Selected = pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
autoControlIndicator.Selected = IsAutoControlled;
PowerButton.Enabled = isActiveLockTimer <= 0.0f;
if (HasPower)
{

View File

@@ -192,9 +192,10 @@ namespace Barotrauma.Items.Components
{
RelativeOffset = new Vector2(0, fissionMeter.RectTransform.RelativeOffset.Y + meterSize.Y)
},
style: "DeviceSlider", barSize: 0.1f)
style: "DeviceSlider", barSize: 0.15f)
{
Enabled = false,
Step = 1.0f / 255,
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
{
LastUser = Character.Controlled;
@@ -209,9 +210,10 @@ namespace Barotrauma.Items.Components
{
RelativeOffset = new Vector2(0, turbineMeter.RectTransform.RelativeOffset.Y + meterSize.Y)
},
style: "DeviceSlider", barSize: 0.1f, isHorizontal: true)
style: "DeviceSlider", barSize: 0.15f, isHorizontal: true)
{
Enabled = false,
Step = 1.0f / 255,
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
{
LastUser = Character.Controlled;
@@ -715,8 +717,14 @@ namespace Barotrauma.Items.Components
targetTurbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
degreeOfSuccess = msg.ReadRangedSingle(0.0f, 1.0f, 8);
FissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
TurbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
if (Math.Abs(FissionRateScrollBar.BarScroll - targetFissionRate / 100.0f) > 0.01f)
{
FissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
}
if (Math.Abs(TurbineOutputScrollBar.BarScroll - targetTurbineOutput / 100.0f) > 0.01f)
{
TurbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
}
IsActive = true;
}

View File

@@ -18,6 +18,8 @@ namespace Barotrauma.Items.Components
Disruption
}
private PathFinder pathFinder;
private bool dynamicDockingIndicator = true;
private bool unsentChanges;
@@ -45,7 +47,7 @@ namespace Barotrauma.Items.Components
private Sprite sonarBlip;
private Sprite lineSprite;
private Dictionary<string, Sprite> targetIcons = new Dictionary<string, Sprite>();
private readonly Dictionary<string, Sprite> targetIcons = new Dictionary<string, Sprite>();
private float displayBorderSize;
@@ -65,7 +67,23 @@ namespace Barotrauma.Items.Components
//Vector2 = vector from the ping source to the position of the disruption
//float = strength of the disruption, between 0-1
List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
private readonly List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
class CachedDistance
{
public readonly Vector2 TransducerWorldPos;
public readonly Vector2 WorldPos;
public readonly float Distance;
public CachedDistance(Vector2 transducerWorldPos, Vector2 worldPos, float dist)
{
TransducerWorldPos = transducerWorldPos;
WorldPos = worldPos;
Distance = dist;
}
}
private readonly Dictionary<object, CachedDistance> markerDistances = new Dictionary<object, CachedDistance>();
private readonly Color positiveColor = Color.Green;
private readonly Color warningColor = Color.Orange;
@@ -74,7 +92,7 @@ namespace Barotrauma.Items.Components
public static readonly Vector2 controlBoxSize = new Vector2(0.33f, 0.32f);
public static readonly Vector2 controlBoxOffset = new Vector2(0.025f, 0);
public static readonly float sonarAreaSize = 1.09f;
private static readonly float sonarAreaSize = 1.09f;
private static readonly Dictionary<BlipType, Color[]> blipColorGradient = new Dictionary<BlipType, Color[]>()
{
@@ -94,6 +112,8 @@ namespace Barotrauma.Items.Components
public float DisplayRadius { get; private set; }
public static Vector2 GUISizeCalculation => Vector2.One * Math.Min(GUI.RelativeHorizontalAspectRatio, 1f) * sonarAreaSize;
partial void InitProjSpecific(XElement element)
{
System.Diagnostics.Debug.Assert(Enum.GetValues(typeof(BlipType)).Cast<BlipType>().All(t => blipColorGradient.ContainsKey(t)));
@@ -254,7 +274,7 @@ namespace Barotrauma.Items.Components
controlContainer.RectTransform.SetPosition(Anchor.TopLeft);
sonarView.RectTransform.ScaleBasis = ScaleBasis.Smallest;
sonarView.RectTransform.SetPosition(Anchor.CenterRight);
sonarView.RectTransform.Resize(Vector2.One * GUI.RelativeHorizontalAspectRatio * sonarAreaSize);
sonarView.RectTransform.Resize(GUISizeCalculation);
GUITextBlock.AutoScaleAndNormalize(passiveTickBox.TextBlock, activeTickBox.TextBlock, zoomText, directionalModeSwitchText);
}
}
@@ -490,6 +510,7 @@ namespace Barotrauma.Items.Components
disruptedDirections.Clear();
foreach (AITarget t in AITarget.List)
{
if (t.Entity is Character c && c.Params.HideInSonar) { continue; }
if (t.SoundRange <= 0.0f || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; }
float distSqr = Vector2.DistanceSquared(t.WorldPosition, transducerCenter);
@@ -652,12 +673,16 @@ namespace Barotrauma.Items.Components
DrawMarker(spriteBatch,
GameMain.GameSession.StartLocation.Name,
"outpost",
(Level.Loaded.StartPosition - transducerCenter), displayScale, center, DisplayRadius);
GameMain.GameSession.StartLocation.Name,
Level.Loaded.StartPosition, transducerCenter,
displayScale, center, DisplayRadius);
DrawMarker(spriteBatch,
GameMain.GameSession.EndLocation.Name,
"outpost",
(Level.Loaded.EndPosition - transducerCenter), displayScale, center, DisplayRadius);
GameMain.GameSession.EndLocation.Name,
Level.Loaded.EndPosition, transducerCenter,
displayScale, center, DisplayRadius);
foreach (AITarget aiTarget in AITarget.List)
{
@@ -669,7 +694,9 @@ namespace Barotrauma.Items.Components
DrawMarker(spriteBatch,
aiTarget.SonarLabel,
aiTarget.SonarIconIdentifier,
aiTarget.WorldPosition - transducerCenter, displayScale, center, DisplayRadius * 0.975f);
aiTarget,
aiTarget.WorldPosition, transducerCenter,
displayScale, center, DisplayRadius * 0.975f);
}
}
@@ -684,7 +711,9 @@ namespace Barotrauma.Items.Components
DrawMarker(spriteBatch,
mission.SonarLabel,
mission.SonarIconIdentifier,
sonarPosition - transducerCenter, displayScale, center, DisplayRadius * 0.95f);
mission,
sonarPosition, transducerCenter,
displayScale, center, DisplayRadius * 0.95f);
}
}
}
@@ -701,9 +730,10 @@ namespace Barotrauma.Items.Components
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
DrawMarker(spriteBatch,
sub.Info.Name,
sub.Info.DisplayName,
sub.Info.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
sub.WorldPosition - transducerCenter,
sub,
sub.WorldPosition, transducerCenter,
displayScale, center, DisplayRadius * 0.95f);
}
@@ -801,8 +831,11 @@ namespace Barotrauma.Items.Components
{
if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
if (dockingPort.Item.Submarine == null) { continue; }
if (dockingPort.Item.Submarine.Info.IsWreck) { continue; }
//don't show the docking ports of the opposing team on the sonar
if (item.Submarine != null && dockingPort.Item.Submarine != null)
if (item.Submarine != null)
{
if ((dockingPort.Item.Submarine.TeamID == Character.TeamType.Team1 && item.Submarine.TeamID == Character.TeamType.Team2) ||
(dockingPort.Item.Submarine.TeamID == Character.TeamType.Team2 && item.Submarine.TeamID == Character.TeamType.Team1))
@@ -947,14 +980,13 @@ namespace Barotrauma.Items.Components
}
foreach (AITarget aiTarget in AITarget.List)
{
if (aiTarget.SonarDisruption <= 0.0f || !aiTarget.Enabled) { continue; }
float disruption = aiTarget.Entity is Character c ? c.Params.SonarDisruption : aiTarget.SonarDisruption;
if (disruption <= 0.0f || !aiTarget.Enabled) { continue; }
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
if (distSqr > worldPingRadiusSqr) { continue; }
float disruptionDist = (float)Math.Sqrt(distSqr);
disruptedDirections.Add(new Pair<Vector2, float>((aiTarget.WorldPosition - pingSource) / disruptionDist, aiTarget.SonarDisruption));
CreateBlipsForDisruption(aiTarget.WorldPosition, aiTarget.SonarDisruption);
CreateBlipsForDisruption(aiTarget.WorldPosition, disruption);
}
}
@@ -1127,6 +1159,7 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.CurrentHull != null || !c.Enabled) { continue; }
if (c.Params.HideInSonar) { continue; }
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) { continue; }
if (c.AnimController.SimplePhysicsEnabled)
@@ -1298,9 +1331,42 @@ namespace Barotrauma.Items.Components
sonarBlip.Draw(spriteBatch, center + pos, color * 0.5f, sonarBlip.Origin, 0, scale * 0.08f, SpriteEffects.None, 0);
}
private void DrawMarker(SpriteBatch spriteBatch, string label, string iconIdentifier, Vector2 position, float scale, Vector2 center, float radius)
private void DrawMarker(SpriteBatch spriteBatch, string label, string iconIdentifier, object targetIdentifier, Vector2 worldPosition, Vector2 transducerPosition, float scale, Vector2 center, float radius)
{
float dist = position.Length();
float dist = Vector2.Distance(worldPosition, transducerPosition);
if (Vector2.DistanceSquared(worldPosition, transducerPosition) > Range * Range)
{
if (markerDistances.TryGetValue(targetIdentifier, out CachedDistance cachedDistance))
{
if (Vector2.DistanceSquared(cachedDistance.TransducerWorldPos, transducerPosition) > 500 * 500 ||
Vector2.DistanceSquared(cachedDistance.WorldPos, worldPosition) > 500 * 500)
{
markerDistances.Remove(targetIdentifier);
CalculateDistance();
}
else
{
dist = cachedDistance.Distance;
}
}
else
{
CalculateDistance();
}
}
void CalculateDistance()
{
pathFinder ??= new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
if (!path.Unreachable)
{
markerDistances.Add(targetIdentifier, new CachedDistance(transducerPosition, worldPosition, path.TotalLength));
dist = path.TotalLength;
}
}
Vector2 position = worldPosition - transducerPosition;
position *= zoom;
position *= scale;

View File

@@ -390,7 +390,7 @@ namespace Barotrauma.Items.Components
};
// Sonar area
steerArea = new GUICustomComponent(new RectTransform(Vector2.One * GUI.RelativeHorizontalAspectRatio * Sonar.sonarAreaSize, GuiFrame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest),
steerArea = new GUICustomComponent(new RectTransform(Sonar.GUISizeCalculation, GuiFrame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest),
(spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null);
steerRadius = steerArea.Rect.Width / 2;
@@ -667,7 +667,7 @@ namespace Barotrauma.Items.Components
if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
{
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsInfoFrameOpen)
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen)
{
Vector2 displaySubPos = (-sonar.DisplayOffset * sonar.Zoom) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
displaySubPos.Y = -displaySubPos.Y;

View File

@@ -13,6 +13,8 @@ namespace Barotrauma.Items.Components
bool isStuck = msg.ReadBoolean();
if (isStuck)
{
ushort submarineID = msg.ReadUInt16();
ushort hullID = msg.ReadUInt16();
Vector2 simPosition = new Vector2(
msg.ReadSingle(),
msg.ReadSingle());
@@ -20,7 +22,12 @@ namespace Barotrauma.Items.Components
msg.ReadSingle(),
msg.ReadSingle());
UInt16 entityID = msg.ReadUInt16();
Entity entity = Entity.FindEntityByID(entityID);
Entity entity = Entity.FindEntityByID(entityID);
Submarine submarine = Entity.FindEntityByID(submarineID) as Submarine;
Hull hull = Entity.FindEntityByID(hullID) as Hull;
item.Submarine = submarine;
item.CurrentHull = hull;
item.body.SetTransform(simPosition, item.body.Rotation);
if (entity is Character character)
{
@@ -30,12 +37,14 @@ namespace Barotrauma.Items.Components
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Limb index out of bounds ({limbIndex}, character: {character.ToString()})");
return;
}
if (character.Removed) { return; }
var limb = character.AnimController.Limbs[limbIndex];
StickToTarget(limb.body.FarseerBody, axis);
}
else if (entity is Structure structure)
{
byte bodyIndex = msg.ReadByte();
if (bodyIndex == 255) { bodyIndex = 0; }
if (bodyIndex >= structure.Bodies.Count)
{
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Structure body index out of bounds ({bodyIndex}, structure: {structure.ToString()})");
@@ -46,6 +55,7 @@ namespace Barotrauma.Items.Components
}
else if (entity is Item item)
{
if (item.Removed) { return; }
StickToTarget(item.body.FarseerBody, axis);
}
else if (entity is Submarine sub)

View File

@@ -27,6 +27,8 @@ namespace Barotrauma.Items.Components
private FixActions requestStartFixAction;
public float FakeBrokenTimer;
[Serialize("", false, description: "An optional description of the needed repairs displayed in the repair interface.")]
public string Description
{
@@ -117,9 +119,18 @@ namespace Barotrauma.Items.Components
case "emitter":
case "particleemitter":
particleEmitters.Add(new ParticleEmitter(subElement));
particleEmitterConditionRanges.Add(new Vector2(
subElement.GetAttributeFloat("mincondition", 0.0f),
subElement.GetAttributeFloat("maxcondition", 100.0f)));
float minCondition = subElement.GetAttributeFloat("mincondition", 0.0f);
float maxCondition = subElement.GetAttributeFloat("maxcondition", 100.0f);
if (maxCondition < minCondition)
{
DebugConsole.ThrowError("Invalid damage particle configuration in the Repairable component of " + item.Name + ". MaxCondition needs to be larger than MinCondition.");
float temp = maxCondition;
maxCondition = minCondition;
minCondition = temp;
}
particleEmitterConditionRanges.Add(new Vector2(minCondition, maxCondition));
break;
}
}
@@ -127,6 +138,9 @@ namespace Barotrauma.Items.Components
partial void UpdateProjSpecific(float deltaTime)
{
FakeBrokenTimer -= deltaTime;
item.FakeBroken = FakeBrokenTimer > 0.0f;
if (!GameMain.IsMultiplayer)
{
switch (requestStartFixAction)
@@ -141,10 +155,10 @@ namespace Barotrauma.Items.Components
break;
}
}
for (int i = 0; i < particleEmitters.Count; i++)
{
if (item.ConditionPercentage >= particleEmitterConditionRanges[i].X && item.ConditionPercentage <= particleEmitterConditionRanges[i].Y)
if ((item.ConditionPercentage >= particleEmitterConditionRanges[i].X && item.ConditionPercentage <= particleEmitterConditionRanges[i].Y) || FakeBrokenTimer > 0.0f)
{
particleEmitters[i].Emit(deltaTime, item.WorldPosition, item.CurrentHull);
}

View File

@@ -66,6 +66,15 @@ namespace Barotrauma.Items.Components
if (target == null) { return; }
Vector2 startPos = new Vector2(source.DrawPosition.X, -source.DrawPosition.Y);
var turret = source?.GetComponent<Turret>();
if (turret != null)
{
startPos = new Vector2(source.WorldRect.X + turret.TransformedBarrelPos.X, -(source.WorldRect.Y - turret.TransformedBarrelPos.Y));
if (turret.BarrelSprite != null)
{
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
}
}
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
if (Snapped)

View File

@@ -379,7 +379,7 @@ namespace Barotrauma.Items.Components
ConnectionPanel.HighlightedWire = wire;
bool allowRewiring = GameMain.NetworkMember?.ServerSettings == null || GameMain.NetworkMember.ServerSettings.AllowRewiring;
if (allowRewiring && !wire.Locked && (!panel.Locked || Screen.Selected == GameMain.SubEditorScreen))
if (allowRewiring && (!wire.Locked && !panel.Locked || Screen.Selected == GameMain.SubEditorScreen))
{
//start dragging the wire
if (PlayerInput.PrimaryMouseButtonHeld()) { DraggingConnected = wire; }

View File

@@ -56,15 +56,6 @@ namespace Barotrauma.Items.Components
};
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
if (!string.IsNullOrEmpty(DisplayedWelcomeMessage))
{
ShowOnDisplay(DisplayedWelcomeMessage);
}
}
private void SendOutput(string input)
{
if (input.Length > MaxMessageLength)
@@ -123,6 +114,11 @@ namespace Barotrauma.Items.Components
public override void AddToGUIUpdateList()
{
base.AddToGUIUpdateList();
if (!string.IsNullOrEmpty(DisplayedWelcomeMessage))
{
ShowOnDisplay(DisplayedWelcomeMessage);
DisplayedWelcomeMessage = "";
}
if (shouldSelectInputBox)
{
inputBox.Select();

View File

@@ -17,14 +17,60 @@ namespace Barotrauma.Items.Components
partial class WireSection
{
public VertexPositionColorTexture[] vertices;
public VertexPositionColorTexture[] shiftedVertices;
private float cachedWidth = 0f;
private void RecalculateVertices(Wire wire, float width)
{
if (MathUtils.NearlyEqual(cachedWidth, width)) { return; }
cachedWidth = width;
vertices = new VertexPositionColorTexture[4];
Vector2 expandDir = start-end;
expandDir.Normalize();
float temp = expandDir.X;
expandDir.X = -expandDir.Y;
expandDir.Y = -temp;
Rectangle srcRect = wire.wireSprite.SourceRect;
expandDir *= width * srcRect.Height * 0.5f;
Vector2 rectLocation = srcRect.Location.ToVector2();
Vector2 rectSize = srcRect.Size.ToVector2();
Vector2 textureSize = new Vector2(wire.wireSprite.Texture.Width, wire.wireSprite.Texture.Height);
Vector2 topLeftUv = rectLocation / textureSize;
Vector2 bottomRightUv = (rectLocation + rectSize) / textureSize;
Vector2 invStart = new Vector2(start.X, -start.Y);
Vector2 invEnd = new Vector2(end.X, -end.Y);
vertices[0] = new VertexPositionColorTexture(new Vector3(invStart + expandDir, 0f), Color.White, topLeftUv);
vertices[2] = new VertexPositionColorTexture(new Vector3(invEnd + expandDir, 0f), Color.White, new Vector2(bottomRightUv.X, topLeftUv.Y));
vertices[1] = new VertexPositionColorTexture(new Vector3(invStart - expandDir, 0f), Color.White, new Vector2(topLeftUv.X, bottomRightUv.Y));
vertices[3] = new VertexPositionColorTexture(new Vector3(invEnd - expandDir, 0f), Color.White, bottomRightUv);
shiftedVertices = (VertexPositionColorTexture[])vertices.Clone();
}
public void Draw(SpriteBatch spriteBatch, Wire wire, Color color, Vector2 offset, float depth, float width = 0.3f)
{
if (width <= 0f) { return; }
RecalculateVertices(wire, width);
for (int i=0;i<vertices.Length;i++)
{
shiftedVertices[i].Color = color;
shiftedVertices[i].Position = vertices[i].Position;
shiftedVertices[i].Position.X += offset.X;
shiftedVertices[i].Position.Y -= offset.Y;
}
spriteBatch.Draw(wire.wireSprite.Texture,
new Vector2(start.X + offset.X, -(start.Y + offset.Y)), wire.wireSprite.SourceRect, color,
-angle,
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
new Vector2(length / wire.wireSprite.size.X, width),
SpriteEffects.None,
shiftedVertices,
depth);
}
@@ -110,7 +156,7 @@ namespace Barotrauma.Items.Components
drawOffset = sub.DrawPosition + sub.HiddenSubPosition;
}
float depth = item.IsSelected ? 0.0f : wireSprite.Depth + ((item.ID % 100) * 0.00001f);
float depth = item.IsSelected ? 0.0f : Screen.Selected is SubEditorScreen editor && editor.WiringMode ? 0.00002f : wireSprite.Depth + ((item.ID % 100) * 0.00001f);
if (item.IsHighlighted)
{
@@ -239,10 +285,12 @@ namespace Barotrauma.Items.Components
public static void UpdateEditing(List<Wire> wires)
{
var doubleClicked = PlayerInput.DoubleClicked();
Wire equippedWire =
Character.Controlled?.SelectedItems[0]?.GetComponent<Wire>() ??
Character.Controlled?.SelectedItems[1]?.GetComponent<Wire>();
if (equippedWire != null)
if (equippedWire != null && GUI.MouseOn == null)
{
if (PlayerInput.PrimaryMouseButtonClicked() && Character.Controlled.SelectedConstruction == null)
{
@@ -252,7 +300,7 @@ namespace Barotrauma.Items.Components
}
//dragging a node of some wire
if (draggingWire != null)
if (draggingWire != null && !doubleClicked)
{
if (Character.Controlled != null)
{
@@ -283,15 +331,18 @@ namespace Barotrauma.Items.Components
if (selectedNodeIndex.HasValue)
{
nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);
if (!PlayerInput.IsShiftDown())
{
nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);
}
draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos;
draggingWire.UpdateSections();
}
else
{
if (Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X)
if (Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X || PlayerInput.IsShiftDown())
{
selectedNodeIndex = highlightedNodeIndex;
}
@@ -304,6 +355,8 @@ namespace Barotrauma.Items.Components
return;
}
bool updateHighlight = true;
//a wire has been selected -> check if we should start dragging one of the nodes
float nodeSelectDist = 10, sectionSelectDist = 5;
highlightedNodeIndex = null;
@@ -359,6 +412,37 @@ namespace Barotrauma.Items.Components
{
selectedWire.nodes.RemoveAt(closestIndex);
selectedWire.UpdateSections();
}
// if only one end of the wire is disconnect pick it back up with double click
else if (doubleClicked && equippedWire == null && Character.Controlled != null && selectedWire.connections.Any(conn => conn != null))
{
if (selectedWire.connections[0] == null && closestIndex == 0 || selectedWire.connections[1] == null && closestIndex == selectedWire.nodes.Count - 1)
{
selectedWire.IsActive = true;
selectedWire.nodes.RemoveAt(closestIndex);
selectedWire.UpdateSections();
// flip the wire
if (closestIndex == 0)
{
selectedWire.nodes.Reverse();
selectedWire.connections[0] = selectedWire.connections[1];
selectedWire.connections[1] = null;
}
selectedWire.shouldClearConnections = false;
Character.Controlled.Inventory.TryPutItem(selectedWire.item, Character.Controlled, new List<InvSlotType> { InvSlotType.LeftHand, InvSlotType.RightHand });
foreach (var entity in MapEntity.mapEntityList)
{
if (entity is Item item)
{
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Remove(selectedWire);
}
}
MapEntity.SelectedList.Clear();
selectedWire.shouldClearConnections = true;
updateHighlight = false;
}
}
}
}
@@ -400,7 +484,7 @@ namespace Barotrauma.Items.Components
}
}
if (highlighted != null)
if (highlighted != null && updateHighlight)
{
highlighted.item.IsHighlighted = true;
if (PlayerInput.PrimaryMouseButtonClicked())
@@ -411,6 +495,20 @@ namespace Barotrauma.Items.Components
}
}
public bool IsMouseOn()
{
if (GUI.MouseOn == null)
{
Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
if (item.Submarine != null) { mousePos -= (item.Submarine.Position + item.Submarine.HiddenSubPosition); }
if (GetClosestNodeIndex(mousePos, 10, out _) > -1) { return true; }
if (GetClosestSectionIndex(mousePos, 10, out _) > -1) { return true; }
}
return false;
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
int eventIndex = msg.ReadRangedInteger(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent));

View File

@@ -5,7 +5,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
@@ -19,6 +19,8 @@ namespace Barotrauma.Items.Components
private float recoilTimer;
private float RetractionTime => Math.Max(Reload * RetractionDurationMultiplier, RecoilTime);
private RoundSound startMoveSound, endMoveSound, moveSound;
private SoundChannel moveSoundChannel;
@@ -83,6 +85,11 @@ namespace Barotrauma.Items.Components
}
}
public Sprite BarrelSprite
{
get { return barrelSprite; }
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
@@ -126,7 +133,7 @@ namespace Barotrauma.Items.Components
partial void LaunchProjSpecific()
{
recoilTimer = Math.Max(Reload, 0.1f);
recoilTimer = RetractionTime;
PlaySound(ActionType.OnUse);
Vector2 particlePos = new Vector2(item.WorldRect.X + transformedBarrelPos.X, item.WorldRect.Y - transformedBarrelPos.Y);
foreach (ParticleEmitter emitter in particleEmitters)
@@ -135,6 +142,12 @@ namespace Barotrauma.Items.Components
}
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
base.UpdateBroken(deltaTime, cam);
recoilTimer -= deltaTime;
}
partial void UpdateProjSpecific(float deltaTime)
{
recoilTimer -= deltaTime;
@@ -232,15 +245,21 @@ namespace Barotrauma.Items.Components
float recoilOffset = 0.0f;
if (Math.Abs(RecoilDistance) > 0.0f && recoilTimer > 0.0f)
{
//move the barrel backwards 0.1 seconds after launching
if (recoilTimer >= Math.Max(Reload, 0.1f) - 0.1f)
float diff = RetractionTime - RecoilTime;
if (recoilTimer >= diff)
{
recoilOffset = RecoilDistance * (1.0f - (recoilTimer - (Math.Max(Reload, 0.1f) - 0.1f)) / 0.1f);
//move the barrel backwards 0.1 seconds (defined by RecoilTime) after launching
recoilOffset = RecoilDistance * (1.0f - (recoilTimer - diff) / RecoilTime);
}
else if (recoilTimer <= diff - RetractionDelay)
{
//move back to normal position while reloading
float t = diff - RetractionDelay;
recoilOffset = RecoilDistance * recoilTimer / t;
}
//move back to normal position while reloading
else
{
recoilOffset = RecoilDistance * recoilTimer / (Math.Max(Reload, 0.1f) - 0.1f);
recoilOffset = RecoilDistance;
}
}
@@ -504,7 +523,7 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
UInt16 projectileID = msg.ReadUInt16();
float newTargetRotation = msg.ReadRangedSingle(minRotation, maxRotation, 8);
float newTargetRotation = msg.ReadRangedSingle(minRotation, maxRotation, 16);
if (Character.Controlled == null || user != Character.Controlled)
{
@@ -514,13 +533,21 @@ namespace Barotrauma.Items.Components
//projectile removed, do nothing
if (projectileID == 0) { return; }
if (!(Entity.FindEntityByID(projectileID) is Item projectile))
//ID ushort.MaxValue = launched without a projectile
if (projectileID == ushort.MaxValue)
{
DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found");
return;
Launch(null);
}
else
{
if (!(Entity.FindEntityByID(projectileID) is Item projectile))
{
DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found");
return;
}
Launch(projectile, launchRotation: newTargetRotation);
}
Launch(projectile);
}
}
}

View File

@@ -31,7 +31,7 @@ namespace Barotrauma
public Sprite SlotSprite;
public Keys QuickUseKey;
public int InventoryKeyIndex = -1;
public int SubInventoryDir = -1;
@@ -191,7 +191,7 @@ namespace Barotrauma
public Item Item;
public bool IsSubSlot;
public string Tooltip;
public List<ColorData> TooltipColorData;
public List<RichTextData> TooltipRichTextData;
public SlotReference(Inventory parentInventory, InventorySlot slot, int slotIndex, bool isSubSlot, Inventory subInventory = null)
{
@@ -201,7 +201,7 @@ namespace Barotrauma
Inventory = subInventory;
IsSubSlot = isSubSlot;
Item = ParentInventory.Items[slotIndex];
TooltipColorData = ColorData.GetColorData(GetTooltip(Item), out Tooltip);
TooltipRichTextData = RichTextData.GetRichTextData(GetTooltip(Item), out Tooltip);
}
private string GetTooltip(Item item)
@@ -450,12 +450,33 @@ namespace Barotrauma
}
}*/
bool mouseOn = interactRect.Contains(PlayerInput.MousePosition) && !Locked && !mouseOnGUI;
bool mouseOn = interactRect.Contains(PlayerInput.MousePosition) && !Locked && !mouseOnGUI && !slot.Disabled;
// Delete item from container in sub editor
if (SubEditorScreen.IsSubEditor() && PlayerInput.IsCtrlDown())
{
draggingItem = null;
var mouseDrag = SubEditorScreen.MouseDragStart != Vector2.Zero && Vector2.Distance(PlayerInput.MousePosition, SubEditorScreen.MouseDragStart) >= GUI.Scale * 20;
if (mouseOn && (PlayerInput.PrimaryMouseButtonClicked() || mouseDrag))
{
if (item != null)
{
if (mouseDrag) { item.OwnInventory?.DeleteAllItems(); }
slot.ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.4f);
if (!mouseDrag)
{
GUI.PlayUISound(GUISoundType.PickItem);
}
item.Remove();
}
}
}
if (PlayerInput.LeftButtonHeld() && PlayerInput.RightButtonHeld())
{
mouseOn = false;
}
if (selectedSlot != null && selectedSlot.Slot != slot)
{
//subinventory slot highlighted -> don't allow highlighting this one
@@ -476,11 +497,14 @@ namespace Barotrauma
// &&
//(highlightedSubInventories.Count == 0 || highlightedSubInventories.Contains(this) || highlightedSubInventorySlot?.Slot == slot || highlightedSubInventory.Owner == item))
{
slot.State = GUIComponent.ComponentState.Hover;
if (selectedSlot == null || (!selectedSlot.IsSubSlot && isSubSlot))
{
selectedSlot = new SlotReference(this, slot, slotIndex, isSubSlot, Items[slotIndex]?.GetComponent<ItemContainer>()?.Inventory);
var slotRef = new SlotReference(this, slot, slotIndex, isSubSlot, Items[slotIndex]?.GetComponent<ItemContainer>()?.Inventory);
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && slotRef.ParentInventory is CharacterInventory) { return; }
selectedSlot = slotRef;
}
if (draggingItem == null)
@@ -668,18 +692,34 @@ namespace Barotrauma
DrawSlot(spriteBatch, this, slots[i], Items[i], i, drawItem);
}
}
/// <summary>
/// Check if the mouse is hovering on top of the slot
/// </summary>
/// <param name="slot">The desired slot we want to check</param>
/// <returns>True if our mouse is hover on the slot, false otherwise</returns>
public static bool IsMouseOnSlot(InventorySlot slot)
{
var rect = new Rectangle(slot.InteractRect.X, slot.InteractRect.Y, slot.InteractRect.Width, slot.InteractRect.Height);
rect.Offset(slot.DrawOffset);
return rect.Contains(PlayerInput.MousePosition);
}
/// <summary>
/// Is the mouse on any inventory element (slot, equip button, subinventory...)
/// </summary>
/// <returns></returns>
public static bool IsMouseOnInventory()
public static bool IsMouseOnInventory(bool ignoreDraggedItem = false)
{
if (Character.Controlled == null) return false;
var isSubEditor = Screen.Selected is SubEditorScreen editor && !editor.WiringMode;
if (Character.Controlled == null) { return false; }
if (draggingItem != null || DraggingInventory != null) return true;
if (!ignoreDraggedItem)
{
if (draggingItem != null || DraggingInventory != null) { return true; }
}
if (Character.Controlled.Inventory != null)
if (Character.Controlled.Inventory != null && !isSubEditor)
{
var inv = Character.Controlled.Inventory;
for (var i = 0; i < inv.slots.Length; i++)
@@ -699,7 +739,8 @@ namespace Barotrauma
}
}
}
if (Character.Controlled.SelectedCharacter?.Inventory != null)
if (Character.Controlled.SelectedCharacter?.Inventory != null && !isSubEditor)
{
var inv = Character.Controlled.SelectedCharacter.Inventory;
for (var i = 0; i < inv.slots.Length; i++)
@@ -830,9 +871,9 @@ namespace Barotrauma
return CursorState.Default;
}
protected static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle highlightedSlot, List<ColorData> colorData = null)
protected static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle highlightedSlot, List<RichTextData> richTextData = null)
{
GUIComponent.DrawToolTip(spriteBatch, toolTip, highlightedSlot, colorData);
GUIComponent.DrawToolTip(spriteBatch, toolTip, highlightedSlot, richTextData);
}
public void DrawSubInventory(SpriteBatch spriteBatch, int slotIndex)
@@ -928,7 +969,8 @@ namespace Barotrauma
{
Character.Controlled.ClearInputs();
if (CharacterHealth.OpenHealthWindow != null &&
if (!IsMouseOnInventory(ignoreDraggedItem: true) &&
CharacterHealth.OpenHealthWindow != null &&
CharacterHealth.OpenHealthWindow.OnItemDropped(draggingItem, false))
{
draggingItem = null;
@@ -946,8 +988,33 @@ namespace Barotrauma
}
else
{
GUI.PlayUISound(GUISoundType.DropItem);
draggingItem.Drop(Character.Controlled);
bool removed = false;
if (Screen.Selected is SubEditorScreen editor)
{
if (editor.EntityMenu.Rect.Contains(PlayerInput.MousePosition))
{
draggingItem.Remove();
removed = true;
}
else
{
if (editor.WiringMode)
{
draggingItem.Remove();
removed = true;
}
else
{
draggingItem.Drop(Character.Controlled);
}
}
}
else
{
draggingItem.Drop(Character.Controlled);
}
GUI.PlayUISound(removed ? GUISoundType.PickItem : GUISoundType.DropItem);
}
}
else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem)
@@ -1015,7 +1082,7 @@ namespace Barotrauma
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
{
Rectangle hoverArea;
if (!subSlot.Inventory.Movable())
if (!subSlot.Inventory.Movable() || Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item))
{
hoverArea = subSlot.Slot.Rect;
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
@@ -1038,7 +1105,9 @@ namespace Barotrauma
}
if (subSlot.Slot.SubInventoryDir < 0)
{
hoverArea.Height -= hoverArea.Bottom - subSlot.Slot.Rect.Bottom;
// 24/2/2020 - the below statement makes the sub inventory extend all the way to the bottom of the screen because of a double negative
// Not sure if it's intentional or not but it was causing hover issues and disabling it seems to have no detrimental effects.
// hoverArea.Height -= hoverArea.Bottom - subSlot.Slot.Rect.Bottom;
}
else
{
@@ -1088,7 +1157,7 @@ namespace Barotrauma
string toolTip = mouseOnHealthInterface ? TextManager.Get("QuickUseAction.UseTreatment") :
Character.Controlled.FocusedItem != null ?
TextManager.GetWithVariable("PutItemIn", "[itemname]", Character.Controlled.FocusedItem.Name, true) :
TextManager.Get("DropItem");
TextManager.Get(Screen.Selected is SubEditorScreen editor && editor.EntityMenu.Rect.Contains(PlayerInput.MousePosition) ? "Delete" : "DropItem");
int textWidth = (int)Math.Max(GUI.Font.MeasureString(draggingItem.Name).X, GUI.SmallFont.MeasureString(toolTip).X);
int textSpacing = (int)(15 * GUI.Scale);
Point shadowBorders = (new Point(40, 10)).Multiply(GUI.Scale);
@@ -1111,7 +1180,7 @@ namespace Barotrauma
{
Rectangle slotRect = selectedSlot.Slot.Rect;
slotRect.Location += selectedSlot.Slot.DrawOffset.ToPoint();
DrawToolTip(spriteBatch, selectedSlot.Tooltip, slotRect, selectedSlot.TooltipColorData);
DrawToolTip(spriteBatch, selectedSlot.Tooltip, slotRect, selectedSlot.TooltipRichTextData);
}
}
@@ -1154,6 +1223,11 @@ namespace Barotrauma
if (inventory != null && inventory.Locked) { slotColor = Color.Gray * 0.5f; }
spriteBatch.Draw(slotSprite.Texture, rect, slotSprite.SourceRect, slotColor);
if (SubEditorScreen.IsSubEditor() && PlayerInput.IsCtrlDown() && selectedSlot?.Slot == slot)
{
GUI.DrawRectangle(spriteBatch, rect, GUI.Style.Red * 0.3f, isFilled: true);
}
bool canBePut = false;
@@ -1181,7 +1255,7 @@ namespace Barotrauma
if (item != null && drawItem)
{
if (!item.IsFullCondition && (itemContainer == null || !itemContainer.ShowConditionInContainedStateIndicator))
if (!item.IsFullCondition && !item.Prefab.HideConditionBar && (itemContainer == null || !itemContainer.ShowConditionInContainedStateIndicator))
{
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, rect.Width, 8), Color.Black * 0.8f, true);
GUI.DrawRectangle(spriteBatch,
@@ -1308,10 +1382,10 @@ namespace Barotrauma
if (inventory != null &&
!inventory.Locked &&
Character.Controlled?.Inventory == inventory &&
slot.QuickUseKey != Keys.None)
slot.InventoryKeyIndex != -1)
{
spriteBatch.Draw(slotHotkeySprite.Texture, rect.ScaleSize(1.15f), slotHotkeySprite.SourceRect, slotColor);
GUI.DrawString(spriteBatch, rect.Location.ToVector2() + new Vector2((int)(4.25f * UIScale), (int)Math.Ceiling(-1.5f * UIScale)), slot.QuickUseKey.ToString().Substring(1, 1), Color.Black, font: GUI.HotkeyFont);
GUI.DrawString(spriteBatch, rect.Location.ToVector2() + new Vector2((int)(4.25f * UIScale), (int)Math.Ceiling(-1.5f * UIScale)), GameMain.Config.InventoryKeyBind(slot.InventoryKeyIndex).Name, Color.Black, font: GUI.HotkeyFont);
}
}

View File

@@ -32,17 +32,28 @@ namespace Barotrauma
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
public bool FakeBroken;
private Sprite activeSprite;
public override Sprite Sprite
{
get { return activeSprite; }
}
public override bool DrawOverWater
public override Rectangle Rect
{
get { return base.DrawOverWater || (GetComponent<Wire>() != null && IsSelected); }
get { return base.Rect; }
set
{
cachedVisibleSize = null;
base.Rect = value;
}
}
public override bool DrawBelowWater => (!(Screen.Selected is SubEditorScreen editor) || !editor.WiringMode || !isWire) && base.DrawBelowWater;
public override bool DrawOverWater => base.DrawOverWater || (IsSelected || Screen.Selected is SubEditorScreen editor && editor.WiringMode) && isWire;
private GUITextBlock itemInUseWarning;
private GUITextBlock ItemInUseWarning
{
@@ -62,6 +73,10 @@ namespace Barotrauma
{
get
{
if (!GameMain.SubEditorScreen.ShowThalamus && prefab.Category.HasFlag(MapEntityCategory.Thalamus))
{
return false;
}
return parentInventory == null && (body == null || body.Enabled) && ShowItems;
}
}
@@ -156,6 +171,14 @@ namespace Barotrauma
decorativeSprite.Sprite.EnsureLazyLoaded();
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
}
UpdateSpriteStates(0.0f);
}
private Vector2? cachedVisibleSize;
public void ResetCachedVisibleSize()
{
cachedVisibleSize = null;
}
public override bool IsVisible(Rectangle worldView)
@@ -167,19 +190,28 @@ namespace Barotrauma
}
//no drawable components and the body has been disabled = nothing to draw
if (drawableComponents.Count == 0 && body != null && !body.Enabled)
if (!hasComponentsToDraw && body != null && !body.Enabled)
{
return false;
}
float padding = 100.0f;
Vector2 size = new Vector2(rect.Width + padding, rect.Height + padding);
foreach (IDrawableComponent drawable in drawableComponents)
Vector2 size;
if (cachedVisibleSize.HasValue)
{
size.X = Math.Max(drawable.DrawSize.X, size.X);
size.Y = Math.Max(drawable.DrawSize.Y, size.Y);
size = cachedVisibleSize.Value;
}
else
{
float padding = 100.0f;
size = new Vector2(rect.Width + padding, rect.Height + padding);
foreach (IDrawableComponent drawable in drawableComponents)
{
size.X = Math.Max(drawable.DrawSize.X, size.X);
size.Y = Math.Max(drawable.DrawSize.Y, size.Y);
}
size *= 0.5f;
cachedVisibleSize = size;
}
size *= 0.5f;
//cache world position so we don't need to calculate it 4 times
Vector2 worldPosition = WorldPosition;
@@ -199,7 +231,8 @@ namespace Barotrauma
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
if (condition < Prefab.Health)
float displayCondition = FakeBroken ? 0.0f : condition;
if (displayCondition < Prefab.Health)
{
for (int i = 0; i < Prefab.BrokenSprites.Count; i++)
{
@@ -207,14 +240,14 @@ namespace Barotrauma
{
float min = i > 0 ? Prefab.BrokenSprites[i - i].MaxCondition : 0.0f;
float max = Prefab.BrokenSprites[i].MaxCondition;
fadeInBrokenSpriteAlpha = 1.0f - ((condition - min) / (max - min));
fadeInBrokenSpriteAlpha = 1.0f - ((displayCondition - min) / (max - min));
if (fadeInBrokenSpriteAlpha > 0.0f && fadeInBrokenSpriteAlpha < 1.0f)
{
fadeInBrokenSprite = Prefab.BrokenSprites[i];
}
continue;
}
if (condition <= Prefab.BrokenSprites[i].MaxCondition)
if (displayCondition <= Prefab.BrokenSprites[i].MaxCondition)
{
activeSprite = Prefab.BrokenSprites[i].Sprite;
break;
@@ -262,7 +295,7 @@ namespace Barotrauma
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
SpriteRotation + rotation, Scale, activeSprite.effects,
SpriteRotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
}
}
@@ -306,7 +339,7 @@ namespace Barotrauma
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + transformedOffset.X, -(DrawPosition.Y + transformedOffset.Y)), color,
-body.Rotation + rotation, Scale, activeSprite.effects,
-body.Rotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
}
@@ -671,6 +704,13 @@ namespace Barotrauma
HUDLayoutSettings.ChatBoxArea.Width + disallowedPadding, HUDLayoutSettings.ChatBoxArea.Height));
}
if (Screen.Selected is SubEditorScreen editor)
{
disallowedAreas.Add(editor.EntityMenu.Rect);
disallowedAreas.Add(editor.TopPanel.Rect);
disallowedAreas.Add(editor.ToggleEntityMenuButton.Rect);
}
GUI.PreventElementOverlap(elementsToMove, disallowedAreas,
new Rectangle(
0, 20,
@@ -826,19 +866,21 @@ namespace Barotrauma
}
readonly List<ColoredText> texts = new List<ColoredText>();
public List<ColoredText> GetHUDTexts(Character character)
public List<ColoredText> GetHUDTexts(Character character, bool recreateHudTexts = true)
{
// Always create the texts if they have not yet been created
if (texts.Any() && !recreateHudTexts) { return texts; }
texts.Clear();
foreach (ItemComponent ic in components)
{
if (string.IsNullOrEmpty(ic.DisplayMsg)) continue;
if (!ic.CanBePicked && !ic.CanBeSelected) continue;
if (ic is Holdable holdable && !holdable.CanBeDeattached()) continue;
if (string.IsNullOrEmpty(ic.DisplayMsg)) { continue; }
if (!ic.CanBePicked && !ic.CanBeSelected) { continue; }
if (ic is Holdable holdable && !holdable.CanBeDeattached()) { continue; }
Color color = Color.Gray;
if (ic.HasRequiredItems(character, false))
{
if (ic is Repairable repairable)
if (ic is Repairable)
{
if (!IsFullCondition) { color = Color.Cyan; }
}
@@ -847,9 +889,12 @@ namespace Barotrauma
color = Color.Cyan;
}
}
texts.Add(new ColoredText(ic.DisplayMsg, color, false));
}
if ((PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift)) && CrewManager.DoesItemHaveContextualOrders(this))
{
texts.Add(new ColoredText(TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders")), Color.Cyan, false));
}
return texts;
}
@@ -857,17 +902,17 @@ namespace Barotrauma
{
if (Screen.Selected is SubEditorScreen)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(); }
}
else
{
if (HasInGameEditableProperties)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(); }
}
}
if (Character.Controlled != null && Character.Controlled?.SelectedConstruction != this) return;
if (Character.Controlled != null && Character.Controlled?.SelectedConstruction != this) { return; }
bool needsLayoutUpdate = false;
foreach (ItemComponent ic in activeHUDs)
@@ -1213,8 +1258,8 @@ namespace Barotrauma
{
if (itemContainerIndex < 0 || itemContainerIndex >= parentItem.components.Count)
{
string errorMsg = "Failed to spawn item \"" + (itemIdentifier ?? "null") +
"\" in the inventory of \"" + parentItem.prefab.Identifier + "\" (component index out of range). Index: " + itemContainerIndex + ", components: " + parentItem.components.Count + ".";
string errorMsg =
$"Failed to spawn item \"{(itemIdentifier ?? "null")}\" in the inventory of \"{parentItem.prefab.Identifier} ({parentItem.ID})\" (component index out of range). Index: {itemContainerIndex}, components: {parentItem.components.Count}.";
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:ContainerIndexOutOfRange" + (itemName ?? "null") + (itemIdentifier ?? "null"),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);

View File

@@ -66,16 +66,17 @@ namespace Barotrauma
[Serialize("", false)]
public string ImpactSoundTag { get; private set; }
public override void UpdatePlacing(Camera cam)
{
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
if (PlayerInput.SecondaryMouseButtonClicked())
{
selected = null;
return;
}
var potentialContainer = MapEntity.GetPotentialContainer(position);
if (!ResizeHorizontal && !ResizeVertical)
{
@@ -88,6 +89,14 @@ namespace Barotrauma
item.SetTransform(ConvertUnits.ToSimUnits(Submarine.MainSub == null ? item.Position : item.Position - Submarine.MainSub.Position), 0.0f);
item.FindHull();
if (PlayerInput.IsShiftDown())
{
if (potentialContainer?.OwnInventory?.TryPutItem(item, Character.Controlled) ?? false)
{
GUI.PlayUISound(GUISoundType.PickItem);
}
}
placePosition = Vector2.Zero;
return;
}
@@ -124,6 +133,12 @@ namespace Barotrauma
}
}
if (potentialContainer != null)
{
potentialContainer.IsHighlighted = true;
}
//if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed) selected = null;
}
@@ -141,26 +156,10 @@ namespace Barotrauma
if (!ResizeHorizontal && !ResizeVertical)
{
sprite.Draw(spriteBatch, new Vector2(position.X, -position.Y) + sprite.size / 2.0f * Scale, SpriteColor, scale: Scale);
}
else
{
Vector2 placeSize = size;
if (placePosition == Vector2.Zero)
{
if (PlayerInput.PrimaryMouseButtonHeld()) placePosition = position;
}
else
{
if (ResizeHorizontal)
placeSize.X = Math.Max(position.X - placePosition.X, size.X);
if (ResizeVertical)
placeSize.Y = Math.Max(placePosition.Y - position.Y, size.Y);
position = placePosition;
}
if (sprite != null) sprite.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), placeSize, color: SpriteColor);
sprite?.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), size, color: SpriteColor);
}
}

View File

@@ -60,10 +60,10 @@ namespace Barotrauma
var particle = GameMain.ParticleManager.CreateParticle("flame",
particlePos, particleVel, 0.0f, hull);
if (particle == null) continue;
if (particle == null) { continue; }
//make some of the particles create another firesource when they enter another hull
if (Rand.Int(20) == 1) particle.OnChangeHull = onChangeHull;
if (Rand.Int(20) == 1) { particle.OnChangeHull = onChangeHull; }
particle.Size *= MathHelper.Clamp(size.X / 60.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f);

View File

@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
{
@@ -24,7 +25,7 @@ namespace Barotrauma
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
{
if (!GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
{
Vector2 center = new Vector2(WorldRect.X + rect.Width / 2.0f, -(WorldRect.Y - rect.Height / 2.0f));
GUI.DrawLine(sb, center, center + new Vector2(flowForce.X, -flowForce.Y) / 10.0f, GUI.Style.Red);
@@ -121,24 +122,36 @@ namespace Barotrauma
partial void EmitParticles(float deltaTime)
{
if (flowTargetHull == null) return;
if (flowTargetHull == null) { return; }
if (linkedTo.Count == 2 && linkedTo[0] is Hull hull1 && linkedTo[1] is Hull hull2)
{
//no flow particles between linked hulls (= rooms consisting of multiple hulls)
if (hull1.linkedTo.Contains(hull2)) { return; }
if (hull1.linkedTo.Any(h => h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2))) { return; }
if (hull2.linkedTo.Any(h => h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2))) { return; }
}
Vector2 pos = Position;
if (IsHorizontal)
{
pos.X += Math.Sign(flowForce.X);
pos.Y = MathHelper.Clamp((higherSurface + lowerSurface) / 2.0f, rect.Y - rect.Height, rect.Y) + 10;
pos.Y = MathHelper.Clamp(Rand.Range(higherSurface, lowerSurface), rect.Y - rect.Height, rect.Y);
}
else
{
pos.Y += Math.Sign(flowForce.Y) * rect.Height / 2.0f;
}
//spawn less particles when there's already a large number of them
float particleAmountMultiplier = 1.0f - GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles;
particleAmountMultiplier *= particleAmountMultiplier;
//light dripping
if (open < 0.2f && LerpedFlowForce.LengthSquared() > 100.0f)
{
particleTimer += deltaTime;
float particlesPerSec = open * 100.0f;
float particlesPerSec = open * 100.0f * particleAmountMultiplier;
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
@@ -174,12 +187,13 @@ namespace Barotrauma
particleTimer += deltaTime;
if (IsHorizontal)
{
float particlesPerSec = open * rect.Height * 0.1f;
float particlesPerSec = open * rect.Height * 0.1f * particleAmountMultiplier;
if (openedTimer > 0.0f) { particlesPerSec *= 1.0f + openedTimer * 10.0f; }
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
Vector2 velocity = new Vector2(
MathHelper.Clamp(flowForce.X, -5000.0f, 5000.0f) * Rand.Range(0.5f, 0.7f),
MathHelper.Clamp(flowForce.X, -5000.0f, 5000.0f) * Rand.Range(0.5f, 0.7f),
flowForce.Y * Rand.Range(0.5f, 0.7f));
if (flowTargetHull.WaterVolume < flowTargetHull.Volume * 0.95f)
@@ -191,11 +205,11 @@ namespace Barotrauma
if (particle != null)
{
particle.Size = particle.Size * Math.Min(Math.Abs(flowForce.X / 1000.0f), 5.0f);
particle.Size *= Math.Min(Math.Abs(flowForce.X / 500.0f), 5.0f);
}
}
if (Math.Abs(flowForce.X) > 300.0f)
if (Math.Abs(flowForce.X) > 300.0f && flowTargetHull.WaterVolume > flowTargetHull.Volume * 0.1f)
{
pos.X += Math.Sign(flowForce.X) * 10.0f;
if (rect.Height < 32)
@@ -211,7 +225,7 @@ namespace Barotrauma
GameMain.ParticleManager.CreateParticle(
"bubbles",
Submarine == null ? pos : pos + Submarine.Position,
flowForce / 10.0f, 0, flowTargetHull);
velocity, 0, flowTargetHull);
}
particleTimer -= emitInterval;
}
@@ -220,7 +234,7 @@ namespace Barotrauma
{
if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) return;
float particlesPerSec = open * rect.Width * 0.3f;
float particlesPerSec = open * rect.Width * 0.3f * particleAmountMultiplier;
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
@@ -237,7 +251,7 @@ namespace Barotrauma
velocity, 0, FlowTargetHull);
if (splash != null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f);
}
if (Math.Abs(flowForce.Y) > 190.0f && Rand.Range(0.0f, 1.0f) < 0.3f)
if (Math.Abs(flowForce.Y) > 190.0f && Rand.Range(0.0f, 1.0f) < 0.3f && flowTargetHull.WaterVolume > flowTargetHull.Volume * 0.1f)
{
GameMain.ParticleManager.CreateParticle(
"bubbles",

View File

@@ -14,7 +14,7 @@ namespace Barotrauma
{
public const int MaxDecalsPerHull = 10;
private List<Decal> decals = new List<Decal>();
private readonly List<Decal> decals = new List<Decal>();
private float serverUpdateDelay;
private float remoteWaterVolume, remoteOxygenPercentage;
@@ -23,6 +23,8 @@ namespace Barotrauma
private bool networkUpdatePending;
private float networkUpdateTimer;
private double lastAmbientLightEditTime;
public override bool SelectableInEditor
{
get
@@ -232,33 +234,36 @@ namespace Barotrauma
return;
}
/*if (!Visible)
if (!ShowHulls && !GameMain.DebugDraw) { return; }
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) { return; }
float alpha = 1.0f;
float hideTimeAfterEdit = 3.0f;
if (lastAmbientLightEditTime > Timing.TotalTime - hideTimeAfterEdit * 2.0f)
{
drawRect =
Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(rect.Width, rect.Height),
Color.Black, true,
0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
}*/
if (!ShowHulls && !GameMain.DebugDraw) return;
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) return;
alpha = Math.Min((float)(Timing.TotalTime - lastAmbientLightEditTime) / hideTimeAfterEdit - 1.0f, 1.0f);
}
Rectangle drawRect =
Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
if ((IsSelected || IsHighlighted) && editing)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(rect.Width, rect.Height),
(IsHighlighted ? Color.LightBlue * 0.8f : GUI.Style.Red * 0.5f) * alpha, false, 0, (int)Math.Max(5.0f / Screen.Selected.Cam.Zoom, 1.0f));
}
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(rect.Width, rect.Height),
Color.Blue, false, (ID % 255) * 0.000001f, (int)Math.Max((1.5f / Screen.Selected.Cam.Zoom), 1.0f));
Color.Blue * alpha, false, (ID % 255) * 0.000001f, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
GUI.DrawRectangle(spriteBatch,
new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height),
GUI.Style.Red * ((100.0f - OxygenPercentage) / 400.0f), true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
GUI.Style.Red * ((100.0f - OxygenPercentage) / 400.0f) * alpha, true, 0, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
if (GameMain.DebugDraw)
{
@@ -277,10 +282,12 @@ namespace Barotrauma
foreach (FireSource fs in FireSources)
{
Rectangle fireSourceRect = new Rectangle((int)fs.WorldPosition.X, -(int)fs.WorldPosition.Y, (int)fs.Size.X, (int)fs.Size.Y);
GUI.DrawRectangle(spriteBatch, fireSourceRect, GUI.Style.Orange, false, 0, 5);
GUI.DrawRectangle(spriteBatch, fireSourceRect, GUI.Style.Red, false, 0, 5);
GUI.DrawRectangle(spriteBatch, new Rectangle(fireSourceRect.X - (int)fs.DamageRange, fireSourceRect.Y, fireSourceRect.Width + (int)fs.DamageRange * 2, fireSourceRect.Height), GUI.Style.Orange, false, 0, 5);
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
}
/*GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
for (int i = 0; i < waveY.Length - 1; i++)
{
@@ -290,24 +297,15 @@ namespace Barotrauma
}*/
}
if ((IsSelected || IsHighlighted) && editing)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X + 5, -drawRect.Y + 5),
new Vector2(rect.Width - 10, rect.Height - 10),
IsHighlighted ? Color.LightBlue * 0.5f : GUI.Style.Red * 0.5f, true, 0, (int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
}
foreach (MapEntity e in linkedTo)
{
if (e is Hull)
if (e is Hull linkedHull)
{
Hull linkedHull = (Hull)e;
Rectangle connectedHullRect = e.Submarine == null ?
linkedHull.rect :
Rectangle connectedHullRect = e.Submarine == null ?
linkedHull.rect :
new Rectangle(
(int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X),
(int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y),
(int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y),
linkedHull.WorldRect.Width, linkedHull.WorldRect.Height);
//center of the hull
@@ -315,7 +313,7 @@ namespace Barotrauma
WorldRect :
new Rectangle(
(int)(Submarine.DrawPosition.X + WorldPosition.X),
(int)(Submarine.DrawPosition.Y + WorldPosition.Y),
(int)(Submarine.DrawPosition.Y + WorldPosition.Y),
WorldRect.Width, WorldRect.Height);
GUI.DrawLine(spriteBatch,
@@ -326,22 +324,22 @@ namespace Barotrauma
}
}
public static void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, WaterRenderer renderer)
public static void UpdateVertices(Camera cam, WaterRenderer renderer)
{
foreach (EntityGrid entityGrid in EntityGrids)
{
if (entityGrid.WorldRect.X > cam.WorldView.Right || entityGrid.WorldRect.Right < cam.WorldView.X) continue;
if (entityGrid.WorldRect.Y - entityGrid.WorldRect.Height > cam.WorldView.Y || entityGrid.WorldRect.Y < cam.WorldView.Y - cam.WorldView.Height) continue;
if (entityGrid.WorldRect.X > cam.WorldView.Right || entityGrid.WorldRect.Right < cam.WorldView.X) { continue; }
if (entityGrid.WorldRect.Y - entityGrid.WorldRect.Height > cam.WorldView.Y || entityGrid.WorldRect.Y < cam.WorldView.Y - cam.WorldView.Height) { continue; }
var allEntities = entityGrid.GetAllEntities();
foreach (Hull hull in allEntities)
{
hull.UpdateVertices(graphicsDevice, cam, entityGrid, renderer);
hull.UpdateVertices(cam, entityGrid, renderer);
}
}
}
private void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, EntityGrid entityGrid, WaterRenderer renderer)
private void UpdateVertices(Camera cam, EntityGrid entityGrid, WaterRenderer renderer)
{
Vector2 submarinePos = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
@@ -451,7 +449,7 @@ namespace Barotrauma
}
//we only create a new quad if this is the first or the last one, of if there's a wave large enough that we need more geometry
if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[3].Y) > 1.0f)
if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[2].Y) > 0.01f)
{
renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(prevCorners[0], prevUVs[0]);
renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]);
@@ -554,11 +552,10 @@ namespace Barotrauma
remoteOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
bool hasFireSources = message.ReadBoolean();
int fireSourceCount = 0;
remoteFireSources = new List<Vector3>();
if (hasFireSources)
{
fireSourceCount = message.ReadRangedInteger(0, 16);
int fireSourceCount = message.ReadRangedInteger(0, 16);
for (int i = 0; i < fireSourceCount; i++)
{
remoteFireSources.Add(new Vector3(

View File

@@ -18,6 +18,7 @@ namespace Barotrauma
foreach (Pair<MapEntityPrefab, Rectangle> entity in DisplayEntities)
{
if (entity.First is CoreEntityPrefab) { continue; }
Rectangle drawRect = entity.Second;
drawRect = new Rectangle(
(int)(drawRect.X * scale) + drawArea.Center.X, (int)((drawRect.Y) * scale) - drawArea.Center.Y,
@@ -33,7 +34,9 @@ namespace Barotrauma
foreach (Pair<MapEntityPrefab, Rectangle> entity in DisplayEntities)
{
Rectangle drawRect = entity.Second;
drawRect.Location += Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
drawRect.Location += placePosition != Vector2.Zero ? placePosition.ToPoint() : Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
entity.First.DrawPlacing(spriteBatch, drawRect, entity.First.Scale);
}
}

View File

@@ -91,11 +91,11 @@ namespace Barotrauma
public void RenderWater(SpriteBatch spriteBatch, RenderTarget2D texture, Camera cam)
{
spriteBatch.GraphicsDevice.BlendState = BlendState.NonPremultiplied;
WaterEffect.Parameters["xTexture"].SetValue(texture);
Vector2 distortionStrength = cam == null ? DistortionStrength : DistortionStrength * cam.Zoom;
WaterEffect.Parameters["xWaveWidth"].SetValue(DistortionStrength.X);
WaterEffect.Parameters["xWaveHeight"].SetValue(DistortionStrength.Y);
WaterEffect.Parameters["xWaveWidth"].SetValue(distortionStrength.X);
WaterEffect.Parameters["xWaveHeight"].SetValue(distortionStrength.Y);
if (BlurAmount > 0.0f)
{
WaterEffect.CurrentTechnique = WaterEffect.Techniques["WaterShaderBlurred"];
@@ -111,6 +111,9 @@ namespace Barotrauma
offset += (cam.Position - new Vector2(cam.WorldView.Width / 2.0f, -cam.WorldView.Height / 2.0f));
offset.Y += cam.WorldView.Height;
offset.X += cam.WorldView.Width;
#if LINUX || OSX
offset.X += cam.WorldView.Width;
#endif
offset *= DistortionScale;
}
offset.Y = -offset.Y;
@@ -176,6 +179,9 @@ namespace Barotrauma
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, subVerts.Value, 0, PositionInIndoorsBuffer[subVerts.Key] / 3);
}
WaterEffect.Parameters["xTexture"].SetValue((Texture2D)null);
WaterEffect.CurrentTechnique.Passes[0].Apply();
}
public void ScrollWater(Vector2 vel, float deltaTime)
@@ -195,7 +201,10 @@ namespace Barotrauma
basicEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, PositionInBuffer / 3);
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, PositionInBuffer / 3);
basicEffect.Texture = null;
basicEffect.CurrentTechnique.Passes[0].Apply();
}
public void ResetBuffers()

View File

@@ -93,9 +93,9 @@ namespace Barotrauma.Lights
public static BasicEffect shadowEffect;
public static BasicEffect penumbraEffect;
private Segment[] segments = new Segment[4];
private SegmentPoint[] vertices = new SegmentPoint[4];
private SegmentPoint[] losVertices = new SegmentPoint[4];
private readonly Segment[] segments = new Segment[4];
private readonly SegmentPoint[] vertices = new SegmentPoint[4];
private readonly SegmentPoint[] losVertices = new SegmentPoint[4];
private readonly bool[] backFacing;
private readonly bool[] ignoreEdge;
@@ -106,6 +106,8 @@ namespace Barotrauma.Lights
public VertexPositionTexture[] PenumbraVertices { get; private set; }
public int ShadowVertexCount { get; private set; }
private readonly HashSet<ConvexHull> overlappingHulls = new HashSet<ConvexHull>();
public MapEntity ParentEntity { get; private set; }
private bool enabled;
@@ -176,7 +178,7 @@ namespace Barotrauma.Lights
if (door != null) { isHorizontal = door.IsHorizontal; }
}
var chList = HullLists.Find(x => x.Submarine == parent.Submarine);
var chList = HullLists.Find(h => h.Submarine == parent.Submarine);
if (chList == null)
{
chList = new ConvexHullList(parent.Submarine);
@@ -194,10 +196,12 @@ namespace Barotrauma.Lights
private void MergeOverlappingSegments(ConvexHull ch)
{
if (ch == this) return;
if (ch == this) { return; }
if (isHorizontal == ch.isHorizontal)
{
if (BoundingBox == ch.BoundingBox) { return; }
//hide segments that are roughly at the some position as some other segment (e.g. the ends of two adjacent wall pieces)
float mergeDist = 32;
float mergeDistSqr = mergeDist * mergeDist;
@@ -206,6 +210,7 @@ namespace Barotrauma.Lights
for (int j = 0; j < ch.segments.Length; j++)
{
if (segments[i].IsHorizontal != ch.segments[j].IsHorizontal) { continue; }
if (ignoreEdge[i] || ch.ignoreEdge[j]) { continue; }
//the segments must be at different sides of the convex hulls to be merged
//(e.g. the right edge of a wall piece and the left edge of another one)
@@ -247,6 +252,7 @@ namespace Barotrauma.Lights
p.Y >= ch.BoundingBox.Y && p.Y <= ch.BoundingBox.Bottom)
{
ignoreEdge[i] = true;
overlappingHulls.Add(ch);
}
}
}
@@ -283,11 +289,25 @@ namespace Barotrauma.Lights
}
else
{
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
(segment1.Start.Pos + segment2.End.Pos) / 2.0f;
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
(segment1.End.Pos + segment2.Start.Pos) / 2.0f;
if (Vector2.DistanceSquared(losVertices[startPointIndex].Pos, segment1.Start.Pos) <
Vector2.DistanceSquared(losVertices[startPointIndex].Pos, segment1.End.Pos))
{
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
(segment1.Start.Pos + segment2.End.Pos) / 2.0f;
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
(segment1.End.Pos + segment2.Start.Pos) / 2.0f;
}
else
{
losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos =
(segment1.End.Pos + segment2.Start.Pos) / 2.0f;
losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos =
(segment1.Start.Pos + segment2.End.Pos) / 2.0f;
}
}
overlappingHulls.Add(segment2.ConvexHull);
segment2.ConvexHull.overlappingHulls.Add(this);
}
public void Rotate(Vector2 origin, float amount)
@@ -328,7 +348,26 @@ namespace Barotrauma.Lights
LastVertexChangeTime = (float)Timing.TotalTime;
overlappingHulls.Clear();
for (int i = 0; i < 4; i++)
{
ignoreEdge[i] = false;
}
CalculateDimensions();
if (ParentEntity == null) { return; }
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
if (chList != null)
{
overlappingHulls.Clear();
foreach (ConvexHull ch in chList.List)
{
MergeOverlappingSegments(ch);
ch.MergeOverlappingSegments(this);
}
}
}
public void SetVertices(Vector2[] points, Matrix? rotationMatrix = null)
@@ -348,6 +387,8 @@ namespace Barotrauma.Lights
ignoreEdge[i] = false;
}
overlappingHulls.Clear();
int margin = 0;
if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[2].Y))
{
@@ -381,9 +422,10 @@ namespace Barotrauma.Lights
if (ParentEntity == null) return;
var chList = HullLists.Find(x => x.Submarine == ParentEntity.Submarine);
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
if (chList != null)
{
overlappingHulls.Clear();
foreach (ConvexHull ch in chList.List)
{
MergeOverlappingSegments(ch);
@@ -484,8 +526,8 @@ namespace Barotrauma.Lights
//find beginning and ending vertices which
//belong to the shadow
int startingIndex = 0;
int endingIndex = 0;
int startingIndex = -1;
int endingIndex = -1;
for (int i = 0; i < 4; i++)
{
int currentEdge = i;
@@ -498,6 +540,8 @@ namespace Barotrauma.Lights
startingIndex = nextEdge;
}
if (startingIndex == -1 || endingIndex == -1) { return; }
//nr of vertices that are in the shadow
if (endingIndex > startingIndex)
ShadowVertexCount = endingIndex - startingIndex + 1;
@@ -663,7 +707,7 @@ namespace Barotrauma.Lights
public void Remove()
{
var chList = HullLists.Find(x => x.Submarine == ParentEntity.Submarine);
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
if (chList != null)
{
@@ -672,8 +716,19 @@ namespace Barotrauma.Lights
{
HullLists.Remove(chList);
}
foreach (ConvexHull ch2 in overlappingHulls)
{
for (int i = 0; i < 4; i++)
{
ch2.ignoreEdge[i] = false;
}
ch2.overlappingHulls.Remove(this);
foreach (ConvexHull ch in chList.List)
{
ch.MergeOverlappingSegments(ch2);
}
}
}
}
}
}

View File

@@ -11,18 +11,6 @@ namespace Barotrauma.Lights
{
class LightManager
{
private const float AmbientLightUpdateInterval = 0.2f;
private const float AmbientLightFalloff = 0.8f;
/// <summary>
/// Enables a feature that makes lights inside the hull increase the brightness of the entire hull
/// and adjacent ones to some extent, if there are gaps for the lights to pass through.
/// Prevents unnaturally dark looking shadows in otherwise well-lit submarines, but disabled at least for
/// the time being because it makes the lighting behave unpredictably and may cause rooms to appear
/// excessively bright if different lighting conditions aren't tested and accounted for.
/// </summary>
private static readonly bool UseHullSpecificAmbientLight = false;
public static Entity ViewTarget { get; set; }
private float currLightMapScale;
@@ -57,7 +45,7 @@ namespace Barotrauma.Lights
public Effect LosEffect { get; private set; }
public Effect SolidColorEffect { get; private set; }
private List<LightSource> lights;
private readonly List<LightSource> lights;
public bool LosEnabled = true;
public LosMode LosMode = LosMode.Transparent;
@@ -66,13 +54,8 @@ namespace Barotrauma.Lights
public bool ObstructVision;
private Texture2D visionCircle;
private readonly Texture2D visionCircle;
private Dictionary<Hull, Color> hullAmbientLights;
private Dictionary<Hull, Color> smoothedHullAmbientLights;
private float ambientLightUpdateTimer;
public IEnumerable<LightSource> Lights
{
get { return lights; }
@@ -80,7 +63,7 @@ namespace Barotrauma.Lights
public LightManager(GraphicsDevice graphics, ContentManager content)
{
lights = new List<LightSource>();
lights = new List<LightSource>(100);
AmbientLight = new Color(20, 20, 20, 255);
@@ -114,9 +97,6 @@ namespace Barotrauma.Lights
};
}
});
hullAmbientLights = new Dictionary<Hull, Color>();
smoothedHullAmbientLights = new Dictionary<Hull, Color>();
}
private void CreateRenderTargets(GraphicsDevice graphics)
@@ -167,43 +147,12 @@ namespace Barotrauma.Lights
}
}
public void Update(float deltaTime)
{
if (UseHullSpecificAmbientLight)
{
if (ambientLightUpdateTimer > 0.0f)
{
ambientLightUpdateTimer -= deltaTime;
}
else
{
CalculateAmbientLights();
ambientLightUpdateTimer = AmbientLightUpdateInterval;
}
foreach (Hull hull in hullAmbientLights.Keys)
{
if (!smoothedHullAmbientLights.ContainsKey(hull))
{
smoothedHullAmbientLights.Add(hull, Color.TransparentBlack);
}
}
foreach (Hull hull in smoothedHullAmbientLights.Keys.ToList())
{
Color targetColor = Color.TransparentBlack;
hullAmbientLights.TryGetValue(hull, out targetColor);
smoothedHullAmbientLights[hull] = Color.Lerp(smoothedHullAmbientLights[hull], targetColor, deltaTime);
}
}
}
private List<LightSource> activeLights = new List<LightSource>(capacity: 100);
private readonly List<LightSource> activeLights = new List<LightSource>(capacity: 100);
public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
{
if (!LightingEnabled) return;
if (!LightingEnabled) { return; }
if (Math.Abs(currLightMapScale - GameMain.Config.LightMapScale) > 0.01f)
{
//lightmap scale has changed -> recreate render targets
@@ -229,7 +178,16 @@ namespace Barotrauma.Lights
light.Position = light.ParentBody.DrawPosition;
if (light.ParentSub != null) { light.Position -= light.ParentSub.DrawPosition; }
}
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.LightSourceParams.TextureRange, viewRect)) { continue; }
float range = light.LightSourceParams.TextureRange;
if (light.LightSprite != null)
{
float spriteRange = Math.Max(
light.LightSprite.size.X * light.SpriteScale.X * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.X - 0.5f)),
light.LightSprite.size.Y * light.SpriteScale.Y * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.Y - 0.5f)));
range = Math.Max(spriteRange, range);
}
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect)) { continue; }
activeLights.Add(light);
}
@@ -252,16 +210,14 @@ namespace Barotrauma.Lights
//draw background lights
//---------------------------------------------------------------------------------------------------
graphics.SetRenderTarget(LightMap);
graphics.Clear(Color.Black);
graphics.Clear(AmbientLight);
graphics.BlendState = BlendState.Additive;
bool backgroundSpritesDrawn = false;
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
foreach (LightSource light in activeLights)
{
if (!light.IsBackground) { continue; }
light.DrawSprite(spriteBatch, cam);
if (light.Color.A > 0 && light.Range > 0.0f) { light.DrawLightVolume(spriteBatch, lightEffect, transform); }
backgroundSpritesDrawn = true;
}
GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
spriteBatch.End();
@@ -269,33 +225,34 @@ namespace Barotrauma.Lights
//draw a black rectangle on hulls to hide background lights behind subs
//---------------------------------------------------------------------------------------------------
Dictionary<Hull, Rectangle> visibleHulls = null;
if (backgroundSpritesDrawn)
if (backgroundObstructor != null)
{
if (backgroundObstructor != null)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
spriteBatch.End();
}
visibleHulls = GetVisibleHulls(cam);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
foreach (Rectangle drawRect in visibleHulls.Values)
{
//TODO: draw some sort of smoothed rectangle
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(drawRect.Width, drawRect.Height),
Color.Black, true);
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
spriteBatch.End();
graphics.BlendState = BlendState.Additive;
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
foreach (KeyValuePair<Hull, Rectangle> hull in visibleHulls)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(hull.Value.X, -hull.Value.Y),
new Vector2(hull.Value.Width, hull.Value.Height),
hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f), true);
}
spriteBatch.End();
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.ToVector4());
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
Submarine.DrawDamageable(spriteBatch, null);
spriteBatch.End();
graphics.BlendState = BlendState.Additive;
//draw the focused item and character to highlight them,
//and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
//---------------------------------------------------------------------------------------------------
@@ -318,33 +275,37 @@ namespace Barotrauma.Lights
//draw characters to obstruct the highlighted items/characters and light sprites
//---------------------------------------------------------------------------------------------------
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
SolidColorEffect.Parameters["color"].SetValue(Color.Black.ToVector4());
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
foreach (Character character in Character.CharacterList)
{
if (character.CurrentHull == null || !character.Enabled) continue;
if (Character.Controlled?.FocusedCharacter == character) continue;
if (character.CurrentHull == null || !character.Enabled) { continue; }
if (Character.Controlled?.FocusedCharacter == character) { continue; }
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
Color.Black :
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.DeformSprite != null) continue;
limb.Draw(spriteBatch, cam, Color.Black);
if (limb.DeformSprite != null) { continue; }
limb.Draw(spriteBatch, cam, lightColor);
}
}
spriteBatch.End();
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidColor"];
DeformableSprite.Effect.Parameters["solidColor"].SetValue(Color.Black.ToVector4());
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
foreach (Character character in Character.CharacterList)
{
if (character.CurrentHull == null || !character.Enabled) continue;
if (Character.Controlled?.FocusedCharacter == character) continue;
if (character.CurrentHull == null || !character.Enabled) { continue; }
if (Character.Controlled?.FocusedCharacter == character) { continue; }
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
Color.Black :
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.DeformSprite == null) continue;
limb.Draw(spriteBatch, cam, Color.Black);
if (limb.DeformSprite == null) { continue; }
limb.Draw(spriteBatch, cam, lightColor);
}
}
spriteBatch.End();
@@ -355,8 +316,6 @@ namespace Barotrauma.Lights
//---------------------------------------------------------------------------------------------------
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
GUI.DrawRectangle(spriteBatch, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), AmbientLight, isFilled: true);
spriteBatch.Draw(LimbLightMap, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);
foreach (ElectricalDischarger discharger in ElectricalDischarger.List)
@@ -373,24 +332,7 @@ namespace Barotrauma.Lights
lightEffect.World = transform;
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
if (UseHullSpecificAmbientLight)
{
if (visibleHulls == null)
{
visibleHulls = GetVisibleHulls(cam);
}
foreach (Hull hull in smoothedHullAmbientLights.Keys)
{
if (smoothedHullAmbientLights[hull].A < 0.01f) continue;
if (!visibleHulls.TryGetValue(hull, out Rectangle drawRect)) continue;
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(hull.Rect.Width, hull.Rect.Height),
smoothedHullAmbientLights[hull], true);
}
}
if (Character.Controlled != null)
{
Vector2 haloDrawPos = Character.Controlled.DrawPosition;
@@ -592,7 +534,10 @@ namespace Barotrauma.Lights
}
}
penumbraVerts.AddRange(convexHull.PenumbraVertices);
if (convexHull.ShadowVertexCount > 0)
{
penumbraVerts.AddRange(convexHull.PenumbraVertices);
}
}
if (shadowVerts.Count > 0)
@@ -613,86 +558,6 @@ namespace Barotrauma.Lights
graphics.SetRenderTarget(null);
}
private void CalculateAmbientLights()
{
hullAmbientLights.Clear();
foreach (LightSource light in lights)
{
if (light.Color.A < 1f || light.Range < 1.0f || light.IsBackground) continue;
var newAmbientLights = AmbientLightHulls(light);
foreach (Hull hull in newAmbientLights.Keys)
{
if (hullAmbientLights.ContainsKey(hull))
{
//hull already lit by some other light source -> add the ambient lights up
hullAmbientLights[hull] = new Color(
hullAmbientLights[hull].R + newAmbientLights[hull].R,
hullAmbientLights[hull].G + newAmbientLights[hull].G,
hullAmbientLights[hull].B + newAmbientLights[hull].B,
hullAmbientLights[hull].A + newAmbientLights[hull].A);
}
else
{
hullAmbientLights.Add(hull, newAmbientLights[hull]);
}
}
}
}
/// <summary>
/// Add ambient light to the hull the lightsource is inside + all adjacent hulls connected by a gap
/// </summary>
private Dictionary<Hull, Color> AmbientLightHulls(LightSource light)
{
Dictionary<Hull, Color> hullAmbientLight = new Dictionary<Hull, Color>();
var hull = Hull.FindHull(light.WorldPosition);
if (hull == null) return hullAmbientLight;
return AmbientLightHulls(hull, hullAmbientLight, light.Color * Math.Min(light.Range / 1000.0f, 1.0f));
}
/// <summary>
/// A flood fill algorithm that adds ambient light to all hulls the starting hull is connected to
/// </summary>
private Dictionary<Hull, Color> AmbientLightHulls(Hull hull, Dictionary<Hull, Color> hullAmbientLight, Color currColor)
{
if (hullAmbientLight.ContainsKey(hull))
{
if (hullAmbientLight[hull].A > currColor.A)
return hullAmbientLight;
else
hullAmbientLight[hull] = currColor;
}
else
{
hullAmbientLight.Add(hull, currColor);
}
Color nextHullLight = currColor * AmbientLightFalloff;
//light getting too dark to notice -> no need to spread further
if (nextHullLight.A < 20) return hullAmbientLight;
//use hashset to make sure that each hull is only included once
HashSet<Hull> hulls = new HashSet<Hull>();
foreach (Gap g in hull.ConnectedGaps)
{
if (!g.IsRoomToRoom || !g.PassAmbientLight || g.Open < 0.5f) continue;
hulls.Add((g.linkedTo[0] == hull ? g.linkedTo[1] : g.linkedTo[0]) as Hull);
}
foreach (Hull h in hulls)
{
hullAmbientLight = AmbientLightHulls(h, hullAmbientLight, nextHullLight);
}
return hullAmbientLight;
}
public void ClearLights()
{
lights.Clear();

View File

@@ -16,7 +16,7 @@ namespace Barotrauma.Lights
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; } = new Dictionary<string, SerializableProperty>();
[Serialize("1.0,1.0,1.0,1.0", true), Editable]
[Serialize("1.0,1.0,1.0,1.0", true, alwaysUseInstanceValues: true), Editable]
public Color Color
{
get;
@@ -25,7 +25,7 @@ namespace Barotrauma.Lights
private float range;
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
[Serialize(100.0f, true, alwaysUseInstanceValues: true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
public float Range
{
get { return range; }
@@ -331,7 +331,7 @@ namespace Barotrauma.Lights
if (lightSourceParams.DeformableLightSpriteElement != null)
{
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement);
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement, invert: true);
}
}
@@ -342,7 +342,7 @@ namespace Barotrauma.Lights
lightSourceParams.Persistent = true;
if (lightSourceParams.DeformableLightSpriteElement != null)
{
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement);
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement, invert: true);
}
}
@@ -952,23 +952,44 @@ namespace Barotrauma.Lights
{
Vector2 origin = DeformableLightSprite.Origin;
Vector2 drawPos = position;
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
if (ParentSub != null)
{
drawPos += ParentSub.DrawPosition;
}
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
{
origin.X = DeformableLightSprite.Sprite.SourceRect.Width - origin.X;
}
if (LightSpriteEffect == SpriteEffects.FlipVertically)
{
origin.Y = DeformableLightSprite.Sprite.SourceRect.Height - origin.Y;
}
DeformableLightSprite.Draw(
cam, new Vector3(drawPos, 0.0f),
origin, -Rotation, SpriteScale,
new Color(Color, lightSourceParams.OverrideLightSpriteAlpha ?? Color.A / 255.0f),
LightSpriteEffect == SpriteEffects.FlipHorizontally);
LightSpriteEffect == SpriteEffects.FlipVertically);
}
if (LightSprite != null)
{
Vector2 origin = LightSprite.Origin;
if (LightSpriteEffect == SpriteEffects.FlipHorizontally) origin.X = LightSprite.SourceRect.Width - origin.X;
if (LightSpriteEffect == SpriteEffects.FlipVertically) origin.Y = LightSprite.SourceRect.Height - origin.Y;
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
{
origin.X = LightSprite.SourceRect.Width - origin.X;
}
if (LightSpriteEffect == SpriteEffects.FlipVertically)
{
origin.Y = LightSprite.SourceRect.Height - origin.Y;
}
Vector2 drawPos = position;
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
if (ParentSub != null)
{
drawPos += ParentSub.DrawPosition;
}
drawPos.Y = -drawPos.Y;
LightSprite.Draw(

View File

@@ -2,7 +2,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
@@ -13,11 +13,28 @@ namespace Barotrauma
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!editing || wallVertices == null) { return; }
Draw(spriteBatch, Position);
Color color = IsHighlighted ? GUI.Style.Orange : GUI.Style.Green;
if (!Item.ShowLinks) { return; }
foreach (MapEntity e in linkedTo)
{
bool isLinkAllowed = e is Item item && item.HasTag("dock");
GUI.DrawLine(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
new Vector2(e.WorldPosition.X, -e.WorldPosition.Y),
isLinkAllowed ? GUI.Style.Green * 0.5f : GUI.Style.Red * 0.5f, width: 3);
}
}
public void Draw(SpriteBatch spriteBatch, Vector2 drawPos, float alpha = 1.0f)
{
Color color = (IsHighlighted) ? GUI.Style.Orange : GUI.Style.Green;
if (IsSelected) { color = GUI.Style.Red; }
Vector2 pos = Position;
Vector2 pos = drawPos;
for (int i = 0; i < wallVertices.Count; i++)
{
@@ -28,26 +45,14 @@ namespace Barotrauma
endPos.Y = -endPos.Y;
GUI.DrawLine(spriteBatch,
startPos,
endPos,
color, 0.0f, 5);
startPos,
endPos,
color * alpha, 0.0f, 5);
}
pos.Y = -pos.Y;
GUI.DrawLine(spriteBatch, pos + Vector2.UnitY * 50.0f, pos - Vector2.UnitY * 50.0f, color, 0.0f, 5);
GUI.DrawLine(spriteBatch, pos + Vector2.UnitX * 50.0f, pos - Vector2.UnitX * 50.0f, color, 0.0f, 5);
if (!Item.ShowLinks) { return; }
foreach (MapEntity e in linkedTo)
{
bool isLinkAllowed = e is Item item && item.HasTag("dock");
GUI.DrawLine(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
new Vector2(e.WorldPosition.X, -e.WorldPosition.Y),
isLinkAllowed ? GUI.Style.Green * 0.5f : GUI.Style.Red * 0.5f, width: 3);
}
GUI.DrawLine(spriteBatch, pos + Vector2.UnitY * 50.0f, pos - Vector2.UnitY * 50.0f, color * alpha, 0.0f, 5);
GUI.DrawLine(spriteBatch, pos + Vector2.UnitX * 50.0f, pos - Vector2.UnitX * 50.0f, color * alpha, 0.0f, 5);
}
public override void UpdateEditing(Camera cam)
@@ -100,10 +105,9 @@ namespace Barotrauma
}
var pathContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), isHorizontal: true);
var pathBox = new GUITextBox(new RectTransform(new Vector2(0.75f, 1.0f), pathContainer.RectTransform), filePath, font: GUI.SmallFont);
var reloadButton = new GUIButton(new RectTransform(new Vector2(0.25f / pathBox.RectTransform.RelativeSize.X, 1.0f), pathBox.RectTransform, Anchor.CenterRight, Pivot.CenterLeft),
TextManager.Get("ReloadLinkedSub"), style: "GUIButtonSmall")
TextManager.Get("ReloadLinkedSub"), style: "GUIButtonSmall")
{
OnClicked = Reload,
UserData = pathBox,
@@ -133,6 +137,7 @@ namespace Barotrauma
XDocument doc = SubmarineInfo.OpenFile(pathBox.Text);
if (doc == null || doc.Root == null) return false;
doc.Root.SetAttributeValue("filepath", pathBox.Text);
pathBox.Flash(GUI.Style.Green);

View File

@@ -16,6 +16,8 @@ namespace Barotrauma
private static Vector2 startMovingPos = Vector2.Zero;
private static float keyDelay;
public static Vector2 StartMovingPos => startMovingPos;
// Quick undo/redo for size and movement only. TODO: Remove if we do a more general implementation.
@@ -132,7 +134,7 @@ namespace Barotrauma
if (highlightedListBox == null ||
(GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
{
UpdateHighlightedListBox(null);
UpdateHighlightedListBox(null, false);
return;
}
}
@@ -147,11 +149,15 @@ namespace Barotrauma
{
if (PlayerInput.KeyDown(Keys.Delete))
{
selectedList.ForEach(e => e.Remove());
selectedList.ForEach(e =>
{
//orphaned wires may already have been removed
if (!e.Removed) { e.Remove(); }
});
selectedList.Clear();
}
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
if (PlayerInput.IsCtrlDown())
{
if (PlayerInput.KeyHit(Keys.C))
{
@@ -244,32 +250,7 @@ namespace Barotrauma
}
}
if (PlayerInput.MouseSpeed.LengthSquared() > 10)
{
highlightTimer = 0.0f;
}
else
{
bool mouseNearHighlightBox = false;
if (highlightedListBox != null)
{
Rectangle expandedRect = highlightedListBox.Rect;
expandedRect.Inflate(20, 20);
mouseNearHighlightBox = expandedRect.Contains(PlayerInput.MousePosition);
if (!mouseNearHighlightBox) highlightedListBox = null;
}
highlightTimer += (float)Timing.Step;
if (highlightTimer > 1.0f)
{
if (!mouseNearHighlightBox)
{
UpdateHighlightedListBox(highlightedEntities);
highlightTimer = 0.0f;
}
}
}
UpdateHighlighting(highlightedEntities);
}
if (highLightedEntity != null) highLightedEntity.isHighlighted = true;
@@ -277,35 +258,65 @@ namespace Barotrauma
if (GUI.KeyboardDispatcher.Subscriber == null)
{
int up = PlayerInput.KeyDown(Keys.Up) ? 1 : 0,
down = PlayerInput.KeyDown(Keys.Down) ? -1 : 0,
left = PlayerInput.KeyDown(Keys.Left) ? -1 : 0,
right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0;
int xKeysDown = (left + right);
int yKeysDown = (up + down);
if (xKeysDown != 0 || yKeysDown != 0) { keyDelay += (float) Timing.Step; } else { keyDelay = 0; }
Vector2 nudgeAmount = Vector2.Zero;
if (PlayerInput.KeyHit(Keys.Up)) nudgeAmount.Y = 1f;
if (keyDelay >= 0.5f)
{
nudgeAmount.Y = yKeysDown;
nudgeAmount.X = xKeysDown;
}
if (PlayerInput.KeyHit(Keys.Up)) nudgeAmount.Y = 1f;
if (PlayerInput.KeyHit(Keys.Down)) nudgeAmount.Y = -1f;
if (PlayerInput.KeyHit(Keys.Left)) nudgeAmount.X = -1f;
if (PlayerInput.KeyHit(Keys.Right)) nudgeAmount.X = 1f;
if (PlayerInput.KeyHit(Keys.Right)) nudgeAmount.X = 1f;
if (nudgeAmount != Vector2.Zero)
{
foreach (MapEntity entityToNudge in selectedList)
{
entityToNudge.Move(nudgeAmount);
}
foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudgeAmount); }
}
}
else
{
keyDelay = 0;
}
bool isShiftDown = PlayerInput.IsShiftDown();
//started moving selected entities
if (startMovingPos != Vector2.Zero)
{
Item targetContainer = GetPotentialContainer(position, selectedList);
if (targetContainer != null) { targetContainer.IsHighlighted = true; }
if (PlayerInput.PrimaryMouseButtonReleased())
{
//mouse released -> move the entities to the new position of the mouse
Vector2 moveAmount = position - startMovingPos;
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y)
if (!isShiftDown)
{
moveAmount = Submarine.VectorToWorldGrid(moveAmount);
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
}
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
{
if (!isShiftDown) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); }
//clone
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
if (PlayerInput.IsCtrlDown())
{
var clones = Clone(selectedList);
selectedList = clones;
@@ -313,6 +324,7 @@ namespace Barotrauma
}
else // move
{
List<MapEntity> deposited = new List<MapEntity>();
foreach (MapEntity e in selectedList)
{
if (e.rectMemento == null)
@@ -321,8 +333,23 @@ namespace Barotrauma
e.rectMemento.Store(e.Rect);
}
e.Move(moveAmount);
if (isShiftDown && e is Item item && targetContainer != null)
{
if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled))
{
GUI.PlayUISound(GUISoundType.DropItem);
deposited.Add(item);
}
else
{
GUI.PlayUISound(GUISoundType.PickItemFail);
}
}
e.rectMemento.Store(e.Rect);
}
deposited.ForEach(entity => { selectedList.Remove(entity); });
}
}
startMovingPos = Vector2.Zero;
@@ -357,8 +384,7 @@ namespace Barotrauma
if (PlayerInput.PrimaryMouseButtonReleased())
{
if (PlayerInput.KeyDown(Keys.LeftControl) ||
PlayerInput.KeyDown(Keys.RightControl))
if (PlayerInput.IsCtrlDown())
{
foreach (MapEntity e in newSelection)
{
@@ -441,7 +467,84 @@ namespace Barotrauma
}
}
private static void UpdateHighlightedListBox(List<MapEntity> highlightedEntities)
public static Item GetPotentialContainer(Vector2 position, List<MapEntity> entities = null)
{
Item targetContainer = null;
bool isShiftDown = PlayerInput.IsShiftDown();
if (!isShiftDown) return null;
foreach (MapEntity e in mapEntityList)
{
if (!e.SelectableInEditor ||!(e is Item potentialContainer)) { continue; }
if (e.IsMouseOn(position))
{
if (entities == null)
{
if (potentialContainer.OwnInventory != null && potentialContainer.ParentInventory == null && !potentialContainer.OwnInventory.IsFull())
{
targetContainer = potentialContainer;
break;
}
}
else
{
foreach (MapEntity selectedEntity in entities)
{
if (!(selectedEntity is Item selectedItem)) { continue; }
if (potentialContainer.OwnInventory != null && potentialContainer.ParentInventory == null && potentialContainer != selectedItem &&
potentialContainer.OwnInventory.CanBePut(selectedItem))
{
targetContainer = potentialContainer;
break;
}
}
}
}
if (targetContainer != null) { break; }
}
return targetContainer;
}
/// <summary>
/// Updates the logic that runs the highlight box when the mouse is sitting still.
/// </summary>
/// <see cref="UpdateHighlightedListBox"/>
/// <param name="highlightedEntities"></param>
/// <param name="wiringMode">true to give items tooltip showing their connection</param>
public static void UpdateHighlighting(List<MapEntity> highlightedEntities, bool wiringMode = false)
{
if (PlayerInput.MouseSpeed.LengthSquared() > 10)
{
highlightTimer = 0.0f;
}
else
{
bool mouseNearHighlightBox = false;
if (highlightedListBox != null)
{
Rectangle expandedRect = highlightedListBox.Rect;
expandedRect.Inflate(20, 20);
mouseNearHighlightBox = expandedRect.Contains(PlayerInput.MousePosition);
if (!mouseNearHighlightBox) highlightedListBox = null;
}
highlightTimer += (float)Timing.Step;
if (highlightTimer > 1.0f)
{
if (!mouseNearHighlightBox)
{
UpdateHighlightedListBox(highlightedEntities, wiringMode);
highlightTimer = 0.0f;
}
}
}
}
private static void UpdateHighlightedListBox(List<MapEntity> highlightedEntities, bool wiringMode)
{
if (highlightedEntities == null || highlightedEntities.Count < 2)
{
@@ -458,14 +561,37 @@ namespace Barotrauma
highlightedListBox = new GUIListBox(new RectTransform(new Point(180, highlightedEntities.Count * 18 + 5), GUI.Canvas)
{
MaxSize = new Point(int.MaxValue, 256),
ScreenSpaceOffset = PlayerInput.MousePosition.ToPoint() + new Point(15)
}, style: "GUIToolTip");
foreach (MapEntity entity in highlightedEntities)
{
var textBlock = new GUITextBlock(new RectTransform(new Point(highlightedListBox.Content.Rect.Width, 15), highlightedListBox.Content.RectTransform),
ToolBox.LimitString(entity.Name, GUI.SmallFont, 140), font: GUI.SmallFont)
var tooltip = string.Empty;
if (wiringMode && entity is Item item)
{
var wire = item.GetComponent<Wire>();
if (wire?.Connections != null)
{
for (var i = 0; i < wire.Connections.Length; i++)
{
var conn = wire.Connections[i];
if (conn != null)
{
string[] tags = { "[item]", "[pin]" };
string[] values = { conn.Item?.Name, conn.Name };
tooltip += TextManager.GetWithVariables("wirelistformat",tags , values);
}
if (i != wire.Connections.Length - 1) { tooltip += '\n'; }
}
}
}
var textBlock = new GUITextBlock(new RectTransform(new Point(highlightedListBox.Content.Rect.Width, 15), highlightedListBox.Content.RectTransform),
ToolBox.LimitString(entity.Name, GUI.SmallFont, 140), font: GUI.SmallFont)
{
ToolTip = tooltip,
UserData = entity
};
}
@@ -474,8 +600,7 @@ namespace Barotrauma
{
MapEntity entity = obj as MapEntity;
if (PlayerInput.KeyDown(Keys.LeftControl) ||
PlayerInput.KeyDown(Keys.RightControl))
if (PlayerInput.IsCtrlDown() && !wiringMode)
{
if (selectedList.Contains(entity))
{
@@ -485,11 +610,10 @@ namespace Barotrauma
{
AddSelection(entity);
}
return true;
}
else
{
SelectEntity(entity);
}
SelectEntity(entity);
return true;
};
@@ -558,6 +682,10 @@ namespace Barotrauma
{
item.UpdateSpriteStates(deltaTime);
}
else if (me is Structure structure)
{
structure.UpdateSpriteStates(deltaTime);
}
}
}
@@ -575,32 +703,52 @@ namespace Barotrauma
{
Vector2 moveAmount = position - startMovingPos;
moveAmount.Y = -moveAmount.Y;
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
bool isShiftDown = PlayerInput.IsShiftDown();
if (!isShiftDown)
{
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
}
//started moving the selected entities
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y)
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
{
foreach (MapEntity e in selectedList)
{
SpriteEffects spriteEffects = SpriteEffects.None;
if (e is Item item)
switch (e)
{
if (item.FlippedX && item.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (item.flippedY && item.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
}
else if (e is Structure structure)
{
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
}
else if (e is WayPoint wayPoint)
{
Vector2 drawPos = e.WorldPosition;
drawPos.Y = -drawPos.Y;
drawPos += moveAmount;
wayPoint.Draw(spriteBatch, drawPos);
continue;
case Item item:
{
if (item.FlippedX && item.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (item.flippedY && item.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
break;
}
case Structure structure:
{
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
break;
}
case WayPoint wayPoint:
{
Vector2 drawPos = e.WorldPosition;
drawPos.Y = -drawPos.Y;
drawPos += moveAmount;
wayPoint.Draw(spriteBatch, drawPos);
continue;
}
case LinkedSubmarine linkedSub:
{
var ma = moveAmount;
ma.Y = -ma.Y;
Vector2 lPos = linkedSub.Position;
lPos += ma;
linkedSub.Draw(spriteBatch, lPos, alpha: 0.5f);
break;
}
}
e.prefab?.DrawPlacing(spriteBatch,
new Rectangle(e.WorldRect.Location + new Point((int)moveAmount.X, (int)-moveAmount.Y), e.WorldRect.Size), e.Scale, spriteEffects);
@@ -656,7 +804,7 @@ namespace Barotrauma
}
}
if ((PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)))
if (PlayerInput.IsCtrlDown())
{
if (PlayerInput.KeyHit(Keys.N))
{
@@ -734,7 +882,10 @@ namespace Barotrauma
CopyEntities(entities);
entities.ForEach(e => e.Remove());
entities.ForEach(e =>
{
e.Remove();
});
entities.Clear();
}
@@ -847,6 +998,7 @@ namespace Barotrauma
resizeDirX = x;
resizeDirY = y;
resizing = true;
startMovingPos = Vector2.Zero;
}
}
}
@@ -864,6 +1016,11 @@ namespace Barotrauma
Vector2 mousePos = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
if (PlayerInput.IsShiftDown())
{
mousePos = cam.ScreenToWorld(PlayerInput.MousePosition);
}
if (resizeDirX > 0)
{
mousePos.X = Math.Max(mousePos.X, rect.X + Submarine.GridSize.X);

View File

@@ -8,6 +8,12 @@ namespace Barotrauma
{
public virtual void UpdatePlacing(Camera cam)
{
if (PlayerInput.SecondaryMouseButtonClicked())
{
selected = null;
return;
}
Vector2 placeSize = Submarine.GridSize;
if (placePosition == Vector2.Zero)
@@ -41,12 +47,6 @@ namespace Barotrauma
newRect.Y = -newRect.Y;
}
if (PlayerInput.SecondaryMouseButtonHeld())
{
placePosition = Vector2.Zero;
selected = null;
}
}
public virtual void DrawPlacing(SpriteBatch spriteBatch, Camera cam)

View File

@@ -24,6 +24,10 @@ namespace Barotrauma
{
get
{
if (!GameMain.SubEditorScreen.ShowThalamus && prefab.Category.HasFlag(MapEntityCategory.Thalamus))
{
return false;
}
return HasBody ? ShowWalls : ShowStructures;
}
}
@@ -46,6 +50,8 @@ namespace Barotrauma
decorativeSprite.Sprite.EnsureLazyLoaded();
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
}
UpdateSpriteStates(0.0f);
}
partial void CreateConvexHull(Vector2 position, Vector2 size, float rotation)
@@ -334,7 +340,7 @@ namespace Barotrauma
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
rotation, Scale, prefab.sprite.effects,
rotation, decorativeSprite.Scale * Scale, prefab.sprite.effects,
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.sprite.Depth), 0.999f));
}
prefab.sprite.effects = oldEffects;
@@ -435,7 +441,7 @@ namespace Barotrauma
byte sectionCount = msg.ReadByte();
if (sectionCount != Sections.Length)
{
string errorMsg = $"Error while reading a network event for the structure \"{Name}\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
string errorMsg = $"Error while reading a network event for the structure \"{Name} ({ID})\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
DebugConsole.NewMessage(errorMsg, Color.Red);
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}

View File

@@ -18,6 +18,12 @@ namespace Barotrauma
public override void UpdatePlacing(Camera cam)
{
if (PlayerInput.SecondaryMouseButtonClicked())
{
selected = null;
return;
}
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
Vector2 size = ScaledSize;
Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y);
@@ -59,8 +65,6 @@ namespace Barotrauma
return;
}
}
if (PlayerInput.SecondaryMouseButtonHeld()) selected = null;
}
public override void DrawPlacing(SpriteBatch spriteBatch, Camera cam)
@@ -70,9 +74,6 @@ namespace Barotrauma
if (placePosition == Vector2.Zero)
{
if (PlayerInput.PrimaryMouseButtonHeld())
placePosition = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
newRect.X = (int)position.X;
newRect.Y = (int)position.Y;
}

View File

@@ -6,9 +6,10 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
namespace Barotrauma
{
@@ -86,7 +87,7 @@ namespace Barotrauma
existingSound = GameMain.SoundManager.LoadSound(filename, stream);
if (existingSound == null) { return null; }
}
catch (FileNotFoundException e)
catch (System.IO.FileNotFoundException e)
{
string errorMsg = "Failed to load sound file \"" + filename + "\".";
DebugConsole.ThrowError(errorMsg, e);
@@ -223,7 +224,7 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, worldBorders, Color.White, false, 0, 5);
if (sub.subBody == null || sub.subBody.PositionBuffer.Count < 2) continue;
if (sub.SubBody == null || sub.subBody.PositionBuffer.Count < 2) continue;
Vector2 prevPos = ConvertUnits.ToDisplayUnits(sub.subBody.PositionBuffer[0].Position);
prevPos.Y = -prevPos.Y;
@@ -246,7 +247,7 @@ namespace Barotrauma
public static Color DamageEffectColor;
private static readonly List<Structure> depthSortedDamageable = new List<Structure>();
public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing = false)
public static void DrawDamageable(SpriteBatch spriteBatch, Effect damageEffect, bool editing = false, Predicate<MapEntity> predicate = null)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList;
@@ -257,6 +258,10 @@ namespace Barotrauma
{
if (e is Structure structure && structure.DrawDamageEffect)
{
if (predicate != null)
{
if (!predicate(e)) continue;
}
float drawDepth = structure.GetDrawDepth();
int i = 0;
while (i < depthSortedDamageable.Count)

View File

@@ -1,7 +1,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
@@ -19,9 +19,9 @@ namespace Barotrauma
{
try
{
using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData)))
using (System.IO.MemoryStream mem = new System.IO.MemoryStream(Convert.FromBase64String(previewImageData)))
{
var texture = TextureLoader.FromStream(mem, path: FilePath);
var texture = TextureLoader.FromStream(mem, path: FilePath, compress: false);
if (texture == null) { throw new Exception("PreviewImage texture returned null"); }
PreviewImage = new Sprite(texture, null, null);
}

View File

@@ -1,6 +1,7 @@
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
@@ -8,7 +9,7 @@ namespace Barotrauma
{
partial class WayPoint : MapEntity
{
private static Dictionary<SpawnType, Sprite> iconSprites;
private static Dictionary<string, Sprite> iconSprites;
private const int WaypointSize = 12, SpawnPointSize = 32;
public override bool IsVisible(Rectangle worldView)
@@ -55,10 +56,18 @@ namespace Barotrauma
Color.White);
}
Sprite sprite = iconSprites[SpawnType];
Sprite sprite = iconSprites[SpawnType.ToString()];
if (spawnType == SpawnType.Human && AssignedJob?.Icon != null)
{
sprite = iconSprites[SpawnType.Path];
sprite = iconSprites["Path"];
}
else if (ConnectedDoor != null)
{
sprite = iconSprites["Door"];
}
else if (Ladders != null)
{
sprite = iconSprites["Ladder"];
}
sprite.Draw(spriteBatch, drawPos, clr, scale: iconSize / (float)sprite.SourceRect.Width, depth: 0.001f);
sprite.RelativeOrigin = Vector2.One * 0.5f;
@@ -107,59 +116,72 @@ namespace Barotrauma
{
editingHUD = CreateEditingHUD();
}
if (IsSelected && PlayerInput.PrimaryMouseButtonClicked())
{
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
// Update gaps, ladders, and stairs
UpdateLinkedEntity(position, Gap.GapList, gap => ConnectedGap = gap, gap =>
if (PlayerInput.KeyDown(Keys.Space))
{
if (ConnectedGap == gap)
foreach (MapEntity e in mapEntityList)
{
ConnectedGap = null;
}
});
UpdateLinkedEntity(position, Item.ItemList, i =>
{
var ladder = i?.GetComponent<Ladder>();
if (ladder != null)
{
Ladders = ladder;
}
}, i =>
{
var ladder = i?.GetComponent<Ladder>();
if (ladder != null)
{
if (Ladders == ladder)
if (e.GetType() != typeof(WayPoint)) continue;
if (e == this) continue;
if (!Submarine.RectContains(e.Rect, position)) continue;
if (linkedTo.Contains(e))
{
Ladders = null;
linkedTo.Remove(e);
e.linkedTo.Remove(this);
}
else
{
linkedTo.Add(e);
e.linkedTo.Add(this);
}
}
}, inflate: 5);
// TODO: Cannot check the rectangle, since the rectangle is not rotated -> Need to use the collider.
//var stairList = mapEntityList.Where(me => me is Structure s && s.StairDirection != Direction.None).Select(me => me as Structure);
//UpdateLinkedEntity(position, stairList, s =>
//{
// Stairs = s;
//}, s =>
//{
// if (Stairs == s)
// {
// Stairs = null;
// }
//});
foreach (MapEntity e in mapEntityList)
}
else
{
if (e.GetType() != typeof(WayPoint)) continue;
if (e == this) continue;
if (!Submarine.RectContains(e.Rect, position)) continue;
linkedTo.Add(e);
e.linkedTo.Add(this);
// Update gaps, ladders, and stairs
UpdateLinkedEntity(position, Gap.GapList, gap => ConnectedGap = gap, gap =>
{
if (ConnectedGap == gap)
{
ConnectedGap = null;
}
});
UpdateLinkedEntity(position, Item.ItemList, i =>
{
var ladder = i?.GetComponent<Ladder>();
if (ladder != null)
{
Ladders = ladder;
}
}, i =>
{
var ladder = i?.GetComponent<Ladder>();
if (ladder != null)
{
if (Ladders == ladder)
{
Ladders = null;
}
}
}, inflate: 5);
// TODO: Cannot check the rectangle, since the rectangle is not rotated -> Need to use the collider.
//var stairList = mapEntityList.Where(me => me is Structure s && s.StairDirection != Direction.None).Select(me => me as Structure);
//UpdateLinkedEntity(position, stairList, s =>
//{
// Stairs = s;
//}, s =>
//{
// if (Stairs == s)
// {
// Stairs = null;
// }
//});
}
}
}

View File

@@ -1,5 +1,5 @@
using System;
using System.IO;
using Barotrauma.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading;

View File

@@ -17,10 +17,12 @@ namespace Barotrauma.Networking
{
UInt16 ID = msg.ReadUInt16();
ChatMessageType type = (ChatMessageType)msg.ReadByte();
PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
string txt = "";
if (type != ChatMessageType.Order)
{
changeType = (PlayerConnectionChangeType)msg.ReadByte();
txt = msg.ReadString();
}
@@ -114,7 +116,7 @@ namespace Barotrauma.Networking
GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
break;
default:
GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter);
GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter, changeType);
break;
}
LastID = ID;

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Barotrauma.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
@@ -18,8 +18,8 @@ namespace Barotrauma.Networking
public static void Start(ProcessStartInfo processInfo)
{
writePipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
readPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
writePipe = new AnonymousPipeServerStream(PipeDirection.Out, System.IO.HandleInheritability.Inheritable);
readPipe = new AnonymousPipeServerStream(PipeDirection.In, System.IO.HandleInheritability.Inheritable);
writeStream = writePipe; readStream = readPipe;
@@ -38,6 +38,13 @@ namespace Barotrauma.Networking
localHandlesDisposed = true;
}
public static void ClosePipes()
{
writePipe?.Close();
readPipe?.Close();
shutDown = true;
}
public static void ShutDown()
{
Process?.Kill(); Process = null;

View File

@@ -14,8 +14,10 @@ namespace Barotrauma.Networking
public UInt64 SteamID;
public byte ID;
public UInt16 CharacterID;
public float Karma;
public bool Muted;
public bool InGame;
public bool HasPermissions;
public bool AllowKicking;
}
@@ -44,6 +46,8 @@ namespace Barotrauma.Networking
public bool AllowKicking;
public float Karma;
public void UpdateSoundPosition()
{
if (VoipSound == null) { return; }

View File

@@ -1,7 +1,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Threading;
using System.Xml;
@@ -100,7 +100,7 @@ namespace Barotrauma.Networking
WriteStream = null;
}
WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None);
WriteStream = File.Open(FilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
TimeStarted = Environment.TickCount;
}
@@ -259,7 +259,7 @@ namespace Barotrauma.Networking
{
newTransfer.OpenStream();
}
catch (IOException e)
catch (System.IO.IOException e)
{
if (i < maxRetries)
{
@@ -422,7 +422,7 @@ namespace Barotrauma.Networking
}
if (string.IsNullOrEmpty(fileName) ||
fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1)
fileName.IndexOfAny(Path.GetInvalidFileNameChars().ToArray()) > -1)
{
errorMessage = "Illegal characters in file name ''" + fileName + "''";
return false;
@@ -455,7 +455,7 @@ namespace Barotrauma.Networking
switch (fileTransfer.FileType)
{
case FileTransferType.Submarine:
Stream stream;
System.IO.Stream stream;
try
{
stream = SaveUtil.DecompressFiletoStream(fileTransfer.FilePath);

View File

@@ -3,7 +3,7 @@ using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
@@ -28,6 +28,8 @@ namespace Barotrauma.Networking
get { return name; }
}
public string PendingName = string.Empty;
public void SetName(string value)
{
value = value.Replace(":", "").Replace(";", "");
@@ -50,7 +52,7 @@ namespace Barotrauma.Networking
public GUITickBox EndVoteTickBox;
private GUIComponent buttonContainer;
private NetStats netStats;
public readonly NetStats NetStats;
protected GUITickBox cameraFollowsSub;
@@ -112,6 +114,7 @@ namespace Barotrauma.Networking
public bool SpawnAsTraitor;
public string TraitorFirstObjective;
public TraitorMissionPrefab TraitorMission = null;
public byte ID
{
@@ -166,9 +169,9 @@ namespace Barotrauma.Networking
allowReconnect = true;
netStats = new NetStats();
NetStats = new NetStats();
inGameHUD = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
inGameHUD = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas), style: null)
{
CanBeFocused = false
};
@@ -482,12 +485,13 @@ namespace Barotrauma.Networking
if (requiresPw && !canStart && !connectCancelled)
{
GUI.ClearCursorWait();
reconnectBox?.Close(); reconnectBox = null;
string pwMsg = TextManager.Get("PasswordRequired");
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, 170));
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, (int)(170 * Math.Max(1.0f, GUI.Scale))));
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
{
@@ -513,6 +517,7 @@ namespace Barotrauma.Networking
{
requiresPw = false;
connectCancelled = true;
GameMain.ServerListScreen.Select();
return true;
};
@@ -564,14 +569,7 @@ namespace Barotrauma.Networking
}
}
/*TODO: reimplement
if (ShowNetStats && client?.ServerConnection != null)
{
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
netStats.AddValue(NetStats.NetStatType.SentBytes, client.ServerConnection.Statistics.SentBytes);
netStats.AddValue(NetStats.NetStatType.ResentMessages, client.ServerConnection.Statistics.ResentMessages);
netStats.Update(deltaTime);
}*/
NetStats.Update(deltaTime);
UpdateHUD(deltaTime);
@@ -669,6 +667,7 @@ namespace Barotrauma.Networking
if (header != ServerPacketHeader.STARTGAMEFINALIZE &&
header != ServerPacketHeader.ENDGAME &&
header != ServerPacketHeader.PING_REQUEST &&
roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
{
//rewind the header byte we just read
@@ -679,6 +678,31 @@ namespace Barotrauma.Networking
switch (header)
{
case ServerPacketHeader.PING_REQUEST:
IWriteMessage response = new WriteOnlyMessage();
response.Write((byte)ClientPacketHeader.PING_RESPONSE);
byte requestLen = inc.ReadByte();
response.Write(requestLen);
for (int i=0;i<requestLen;i++)
{
byte b = inc.ReadByte();
response.Write(b);
}
clientPeer.Send(response, DeliveryMethod.Unreliable);
break;
case ServerPacketHeader.CLIENT_PINGS:
byte clientCount = inc.ReadByte();
for (int i=0;i<clientCount;i++)
{
byte clientId = inc.ReadByte();
UInt16 clientPing = inc.ReadUInt16();
Client client = ConnectedClients.Find(c => c.ID == clientId);
if (client != null)
{
client.Ping = clientPing;
}
}
break;
case ServerPacketHeader.UPDATE_LOBBY:
ReadLobbyUpdate(inc);
break;
@@ -750,7 +774,7 @@ namespace Barotrauma.Networking
if (readyToStart && !CoroutineManager.IsCoroutineRunning("WaitForStartRound"))
{
CoroutineManager.StartCoroutine(GameMain.NetLobbyScreen.WaitForStartRound(startButton: null, allowCancel: false), "WaitForStartRound");
CoroutineManager.StartCoroutine(GameMain.NetLobbyScreen.WaitForStartRound(startButton: null), "WaitForStartRound");
}
break;
case ServerPacketHeader.STARTGAME:
@@ -1056,11 +1080,13 @@ namespace Barotrauma.Networking
var missionPrefab = TraitorMissionPrefab.List.Find(t => t.Identifier == missionIdentifier);
Sprite icon = missionPrefab?.Icon;
switch(messageType) {
switch(messageType)
{
case TraitorMessageType.Objective:
var isTraitor = !string.IsNullOrEmpty(message);
SpawnAsTraitor = isTraitor;
TraitorFirstObjective = message;
TraitorMission = missionPrefab;
if (Character != null)
{
Character.IsTraitor = isTraitor;
@@ -1422,6 +1448,15 @@ namespace Barotrauma.Networking
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
Submarine.MainSubs[i].TeamID = teamID;
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null) { continue; }
if (item.Submarine != Submarine.MainSubs[i] && !Submarine.MainSubs[i].DockedTo.Contains(item.Submarine)) { continue; }
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
{
wifiComponent.TeamID = Submarine.MainSubs[i].TeamID;
}
}
foreach (Submarine sub in Submarine.MainSubs[i].DockedTo)
{
sub.TeamID = teamID;
@@ -1503,7 +1538,7 @@ namespace Barotrauma.Networking
var matchingSub =
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash);
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash, tryLoad: false);
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
serverSubmarines.Add(matchingSub);
@@ -1537,9 +1572,11 @@ namespace Barotrauma.Networking
string name = inc.ReadString();
string preferredJob = inc.ReadString();
UInt16 characterID = inc.ReadUInt16();
float karma = inc.ReadSingle();
bool muted = inc.ReadBoolean();
bool inGame = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean();
bool hasPermissions = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean() || IsServerOwner;
inc.ReadPadBits();
tempClients.Add(new TempClient
@@ -1550,8 +1587,10 @@ namespace Barotrauma.Networking
Name = name,
PreferredJob = preferredJob,
CharacterID = characterID,
Karma = karma,
Muted = muted,
InGame = inGame,
HasPermissions = hasPermissions,
AllowKicking = allowKicking
});
}
@@ -1579,7 +1618,9 @@ namespace Barotrauma.Networking
existingClient.NameID = tc.NameID;
existingClient.PreferredJob = tc.PreferredJob;
existingClient.Character = null;
existingClient.Karma = tc.Karma;
existingClient.Muted = tc.Muted;
existingClient.HasPermissions = tc.HasPermissions;
existingClient.InGame = tc.InGame;
existingClient.AllowKicking = tc.AllowKicking;
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
@@ -1852,8 +1893,8 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError("Writing object data to \"crashreport_object.bin\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
using (FileStream fl = File.Open("crashreport_object.bin", FileMode.Create))
using (BinaryWriter sw = new BinaryWriter(fl))
using (FileStream fl = File.Open("crashreport_object.bin", System.IO.FileMode.Create))
using (System.IO.BinaryWriter sw = new System.IO.BinaryWriter(fl))
{
sw.Write(inc.Buffer, (int)(prevBytePos - prevByteLength), (int)(prevByteLength));
}
@@ -2085,7 +2126,8 @@ namespace Barotrauma.Networking
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
}
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
GameMain.GameSession?.SubmarineInfo?.Reload();
GameMain.GameSession?.SubmarineInfo?.CheckSubsLeftBehind();
if (GameMain.GameSession?.SubmarineInfo?.Name != null)
{
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.SubmarineInfo);
@@ -2540,6 +2582,11 @@ namespace Barotrauma.Networking
inGameHUD.AddToGUIUpdateList();
GameMain.NetLobbyScreen.FileTransferFrame?.AddToGUIUpdateList();
}
serverSettings.AddToGUIUpdateList();
if (serverSettings.ServerLog.LogFrame != null) serverSettings.ServerLog.LogFrame.AddToGUIUpdateList();
GameMain.NetLobbyScreen?.PlayerFrame?.AddToGUIUpdateList();
}
public void UpdateHUD(float deltaTime)
@@ -2583,7 +2630,7 @@ namespace Barotrauma.Networking
if (GUI.KeyboardDispatcher.Subscriber == null)
{
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 0);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100);
if (chatKeyHit || radioKeyHit)
{
@@ -2629,8 +2676,6 @@ namespace Barotrauma.Networking
}
}
}
serverSettings.AddToGUIUpdateList();
if (serverSettings.ServerLog.LogFrame != null) serverSettings.ServerLog.LogFrame.AddToGUIUpdateList();
}
public virtual void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
@@ -2716,15 +2761,15 @@ namespace Barotrauma.Networking
if (!ShowNetStats) return;
netStats.Draw(spriteBatch, new Rectangle(300, 10, 300, 150));
NetStats.Draw(spriteBatch, new Rectangle(300, 10, 300, 150));
/* TODO: reimplement
int width = 200, height = 300;
int x = GameMain.GraphicsWidth - width, y = (int)(GameMain.GraphicsHeight * 0.3f);
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black * 0.7f, true);
GUI.Font.DrawString(spriteBatch, "Network statistics:", new Vector2(x + 10, y + 10), Color.White);
/* TODO: reimplement
if (client.ServerConnection != null)
{
GUI.Font.DrawString(spriteBatch, "Ping: " + (int)(client.ServerConnection.AverageRoundtripTime * 1000.0f) + " ms", new Vector2(x + 10, y + 25), Color.White);
@@ -2743,73 +2788,106 @@ namespace Barotrauma.Networking
}*/
}
public virtual bool SelectCrewCharacter(Character character, GUIComponent characterFrame)
public virtual bool SelectCrewCharacter(Character character, GUIComponent frame)
{
if (character == null) { return false; }
if (character == null) return false;
if (character != myCharacter)
{
var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.Character == character);
if (client == null) { return false; }
if (client == null) return false;
var content = new GUIFrame(new RectTransform(new Vector2(0.9f, 1.0f - characterFrame.RectTransform.RelativeSize.Y), characterFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter),
style: null);
var mute = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.TopCenter),
TextManager.Get("Mute"))
{
Selected = client.MutedLocally,
OnSelected = (tickBox) => { client.MutedLocally = tickBox.Selected; return true; }
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.BottomCenter), isHorizontal: true)
{
RelativeSpacing = 0.05f,
ChildAnchor = Anchor.CenterLeft,
Stretch = true
};
if (HasPermission(ClientPermissions.Ban))
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Ban"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.BanPlayer(client); return false; }
};
}
if (HasPermission(ClientPermissions.Kick))
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Kick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.KickPlayer(client); return false; }
};
}
else if (serverSettings.Voting.AllowVoteKick)
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("VoteToKick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { VoteForKick(client); btn.Enabled = false; return true; }
};
if (GameMain.NetworkMember.ConnectedClients != null)
{
kickVoteButton.Enabled = !client.HasKickVoteFromID(myID);
}
}
CreateSelectionRelatedButtons(client, frame);
}
return true;
}
public virtual bool SelectCrewClient(Client client, GUIComponent frame)
{
if (client == null || client.ID == ID) return false;
CreateSelectionRelatedButtons(client, frame);
return true;
}
private void CreateSelectionRelatedButtons(Client client, GUIComponent frame)
{
var content = new GUIFrame(new RectTransform(new Vector2(1f, 1.0f - frame.RectTransform.RelativeSize.Y), frame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter),
style: null);
var mute = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.TopCenter),
TextManager.Get("Mute"))
{
Selected = client.MutedLocally,
OnSelected = (tickBox) => { client.MutedLocally = tickBox.Selected; return true; }
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.35f), content.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft)
{
RelativeSpacing = 0.05f,
Stretch = true
};
if (!GameMain.Client.GameStarted || (GameMain.Client.Character == null || GameMain.Client.Character.IsDead) && (client.Character == null || client.Character.IsDead))
{
var messageButton = new GUIButton(new RectTransform(new Vector2(1f, 0.2f), content.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0f, buttonContainer.RectTransform.RelativeSize.Y) },
TextManager.Get("message"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) =>
{
chatBox.InputBox.Text = $"{client.Name}; ";
CoroutineManager.StartCoroutine(selectCoroutine());
return false;
}
};
}
// Need a delayed selection due to the inputbox being deselected when a left click occurs outside of it
IEnumerable<object> selectCoroutine()
{
yield return new WaitForSeconds(0.01f, true);
chatBox.InputBox.Select(chatBox.InputBox.Text.Length);
}
if (HasPermission(ClientPermissions.Ban) && client.AllowKicking)
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Ban"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.BanPlayer(client); return false; }
};
}
if (HasPermission(ClientPermissions.Kick) && client.AllowKicking)
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Kick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.KickPlayer(client); return false; }
};
}
else if (serverSettings.Voting.AllowVoteKick && client.AllowKicking)
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("VoteToKick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { VoteForKick(client); btn.Enabled = false; return true; }
};
if (GameMain.NetworkMember.ConnectedClients != null)
{
kickVoteButton.Enabled = !client.HasKickVoteFromID(myID);
}
}
}
public void CreateKickReasonPrompt(string clientName, bool ban, bool rangeBan = false)
{
var banReasonPrompt = new GUIMessageBox(
TextManager.Get(ban ? "BanReasonPrompt" : "KickReasonPrompt"),
"", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") }, new Vector2(0.25f, 0.2f), new Point(400, 200));
"", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") }, new Vector2(0.25f, 0.22f), new Point(400, 220));
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.6f), banReasonPrompt.InnerFrame.RectTransform, Anchor.Center));
var banReasonBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.3f), content.RectTransform))
@@ -2823,14 +2901,16 @@ namespace Barotrauma.Networking
if (ban)
{
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform), TextManager.Get("BanDuration"));
permaBanTickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) },
TextManager.Get("BanPermanent"))
var labelContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), content.RectTransform), isHorizontal: false);
new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), labelContainer.RectTransform), TextManager.Get("BanDuration")) { Padding = Vector4.Zero };
var buttonContent = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), labelContainer.RectTransform), isHorizontal: true);
permaBanTickBox = new GUITickBox(new RectTransform(new Vector2(0.4f, 0.15f), buttonContent.RectTransform), TextManager.Get("BanPermanent"))
{
Selected = true
};
var durationContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform), isHorizontal: true)
var durationContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), buttonContent.RectTransform), isHorizontal: true)
{
Visible = false
};
@@ -2930,6 +3010,11 @@ namespace Barotrauma.Networking
if (GameMain.GameSession?.GameMode != null)
{
errorLines.Add("Game mode: " + GameMain.GameSession.GameMode.Name);
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
{
errorLines.Add("Campaign ID: " + campaign.CampaignID);
errorLines.Add("Campaign save ID: " + campaign.LastSaveID + "(pending: " + campaign.PendingSaveID + ")");
}
}
if (GameMain.GameSession?.Submarine != null)
{
@@ -2938,6 +3023,13 @@ namespace Barotrauma.Networking
if (Level.Loaded != null)
{
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + Level.Loaded.EqualityCheckVal);
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
errorLines.Add("Entities:");
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate)
{
errorLines.Add(" " + e.ID + ": " + e.ToString());
}
errorLines.Add("Entity count after generating level: " + Level.Loaded.EntityCountAfterGenerate);
}
errorLines.Add("Entity IDs:");

View File

@@ -47,11 +47,30 @@ namespace Barotrauma
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(StructureDamageKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(DamageFriendlyKarmaDecrease));
//hide these for now if a localized text is not available
if (TextManager.ContainsTag("Karma." + nameof(StunFriendlyKarmaDecrease)))
{
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(StunFriendlyKarmaDecrease));
}
if (TextManager.ContainsTag("Karma." + nameof(StunFriendlyKarmaDecreaseThreshold)))
{
CreateLabeledSlider(parent, 0.0f, 10.0f, 1.0f, nameof(StunFriendlyKarmaDecreaseThreshold));
}
CreateLabeledSlider(parent, 0.0f, 100.0f, 1.0f, nameof(ReactorMeltdownKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, nameof(ReactorOverheatKarmaDecrease));
CreateLabeledNumberInput(parent, 0, 20, nameof(AllowedWireDisconnectionsPerMinute));
CreateLabeledSlider(parent, 0.0f, 20.0f, 0.5f, nameof(WireDisconnectionKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, nameof(SpamFilterKarmaDecrease));
//hide these for now if a localized text is not available
if (TextManager.ContainsTag("Karma." + nameof(DangerousItemStealKarmaDecrease)))
{
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, nameof(DangerousItemStealKarmaDecrease));
}
if (TextManager.ContainsTag("Karma." + nameof(DangerousItemStealBots)))
{
CreateLabeledTickBox(parent, nameof(DangerousItemStealBots));
}
}
private void CreateLabeledSlider(GUIComponent parent, float min, float max, float step, string propertyName)

View File

@@ -14,10 +14,10 @@ namespace Barotrauma.Networking
ResentMessages = 2
}
private Graph[] graphs;
private readonly Graph[] graphs;
private float[] totalValue;
private float[] lastValue;
private readonly float[] totalValue;
private readonly float[] lastValue;
const float UpdateInterval = 0.1f;
float updateTimer;
@@ -37,9 +37,7 @@ namespace Barotrauma.Networking
public void AddValue(NetStatType statType, float value)
{
float valueChange = value - lastValue[(int)statType];
totalValue[(int)statType] += valueChange;
lastValue[(int)statType] = value;
}
@@ -51,7 +49,6 @@ namespace Barotrauma.Networking
for (int i = 0; i < 3; i++)
{
graphs[i].Update(totalValue[i] / UpdateInterval);
totalValue[i] = 0.0f;
}
@@ -64,23 +61,22 @@ namespace Barotrauma.Networking
GUI.DrawRectangle(spriteBatch, rect, Color.Black * 0.4f, true);
graphs[(int)NetStatType.ReceivedBytes].Draw(spriteBatch, rect, null, 0.0f, Color.Cyan);
graphs[(int)NetStatType.SentBytes].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Orange);
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Red);
if (graphs[(int)NetStatType.ResentMessages].Average() > 0)
{
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Red);
GUI.SmallFont.DrawString(spriteBatch, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.Right + 10, rect.Y + 50), GUI.Style.Red);
}
GUI.SmallFont.DrawString(spriteBatch,
"Peak received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].LargestValue()) + "/s " +
"Avg received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].Average()) + "/s",
new Vector2(rect.Right + 10, rect.Y + 10), Color.Cyan);
GUI.SmallFont.DrawString(spriteBatch, "Peak sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].LargestValue()) + "/s " +
"Avg sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].Average()) + "/s",
new Vector2(rect.Right + 10, rect.Y + 30), GUI.Style.Orange);
GUI.SmallFont.DrawString(spriteBatch, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.Right + 10, rect.Y + 50), GUI.Style.Red);
#if DEBUG
/*int y = 10;

View File

@@ -39,7 +39,10 @@ namespace Barotrauma.Networking
contentPackageOrderReceived = false;
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
{
UseDualModeSockets = GameMain.Config.UseDualModeSockets
};
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
@@ -94,6 +97,9 @@ namespace Barotrauma.Networking
incomingLidgrenMessages.Clear();
netClient.ReadMessages(incomingLidgrenMessages);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, netClient.Statistics.ReceivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, netClient.Statistics.SentBytes);
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
{
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }

View File

@@ -18,6 +18,8 @@ namespace Barotrauma.Networking
private double timeout;
private double heartbeatTimer;
private long sentBytes, receivedBytes;
private List<IReadMessage> incomingInitializationMessages;
private List<IReadMessage> incomingDataMessages;
@@ -63,6 +65,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)ConnectionInitialization.ConnectionStarted);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
@@ -99,11 +102,11 @@ namespace Barotrauma.Networking
if (isConnectionInitializationStep)
{
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8+32);
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8 + 32);
ulong lobbyId = low + (high << 32);
Steam.SteamManager.JoinLobby(lobbyId, false);
IReadMessage inc = new ReadOnlyMessage(data, false, 1+8, dataLength - 9, ServerConnection);
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - 9, ServerConnection);
if (initializationStep != ConnectionInitialization.Success)
{
incomingInitializationMessages.Add(inc);
@@ -137,15 +140,20 @@ namespace Barotrauma.Networking
timeout -= deltaTime;
heartbeatTimer -= deltaTime;
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
for (int i = 0; i < 100; i++)
{
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
receivedBytes += packet?.Data.Length ?? 0;
}
}
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, receivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, sentBytes);
if (heartbeatTimer < 0.0)
{
IWriteMessage outMsg = new WriteOnlyMessage();
@@ -153,6 +161,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)PacketHeader.IsHeartbeatMessage);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Unreliable);
sentBytes += outMsg.LengthBytes;
heartbeatTimer = 5.0;
}
@@ -226,6 +235,7 @@ namespace Barotrauma.Networking
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.ContentPackageOrder:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
@@ -253,7 +263,7 @@ namespace Barotrauma.Networking
}
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
@@ -333,6 +343,7 @@ namespace Barotrauma.Networking
private void Send(byte[] buf, int length, Steamworks.P2PSend sendType)
{
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
sentBytes += length + 4;
if (!successSend)
{
if (sendType != Steamworks.P2PSend.Reliable)
@@ -340,6 +351,7 @@ namespace Barotrauma.Networking
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
sentBytes += length + 4;
}
if (!successSend)
{
@@ -363,6 +375,7 @@ namespace Barotrauma.Networking
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
public override void Close(string msg = null)
@@ -379,6 +392,7 @@ namespace Barotrauma.Networking
outMsg.Write(msg ?? "Disconnected");
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
Thread.Sleep(100);

View File

@@ -13,7 +13,9 @@ namespace Barotrauma.Networking
private bool isActive;
private ConnectionInitialization initializationStep;
private UInt64 selfSteamID;
private readonly UInt64 selfSteamID;
private long sentBytes, receivedBytes;
class RemotePeer
{
@@ -204,22 +206,24 @@ namespace Barotrauma.Networking
}
}
for (int i=0;i<100;i++)
for (int i = 0; i < 100; i++)
{
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
receivedBytes += packet?.Data.Length ?? 0;
}
}
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, receivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, sentBytes);
while (ChildServerRelay.Read(out byte[] incBuf))
{
ChildServerRelay.DisposeLocalHandles();
IReadMessage inc = new ReadOnlyMessage(incBuf, false, 0, incBuf.Length, ServerConnection);
HandleDataMessage(inc);
}
}
@@ -295,6 +299,7 @@ namespace Barotrauma.Networking
}
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
if (!successSend)
{
@@ -303,6 +308,7 @@ namespace Barotrauma.Networking
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
}
if (!successSend)
{
@@ -336,7 +342,6 @@ namespace Barotrauma.Networking
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
Array.Resize(ref msgToSend, outMsg.LengthBytes);
ChildServerRelay.Write(msgToSend);
return;
}
else
@@ -369,6 +374,7 @@ namespace Barotrauma.Networking
outMsg.Write(msg);
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamID, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
else
{
@@ -405,7 +411,7 @@ namespace Barotrauma.Networking
ClosePeerSession(remotePeers[i]);
}
ChildServerRelay.ShutDown();
ChildServerRelay.ClosePipes();
OnDisconnect?.Invoke();

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