(f0d812055) v0.9.9.0
This commit is contained in:
@@ -335,7 +335,8 @@ namespace Barotrauma
|
||||
//an ad-hoc way of allowing the players to have roughly the same maximum view distance regardless of the resolution,
|
||||
//while still keeping the zoom around 1.0 when not looking further away (because otherwise we'd always be downsampling
|
||||
//on lower resolutions, which doesn't look that good)
|
||||
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom, (float)Math.Sqrt(zoomOutAmount));
|
||||
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom,
|
||||
(GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(zoomOutAmount) : 0.3f);
|
||||
|
||||
Zoom += (newZoom - zoom) / ZoomSmoothness;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
//color = Color.WhiteSmoke;
|
||||
// disable the indicators for structures, because they clutter the debug view
|
||||
// disable the indicators for structures and hulls, because they clutter the debug view
|
||||
return;
|
||||
}
|
||||
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ namespace Barotrauma
|
||||
{
|
||||
bool inWater = limb.inWater;
|
||||
if (character.CurrentHull != null &&
|
||||
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height &&
|
||||
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height + 5.0f &&
|
||||
limb.SimPosition.Y < ConvertUnits.ToSimUnits(character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height) + limb.body.GetMaxExtent())
|
||||
{
|
||||
inWater = true;
|
||||
@@ -370,6 +370,7 @@ namespace Barotrauma
|
||||
foreach (var deformation in SpriteDeformations)
|
||||
{
|
||||
if (character.IsDead && deformation.Params.StopWhenHostIsDead) { continue; }
|
||||
if (!character.AnimController.InWater && deformation.Params.OnlyInWater) { continue; }
|
||||
if (deformation.Params.UseMovementSine)
|
||||
{
|
||||
if (this is AnimController animator)
|
||||
|
||||
@@ -233,7 +233,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 +355,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)
|
||||
@@ -365,7 +365,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction)
|
||||
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && controlled == this)
|
||||
{
|
||||
@@ -444,6 +444,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)
|
||||
{
|
||||
@@ -466,7 +467,7 @@ namespace Barotrauma
|
||||
//modify the distance based on the size of the trigger (preferring smaller items)
|
||||
distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (transformedTrigger.Width + transformedTrigger.Height) / 250.0f);
|
||||
}
|
||||
else
|
||||
else if (!item.Prefab.RequireCursorInsideTrigger)
|
||||
{
|
||||
Rectangle itemDisplayRect = new Rectangle(item.InteractionRect.X, item.InteractionRect.Y - item.InteractionRect.Height, item.InteractionRect.Width, item.InteractionRect.Height);
|
||||
|
||||
@@ -551,7 +552,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!enabled) { return; }
|
||||
|
||||
if (!IsDead && !IsUnconscious)
|
||||
if (!IsDead && !IsIncapacitated)
|
||||
{
|
||||
if (soundTimer > 0)
|
||||
{
|
||||
@@ -603,6 +604,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void SetOrderProjSpecific(Order order, string orderOption)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption);
|
||||
}
|
||||
|
||||
public static void AddAllToGUIUpdateList()
|
||||
{
|
||||
for (int i = 0; i < CharacterList.Count; i++)
|
||||
@@ -812,6 +818,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (sounds == null || sounds.Count == 0) { return; }
|
||||
if (soundChannel != null && soundChannel.IsPlaying) { return; }
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return; }
|
||||
|
||||
var matchingSounds = sounds.Where(s =>
|
||||
s.Type == soundType &&
|
||||
@@ -820,6 +827,7 @@ namespace Barotrauma
|
||||
|
||||
var matchingSoundsList = matchingSounds.ToList();
|
||||
var selectedSound = matchingSoundsList[Rand.Int(matchingSoundsList.Count)];
|
||||
if (selectedSound?.Sound == null) { return; }
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, CurrentHull);
|
||||
soundTimer = soundInterval;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -37,6 +38,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static bool shouldRecreateHudTexts = true;
|
||||
private static bool heldDownShiftWhenGotHudTexts;
|
||||
|
||||
private static bool ShouldDrawInventory(Character character)
|
||||
{
|
||||
return
|
||||
@@ -61,7 +65,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
@@ -90,7 +94,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null)
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +162,7 @@ namespace Barotrauma
|
||||
brokenItemsCheckTimer = 1.0f;
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine == null || item.Submarine.TeamID != character.TeamID || item.Submarine.Info.IsWreck) { continue; }
|
||||
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.AIRepairThreshold)) { continue; }
|
||||
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
|
||||
|
||||
@@ -201,27 +210,27 @@ namespace Barotrauma
|
||||
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
|
||||
}
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -237,7 +246,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);
|
||||
|
||||
@@ -309,7 +325,7 @@ namespace Barotrauma
|
||||
(int)(HUDLayoutSettings.BottomRightInfoArea.Y + HUDLayoutSettings.BottomRightInfoArea.Height * 0.1f),
|
||||
(int)(HUDLayoutSettings.BottomRightInfoArea.Width / 2),
|
||||
(int)(HUDLayoutSettings.BottomRightInfoArea.Height * 0.7f)));
|
||||
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2((int)(-4 * GUI.Scale), (int)(2 * GUI.Scale)), targetWidth: HUDLayoutSettings.PortraitArea.Width, true);
|
||||
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2(-12 * GUI.Scale, 4 * GUI.Scale), targetWidth: HUDLayoutSettings.PortraitArea.Width, true);
|
||||
}
|
||||
mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud();
|
||||
if (mouseOnPortrait)
|
||||
@@ -327,7 +343,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
{
|
||||
|
||||
@@ -10,84 +10,116 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CharacterInfo
|
||||
{
|
||||
public const float BgScale = 1.2f;
|
||||
private static Sprite infoAreaPortraitBG;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
infoAreaPortraitBG = new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
||||
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
@@ -171,6 +203,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawBackground(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (infoAreaPortraitBG == null) { return; }
|
||||
infoAreaPortraitBG.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(), Color.White, Vector2.Zero, 0.0f,
|
||||
scale: new Vector2(
|
||||
HUDLayoutSettings.BottomRightInfoArea.Width / (float)infoAreaPortraitBG.SourceRect.Width,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -277,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:
|
||||
@@ -337,6 +338,36 @@ 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();
|
||||
|
||||
if (attackLimbIndex >= AnimController.Limbs.Length)
|
||||
{
|
||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds ({attackLimbIndex})");
|
||||
break;
|
||||
}
|
||||
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
||||
IDamageable targetEntity = FindEntityByID(targetEntityID) as IDamageable;
|
||||
Limb targetLimb = null;
|
||||
if (targetEntity == null)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
|
||||
break;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
break;
|
||||
@@ -384,6 +415,36 @@ namespace Barotrauma
|
||||
character = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
|
||||
character.ID = id;
|
||||
character.TeamID = (TeamType)teamID;
|
||||
|
||||
// Check if the character has a current order
|
||||
if (inc.ReadBoolean())
|
||||
{
|
||||
int orderPrefabIndex = inc.ReadByte();
|
||||
Entity targetEntity = FindEntityByID(inc.ReadUInt16());
|
||||
Character orderGiver = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
|
||||
int orderOptionIndex = inc.ReadByte();
|
||||
|
||||
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
|
||||
{
|
||||
var orderPrefab = Order.PrefabList[orderPrefabIndex];
|
||||
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),
|
||||
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
|
||||
orderGiver, speak: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Could not set order \"" + orderPrefab.Identifier + "\" for character \"" + character.Name + "\" because required target entity was not found.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid order prefab index - index (" + orderPrefabIndex + ") out of bounds.");
|
||||
}
|
||||
}
|
||||
|
||||
bool containsStatusData = inc.ReadBoolean();
|
||||
if (containsStatusData)
|
||||
{
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Barotrauma
|
||||
|
||||
public SoundType Type => Params.State;
|
||||
public Gender Gender => Params.Gender;
|
||||
public float Volume => roundSound.Volume;
|
||||
public float Range => roundSound.Range;
|
||||
public float Volume => roundSound == null ? 0.0f : roundSound.Volume;
|
||||
public float Range => roundSound == null ? 0.0f : roundSound.Range;
|
||||
public Sound Sound => roundSound?.Sound;
|
||||
|
||||
public CharacterSound(CharacterParams.SoundParams soundParams)
|
||||
|
||||
@@ -246,11 +246,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private GUIFrame healthBarHolder;
|
||||
|
||||
private Point healthBarOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Point(5 - (int)Math.Ceiling(1 - 1 * GUI.Scale), (int)Math.Min(Math.Ceiling(17 * GUI.Scale), 20));
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +260,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Point(healthBarHolder.Rect.Width - (int)Math.Ceiling(Math.Min(46 * GUI.Scale, 53)), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2);
|
||||
return new Point((int)Math.Ceiling(HUDLayoutSettings.HealthBarArea.Size.X - 45 * GUI.Scale), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +305,7 @@ namespace Barotrauma
|
||||
healthShadowSize = 1.0f;
|
||||
|
||||
healthBar = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight),
|
||||
barSize: 1.0f, color: GUIColorSettings.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
|
||||
barSize: 1.0f, color: GUI.Style.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
|
||||
{
|
||||
HoverCursor = CursorState.Hand,
|
||||
Enabled = true,
|
||||
@@ -503,8 +505,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)
|
||||
@@ -520,8 +520,10 @@ namespace Barotrauma
|
||||
|
||||
UpdateAlignment();
|
||||
|
||||
suicideButton = new GUIButton(new RectTransform(new Vector2(0.06f, 0.02f), GUI.Canvas, Anchor.TopCenter)
|
||||
{ MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f) },
|
||||
suicideButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.02f), GUI.Canvas, Anchor.TopCenter)
|
||||
{
|
||||
MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f)
|
||||
},
|
||||
TextManager.Get("GiveInButton"), style: "GUIButtonLarge")
|
||||
{
|
||||
ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer"),
|
||||
@@ -647,10 +649,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)
|
||||
@@ -761,7 +767,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;
|
||||
@@ -847,7 +854,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, GUIColorSettings.HealthBarColorLow, GUIColorSettings.HealthBarColorMedium, GUIColorSettings.HealthBarColorHigh);
|
||||
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, GUI.Style.HealthBarColorLow, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorHigh);
|
||||
healthBar.HoverColor = healthWindowHealthBar.HoverColor = healthBar.Color * 2.0f;
|
||||
healthBar.BarSize = healthWindowHealthBar.BarSize =
|
||||
(DisplayedVitality > 0.0f) ?
|
||||
@@ -934,7 +941,7 @@ namespace Barotrauma
|
||||
healthBar.State = GUIComponent.ComponentState.None;
|
||||
}
|
||||
|
||||
suicideButton.Visible = Character == Character.Controlled && Character.IsUnconscious && !Character.IsDead;
|
||||
suicideButton.Visible = Character == Character.Controlled && !Character.IsDead && Character.IsIncapacitated;
|
||||
|
||||
cprButton.Visible =
|
||||
Character == Character.Controlled?.SelectedCharacter
|
||||
@@ -942,6 +949,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));
|
||||
@@ -1132,11 +1143,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (prefab.IsBuff)
|
||||
{
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUIColorSettings.BuffColorLow, GUIColorSettings.BuffColorMedium, GUIColorSettings.BuffColorHigh);
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.BuffColorLow, GUI.Style.BuffColorMedium, GUI.Style.BuffColorHigh);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUIColorSettings.DebuffColorLow, GUIColorSettings.DebuffColorMedium, GUIColorSettings.DebuffColorHigh);
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.DebuffColorLow, GUI.Style.DebuffColorMedium, GUI.Style.DebuffColorHigh);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1870,10 +1881,11 @@ namespace Barotrauma
|
||||
healthBarHolder.Visible = value;
|
||||
}
|
||||
|
||||
private readonly List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
|
||||
private readonly List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
|
||||
|
||||
newAfflictions.Clear();
|
||||
byte afflictionCount = inc.ReadByte();
|
||||
for (int i = 0; i < afflictionCount; i++)
|
||||
{
|
||||
@@ -1913,7 +1925,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
|
||||
newLimbAfflictions.Clear();
|
||||
byte limbAfflictionCount = inc.ReadByte();
|
||||
for (int i = 0; i < limbAfflictionCount; i++)
|
||||
{
|
||||
|
||||
@@ -83,22 +83,22 @@ namespace Barotrauma
|
||||
// pos.Y = -pos.Y;
|
||||
// ShapeExtensions.DrawPoint(spriteBatch, pos, GUI.Style.Red, size: 5);
|
||||
//}
|
||||
return;
|
||||
|
||||
// A debug visualisation on the bezier curve between limbs.
|
||||
var start = LimbA.WorldPosition;
|
||||
/*var start = LimbA.WorldPosition;
|
||||
var end = LimbB.WorldPosition;
|
||||
var jointAPos = ConvertUnits.ToDisplayUnits(LocalAnchorA);
|
||||
var control = start + Vector2.Transform(jointAPos, Matrix.CreateRotationZ(LimbA.Rotation));
|
||||
start.Y = -start.Y;
|
||||
end.Y = -end.Y;
|
||||
control.Y = -control.Y;
|
||||
//GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
|
||||
//GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
|
||||
//GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
|
||||
//GUI.DrawLine(spriteBatch, start, end, Color.White);
|
||||
//GUI.DrawLine(spriteBatch, start, control, Color.Black);
|
||||
//GUI.DrawLine(spriteBatch, control, end, Color.Black);
|
||||
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, GUI.Style.Red);
|
||||
GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
|
||||
GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
|
||||
GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
|
||||
GUI.DrawLine(spriteBatch, start, end, Color.White);
|
||||
GUI.DrawLine(spriteBatch, start, control, Color.Black);
|
||||
GUI.DrawLine(spriteBatch, control, end, Color.Black);
|
||||
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, GUI.Style.Red);*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace Barotrauma
|
||||
|
||||
private float wetTimer;
|
||||
private float dripParticleTimer;
|
||||
private float deadTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Note that different limbs can share the same deformations.
|
||||
@@ -418,14 +419,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void AddDamageProjSpecific(Vector2 simPosition, List<Affliction> afflictions, bool playSound, List<DamageModifier> appliedDamageModifiers)
|
||||
partial void AddDamageProjSpecific(IEnumerable<Affliction> afflictions, bool playSound, IEnumerable<DamageModifier> appliedDamageModifiers)
|
||||
{
|
||||
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 bleedingDamage = character.CharacterHealth.DoesBleed ? afflictions.Where(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth)) : 0;
|
||||
float damage = afflictions.Where(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
|
||||
float damageMultiplier = 1;
|
||||
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
||||
{
|
||||
damageMultiplier *= damageModifier.DamageMultiplier;
|
||||
foreach (var afflictionPrefab in AfflictionPrefab.List)
|
||||
{
|
||||
if (damageModifier.MatchesAffliction(afflictionPrefab.Identifier, afflictionPrefab.AfflictionType))
|
||||
{
|
||||
if (afflictionPrefab.Effects.Any(e => e.MaxVitalityDecrease > 0))
|
||||
{
|
||||
damageMultiplier *= damageModifier.DamageMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playSound)
|
||||
{
|
||||
@@ -477,13 +487,21 @@ namespace Barotrauma
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (!body.Enabled) return;
|
||||
if (!body.Enabled) { return; }
|
||||
|
||||
if (!character.IsDead)
|
||||
{
|
||||
DamageOverlayStrength -= deltaTime;
|
||||
BurnOverlayStrength -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
var spriteParams = Params.GetSprite();
|
||||
if (spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
|
||||
{
|
||||
deadTimer += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (inWater)
|
||||
{
|
||||
@@ -524,7 +542,12 @@ 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();
|
||||
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;
|
||||
|
||||
@@ -594,13 +617,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;
|
||||
|
||||
@@ -12,6 +12,7 @@ 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);
|
||||
@@ -423,7 +426,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (args.Length > 0)
|
||||
{
|
||||
Submarine.Load(string.Join(" ", args), true);
|
||||
var subInfo = new SubmarineInfo(string.Join(" ", args));
|
||||
Submarine.MainSub = Submarine.Load(subInfo, true);
|
||||
}
|
||||
GameMain.SubEditorScreen.Select();
|
||||
}, isCheat: true));
|
||||
@@ -464,16 +468,23 @@ namespace Barotrauma
|
||||
}
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks debug logging.", (string[] args) =>
|
||||
{
|
||||
SteamManager.NetworkingDebugLog = !SteamManager.NetworkingDebugLog;
|
||||
}));
|
||||
|
||||
AssignRelayToServer("kick", false);
|
||||
AssignRelayToServer("kickid", false);
|
||||
AssignRelayToServer("ban", false);
|
||||
AssignRelayToServer("banid", false);
|
||||
AssignRelayToServer("dumpids", false);
|
||||
AssignRelayToServer("dumptofile", false);
|
||||
AssignRelayToServer("findentityids", false);
|
||||
AssignRelayToServer("campaigninfo", false);
|
||||
AssignRelayToServer("help", false);
|
||||
AssignRelayToServer("verboselogging", false);
|
||||
AssignRelayToServer("freecam", false);
|
||||
AssignRelayToServer("steamnetdebug", false);
|
||||
#if DEBUG
|
||||
AssignRelayToServer("crash", false);
|
||||
AssignRelayToServer("simulatedlatency", false);
|
||||
@@ -513,13 +524,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) =>
|
||||
@@ -834,7 +846,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub")))
|
||||
if (Submarine.MainSub.SaveAs(System.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
|
||||
{
|
||||
NewMessage("Sub saved", Color.Green);
|
||||
}
|
||||
@@ -843,7 +855,8 @@ namespace Barotrauma
|
||||
commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) return;
|
||||
Submarine.Load(string.Join(" ", args), true);
|
||||
SubmarineInfo subInfo = new SubmarineInfo(string.Join(" ", args));
|
||||
Submarine.Load(subInfo, true);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("cleansub", "", (string[] args) =>
|
||||
@@ -1086,23 +1099,69 @@ namespace Barotrauma
|
||||
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
foreach (MapEntity me in MapEntity.SelectedList)
|
||||
{
|
||||
if (me is ISerializableEntity serializableEntity)
|
||||
bool propertyFound = false;
|
||||
if (!(me is ISerializableEntity serializableEntity)) { continue; }
|
||||
if (serializableEntity.SerializableProperties == null) { continue; }
|
||||
|
||||
if (serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
|
||||
{
|
||||
if (serializableEntity.SerializableProperties == null)
|
||||
propertyFound = true;
|
||||
object prevValue = property.GetValue(me);
|
||||
if (property.TrySetValue(me, args[1]))
|
||||
{
|
||||
continue;
|
||||
NewMessage($"Changed the value \"{args[0]}\" from {(prevValue?.ToString() ?? null)} to {args[1]} on entity \"{me.ToString()}\".", Color.LightGreen);
|
||||
}
|
||||
if (!serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
|
||||
else
|
||||
{
|
||||
NewMessage("Property \"" + args[0] + "\" not found in the entity \"" + me.ToString() + "\".", Color.Orange);
|
||||
continue;
|
||||
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the entity \"{me.ToString()}\".", Color.Orange);
|
||||
}
|
||||
if (!property.TrySetValue(me, args[1]))
|
||||
}
|
||||
if (me is Item item)
|
||||
{
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
NewMessage("Failed to set the value of \"" + args[0] + "\" to \"" + args[1] + "\" on the entity \"" + me.ToString() + "\".", Color.Orange);
|
||||
ic.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty componentProperty);
|
||||
if (componentProperty == null) { continue; }
|
||||
propertyFound = true;
|
||||
object prevValue = componentProperty.GetValue(ic);
|
||||
if (componentProperty.TrySetValue(ic, args[1]))
|
||||
{
|
||||
NewMessage($"Changed the value \"{args[0]}\" from {prevValue} to {args[1]} on item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.LightGreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.Orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!propertyFound)
|
||||
{
|
||||
NewMessage($"Property \"{args[0]}\" not found in the entity \"{me.ToString()}\".", Color.Orange);
|
||||
}
|
||||
}
|
||||
},
|
||||
() =>
|
||||
{
|
||||
List<string> propertyList = new List<string>();
|
||||
foreach (MapEntity me in MapEntity.SelectedList)
|
||||
{
|
||||
if (!(me is ISerializableEntity serializableEntity)) { continue; }
|
||||
if (serializableEntity.SerializableProperties == null) { continue; }
|
||||
propertyList.AddRange(serializableEntity.SerializableProperties.Select(p => p.Key));
|
||||
if (me is Item item)
|
||||
{
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
propertyList.AddRange(ic.SerializableProperties.Select(p => p.Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
propertyList.Distinct().ToArray(),
|
||||
new string[0]
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("checkmissingloca", "", (string[] args) =>
|
||||
@@ -1135,7 +1194,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Submarine sub in Submarine.SavedSubmarines)
|
||||
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
|
||||
{
|
||||
string nameIdentifier = "submarine.name." + sub.Name.ToLowerInvariant();
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
@@ -2269,7 +2328,8 @@ namespace Barotrauma
|
||||
}
|
||||
try
|
||||
{
|
||||
Submarine spawnedSub = Submarine.Load(args[0], false);
|
||||
SubmarineInfo subInfo = new SubmarineInfo(args[0]);
|
||||
Submarine spawnedSub = Submarine.Load(subInfo, false);
|
||||
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -2347,7 +2407,7 @@ namespace Barotrauma
|
||||
switch (firstArg)
|
||||
{
|
||||
case "name":
|
||||
var sprites = Sprite.LoadedSprites.Where(s => s.Name?.ToLowerInvariant() == secondArg.ToLowerInvariant());
|
||||
var sprites = Sprite.LoadedSprites.Where(s => s.Name != null && s.Name.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
|
||||
if (sprites.Any())
|
||||
{
|
||||
foreach (var s in sprites)
|
||||
@@ -2363,7 +2423,7 @@ namespace Barotrauma
|
||||
}
|
||||
case "identifier":
|
||||
case "id":
|
||||
sprites = Sprite.LoadedSprites.Where(s => s.EntityID?.ToLowerInvariant() == secondArg.ToLowerInvariant());
|
||||
sprites = Sprite.LoadedSprites.Where(s => s.EntityID != null && s.EntityID.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
|
||||
if (sprites.Any())
|
||||
{
|
||||
foreach (var s in sprites)
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "icon") { continue; }
|
||||
if (!subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
Icon = new Sprite(subElement);
|
||||
IconColor = subElement.GetAttributeColor("color", Color.White);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,38 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
item = Item.ReadSpawnData(msg);
|
||||
if (item == null)
|
||||
bool usedExistingItem = msg.ReadBoolean();
|
||||
if (usedExistingItem)
|
||||
{
|
||||
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
|
||||
ushort id = msg.ReadUInt16();
|
||||
item = Entity.FindEntityByID(id) as Item;
|
||||
if (item == null)
|
||||
{
|
||||
throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item = Item.ReadSpawnData(msg);
|
||||
if (item == null)
|
||||
{
|
||||
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Barotrauma
|
||||
Point size = new Point(0, 0);
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "size") { continue; }
|
||||
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
|
||||
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Barotrauma
|
||||
Click,
|
||||
PickItem,
|
||||
PickItemFail,
|
||||
DropItem
|
||||
DropItem,
|
||||
PopupMenu
|
||||
}
|
||||
|
||||
public enum CursorState
|
||||
@@ -82,6 +83,9 @@ namespace Barotrauma
|
||||
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 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);
|
||||
@@ -242,6 +246,7 @@ namespace Barotrauma
|
||||
sounds[(int)GUISoundType.RadioMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/RadioMsg.ogg", false);
|
||||
sounds[(int)GUISoundType.DeadMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/DeadMsg.ogg", false);
|
||||
sounds[(int)GUISoundType.Click] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/Click.ogg", false);
|
||||
sounds[(int)GUISoundType.PopupMenu] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/PopupMenu.ogg", false);
|
||||
|
||||
sounds[(int)GUISoundType.PickItem] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItem.ogg", false);
|
||||
sounds[(int)GUISoundType.PickItemFail] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItemFail.ogg", false);
|
||||
@@ -494,9 +499,27 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,6 +542,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();
|
||||
@@ -539,6 +590,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();
|
||||
|
||||
@@ -778,6 +833,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)
|
||||
{
|
||||
@@ -814,8 +871,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;
|
||||
}
|
||||
@@ -1135,7 +1191,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)
|
||||
@@ -1144,7 +1200,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)
|
||||
@@ -1922,6 +1978,19 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else if (GameMain.GameSession.GameMode is SubTestMode)
|
||||
{
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.GameSession.GameMode.End("");
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
button.OnClicked += TogglePauseMenu;
|
||||
}
|
||||
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("EndRound"))
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIColorSettings
|
||||
{
|
||||
// Inventory
|
||||
public static Color EquipmentSlotIconColor = new Color(99, 70, 64);
|
||||
|
||||
// Health HUD
|
||||
public static Color BuffColorLow = Color.LightGreen;
|
||||
public static Color BuffColorMedium = Color.Green;
|
||||
public static Color BuffColorHigh = Color.DarkGreen;
|
||||
|
||||
public static Color DebuffColorLow = Color.DarkSalmon;
|
||||
public static Color DebuffColorMedium = Color.Red;
|
||||
public static Color DebuffColorHigh = Color.DarkRed;
|
||||
|
||||
public static Color HealthBarColorLow = Color.Red;
|
||||
public static Color HealthBarColorMedium = Color.Orange;
|
||||
public static Color HealthBarColorHigh = new Color(78, 114, 88);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
@@ -787,8 +799,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "conditional" &&
|
||||
!CheckConditional(subElement))
|
||||
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase) && !CheckConditional(subElement))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -837,7 +848,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "conditional") { continue; }
|
||||
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
FromXML(subElement, component is GUIListBox listBox ? listBox.Content.RectTransform : component.RectTransform);
|
||||
}
|
||||
|
||||
@@ -1005,7 +1016,7 @@ namespace Barotrauma
|
||||
|
||||
private static GUIFrame LoadGUIFrame(XElement element, RectTransform parent)
|
||||
{
|
||||
string style = element.GetAttributeString("style", element.Name.ToString().ToLowerInvariant() == "spacing" ? null : "");
|
||||
string style = element.GetAttributeString("style", element.Name.ToString().Equals("spacing", StringComparison.OrdinalIgnoreCase) ? null : "");
|
||||
if (style == "null") { style = null; }
|
||||
return new GUIFrame(RectTransform.Load(element, parent), style: style);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
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 HashSet<string> activeTextureLoads = new HashSet<string>();
|
||||
|
||||
public float Rotation;
|
||||
|
||||
private Sprite sprite;
|
||||
@@ -15,7 +20,11 @@ namespace Barotrauma
|
||||
|
||||
private bool crop;
|
||||
|
||||
private bool scaleToFit;
|
||||
private readonly bool scaleToFit;
|
||||
|
||||
private bool lazyLoaded, loading;
|
||||
|
||||
public bool LoadAsynchronously;
|
||||
|
||||
public bool Crop
|
||||
{
|
||||
@@ -75,7 +84,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 +103,44 @@ 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)
|
||||
{
|
||||
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 +180,52 @@ 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);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,18 @@ namespace Barotrauma
|
||||
|
||||
public GUILayoutGroup(RectTransform rectT, bool isHorizontal = false, Anchor childAnchor = Anchor.TopLeft) : base(null, rectT)
|
||||
{
|
||||
CanBeFocused = false;
|
||||
#if DEBUG
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
CanBeFocused = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
CanBeFocused = false;
|
||||
#if DEBUG
|
||||
}
|
||||
#endif
|
||||
|
||||
this.isHorizontal = isHorizontal;
|
||||
this.childAnchor = childAnchor;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -59,11 +59,41 @@ 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;
|
||||
public Color ColorInventoryBackground { get; private set; } = Color.Gray;
|
||||
|
||||
public Color TextColor { get; private set; } = Color.White * 0.8f;
|
||||
public Color TextColorBright { get; private set; } = Color.White * 0.9f;
|
||||
public Color TextColorDark { get; private set; } = Color.Black * 0.9f;
|
||||
public Color TextColorDim { get; private set; } = Color.White * 0.6f;
|
||||
|
||||
// Inventory
|
||||
public Color EquipmentSlotIconColor { get; private set; } = new Color(99, 70, 64);
|
||||
|
||||
// Health HUD
|
||||
public Color BuffColorLow { get; private set; } = Color.LightGreen;
|
||||
public Color BuffColorMedium { get; private set; } = Color.Green;
|
||||
public Color BuffColorHigh { get; private set; } = Color.DarkGreen;
|
||||
|
||||
public Color DebuffColorLow { get; private set; } = Color.DarkSalmon;
|
||||
public Color DebuffColorMedium { get; private set; } = Color.Red;
|
||||
public Color DebuffColorHigh { get; private set; } = Color.DarkRed;
|
||||
|
||||
public Color HealthBarColorLow { get; private set; } = Color.Red;
|
||||
public Color HealthBarColorMedium { get; private set; } = Color.Orange;
|
||||
public Color HealthBarColorHigh { get; private set; } = new Color(78, 114, 88);
|
||||
|
||||
public Color EquipmentIndicatorNotEquipped { get; private set; } = Color.Gray;
|
||||
public Color EquipmentIndicatorEquipped { get; private set; } = new Color(105, 202, 125);
|
||||
public Color EquipmentIndicatorRunningOut { get; private set; } = new Color(202, 105, 105);
|
||||
|
||||
public static Point ItemFrameMargin => new Point(50, 56).Multiply(GUI.SlicedSpriteScale);
|
||||
public static Point ItemFrameOffset => new Point(0, 3).Multiply(GUI.SlicedSpriteScale);
|
||||
|
||||
@@ -103,10 +133,25 @@ 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;
|
||||
case "colorinventoryhalf":
|
||||
ColorInventoryHalf = subElement.GetAttributeColor("color", ColorInventoryHalf);
|
||||
break;
|
||||
case "colorinventoryfull":
|
||||
ColorInventoryFull = subElement.GetAttributeColor("color", ColorInventoryFull);
|
||||
break;
|
||||
case "colorinventorybackground":
|
||||
ColorInventoryBackground = subElement.GetAttributeColor("color", ColorInventoryBackground);
|
||||
break;
|
||||
case "textcolordark":
|
||||
TextColorDark = subElement.GetAttributeColor("color", TextColorDark);
|
||||
break;
|
||||
case "TextColorBright":
|
||||
case "textcolorbright":
|
||||
TextColorBright = subElement.GetAttributeColor("color", TextColorBright);
|
||||
break;
|
||||
case "textcolordim":
|
||||
@@ -116,6 +161,45 @@ namespace Barotrauma
|
||||
case "textcolor":
|
||||
TextColor = subElement.GetAttributeColor("color", TextColor);
|
||||
break;
|
||||
case "equipmentsloticoncolor":
|
||||
EquipmentSlotIconColor = subElement.GetAttributeColor("color", EquipmentSlotIconColor);
|
||||
break;
|
||||
case "buffcolorlow":
|
||||
BuffColorLow = subElement.GetAttributeColor("color", BuffColorLow);
|
||||
break;
|
||||
case "buffcolormedium":
|
||||
BuffColorMedium = subElement.GetAttributeColor("color", BuffColorMedium);
|
||||
break;
|
||||
case "buffcolorhigh":
|
||||
BuffColorHigh = subElement.GetAttributeColor("color", BuffColorHigh);
|
||||
break;
|
||||
case "debuffcolorlow":
|
||||
DebuffColorLow = subElement.GetAttributeColor("color", DebuffColorLow);
|
||||
break;
|
||||
case "debuffcolormedium":
|
||||
DebuffColorMedium = subElement.GetAttributeColor("color", DebuffColorMedium);
|
||||
break;
|
||||
case "debuffcolorhigh":
|
||||
DebuffColorHigh = subElement.GetAttributeColor("color", DebuffColorHigh);
|
||||
break;
|
||||
case "healthbarcolorlow":
|
||||
HealthBarColorLow = subElement.GetAttributeColor("color", HealthBarColorLow);
|
||||
break;
|
||||
case "healthbarcolormedium":
|
||||
HealthBarColorMedium = subElement.GetAttributeColor("color", HealthBarColorMedium);
|
||||
break;
|
||||
case "healthbarcolorhigh":
|
||||
HealthBarColorHigh = subElement.GetAttributeColor("color", HealthBarColorHigh);
|
||||
break;
|
||||
case "equipmentindicatornotequipped":
|
||||
EquipmentIndicatorNotEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorNotEquipped);
|
||||
break;
|
||||
case "equipmentindicatorequipped":
|
||||
EquipmentIndicatorEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorEquipped);
|
||||
break;
|
||||
case "equipmentindicatorrunningout":
|
||||
EquipmentIndicatorRunningOut = subElement.GetAttributeColor("color", EquipmentIndicatorRunningOut);
|
||||
break;
|
||||
case "uiglow":
|
||||
UIGlow = new UISprite(subElement);
|
||||
break;
|
||||
@@ -250,9 +334,8 @@ namespace Barotrauma
|
||||
//check if any of the language override fonts want to override the font size as well
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
|
||||
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
|
||||
if (GameMain.Config.Language.ToLowerInvariant() == language)
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
uint overrideFontSize = GetFontSize(subElement, 0);
|
||||
if (overrideFontSize > 0) { return overrideFontSize; }
|
||||
@@ -261,7 +344,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "size") { continue; }
|
||||
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
|
||||
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
|
||||
{
|
||||
@@ -275,9 +358,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
|
||||
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
|
||||
if (GameMain.Config.Language.ToLowerInvariant() == language)
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return subElement.GetAttributeString("file", "");
|
||||
}
|
||||
@@ -289,9 +371,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
|
||||
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
|
||||
if (GameMain.Config.Language.ToLowerInvariant() == language)
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return subElement.GetAttributeBool("dynamicloading", false);
|
||||
}
|
||||
@@ -303,9 +384,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
|
||||
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
|
||||
if (GameMain.Config.Language.ToLowerInvariant() == language)
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return subElement.GetAttributeBool("iscjk", false);
|
||||
}
|
||||
|
||||
@@ -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,129 @@ 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];
|
||||
|
||||
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 : 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 +634,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,14 @@ namespace Barotrauma
|
||||
private Vector2 selectionRectSize;
|
||||
|
||||
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
|
||||
{
|
||||
get { return frame; }
|
||||
}
|
||||
|
||||
public GUITextBlock.TextGetterHandler TextGetter
|
||||
{
|
||||
@@ -357,114 +365,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;
|
||||
@@ -494,6 +402,13 @@ 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;
|
||||
@@ -513,7 +428,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!MathUtils.NearlyEqual(PlayerInput.MouseSpeed.X, 0))
|
||||
{
|
||||
CaretIndex = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
|
||||
CaretIndex = textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
|
||||
CalculateCaretPos();
|
||||
CalculateSelection();
|
||||
}
|
||||
@@ -788,7 +703,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();
|
||||
@@ -799,7 +714,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();
|
||||
|
||||
@@ -112,16 +112,16 @@ namespace Barotrauma
|
||||
//slice from the top of the screen for misc buttons (info, end round, server controls)
|
||||
ButtonAreaTop = new Rectangle(Padding, Padding, GameMain.GraphicsWidth - Padding * 2, (int)(50 * GUI.Scale));
|
||||
|
||||
int infoAreaWidth = (int)(142 * GUI.Scale * CharacterInfo.BgScale);
|
||||
int infoAreaHeight = (int)(98 * GUI.Scale * CharacterInfo.BgScale);
|
||||
int portraitSize = (int)(125 * GUI.Scale);
|
||||
int infoAreaWidth = (int)(142 * GUI.Scale);
|
||||
int infoAreaHeight = (int)(98 * GUI.Scale);
|
||||
int portraitSize = (int)(infoAreaHeight * 0.95f);
|
||||
BottomRightInfoArea = new Rectangle(GameMain.GraphicsWidth - Padding * 2 - infoAreaWidth, GameMain.GraphicsHeight - Padding * 2 - infoAreaHeight, infoAreaWidth, infoAreaHeight);
|
||||
PortraitArea = new Rectangle(GameMain.GraphicsWidth - Padding - portraitSize, GameMain.GraphicsHeight - Padding - portraitSize, portraitSize, portraitSize);
|
||||
PortraitArea = new Rectangle(GameMain.GraphicsWidth - portraitSize, BottomRightInfoArea.Bottom - portraitSize + Padding / 2, portraitSize, portraitSize);
|
||||
|
||||
//horizontal slices at the corners of the screen for health bar and affliction icons
|
||||
int afflictionAreaHeight = (int)(50 * GUI.Scale);
|
||||
int healthBarWidth = (int)((BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing) * 1.1f);
|
||||
int healthBarHeight = (int)Math.Max(50f * GUI.Scale, 25f);
|
||||
int healthBarWidth = BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing * 2 + CharacterInventory.HideButtonWidth;
|
||||
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);
|
||||
|
||||
|
||||
@@ -338,6 +338,8 @@ namespace Barotrauma
|
||||
PendingSplashScreens.Clear();
|
||||
currSplashScreen = null;
|
||||
}
|
||||
|
||||
if (currSplashScreen == null) { return; }
|
||||
}
|
||||
|
||||
if (currSplashScreen.IsPlaying)
|
||||
|
||||
@@ -651,6 +651,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; }
|
||||
|
||||
932
Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs
Normal file
932
Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs
Normal file
@@ -0,0 +1,932 @@
|
||||
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), 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
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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: client.Character != null ? client.Character.Info.Job.Prefab.UIColor : Color.White);
|
||||
|
||||
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: client.Character != null ? client.Character.Info.Job.Prefab.UIColor : Color.White);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
||||
if (vanillaContent == null)
|
||||
{
|
||||
// TODO: Dynamic method for defining and finding the vanilla content package.
|
||||
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
|
||||
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
return vanillaContent;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
@@ -385,6 +403,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadingException : Exception
|
||||
{
|
||||
public LoadingException(Exception e) : base("Loading was interrupted due to an error.", innerException: e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> Load(bool isSeparateThread)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
@@ -402,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 * 20.0f, 0);
|
||||
SoundManager.SetCategoryGainMultiplier("voip", Math.Min(Config.VoiceChatVolume, 1.0f), 0);
|
||||
|
||||
if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro"))
|
||||
{
|
||||
@@ -430,7 +455,7 @@ namespace Barotrauma
|
||||
{
|
||||
bool waitingForWorkshopUpdates = true;
|
||||
bool result = false;
|
||||
TaskPool.Add(SteamManager.AutoUpdateWorkshopItems(), (task) =>
|
||||
TaskPool.Add(SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
|
||||
{
|
||||
result = task.Result;
|
||||
waitingForWorkshopUpdates = false;
|
||||
@@ -503,6 +528,7 @@ namespace Barotrauma
|
||||
Tutorials.Tutorial.Init();
|
||||
MapGenerationParams.Init();
|
||||
LevelGenerationParams.LoadPresets();
|
||||
WreckAIConfig.LoadAll();
|
||||
ScriptedEventSet.LoadPrefabs();
|
||||
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
|
||||
@@ -518,6 +544,7 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
|
||||
CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses));
|
||||
|
||||
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
|
||||
|
||||
@@ -527,7 +554,7 @@ namespace Barotrauma
|
||||
|
||||
GameModePreset.Init();
|
||||
|
||||
Submarine.RefreshSavedSubs();
|
||||
SubmarineInfo.RefreshSavedSubs();
|
||||
|
||||
TitleScreen.LoadState = 65.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -664,6 +691,8 @@ namespace Barotrauma
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect invitation command ({connectCommand})", e);
|
||||
#else
|
||||
DebugConsole.Log($"Failed to parse a Steam friend's connect invitation command ({connectCommand})\n" + e.StackTrace);
|
||||
#endif
|
||||
ConnectName = null;
|
||||
ConnectEndpoint = null;
|
||||
@@ -756,12 +785,7 @@ namespace Barotrauma
|
||||
|
||||
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
|
||||
{
|
||||
string errMsg = "Loading was interrupted due to an error";
|
||||
if (loadingCoroutine.Exception != null)
|
||||
{
|
||||
errMsg += ": " + loadingCoroutine.Exception.Message + "\n" + loadingCoroutine.Exception.StackTrace;
|
||||
}
|
||||
throw new Exception(errMsg);
|
||||
throw new LoadingException(loadingCoroutine.Exception);
|
||||
}
|
||||
}
|
||||
else if (hasLoaded)
|
||||
@@ -823,6 +847,10 @@ namespace Barotrauma
|
||||
{
|
||||
(GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI();
|
||||
}
|
||||
else if (GameSession.IsTabMenuOpen)
|
||||
{
|
||||
gameSession.ToggleTabMenu();
|
||||
}
|
||||
else if (GUI.PauseMenuOpen)
|
||||
{
|
||||
GUI.TogglePauseMenu();
|
||||
@@ -831,7 +859,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();
|
||||
@@ -922,7 +951,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);
|
||||
}
|
||||
|
||||
@@ -944,10 +973,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);
|
||||
@@ -972,7 +1004,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1101,7 +1133,10 @@ namespace Barotrauma
|
||||
UserData = "https://steamcommunity.com/app/602960/discussions/1/",
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
SteamManager.OverlayCustomURL(userdata as string);
|
||||
if (!SteamManager.OverlayCustomURL(userdata as string))
|
||||
{
|
||||
ShowOpenUrlInWebBrowserPrompt(userdata as string);
|
||||
}
|
||||
msgBox.Close();
|
||||
return true;
|
||||
}
|
||||
@@ -1138,7 +1173,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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +276,11 @@ namespace Barotrauma
|
||||
c.SaveInventory(c.Inventory, inventoryElement);
|
||||
c.Info.InventoryData = inventoryElement;
|
||||
c.Inventory?.DeleteAllItems();
|
||||
c.ResetCurrentOrder();
|
||||
}
|
||||
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using Barotrauma.Tutorials;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SubTestMode : GameMode
|
||||
{
|
||||
public SubTestMode(GameModePreset preset, object param)
|
||||
: base(preset, param)
|
||||
{
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||
{
|
||||
for (int i = 0; i < jobPrefab.InitialCount; i++)
|
||||
{
|
||||
var variant = Rand.Range(0, jobPrefab.Variants);
|
||||
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
isRunning = true;
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
|
||||
Submarine.MainSub.SetPosition(Vector2.Zero);
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!isRunning|| GUI.DisableHUD || GUI.DisableUpperHUD) return;
|
||||
|
||||
if (Submarine.MainSub == null) return;
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
if (!isRunning) return;
|
||||
|
||||
base.AddToGUIUpdateList();
|
||||
CrewManager.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isRunning) { return; }
|
||||
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
public override void End(string endMessage = "")
|
||||
{
|
||||
isRunning = false;
|
||||
|
||||
GameMain.GameSession.EndRound("");
|
||||
|
||||
CrewManager.EndRound();
|
||||
|
||||
Submarine.Unload();
|
||||
|
||||
GameMain.SubEditorScreen.Select();
|
||||
}
|
||||
|
||||
private bool EndRound(Submarine leavingSub)
|
||||
{
|
||||
isRunning = false;
|
||||
|
||||
End("");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace Barotrauma.Tutorials
|
||||
private string levelSeed;
|
||||
private string levelParams;
|
||||
|
||||
private Submarine startOutpost = null;
|
||||
private Submarine endOutpost = null;
|
||||
private SubmarineInfo startOutpost = null;
|
||||
private SubmarineInfo endOutpost = null;
|
||||
private bool currentTutorialCompleted = false;
|
||||
private float fadeOutTime = 3f;
|
||||
protected float waitBeforeFade = 4f;
|
||||
@@ -56,13 +56,13 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
private IEnumerable<object> Loading()
|
||||
{
|
||||
Submarine.MainSub = Submarine.Load(submarinePath, "", true);
|
||||
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
|
||||
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Name == levelParams);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
GameMain.GameSession = new GameSession(Submarine.MainSub, "",
|
||||
GameMain.GameSession = new GameSession(subInfo, "",
|
||||
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
|
||||
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
|
||||
|
||||
@@ -72,12 +72,12 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
if (startOutpostPath != string.Empty)
|
||||
{
|
||||
startOutpost = Submarine.Load(startOutpostPath, "", false);
|
||||
startOutpost = new SubmarineInfo(startOutpostPath);
|
||||
}
|
||||
|
||||
if (endOutpostPath != string.Empty)
|
||||
{
|
||||
endOutpost = Submarine.Load(endOutpostPath, "", false);
|
||||
endOutpost = new SubmarineInfo(endOutpostPath);
|
||||
}
|
||||
|
||||
Level tutorialLevel = new Level(levelSeed, 0, 0, generationParams, biome, startOutpost, endOutpost);
|
||||
@@ -160,11 +160,11 @@ namespace Barotrauma.Tutorials
|
||||
switch (this.spawnSub)
|
||||
{
|
||||
case "startoutpost":
|
||||
spawnSub = startOutpost;
|
||||
spawnSub = Level.Loaded.StartOutpost;
|
||||
break;
|
||||
|
||||
case "endoutpost":
|
||||
spawnSub = endOutpost;
|
||||
spawnSub = Level.Loaded.EndOutpost;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Barotrauma
|
||||
public GUIFrame CreateSummaryFrame(string endMessage)
|
||||
{
|
||||
bool singleplayer = GameMain.NetworkMember == null;
|
||||
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsUnconscious);
|
||||
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated);
|
||||
bool progress = Submarine.MainSub.AtEndPosition;
|
||||
if (!singleplayer)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ namespace Barotrauma
|
||||
|
||||
string summaryText = TextManager.GetWithVariables(gameOver ? "RoundSummaryGameOver" :
|
||||
(progress ? "RoundSummaryProgress" : "RoundSummaryReturn"), new string[2] { "[sub]", "[location]" },
|
||||
new string[2] { Submarine.MainSub.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
|
||||
new string[2] { Submarine.MainSub.Info.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
|
||||
|
||||
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
summaryText, wrap: true);
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Barotrauma
|
||||
{
|
||||
Graphics,
|
||||
Audio,
|
||||
VoiceChat,
|
||||
Controls,
|
||||
#if DEBUG
|
||||
Debug
|
||||
@@ -60,6 +61,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")
|
||||
@@ -443,11 +445,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 +461,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; }
|
||||
@@ -677,10 +681,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 +722,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 +770,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 +786,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 +807,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 +832,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 +870,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 +895,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 +941,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 +950,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 +963,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 +1012,7 @@ namespace Barotrauma
|
||||
{
|
||||
VoiceSetting = vMode = VoiceMode.Disabled;
|
||||
voiceActivityGroup.Visible = false;
|
||||
voiceInputContainer.Visible = false;
|
||||
voiceInputContainerHorizontal.Visible = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -977,7 +1028,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)
|
||||
@@ -1182,7 +1233,7 @@ namespace Barotrauma
|
||||
{ RelativeOffset = new Vector2(0.02f, 0.02f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
var automaticQuickStartTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Enable automatic quickstart", style: "GUITickBox");
|
||||
var automaticQuickStartTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Automatic quickstart enabled", style: "GUITickBox");
|
||||
automaticQuickStartTickBox.Selected = AutomaticQuickStartEnabled;
|
||||
automaticQuickStartTickBox.ToolTip = "Will the game automatically move on to Quickstart when the game is launched";
|
||||
automaticQuickStartTickBox.OnSelected = (tickBox) =>
|
||||
@@ -1192,7 +1243,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
var showSplashScreenTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Show splash screen", style: "GUITickBox");
|
||||
var showSplashScreenTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Splash screen enabled", style: "GUITickBox");
|
||||
showSplashScreenTickBox.Selected = EnableSplashScreen;
|
||||
showSplashScreenTickBox.ToolTip = "Are the splash screens shown when the game is launched";
|
||||
showSplashScreenTickBox.OnSelected = (tickBox) =>
|
||||
@@ -1202,7 +1253,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
var verboseLoggingTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Enable verbose logging", style: "GUITickBox");
|
||||
var verboseLoggingTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Verbose logging enabled", style: "GUITickBox");
|
||||
verboseLoggingTickBox.Selected = VerboseLogging;
|
||||
verboseLoggingTickBox.ToolTip = "Should verbose logging be used";
|
||||
verboseLoggingTickBox.OnSelected = (tickBox) =>
|
||||
@@ -1211,6 +1262,16 @@ namespace Barotrauma
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
var textManagerDebugModeTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "TextManager debug mode enabled", style: "GUITickBox");
|
||||
textManagerDebugModeTickBox.Selected = TextManagerDebugModeEnabled;
|
||||
textManagerDebugModeTickBox.ToolTip = "Does the TextManager return the text tags for debug purposes?";
|
||||
textManagerDebugModeTickBox.OnSelected = (tickBox) =>
|
||||
{
|
||||
TextManagerDebugModeEnabled = tickBox.Selected;
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
UnsavedSettings = false; // Reset unsaved settings to false once the UI has been created
|
||||
@@ -1279,7 +1340,7 @@ namespace Barotrauma
|
||||
string[] prefixes = { "OpenAL Soft on " };
|
||||
foreach (string prefix in prefixes)
|
||||
{
|
||||
if (name.StartsWith(prefix, StringComparison.InvariantCulture))
|
||||
if (name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return name.Remove(0, prefix.Length);
|
||||
}
|
||||
@@ -1292,7 +1353,7 @@ namespace Barotrauma
|
||||
{
|
||||
switch (tab)
|
||||
{
|
||||
case Tab.Audio:
|
||||
case Tab.VoiceChat:
|
||||
if (VoiceSetting != VoiceMode.Disabled)
|
||||
{
|
||||
if (GameMain.Client == null && VoipCapture.Instance == null)
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace Barotrauma
|
||||
public Vector2[] SlotPositions;
|
||||
public static Point SlotSize;
|
||||
public static int Spacing;
|
||||
public static int HideButtonWidth;
|
||||
|
||||
private Layout layout;
|
||||
public Layout CurrentLayout
|
||||
@@ -71,22 +72,44 @@ namespace Barotrauma
|
||||
{
|
||||
get { return personalSlotArea; }
|
||||
}
|
||||
|
||||
|
||||
private GUIImage[] indicators = new GUIImage[5];
|
||||
private int[] indicatorIndexes = new int[5];
|
||||
private Vector2 indicatorSpriteSize;
|
||||
private GUILayoutGroup indicatorGroup;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
Hidden = true;
|
||||
|
||||
hideButton = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), (int)(60 * GUI.Scale)), GUI.Canvas)
|
||||
hideButton = new GUIButton(new RectTransform(new Point((int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f)), HUDLayoutSettings.BottomRightInfoArea.Height), GUI.Canvas)
|
||||
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
|
||||
"", style: "UIToggleButton");
|
||||
hideButton.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
|
||||
"", style: "EquipmentToggleButton");
|
||||
|
||||
indicatorGroup = new GUILayoutGroup(new RectTransform(Point.Zero, hideButton.RectTransform)) { IsHorizontal = false };
|
||||
indicatorGroup.ChildAnchor = Anchor.TopCenter;
|
||||
indicatorSpriteSize = GUI.Style.GetComponentStyle("EquipmentIndicatorDivingSuit").Sprites[GUIComponent.ComponentState.None][0].Sprite.size;
|
||||
|
||||
indicators[0] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorDivingSuit");
|
||||
indicators[1] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorID");
|
||||
indicators[2] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorOutfit");
|
||||
indicators[3] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadwear");
|
||||
indicators[4] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadphones");
|
||||
|
||||
indicatorIndexes[0] = FindLimbSlot(InvSlotType.OuterClothes);
|
||||
indicatorIndexes[1] = FindLimbSlot(InvSlotType.Card);
|
||||
indicatorIndexes[2] = FindLimbSlot(InvSlotType.InnerClothes);
|
||||
indicatorIndexes[3] = FindLimbSlot(InvSlotType.Head);
|
||||
indicatorIndexes[4] = FindLimbSlot(InvSlotType.Headset);
|
||||
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
indicators[i].CanBeFocused = false;
|
||||
}
|
||||
|
||||
hideButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||
{
|
||||
hidePersonalSlots = !hidePersonalSlots;
|
||||
foreach (GUIComponent child in btn.Children)
|
||||
{
|
||||
child.SpriteEffects = hidePersonalSlots ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -245,6 +268,26 @@ namespace Barotrauma
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetIndicatorSizes()
|
||||
{
|
||||
indicatorGroup.RectTransform.AbsoluteOffset = new Point((int)Math.Round(4 * GUI.Scale), (int)Math.Round(7 * GUI.Scale));
|
||||
indicatorGroup.RectTransform.NonScaledSize = new Point(hideButton.Rect.Width - indicatorGroup.RectTransform.AbsoluteOffset.X * 2, hideButton.Rect.Height - indicatorGroup.RectTransform.AbsoluteOffset.Y * 2);
|
||||
indicatorGroup.AbsoluteSpacing = (int)Math.Ceiling(2 * GUI.Scale);
|
||||
|
||||
int indicatorHeight = (indicatorGroup.RectTransform.NonScaledSize.Y - indicatorGroup.AbsoluteSpacing * (indicators.Length - 1)) / indicators.Length;
|
||||
int indicatorWidth = (int)(indicatorSpriteSize.X / (indicatorSpriteSize.Y / indicatorHeight));
|
||||
|
||||
if (HideButtonWidth % 2 != indicatorWidth % 2) indicatorWidth++;
|
||||
|
||||
Point indicatorSize = new Point(indicatorWidth, indicatorHeight);
|
||||
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
indicators[i].RectTransform.NonScaledSize = indicatorSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSlotPositions(Layout layout)
|
||||
{
|
||||
bool isFourByThree = GUI.IsFourByThree();
|
||||
@@ -257,6 +300,8 @@ namespace Barotrauma
|
||||
Spacing = (int)(8 * UIScale);
|
||||
}
|
||||
|
||||
HideButtonWidth = (int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f));
|
||||
|
||||
SlotSize = !isFourByThree ? (SlotSpriteSmall.size * UIScale).ToPoint() : (SlotSpriteSmall.size * UIScale * .925f).ToPoint();
|
||||
int bottomOffset = SlotSize.Y + Spacing * 2 + ContainedIndicatorHeight;
|
||||
|
||||
@@ -272,8 +317,7 @@ namespace Barotrauma
|
||||
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
|
||||
|
||||
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
|
||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - Spacing * 2 - SlotSize.X - SlotSize.X / 2;
|
||||
//int upperX = GameMain.GraphicsWidth - personalSlotCount * (slotSize.X + spacing) + (int)(11 * GUI.Scale) + spacing;
|
||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
|
||||
|
||||
//make sure the rightmost normal slot doesn't overlap with the personal slots
|
||||
x -= Math.Max((x + normalSlotCount * (SlotSize.X + Spacing)) - (upperX - personalSlotCount * (SlotSize.X + Spacing)), 0);
|
||||
@@ -300,11 +344,11 @@ namespace Barotrauma
|
||||
if (hideButtonSlotIndex > -1)
|
||||
{
|
||||
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
|
||||
hideButton.RectTransform.NonScaledSize = new Point(SlotSize.X / 2, HUDLayoutSettings.BottomRightInfoArea.Height);
|
||||
hideButton.RectTransform.AbsoluteOffset = new Point(
|
||||
personalSlotArea.Right + Spacing,
|
||||
HUDLayoutSettings.BottomRightInfoArea.Y);
|
||||
hideButton.RectTransform.NonScaledSize = new Point(HideButtonWidth, HUDLayoutSettings.BottomRightInfoArea.Height);
|
||||
hideButton.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.BottomRightInfoArea.Left - HideButtonWidth + GUI.IntScaleCeiling(2f), HUDLayoutSettings.BottomRightInfoArea.Y + GUI.IntScaleCeiling(1f));
|
||||
hideButton.Visible = true;
|
||||
|
||||
SetIndicatorSizes();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -447,7 +491,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)
|
||||
{
|
||||
@@ -457,7 +501,8 @@ namespace Barotrauma
|
||||
hidePersonalSlotsState = hidePersonalSlots ?
|
||||
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
|
||||
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
|
||||
|
||||
|
||||
bool personalSlotsMoving = hidePersonalSlotsState > 0 && hidePersonalSlotsState < 1f;
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
|
||||
@@ -466,6 +511,7 @@ namespace Barotrauma
|
||||
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
|
||||
}
|
||||
slots[i].IsMoving = personalSlotsMoving;
|
||||
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
|
||||
}
|
||||
}
|
||||
@@ -538,6 +584,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)
|
||||
{
|
||||
@@ -551,6 +610,8 @@ namespace Barotrauma
|
||||
|
||||
if (character == Character.Controlled && character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
|
||||
{
|
||||
UpdateEquipmentIndicators();
|
||||
|
||||
//remove the highlighted slots of other characters' inventories when not grabbing anyone
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory != this && s.ParentInventory?.Owner is Character);
|
||||
|
||||
@@ -651,6 +712,39 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEquipmentIndicators()
|
||||
{
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
Item item = Items[indicatorIndexes[i]];
|
||||
if (item != null)
|
||||
{
|
||||
Wearable wearable = item.GetComponent<Wearable>();
|
||||
if (wearable != null && wearable.DisplayContainedStatus)
|
||||
{
|
||||
float conditionPercentage = item.GetContainedItemConditionPercentage();
|
||||
|
||||
if (conditionPercentage != -1)
|
||||
{
|
||||
indicators[i].Color = ToolBox.GradientLerp(conditionPercentage, GUI.Style.EquipmentIndicatorRunningOut, GUI.Style.EquipmentIndicatorEquipped);
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUI.Style.EquipmentIndicatorRunningOut;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUI.Style.EquipmentIndicatorEquipped;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUI.Style.EquipmentIndicatorNotEquipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List<SlotReference> hideSubInventories, bool isEquippedSubInventory)
|
||||
{
|
||||
@@ -771,7 +865,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;
|
||||
}
|
||||
@@ -799,13 +893,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;
|
||||
@@ -815,7 +936,7 @@ 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
|
||||
@@ -964,7 +1085,7 @@ namespace Barotrauma
|
||||
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
|
||||
{
|
||||
var icon = limbSlotIcons[SlotTypes[i]];
|
||||
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUIColorSettings.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
|
||||
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUI.Style.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -52,10 +52,14 @@ namespace Barotrauma.Items.Components
|
||||
get { return sounds.Count > 0; }
|
||||
}
|
||||
|
||||
private bool[] hasSoundsOfType;
|
||||
private Dictionary<ActionType, List<ItemSound>> sounds;
|
||||
private readonly bool[] hasSoundsOfType;
|
||||
private readonly Dictionary<ActionType, List<ItemSound>> sounds;
|
||||
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
|
||||
|
||||
protected float correctionTimer;
|
||||
|
||||
public float IsActiveTimer;
|
||||
|
||||
public GUILayoutSettings DefaultLayout { get; protected set; }
|
||||
public GUILayoutSettings AlternativeLayout { get; protected set; }
|
||||
|
||||
@@ -230,20 +234,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (loopingSound != null)
|
||||
{
|
||||
float targetGain = 0.0f;
|
||||
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(item.WorldPosition, 0.0f)) > loopingSound.Range * loopingSound.Range ||
|
||||
(targetGain = GetSoundVolume(loopingSound)) <= 0.0001f)
|
||||
(GetSoundVolume(loopingSound)) <= 0.0001f)
|
||||
{
|
||||
if (loopingSoundChannel != null)
|
||||
{
|
||||
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
|
||||
loopingSoundChannel.FadeOutAndDispose();
|
||||
loopingSoundChannel = null;
|
||||
loopingSound = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
|
||||
{
|
||||
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
|
||||
loopingSoundChannel.FadeOutAndDispose();
|
||||
loopingSoundChannel = null;
|
||||
loopingSound = null;
|
||||
}
|
||||
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||
{
|
||||
@@ -258,8 +265,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ItemSound itemSound = null;
|
||||
|
||||
var matchingSounds = sounds[type];
|
||||
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||
{
|
||||
@@ -277,7 +283,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (ItemSound sound in matchingSounds)
|
||||
{
|
||||
PlaySound(sound, item.WorldPosition, user);
|
||||
PlaySound(sound, item.WorldPosition);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -286,13 +292,12 @@ namespace Barotrauma.Items.Components
|
||||
index = Rand.Int(matchingSounds.Count);
|
||||
}
|
||||
|
||||
itemSound = matchingSounds[index];
|
||||
PlaySound(matchingSounds[index], item.WorldPosition, user);
|
||||
PlaySound(matchingSounds[index], item.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void PlaySound(ItemSound itemSound, Vector2 position, Character user = null)
|
||||
private void PlaySound(ItemSound itemSound, Vector2 position)
|
||||
{
|
||||
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > itemSound.Range * itemSound.Range)
|
||||
{
|
||||
@@ -301,8 +306,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (itemSound.Loop)
|
||||
{
|
||||
loopingSound = itemSound;
|
||||
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
|
||||
if (loopingSoundChannel != null && loopingSoundChannel.Sound != itemSound.RoundSound.Sound)
|
||||
{
|
||||
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
|
||||
}
|
||||
@@ -310,6 +314,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float volume = GetSoundVolume(itemSound);
|
||||
if (volume <= 0.0001f) { return; }
|
||||
loopingSound = itemSound;
|
||||
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
|
||||
new Vector3(position.X, position.Y, 0.0f),
|
||||
0.01f,
|
||||
|
||||
@@ -3,11 +3,17 @@ using Barotrauma.Lights;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
|
||||
{
|
||||
private bool? lastReceivedState;
|
||||
|
||||
private CoroutineHandle resetPredictionCoroutine;
|
||||
private float resetPredictionTimer;
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get { return new Vector2(light.Range * 2, light.Range * 2); }
|
||||
@@ -32,6 +38,12 @@ namespace Barotrauma.Items.Components
|
||||
light.Color = LightColor.Multiply(brightness);
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
SetLightSourceState(IsActive, lightBrightness);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
|
||||
@@ -49,9 +61,36 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnStateChanged()
|
||||
{
|
||||
if (GameMain.Client == null || !lastReceivedState.HasValue) { return; }
|
||||
//reset to last known server state after the state hasn't changed in 1.0 seconds client-side
|
||||
resetPredictionTimer = 1.0f;
|
||||
if (resetPredictionCoroutine == null || !CoroutineManager.IsCoroutineRunning(resetPredictionCoroutine))
|
||||
{
|
||||
resetPredictionCoroutine = CoroutineManager.StartCoroutine(ResetPredictionAfterDelay());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset client-side prediction of the light's state to the last known state sent by the server after resetPredictionTimer runs out
|
||||
/// </summary>
|
||||
private IEnumerable<object> ResetPredictionAfterDelay()
|
||||
{
|
||||
while (resetPredictionTimer > 0.0f)
|
||||
{
|
||||
resetPredictionTimer -= CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
if (lastReceivedState.HasValue) { IsActive = lastReceivedState.Value; }
|
||||
resetPredictionCoroutine = null;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
IsOn = msg.ReadBoolean();
|
||||
IsActive = msg.ReadBoolean();
|
||||
lastReceivedState = IsActive;
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
|
||||
@@ -140,11 +140,11 @@ namespace Barotrauma.Items.Components
|
||||
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 1f), bottomFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft);
|
||||
|
||||
// === INPUT SLOTS === //
|
||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.8f, 1f), inputArea.RectTransform), style: null);
|
||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay) { CanBeFocused = false };
|
||||
|
||||
// === ACTIVATE BUTTON === //
|
||||
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
|
||||
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
|
||||
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
|
||||
TextManager.Get("FabricatorCreate"), style: "DeviceButton")
|
||||
{
|
||||
@@ -356,6 +356,8 @@ namespace Barotrauma.Items.Components
|
||||
private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
{
|
||||
overlayComponent.RectTransform.SetAsLastChild();
|
||||
|
||||
if (outputContainer.Inventory.Items.First() != null) { return; }
|
||||
|
||||
FabricationRecipe targetItem = fabricatedItem ?? selectedItem;
|
||||
if (targetItem != null)
|
||||
|
||||
@@ -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,21 +117,23 @@ 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)
|
||||
{
|
||||
if (hull.Submarine == null || !hull.Submarine.IsOutpost) { continue; }
|
||||
string text = TextManager.GetWithVariable("MiniMapOutpostDockingInfo", "[outpost]", hull.Submarine.Name);
|
||||
if (hull.Submarine == null || !hull.Submarine.Info.IsOutpost) { continue; }
|
||||
string text = TextManager.GetWithVariable("MiniMapOutpostDockingInfo", "[outpost]", hull.Submarine.Info.Name);
|
||||
Vector2 textSize = GUI.Font.MeasureString(text);
|
||||
Vector2 textPos = child.Center;
|
||||
if (textPos.X + textSize.X / 2 > submarineContainer.Rect.Right)
|
||||
@@ -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);
|
||||
|
||||
@@ -99,6 +99,10 @@ namespace Barotrauma.Items.Components
|
||||
Step = 0.05f,
|
||||
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
{
|
||||
if (pumpSpeedLockTimer <= 0.0f)
|
||||
{
|
||||
targetLevel = null;
|
||||
}
|
||||
float newValue = barScroll * 200.0f - 100.0f;
|
||||
if (Math.Abs(newValue - FlowPercentage) < 0.1f) { return false; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -490,6 +490,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);
|
||||
@@ -647,6 +648,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (GameMain.GameSession == null) { return; }
|
||||
|
||||
if (Level.Loaded == null) { return; }
|
||||
|
||||
DrawMarker(spriteBatch,
|
||||
GameMain.GameSession.StartLocation.Name,
|
||||
"outpost",
|
||||
@@ -699,8 +702,8 @@ namespace Barotrauma.Items.Components
|
||||
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||
|
||||
DrawMarker(spriteBatch,
|
||||
sub.Name,
|
||||
sub.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
|
||||
sub.Info.DisplayName,
|
||||
sub.Info.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
|
||||
sub.WorldPosition - transducerCenter,
|
||||
displayScale, center, DisplayRadius * 0.95f);
|
||||
}
|
||||
@@ -799,8 +802,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))
|
||||
@@ -1125,6 +1131,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)
|
||||
|
||||
@@ -46,6 +46,8 @@ namespace Barotrauma.Items.Components
|
||||
private float checkConnectedPortsTimer;
|
||||
private const float CheckConnectedPortsInterval = 1.0f;
|
||||
|
||||
public DockingPort ActiveDockingSource, DockingTarget;
|
||||
|
||||
private Vector2 keyboardInput = Vector2.Zero;
|
||||
private float inputCumulation;
|
||||
|
||||
@@ -665,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;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Projectile : ItemComponent
|
||||
{
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
bool isStuck = msg.ReadBoolean();
|
||||
if (isStuck)
|
||||
{
|
||||
ushort submarineID = msg.ReadUInt16();
|
||||
ushort hullID = msg.ReadUInt16();
|
||||
Vector2 simPosition = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
Vector2 axis = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
|
||||
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)
|
||||
{
|
||||
byte limbIndex = msg.ReadByte();
|
||||
if (limbIndex >= character.AnimController.Limbs.Length)
|
||||
{
|
||||
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()})");
|
||||
return;
|
||||
}
|
||||
var body = structure.Bodies[bodyIndex];
|
||||
StickToTarget(body, axis);
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
if (item.Removed) { return; }
|
||||
StickToTarget(item.body.FarseerBody, axis);
|
||||
}
|
||||
else if (entity is Submarine sub)
|
||||
{
|
||||
StickToTarget(sub.PhysicsBody.FarseerBody, axis);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Invalid stick target ({entity?.ToString() ?? "null"}, {entityID})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Unstick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,9 +117,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;
|
||||
}
|
||||
}
|
||||
@@ -236,15 +245,7 @@ namespace Barotrauma.Items.Components
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
ushort currentFixerID = msg.ReadUInt16();
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
|
||||
if (currentFixerID == 0)
|
||||
{
|
||||
CurrentFixer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentFixer = Entity.FindEntityByID(currentFixerID) as Character;
|
||||
}
|
||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Rope : ItemComponent, IDrawableComponent
|
||||
{
|
||||
private Sprite sprite, startSprite, endSprite;
|
||||
|
||||
[Serialize(5, false)]
|
||||
public int SpriteWidth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("255,255,255,255", false)]
|
||||
public Color SpriteColor
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool Tile
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (target == null || source == null) { return Vector2.Zero; }
|
||||
return new Vector2(
|
||||
Math.Abs(target.DrawPosition.X - source.DrawPosition.X),
|
||||
Math.Abs(target.DrawPosition.Y - source.DrawPosition.Y)) * 1.5f;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
sprite = new Sprite(subElement);
|
||||
break;
|
||||
case "startsprite":
|
||||
startSprite = new Sprite(subElement);
|
||||
break;
|
||||
case "endsprite":
|
||||
endSprite = new Sprite(subElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
float snapState = 1.0f - snapTimer / SnapAnimDuration;
|
||||
Vector2 diff = target.DrawPosition - source.DrawPosition;
|
||||
diff.Y = -diff.Y;
|
||||
|
||||
int width = (int)(SpriteWidth * snapState);
|
||||
if (width > 0.0f)
|
||||
{
|
||||
DrawRope(spriteBatch, endPos - diff * snapState * 0.5f, endPos, width);
|
||||
DrawRope(spriteBatch, startPos, startPos + diff * snapState * 0.5f, width);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRope(spriteBatch, startPos, endPos, SpriteWidth);
|
||||
}
|
||||
|
||||
if (startSprite != null || endSprite != null)
|
||||
{
|
||||
Vector2 dir = endPos - startPos;
|
||||
float angle = (float)Math.Atan2(dir.Y, dir.X);
|
||||
if (startSprite != null)
|
||||
{
|
||||
float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f);
|
||||
startSprite?.Draw(spriteBatch, startPos, SpriteColor, angle, depth: depth);
|
||||
}
|
||||
if (endSprite != null)
|
||||
{
|
||||
float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f);
|
||||
endSprite?.Draw(spriteBatch, endPos, SpriteColor, angle, depth: depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRope(SpriteBatch spriteBatch, Vector2 startPos, Vector2 endPos, int width)
|
||||
{
|
||||
float depth = sprite == null ?
|
||||
item.Sprite.Depth + 0.001f :
|
||||
Math.Min(item.GetDrawDepth() + (sprite.Depth - item.Sprite.Depth), 0.999f);
|
||||
|
||||
if (sprite?.Texture == null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
startPos,
|
||||
endPos,
|
||||
SpriteColor, depth: depth, width: width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tile)
|
||||
{
|
||||
float length = Vector2.Distance(startPos, endPos);
|
||||
Vector2 dir = (endPos - startPos) / length;
|
||||
float x;
|
||||
for (x = 0.0f; x <= length - sprite.size.X; x += sprite.size.X)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, sprite,
|
||||
startPos + dir * (x - 5.0f),
|
||||
startPos + dir * (x + sprite.size.X),
|
||||
SpriteColor, depth: depth, width: width);
|
||||
}
|
||||
float leftOver = length - x;
|
||||
if (leftOver > 0.0f)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, sprite,
|
||||
startPos + dir * (x - 5.0f),
|
||||
endPos,
|
||||
SpriteColor, depth: depth, width: width);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, sprite,
|
||||
startPos,
|
||||
endPos,
|
||||
SpriteColor, depth: depth, width: width);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
snapped = msg.ReadBoolean();
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
sprite?.Remove(); sprite = null;
|
||||
startSprite?.Remove(); startSprite = null;
|
||||
endSprite?.Remove(); endSprite = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,13 +45,48 @@ namespace Barotrauma.Items.Components
|
||||
float elementSize = Math.Min(1.0f / visibleElements.Count(), 1);
|
||||
foreach (CustomInterfaceElement ciElement in visibleElements)
|
||||
{
|
||||
if (ciElement.ContinuousSignal)
|
||||
if (!string.IsNullOrEmpty(ciElement.PropertyName))
|
||||
{
|
||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.02f,
|
||||
UserData = ciElement
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
|
||||
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label);
|
||||
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), "", style: "GUITextBoxNoIcon")
|
||||
{
|
||||
OverflowClip = true,
|
||||
UserData = ciElement
|
||||
};
|
||||
//reset size restrictions set by the Style to make sure the elements can fit the interface
|
||||
textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize = new Point(0, 0);
|
||||
textBox.RectTransform.MaxSize = textBox.Frame.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
|
||||
textBox.OnDeselected += (tb, key) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
TextChanged(tb.UserData as CustomInterfaceElement, textBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
};
|
||||
|
||||
textBox.OnEnterPressed += (tb, text) =>
|
||||
{
|
||||
tb.Deselect();
|
||||
return true;
|
||||
};
|
||||
uiElements.Add(textBox);
|
||||
}
|
||||
else if (ciElement.ContinuousSignal)
|
||||
{
|
||||
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform)
|
||||
{
|
||||
MaxSize = ElementMaxSize
|
||||
},
|
||||
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label)
|
||||
}, TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label)
|
||||
{
|
||||
UserData = ciElement
|
||||
};
|
||||
@@ -148,7 +183,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (var uiElement in uiElements)
|
||||
{
|
||||
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
|
||||
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
|
||||
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || !string.IsNullOrEmpty(element.PropertyName) || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
|
||||
if (visible) { visibleElementCount++; }
|
||||
if (uiElement.Visible != visible)
|
||||
{
|
||||
@@ -188,6 +223,22 @@ namespace Barotrauma.Items.Components
|
||||
customInterfaceElementList[i].Label;
|
||||
tickBox.TextBlock.Wrap = tickBox.Text.Contains(' ');
|
||||
}
|
||||
if (uiElements[i] is GUITextBox textBox)
|
||||
{
|
||||
var textBlock = textBox.Parent.GetChild<GUITextBlock>();
|
||||
textBlock.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
|
||||
TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
|
||||
customInterfaceElementList[i].Label;
|
||||
textBlock.Wrap = textBlock.Text.Contains(' ');
|
||||
|
||||
foreach (ISerializableEntity e in item.AllPropertyObjects)
|
||||
{
|
||||
if (e.SerializableProperties.ContainsKey(customInterfaceElementList[i].PropertyName))
|
||||
{
|
||||
textBox.Text = e.SerializableProperties[customInterfaceElementList[i].PropertyName].GetValue(e) as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uiElementContainer.Recalculate();
|
||||
@@ -206,6 +257,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
textBlocks.Add(tickBox.TextBlock);
|
||||
}
|
||||
else if (element is GUILayoutGroup)
|
||||
{
|
||||
textBlocks.Add(element.GetChild<GUITextBlock>());
|
||||
}
|
||||
}
|
||||
uiElementContainer.Recalculate();
|
||||
GUITextBlock.AutoScaleAndNormalize(textBlocks);
|
||||
@@ -216,7 +271,11 @@ namespace Barotrauma.Items.Components
|
||||
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
if (customInterfaceElementList[i].ContinuousSignal)
|
||||
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
|
||||
{
|
||||
msg.Write(((GUITextBox)uiElements[i]).Text);
|
||||
}
|
||||
else if (customInterfaceElementList[i].ContinuousSignal)
|
||||
{
|
||||
msg.Write(((GUITickBox)uiElements[i]).Selected);
|
||||
}
|
||||
@@ -231,15 +290,22 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
bool elementState = msg.ReadBoolean();
|
||||
if (customInterfaceElementList[i].ContinuousSignal)
|
||||
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
|
||||
{
|
||||
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||
TickBoxToggled(customInterfaceElementList[i], elementState);
|
||||
TextChanged(customInterfaceElementList[i], msg.ReadString());
|
||||
}
|
||||
else if (elementState)
|
||||
else
|
||||
{
|
||||
ButtonClicked(customInterfaceElementList[i]);
|
||||
bool elementState = msg.ReadBoolean();
|
||||
if (customInterfaceElementList[i].ContinuousSignal)
|
||||
{
|
||||
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||
TickBoxToggled(customInterfaceElementList[i], elementState);
|
||||
}
|
||||
else if (elementState)
|
||||
{
|
||||
ButtonClicked(customInterfaceElementList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)), null, color,
|
||||
-angle,
|
||||
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
|
||||
new Vector2(length / wire.wireSprite.Texture.Width, width),
|
||||
SpriteEffects.None,
|
||||
shiftedVertices,
|
||||
depth);
|
||||
}
|
||||
|
||||
@@ -34,10 +80,10 @@ namespace Barotrauma.Items.Components
|
||||
end.Y = -end.Y;
|
||||
|
||||
spriteBatch.Draw(wire.wireSprite.Texture,
|
||||
start, null, color,
|
||||
start, wire.wireSprite.SourceRect, color,
|
||||
MathUtils.VectorToAngle(end - start),
|
||||
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
|
||||
new Vector2((Vector2.Distance(start, end)) / wire.wireSprite.Texture.Width, width),
|
||||
new Vector2((Vector2.Distance(start, end)) / wire.wireSprite.size.X, width),
|
||||
SpriteEffects.None,
|
||||
depth);
|
||||
}
|
||||
@@ -50,6 +96,13 @@ namespace Barotrauma.Items.Components
|
||||
private static int? selectedNodeIndex;
|
||||
private static int? highlightedNodeIndex;
|
||||
|
||||
[Serialize(0.3f, false)]
|
||||
public float Width
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get { return sectionExtents; }
|
||||
@@ -72,7 +125,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "wiresprite")
|
||||
if (subElement.Name.ToString().Equals("wiresprite", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
overrideSprite = new Sprite(subElement);
|
||||
break;
|
||||
@@ -103,26 +156,26 @@ 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)
|
||||
{
|
||||
foreach (WireSection section in sections)
|
||||
{
|
||||
section.Draw(spriteBatch, this, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, 0.7f);
|
||||
section.Draw(spriteBatch, this, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
||||
}
|
||||
}
|
||||
else if (item.IsSelected)
|
||||
{
|
||||
foreach (WireSection section in sections)
|
||||
{
|
||||
section.Draw(spriteBatch, this, editorSelectedColor, drawOffset, depth + 0.00001f, 0.7f);
|
||||
section.Draw(spriteBatch, this, editorSelectedColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WireSection section in sections)
|
||||
{
|
||||
section.Draw(spriteBatch, this, item.Color, drawOffset, depth, 0.3f);
|
||||
section.Draw(spriteBatch, this, item.Color, drawOffset, depth, Width);
|
||||
}
|
||||
|
||||
if (nodes.Count > 0)
|
||||
@@ -167,13 +220,13 @@ namespace Barotrauma.Items.Components
|
||||
spriteBatch, this,
|
||||
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
|
||||
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
||||
item.Color, 0.0f, 0.3f);
|
||||
item.Color, 0.0f, Width);
|
||||
|
||||
WireSection.Draw(
|
||||
spriteBatch, this,
|
||||
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
||||
item.DrawPosition,
|
||||
item.Color, itemDepth, 0.3f);
|
||||
item.Color, itemDepth, Width);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(newNodePos.X + drawOffset.X, -(newNodePos.Y + drawOffset.Y)) - Vector2.One * 3, Vector2.One * 6, item.Color);
|
||||
}
|
||||
@@ -183,7 +236,7 @@ namespace Barotrauma.Items.Components
|
||||
spriteBatch, this,
|
||||
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
|
||||
item.DrawPosition,
|
||||
item.Color, 0.0f, 0.3f);
|
||||
item.Color, 0.0f, Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +288,7 @@ namespace Barotrauma.Items.Components
|
||||
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)
|
||||
{
|
||||
@@ -404,6 +457,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));
|
||||
|
||||
@@ -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;
|
||||
@@ -223,21 +236,30 @@ namespace Barotrauma.Items.Components
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) drawPos += item.Submarine.DrawPosition;
|
||||
if (item.Submarine != null)
|
||||
{
|
||||
drawPos += item.Submarine.DrawPosition;
|
||||
}
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
float recoilOffset = 0.0f;
|
||||
if (RecoilDistance > 0.0f && recoilTimer > 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,13 +391,26 @@ namespace Barotrauma.Items.Components
|
||||
tooltipOffset = new Vector2(size / 2 + 5, -10),
|
||||
inputAreaMargin = 20,
|
||||
RequireMouseOn = false
|
||||
};
|
||||
};
|
||||
widgets.Add(id, widget);
|
||||
initMethod?.Invoke(widget);
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
private void GetAvailablePower(out float availableCharge, out float availableCapacity)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
availableCharge = 0.0f;
|
||||
availableCapacity = 0.0f;
|
||||
foreach (PowerContainer battery in batteries)
|
||||
{
|
||||
availableCharge += battery.Charge;
|
||||
availableCapacity += battery.Capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns correct angle between -2PI and +2PI
|
||||
/// </summary>
|
||||
@@ -488,17 +523,31 @@ namespace Barotrauma.Items.Components
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
UInt16 projectileID = msg.ReadUInt16();
|
||||
//projectile removed, do nothing
|
||||
if (projectileID == 0) return;
|
||||
float newTargetRotation = msg.ReadRangedSingle(minRotation, maxRotation, 16);
|
||||
|
||||
Item projectile = Entity.FindEntityByID(projectileID) as Item;
|
||||
if (projectile == null)
|
||||
if (Character.Controlled == null || user != Character.Controlled)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found");
|
||||
return;
|
||||
targetRotation = newTargetRotation;
|
||||
}
|
||||
|
||||
//projectile removed, do nothing
|
||||
if (projectileID == 0) { return; }
|
||||
|
||||
//ID ushort.MaxValue = launched without a projectile
|
||||
if (projectileID == ushort.MaxValue)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ namespace Barotrauma.Items.Components
|
||||
if (joint == null)
|
||||
{
|
||||
string errorMsg = "Error while reading a docking port network event (Dock method did not create a joint between the ports)." +
|
||||
" Submarine: " + (item.Submarine?.Name ?? "null") +
|
||||
", target submarine: " + (DockingTarget.item.Submarine?.Name ?? "null");
|
||||
" Submarine: " + (item.Submarine?.Info.Name ?? "null") +
|
||||
", target submarine: " + (DockingTarget.item.Submarine?.Info.Name ?? "null");
|
||||
if (item.Submarine?.ConnectedDockingPorts.ContainsKey(DockingTarget.item.Submarine) ?? false)
|
||||
{
|
||||
errorMsg += "\nAlready docked.";
|
||||
|
||||
@@ -45,12 +45,17 @@ namespace Barotrauma
|
||||
|
||||
public float QuickUseTimer;
|
||||
public string QuickUseButtonToolTip;
|
||||
public bool IsMoving = false;
|
||||
|
||||
private static Rectangle offScreenRect = new Rectangle(new Point(-1000, 0), Point.Zero);
|
||||
public GUIComponent.ComponentState EquipButtonState;
|
||||
public Rectangle EquipButtonRect
|
||||
{
|
||||
get
|
||||
{
|
||||
// Returns a point off-screen, Rectangle.Empty places buttons in the top left of the screen
|
||||
if (IsMoving) return offScreenRect;
|
||||
|
||||
int buttonDir = Math.Sign(SubInventoryDir);
|
||||
|
||||
float sizeY = Inventory.UnequippedIndicator.size.Y * Inventory.UIScale * Inventory.IndicatorScaleAdjustment;
|
||||
@@ -186,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)
|
||||
{
|
||||
@@ -196,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)
|
||||
@@ -445,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
|
||||
@@ -471,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)
|
||||
@@ -663,6 +692,18 @@ 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...)
|
||||
@@ -670,11 +711,12 @@ namespace Barotrauma
|
||||
/// <returns></returns>
|
||||
public static bool IsMouseOnInventory()
|
||||
{
|
||||
var isSubEditor = Screen.Selected is SubEditorScreen editor && !editor.WiringMode;
|
||||
if (Character.Controlled == null) return false;
|
||||
|
||||
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++)
|
||||
@@ -694,7 +736,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++)
|
||||
@@ -825,9 +868,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)
|
||||
@@ -941,8 +984,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)
|
||||
@@ -1033,7 +1101,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
|
||||
{
|
||||
@@ -1083,7 +1153,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);
|
||||
@@ -1106,7 +1176,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1140,15 +1210,20 @@ namespace Barotrauma
|
||||
/*if (inventory != null && (CharacterInventory.PersonalSlots.HasFlag(type) || (inventory.isSubInventory && (inventory.Owner as Item) != null
|
||||
&& (inventory.Owner as Item).AllowedSlots.Any(a => CharacterInventory.PersonalSlots.HasFlag(a)))))
|
||||
{
|
||||
slotColor = slot.IsHighlighted ? GUIColorSettings.EquipmentSlotColor : GUIColorSettings.EquipmentSlotColor * 0.8f;
|
||||
slotColor = slot.IsHighlighted ? GUI.Style.EquipmentSlotColor : GUI.Style.EquipmentSlotColor * 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotColor = slot.IsHighlighted ? GUIColorSettings.InventorySlotColor : GUIColorSettings.InventorySlotColor * 0.8f;
|
||||
slotColor = slot.IsHighlighted ? GUI.Style.InventorySlotColor : GUI.Style.InventorySlotColor * 0.8f;
|
||||
}*/
|
||||
|
||||
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;
|
||||
|
||||
@@ -1203,13 +1278,15 @@ namespace Barotrauma
|
||||
dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
|
||||
containedIndicatorArea.Inflate(-4, 0);
|
||||
|
||||
Color backgroundColor = GUI.Style.ColorInventoryBackground;
|
||||
|
||||
if (itemContainer.ContainedStateIndicator?.Texture == null)
|
||||
{
|
||||
containedIndicatorArea.Inflate(0, -2);
|
||||
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.Gray * 0.9f, true);
|
||||
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, backgroundColor, true);
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height),
|
||||
ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.LightGreen) * 0.8f, true);
|
||||
ToolBox.GradientLerp(containedState, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull) * 0.8f, true);
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(containedIndicatorArea.X + (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Y),
|
||||
new Vector2(containedIndicatorArea.X + (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Bottom),
|
||||
@@ -1228,12 +1305,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
|
||||
(inventory != null && inventory.Locked) ? Color.Gray * 0.5f : Color.Gray * 0.9f,
|
||||
(inventory != null && inventory.Locked) ? backgroundColor * 0.5f : backgroundColor,
|
||||
origin: indicatorSprite.size / 2,
|
||||
rotate: 0.0f,
|
||||
scale: indicatorScale);
|
||||
|
||||
Color indicatorColor = ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.LightGreen);
|
||||
Color indicatorColor = ToolBox.GradientLerp(containedState, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull);
|
||||
if (inventory != null && inventory.Locked) { indicatorColor *= 0.5f; }
|
||||
|
||||
spriteBatch.Draw(indicatorSprite.Texture, containedIndicatorArea.Center.ToVector2(),
|
||||
|
||||
@@ -29,14 +29,8 @@ namespace Barotrauma
|
||||
private bool editingHUDRefreshPending;
|
||||
private float editingHUDRefreshTimer;
|
||||
|
||||
class SpriteState
|
||||
{
|
||||
public float RotationState;
|
||||
public float OffsetState;
|
||||
public bool IsActive = true;
|
||||
}
|
||||
|
||||
private Dictionary<DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<DecorativeSprite, SpriteState>();
|
||||
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
|
||||
|
||||
private Sprite activeSprite;
|
||||
public override Sprite Sprite
|
||||
@@ -44,11 +38,20 @@ namespace Barotrauma
|
||||
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
|
||||
{
|
||||
@@ -160,8 +163,16 @@ namespace Barotrauma
|
||||
foreach (var decorativeSprite in ((ItemPrefab)prefab).DecorativeSprites)
|
||||
{
|
||||
decorativeSprite.Sprite.EnsureLazyLoaded();
|
||||
spriteAnimState.Add(decorativeSprite, new SpriteState());
|
||||
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
|
||||
}
|
||||
UpdateSpriteStates(0.0f);
|
||||
}
|
||||
|
||||
private Vector2? cachedVisibleSize;
|
||||
|
||||
public void ResetCachedVisibleSize()
|
||||
{
|
||||
cachedVisibleSize = null;
|
||||
}
|
||||
|
||||
public override bool IsVisible(Rectangle worldView)
|
||||
@@ -173,19 +184,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;
|
||||
@@ -197,8 +217,8 @@ namespace Barotrauma
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (!Visible || (!editing && HiddenInGame)) return;
|
||||
if (editing && !ShowItems) return;
|
||||
if (!Visible || (!editing && HiddenInGame)) { return; }
|
||||
if (editing && !ShowItems) { return; }
|
||||
|
||||
Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange : GetSpriteColor();
|
||||
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||
@@ -268,7 +288,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));
|
||||
}
|
||||
}
|
||||
@@ -312,7 +332,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));
|
||||
}
|
||||
}
|
||||
@@ -398,46 +418,7 @@ namespace Barotrauma
|
||||
|
||||
public void UpdateSpriteStates(float deltaTime)
|
||||
{
|
||||
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
|
||||
{
|
||||
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
|
||||
{
|
||||
var decorativeSprite = Prefab.DecorativeSpriteGroups[spriteGroup][i];
|
||||
if (decorativeSprite == null) { continue; }
|
||||
if (spriteGroup > 0)
|
||||
{
|
||||
int activeSpriteIndex = ID % Prefab.DecorativeSpriteGroups[spriteGroup].Count;
|
||||
if (i != activeSpriteIndex)
|
||||
{
|
||||
spriteAnimState[decorativeSprite].IsActive = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//check if the sprite is active (whether it should be drawn or not)
|
||||
var spriteState = spriteAnimState[decorativeSprite];
|
||||
spriteState.IsActive = true;
|
||||
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
|
||||
{
|
||||
if (!ConditionalMatches(conditional))
|
||||
{
|
||||
spriteState.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!spriteState.IsActive) { continue; }
|
||||
|
||||
//check if the sprite should be animated
|
||||
bool animate = true;
|
||||
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
|
||||
{
|
||||
if (!ConditionalMatches(conditional)) { animate = false; break; }
|
||||
}
|
||||
if (!animate) { continue; }
|
||||
spriteState.OffsetState += deltaTime;
|
||||
spriteState.RotationState += deltaTime;
|
||||
}
|
||||
}
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
@@ -716,6 +697,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,
|
||||
@@ -871,19 +859,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; }
|
||||
}
|
||||
@@ -892,9 +882,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;
|
||||
}
|
||||
|
||||
@@ -902,17 +895,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)
|
||||
@@ -1218,6 +1211,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
byte bodyType = msg.ReadByte();
|
||||
|
||||
byte teamID = msg.ReadByte();
|
||||
bool tagsChanged = msg.ReadBoolean();
|
||||
string tags = "";
|
||||
@@ -1256,8 +1251,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);
|
||||
@@ -1275,6 +1270,11 @@ namespace Barotrauma
|
||||
ID = itemId
|
||||
};
|
||||
|
||||
if (item.body != null)
|
||||
{
|
||||
item.body.BodyType = (BodyType)bodyType;
|
||||
}
|
||||
|
||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||
{
|
||||
wifiComponent.TeamID = (Character.TeamType)teamID;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
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);
|
||||
@@ -41,7 +41,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!editing || !ShowGaps) return;
|
||||
if (!editing || !ShowGaps) { return; }
|
||||
|
||||
Color clr = (open == 0.0f) ? GUI.Style.Red : Color.Cyan;
|
||||
if (IsHighlighted) clr = Color.Gold;
|
||||
@@ -76,32 +76,35 @@ namespace Barotrauma
|
||||
clr * 0.6f, width: lineWidth);
|
||||
}
|
||||
|
||||
for (int i = 0; i < linkedTo.Count; i++)
|
||||
if (linkedTo.Count != 2 || linkedTo[0] != linkedTo[1])
|
||||
{
|
||||
Vector2 dir = IsHorizontal ?
|
||||
new Vector2(Math.Sign(linkedTo[i].Rect.Center.X - rect.Center.X), 0.0f)
|
||||
: new Vector2(0.0f, Math.Sign((linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f) - (rect.Y - rect.Height / 2.0f)));
|
||||
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
float arrowWidth = 32.0f;
|
||||
float arrowSize = 15.0f;
|
||||
|
||||
bool invalidDir = false;
|
||||
if (dir == Vector2.Zero)
|
||||
for (int i = 0; i < linkedTo.Count; i++)
|
||||
{
|
||||
invalidDir = true;
|
||||
dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY;
|
||||
}
|
||||
Vector2 dir = IsHorizontal ?
|
||||
new Vector2(Math.Sign(linkedTo[i].Rect.Center.X - rect.Center.X), 0.0f)
|
||||
: new Vector2(0.0f, Math.Sign((linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f) - (rect.Y - rect.Height / 2.0f)));
|
||||
|
||||
GUI.Arrow.Draw(sb,
|
||||
arrowPos, invalidDir ? Color.Red : clr * 0.8f,
|
||||
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
|
||||
IsHorizontal ?
|
||||
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) :
|
||||
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y),
|
||||
SpriteEffects.None, depth);
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
float arrowWidth = 32.0f;
|
||||
float arrowSize = 15.0f;
|
||||
|
||||
bool invalidDir = false;
|
||||
if (dir == Vector2.Zero)
|
||||
{
|
||||
invalidDir = true;
|
||||
dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY;
|
||||
}
|
||||
|
||||
GUI.Arrow.Draw(sb,
|
||||
arrowPos, invalidDir ? Color.Red : clr * 0.8f,
|
||||
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
|
||||
IsHorizontal ?
|
||||
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) :
|
||||
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y),
|
||||
SpriteEffects.None, depth);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSelected)
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Barotrauma
|
||||
|
||||
if (!ShowHulls && !GameMain.DebugDraw) return;
|
||||
|
||||
if (!editing && !GameMain.DebugDraw) return;
|
||||
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) return;
|
||||
|
||||
Rectangle drawRect =
|
||||
Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
|
||||
@@ -269,7 +269,8 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * Math.Min(waterVolume / Volume, 1.0f))), Color.Cyan, true);
|
||||
if (WaterVolume > Volume)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / MaxCompress)), GUI.Style.Red, true);
|
||||
float maxExcessWater = Volume * MaxCompress;
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / maxExcessWater)), GUI.Style.Red, true);
|
||||
}
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, 100), Color.Black);
|
||||
|
||||
@@ -450,7 +451,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]);
|
||||
|
||||
@@ -33,7 +33,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "sprite") continue;
|
||||
if (!subElement.Name.ToString().Equals("sprite", System.StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
Sprite = new Sprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FarseerPhysics;
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
||||
if (renderer == null) return;
|
||||
renderer.Draw(spriteBatch, cam);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
{
|
||||
foreach (InterestingPosition pos in positionsOfInterest)
|
||||
{
|
||||
@@ -78,6 +78,35 @@ namespace Barotrauma
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, ruinArea, Color.DarkSlateBlue, false, 0, 5);
|
||||
}
|
||||
|
||||
foreach (var positions in wreckPositions.Values)
|
||||
{
|
||||
for (int i = 0; i < positions.Count; i++)
|
||||
{
|
||||
float t = (i + 1) / (float)positions.Count;
|
||||
float multiplier = MathHelper.Lerp(0, 1, t);
|
||||
Color color = Color.Red * multiplier;
|
||||
var pos = positions[i];
|
||||
pos.Y = -pos.Y;
|
||||
var size = new Vector2(100);
|
||||
GUI.DrawRectangle(spriteBatch, pos - size / 2, size, color, thickness: 10);
|
||||
if (i < positions.Count - 1)
|
||||
{
|
||||
var nextPos = positions[i + 1];
|
||||
nextPos.Y = -nextPos.Y;
|
||||
GUI.DrawLine(spriteBatch, pos, nextPos, color, width: 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var rects in blockedRects.Values)
|
||||
{
|
||||
foreach (var rect in rects)
|
||||
{
|
||||
Rectangle newRect = rect;
|
||||
newRect.Y = -newRect.Y;
|
||||
GUI.DrawRectangle(spriteBatch, newRect, Color.Red, thickness: 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Barotrauma
|
||||
int j = 0;
|
||||
foreach (XElement subElement in Prefab.Config.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "deformablesprite") continue;
|
||||
if (!subElement.Name.ToString().Equals("deformablesprite", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
foreach (XElement animationElement in subElement.Elements())
|
||||
{
|
||||
var newDeformation = SpriteDeformation.Load(animationElement, Prefab.Name);
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Barotrauma
|
||||
bool elementFound = false;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "overridecommonness"
|
||||
if (subElement.Name.ToString().Equals("overridecommonness", System.StringComparison.OrdinalIgnoreCase)
|
||||
&& subElement.GetAttributeString("leveltype", "") == overrideCommonness.Key)
|
||||
{
|
||||
subElement.Attribute("commonness").Value = overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GameMain.DebugDraw && cam.Zoom > 0.05f)
|
||||
if (GameMain.DebugDraw && cam.Zoom > 0.1f)
|
||||
{
|
||||
var cells = level.GetCells(cam.WorldViewCenter, 2);
|
||||
foreach (VoronoiCell cell in cells)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -229,7 +229,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -977,7 +977,7 @@ namespace Barotrauma.Lights
|
||||
origin, -Rotation, SpriteScale, LightSpriteEffect);
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
{
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
|
||||
@@ -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,
|
||||
@@ -131,8 +135,9 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
XDocument doc = Submarine.OpenFile(pathBox.Text);
|
||||
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);
|
||||
|
||||
|
||||
@@ -16,8 +16,15 @@ 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.
|
||||
private Memento<Rectangle> rectMemento;
|
||||
|
||||
public event Action<Rectangle> Resized;
|
||||
|
||||
private static bool resizing;
|
||||
private int resizeDirX, resizeDirY;
|
||||
|
||||
@@ -127,7 +134,7 @@ namespace Barotrauma
|
||||
if (highlightedListBox == null ||
|
||||
(GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
|
||||
{
|
||||
UpdateHighlightedListBox(null);
|
||||
UpdateHighlightedListBox(null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -142,11 +149,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (PlayerInput.KeyDown(Keys.Delete))
|
||||
{
|
||||
selectedList.ForEach(e => e.Remove());
|
||||
selectedList.ForEach(e =>
|
||||
{
|
||||
e.Remove();
|
||||
});
|
||||
selectedList.Clear();
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.C))
|
||||
{
|
||||
@@ -239,32 +249,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;
|
||||
@@ -272,35 +257,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;
|
||||
@@ -308,6 +323,7 @@ namespace Barotrauma
|
||||
}
|
||||
else // move
|
||||
{
|
||||
List<MapEntity> deposited = new List<MapEntity>();
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
if (e.rectMemento == null)
|
||||
@@ -316,8 +332,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;
|
||||
@@ -352,8 +383,7 @@ namespace Barotrauma
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonReleased())
|
||||
{
|
||||
if (PlayerInput.KeyDown(Keys.LeftControl) ||
|
||||
PlayerInput.KeyDown(Keys.RightControl))
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
foreach (MapEntity e in newSelection)
|
||||
{
|
||||
@@ -436,7 +466,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)
|
||||
{
|
||||
@@ -453,14 +560,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
|
||||
};
|
||||
}
|
||||
@@ -469,8 +599,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))
|
||||
{
|
||||
@@ -480,11 +609,10 @@ namespace Barotrauma
|
||||
{
|
||||
AddSelection(entity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectEntity(entity);
|
||||
}
|
||||
SelectEntity(entity);
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -553,6 +681,10 @@ namespace Barotrauma
|
||||
{
|
||||
item.UpdateSpriteStates(deltaTime);
|
||||
}
|
||||
else if (me is Structure structure)
|
||||
{
|
||||
structure.UpdateSpriteStates(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,24 +702,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;
|
||||
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);
|
||||
@@ -643,7 +803,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if ((PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)))
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.N))
|
||||
{
|
||||
@@ -721,7 +881,10 @@ namespace Barotrauma
|
||||
|
||||
CopyEntities(entities);
|
||||
|
||||
entities.ForEach(e => e.Remove());
|
||||
entities.ForEach(e =>
|
||||
{
|
||||
e.Remove();
|
||||
});
|
||||
entities.Clear();
|
||||
}
|
||||
|
||||
@@ -834,6 +997,7 @@ namespace Barotrauma
|
||||
resizeDirX = x;
|
||||
resizeDirY = y;
|
||||
resizing = true;
|
||||
startMovingPos = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -851,6 +1015,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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -18,11 +18,13 @@ namespace Barotrauma
|
||||
|
||||
private List<ConvexHull> convexHulls;
|
||||
|
||||
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return HasBody ? ShowWalls : ShowStructures;;
|
||||
return HasBody ? ShowWalls : ShowStructures;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +40,14 @@ namespace Barotrauma
|
||||
{
|
||||
Prefab.sprite?.EnsureLazyLoaded();
|
||||
Prefab.BackgroundSprite?.EnsureLazyLoaded();
|
||||
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
decorativeSprite.Sprite.EnsureLazyLoaded();
|
||||
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
|
||||
}
|
||||
|
||||
UpdateSpriteStates(0.0f);
|
||||
}
|
||||
|
||||
partial void CreateConvexHull(Vector2 position, Vector2 size, float rotation)
|
||||
@@ -156,19 +166,19 @@ namespace Barotrauma
|
||||
{
|
||||
Rectangle worldRect = WorldRect;
|
||||
|
||||
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) return false;
|
||||
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) return false;
|
||||
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) { return false; }
|
||||
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (prefab.sprite == null) return;
|
||||
if (prefab.sprite == null) { return; }
|
||||
if (editing)
|
||||
{
|
||||
if (!HasBody && !ShowStructures) return;
|
||||
if (HasBody && !ShowWalls) return;
|
||||
if (!HasBody && !ShowStructures) { return; }
|
||||
if (HasBody && !ShowWalls) { return; }
|
||||
}
|
||||
|
||||
Draw(spriteBatch, editing, back, null);
|
||||
@@ -188,12 +198,13 @@ namespace Barotrauma
|
||||
|
||||
private void Draw(SpriteBatch spriteBatch, bool editing, bool back = true, Effect damageEffect = null)
|
||||
{
|
||||
if (prefab.sprite == null) return;
|
||||
if (prefab.sprite == null) { return; }
|
||||
if (editing)
|
||||
{
|
||||
if (!HasBody && !ShowStructures) return;
|
||||
if (HasBody && !ShowWalls) return;
|
||||
if (!HasBody && !ShowStructures) { return; }
|
||||
if (HasBody && !ShowWalls) { return; }
|
||||
}
|
||||
else if (HiddenInGame) { return; }
|
||||
|
||||
Color color = IsHighlighted ? GUI.Style.Orange : spriteColor;
|
||||
if (IsSelected && editing)
|
||||
@@ -254,7 +265,7 @@ namespace Barotrauma
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
|
||||
new Vector2(rect.Width, rect.Height),
|
||||
color: color,
|
||||
color: Prefab.BackgroundSpriteColor,
|
||||
textureScale: TextureScale * Scale,
|
||||
startOffset: backGroundOffset,
|
||||
depth: Math.Max(Prefab.BackgroundSprite.Depth + (ID % 255) * 0.000001f, depth + 0.000001f));
|
||||
@@ -318,10 +329,20 @@ namespace Barotrauma
|
||||
depth: depth,
|
||||
textureScale: TextureScale * Scale);
|
||||
}
|
||||
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
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, decorativeSprite.Scale * Scale, prefab.sprite.effects,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.sprite.Depth), 0.999f));
|
||||
}
|
||||
prefab.sprite.effects = oldEffects;
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.5f)
|
||||
{
|
||||
if (Bodies != null)
|
||||
{
|
||||
@@ -353,12 +374,70 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSpriteStates(float deltaTime)
|
||||
{
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
|
||||
{
|
||||
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
|
||||
{
|
||||
var decorativeSprite = Prefab.DecorativeSpriteGroups[spriteGroup][i];
|
||||
if (decorativeSprite == null) { continue; }
|
||||
if (spriteGroup > 0)
|
||||
{
|
||||
int activeSpriteIndex = ID % Prefab.DecorativeSpriteGroups[spriteGroup].Count;
|
||||
if (i != activeSpriteIndex)
|
||||
{
|
||||
spriteAnimState[decorativeSprite].IsActive = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//check if the sprite is active (whether it should be drawn or not)
|
||||
var spriteState = spriteAnimState[decorativeSprite];
|
||||
spriteState.IsActive = true;
|
||||
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
|
||||
{
|
||||
if (!ConditionalMatches(conditional))
|
||||
{
|
||||
spriteState.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!spriteState.IsActive) { continue; }
|
||||
|
||||
//check if the sprite should be animated
|
||||
bool animate = true;
|
||||
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
|
||||
{
|
||||
if (!ConditionalMatches(conditional)) { animate = false; break; }
|
||||
}
|
||||
if (!animate) { continue; }
|
||||
spriteState.OffsetState += deltaTime;
|
||||
spriteState.RotationState += deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConditionalMatches(PropertyConditional conditional)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(conditional.TargetItemComponentName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!conditional.Matches(this)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class StructurePrefab : MapEntityPrefab
|
||||
{
|
||||
public Color BackgroundSpriteColor
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<DecorativeSprite> DecorativeSprites = new List<DecorativeSprite>();
|
||||
public Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
|
||||
|
||||
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);
|
||||
@@ -40,7 +56,7 @@ namespace Barotrauma
|
||||
if (PlayerInput.PrimaryMouseButtonReleased())
|
||||
{
|
||||
newRect.Location -= MathUtils.ToPoint(Submarine.MainSub.Position);
|
||||
var structure = new Structure(newRect, this, Submarine.MainSub)
|
||||
new Structure(newRect, this, Submarine.MainSub)
|
||||
{
|
||||
Submarine = Submarine.MainSub
|
||||
};
|
||||
@@ -49,8 +65,6 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (PlayerInput.SecondaryMouseButtonHeld()) selected = null;
|
||||
}
|
||||
|
||||
public override void DrawPlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
@@ -60,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;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -35,7 +36,6 @@ namespace Barotrauma
|
||||
|
||||
partial class Submarine : Entity, IServerSerializable
|
||||
{
|
||||
public Sprite PreviewImage;
|
||||
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
|
||||
{
|
||||
Vector2 position = PlayerInput.MousePosition;
|
||||
@@ -56,6 +56,8 @@ namespace Barotrauma
|
||||
private static List<RoundSound> roundSounds = null;
|
||||
public static RoundSound LoadRoundSound(XElement element, bool stream = false)
|
||||
{
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return null; }
|
||||
|
||||
string filename = element.GetAttributeString("file", "");
|
||||
if (string.IsNullOrEmpty(filename)) filename = element.GetAttributeString("sound", "");
|
||||
|
||||
@@ -222,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;
|
||||
@@ -245,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;
|
||||
|
||||
@@ -256,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)
|
||||
@@ -329,125 +335,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SaveCurrent(string filePath, MemoryStream previewImage = null)
|
||||
{
|
||||
if (MainSub == null)
|
||||
{
|
||||
MainSub = new Submarine(filePath);
|
||||
}
|
||||
|
||||
MainSub.filePath = filePath;
|
||||
return MainSub.SaveAs(filePath, previewImage);
|
||||
}
|
||||
|
||||
public void CreatePreviewWindow(GUIComponent parent)
|
||||
{
|
||||
var content = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform), style: null);
|
||||
|
||||
if (PreviewImage == null)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), TextManager.Get(SavedSubmarines.Contains(this) ? "SubPreviewImageNotFound" : "SubNotDownloaded"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var submarinePreviewBackground = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), style: null) { Color = Color.Black };
|
||||
new GUIImage(new RectTransform(new Vector2(0.98f), submarinePreviewBackground.RectTransform, Anchor.Center), PreviewImage, scaleToFit: true);
|
||||
new GUIFrame(new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform), "InnerGlow", color: Color.Black);
|
||||
}
|
||||
var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.5f), content.RectTransform, Anchor.BottomCenter))
|
||||
{
|
||||
UserData = "descriptionbox",
|
||||
ScrollBarVisible = true,
|
||||
Spacing = 5
|
||||
};
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), descriptionBox.Content.RectTransform), style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("submarine.name." + Name, true) ?? Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false };
|
||||
|
||||
float leftPanelWidth = 0.6f;
|
||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||
|
||||
ScalableFont font = descriptionBox.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
if (realWorldDimensions != Vector2.Zero)
|
||||
{
|
||||
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
||||
|
||||
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RecommendedCrewSizeMax > 0)
|
||||
{
|
||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
|
||||
{
|
||||
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RequiredContentPackages.Any())
|
||||
{
|
||||
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
// show what game version the submarine was created on
|
||||
if (!IsVanillaSubmarine() && GameVersion != null)
|
||||
{
|
||||
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
|
||||
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(descriptionBox.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>());
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null);
|
||||
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("SaveSubDialogDescription", fallBackTag: "WorkshopItemDescription"), font: GUI.Font, wrap: true) { CanBeFocused = false, ForceUpperCase = true };
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Description, font: font, wrap: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null)
|
||||
{
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
@@ -496,21 +383,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVanillaSubmarine()
|
||||
{
|
||||
var vanilla = GameMain.VanillaContent;
|
||||
if (vanilla != null)
|
||||
{
|
||||
var vanillaSubs = vanilla.GetFilesOfType(ContentType.Submarine);
|
||||
string pathToCompare = filePath.Replace(@"\", @"/").ToLowerInvariant();
|
||||
if (vanillaSubs.Any(sub => sub.Replace(@"\", @"/").ToLowerInvariant() == pathToCompare))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CheckForErrors()
|
||||
{
|
||||
List<string> errorMsgs = new List<string>();
|
||||
@@ -531,6 +403,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
|
||||
}
|
||||
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
|
||||
@@ -605,7 +482,7 @@ namespace Barotrauma
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Name);
|
||||
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Info.Name);
|
||||
msg.ReadPadBits();
|
||||
|
||||
if (posInfo != null)
|
||||
|
||||
149
Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs
Normal file
149
Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class SubmarineInfo : IDisposable
|
||||
{
|
||||
public Sprite PreviewImage;
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
string previewImageData = SubmarineElement.GetAttributeString("previewimage", "");
|
||||
if (!string.IsNullOrEmpty(previewImageData))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData)))
|
||||
{
|
||||
var texture = TextureLoader.FromStream(mem, path: FilePath);
|
||||
if (texture == null) { throw new Exception("PreviewImage texture returned null"); }
|
||||
PreviewImage = new Sprite(texture, null, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.");
|
||||
PreviewImage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void CreatePreviewWindow(GUIComponent parent)
|
||||
{
|
||||
var content = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform), style: null);
|
||||
|
||||
if (PreviewImage == null)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), TextManager.Get(SavedSubmarines.Contains(this) ? "SubPreviewImageNotFound" : "SubNotDownloaded"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var submarinePreviewBackground = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), style: null) { Color = Color.Black };
|
||||
new GUIImage(new RectTransform(new Vector2(0.98f), submarinePreviewBackground.RectTransform, Anchor.Center), PreviewImage, scaleToFit: true);
|
||||
new GUIFrame(new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform), "InnerGlow", color: Color.Black);
|
||||
}
|
||||
var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.5f), content.RectTransform, Anchor.BottomCenter))
|
||||
{
|
||||
UserData = "descriptionbox",
|
||||
ScrollBarVisible = true,
|
||||
Spacing = 5
|
||||
};
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), descriptionBox.Content.RectTransform), style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("submarine.name." + Name, true) ?? Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false };
|
||||
|
||||
float leftPanelWidth = 0.6f;
|
||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||
|
||||
ScalableFont font = descriptionBox.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
if (realWorldDimensions != Vector2.Zero)
|
||||
{
|
||||
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
||||
|
||||
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RecommendedCrewSizeMax > 0)
|
||||
{
|
||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
|
||||
{
|
||||
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RequiredContentPackages.Any())
|
||||
{
|
||||
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
// show what game version the submarine was created on
|
||||
if (!IsVanillaSubmarine() && GameVersion != null)
|
||||
{
|
||||
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
|
||||
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(descriptionBox.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>());
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null);
|
||||
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("SaveSubDialogDescription", fallBackTag: "WorkshopItemDescription"), font: GUI.Font, wrap: true)
|
||||
{ CanBeFocused = false, ForceUpperCase = true };
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Description, font: font, wrap: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class WayPoint : MapEntity
|
||||
{
|
||||
private static Texture2D iconTexture;
|
||||
private const int IconSize = 32;
|
||||
private static int[] iconIndices = { 3, 0, 1, 2 };
|
||||
private static Dictionary<SpawnType, Sprite> iconSprites;
|
||||
private const int WaypointSize = 12, SpawnPointSize = 32;
|
||||
|
||||
public override bool IsVisible(Rectangle worldView)
|
||||
{
|
||||
@@ -23,58 +22,58 @@ namespace Barotrauma
|
||||
get { return !IsHidden(); }
|
||||
}
|
||||
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (!editing && !GameMain.DebugDraw) { return; }
|
||||
|
||||
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) { return; }
|
||||
if (IsHidden()) { return; }
|
||||
|
||||
//Rectangle drawRect =
|
||||
// Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
|
||||
|
||||
Vector2 drawPos = Position;
|
||||
if (Submarine != null) drawPos += Submarine.DrawPosition;
|
||||
if (Submarine != null) { drawPos += Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
Color clr = currentHull == null ? Color.Blue : Color.White;
|
||||
Draw(spriteBatch, drawPos);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Vector2 drawPos)
|
||||
{
|
||||
Color clr = currentHull == null ? Color.CadetBlue : GUI.Style.Green;
|
||||
if (spawnType != SpawnType.Path) { clr = Color.Gray; }
|
||||
if (isObstructed)
|
||||
{
|
||||
clr = Color.Black;
|
||||
}
|
||||
if (IsSelected) clr = GUI.Style.Red;
|
||||
if (IsHighlighted) clr = Color.DarkRed;
|
||||
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
|
||||
|
||||
int iconX = iconIndices[(int)spawnType] * IconSize % iconTexture.Width;
|
||||
int iconY = (int)(Math.Floor(iconIndices[(int)spawnType] * IconSize / (float)iconTexture.Width)) * IconSize;
|
||||
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
|
||||
if (ConnectedGap != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path) { iconSize = (int)(iconSize * 1.5f); }
|
||||
|
||||
int iconSize = IconSize;
|
||||
if (ConnectedGap != null)
|
||||
if (IsSelected || IsHighlighted)
|
||||
{
|
||||
iconSize = (int)(iconSize * 1.5f);
|
||||
}
|
||||
if (Ladders != null)
|
||||
{
|
||||
iconSize = (int)(iconSize * 1.5f);
|
||||
}
|
||||
if (Stairs != null)
|
||||
{
|
||||
iconSize = (int)(iconSize * 1.5f);
|
||||
int glowSize = (int)(iconSize * 1.5f);
|
||||
GUI.Style.UIGlowCircular.Draw(spriteBatch,
|
||||
new Rectangle((int)(drawPos.X - glowSize / 2), (int)(drawPos.Y - glowSize / 2), glowSize, glowSize),
|
||||
Color.White);
|
||||
}
|
||||
|
||||
spriteBatch.Draw(iconTexture,
|
||||
new Rectangle((int)(drawPos.X - iconSize / 2), (int)(drawPos.Y - iconSize / 2), iconSize, iconSize),
|
||||
new Rectangle(iconX, iconY, IconSize, IconSize), clr);
|
||||
|
||||
//GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height), clr, true);
|
||||
|
||||
//GUI.SmallFont.DrawString(spriteBatch, Position.ToString(), new Vector2(Position.X, -Position.Y), Color.White);
|
||||
Sprite sprite = iconSprites[SpawnType];
|
||||
if (spawnType == SpawnType.Human && AssignedJob?.Icon != null)
|
||||
{
|
||||
sprite = iconSprites[SpawnType.Path];
|
||||
}
|
||||
sprite.Draw(spriteBatch, drawPos, clr, scale: iconSize / (float)sprite.SourceRect.Width, depth: 0.001f);
|
||||
sprite.RelativeOrigin = Vector2.One * 0.5f;
|
||||
if (spawnType == SpawnType.Human && AssignedJob?.Icon != null)
|
||||
{
|
||||
AssignedJob.Icon.Draw(spriteBatch, drawPos, AssignedJob.UIColor, scale: iconSize / (float)AssignedJob.Icon.SourceRect.Width * 0.8f, depth: 0.0f);
|
||||
}
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(e.DrawPosition.X, -e.DrawPosition.Y),
|
||||
isObstructed ? Color.Gray : GUI.Style.Green, width: 5);
|
||||
(isObstructed ? Color.Gray : GUI.Style.Green) * 0.7f, width: 5, depth: 0.002f);
|
||||
}
|
||||
|
||||
GUI.SmallFont.DrawString(spriteBatch,
|
||||
@@ -83,6 +82,14 @@ namespace Barotrauma
|
||||
Color.WhiteSmoke);
|
||||
}
|
||||
|
||||
public override bool IsMouseOn(Vector2 position)
|
||||
{
|
||||
if (IsHidden()) { return false; }
|
||||
float dist = Vector2.DistanceSquared(position, WorldPosition);
|
||||
float radius = (SpawnType == SpawnType.Path ? WaypointSize : SpawnPointSize) * 0.6f;
|
||||
return dist < radius * radius;
|
||||
}
|
||||
|
||||
private bool IsHidden()
|
||||
{
|
||||
if (spawnType == SpawnType.Path)
|
||||
@@ -101,59 +108,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;
|
||||
// }
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,14 +198,19 @@ namespace Barotrauma
|
||||
private bool ChangeSpawnType(GUIButton button, object obj)
|
||||
{
|
||||
GUITextBlock spawnTypeText = button.Parent.GetChildByUserData("spawntypetext") as GUITextBlock;
|
||||
|
||||
spawnType += (int)button.UserData;
|
||||
|
||||
if (spawnType > SpawnType.Cargo) spawnType = SpawnType.Human;
|
||||
if (spawnType < SpawnType.Human) spawnType = SpawnType.Cargo;
|
||||
|
||||
var values = Enum.GetValues(typeof(SpawnType));
|
||||
int firstIndex = 1;
|
||||
int lastIndex = values.Length - 1;
|
||||
if ((int)spawnType > lastIndex)
|
||||
{
|
||||
spawnType = (SpawnType)firstIndex;
|
||||
}
|
||||
if ((int)spawnType < firstIndex)
|
||||
{
|
||||
spawnType = (SpawnType)values.GetValue(lastIndex);
|
||||
}
|
||||
spawnTypeText.Text = spawnType.ToString();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
@@ -72,7 +76,8 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
VoipSound.SetPosition(null);
|
||||
}
|
||||
VoipSound.Gain = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Barotrauma.Networking
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public string PendingName = string.Empty;
|
||||
|
||||
public void SetName(string value)
|
||||
{
|
||||
value = value.Replace(":", "").Replace(";", "");
|
||||
@@ -78,7 +80,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
private List<Client> otherClients;
|
||||
|
||||
private readonly List<Submarine> serverSubmarines = new List<Submarine>();
|
||||
private readonly List<SubmarineInfo> serverSubmarines = new List<SubmarineInfo>();
|
||||
|
||||
private string serverIP, serverName;
|
||||
|
||||
@@ -112,6 +114,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool SpawnAsTraitor;
|
||||
public string TraitorFirstObjective;
|
||||
public TraitorMissionPrefab TraitorMission = null;
|
||||
|
||||
public byte ID
|
||||
{
|
||||
@@ -482,19 +485,24 @@ 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));
|
||||
var passwordHolder = new GUILayoutGroup(new RectTransform(Vector2.One, msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f) , passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
|
||||
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) })
|
||||
{
|
||||
UserData = "password",
|
||||
Censor = true
|
||||
};
|
||||
|
||||
msgBox.Content.Recalculate();
|
||||
msgBox.Content.RectTransform.MinSize = new Point(0, msgBox.Content.RectTransform.Children.Sum(c => c.Rect.Height));
|
||||
msgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(msgBox.Content.RectTransform.MinSize.Y / msgBox.Content.RectTransform.RelativeSize.Y));
|
||||
|
||||
var okButton = msgBox.Buttons[0];
|
||||
var cancelButton = msgBox.Buttons[1];
|
||||
|
||||
@@ -509,6 +517,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
requiresPw = false;
|
||||
connectCancelled = true;
|
||||
GameMain.ServerListScreen.Select();
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -540,6 +549,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (Client c in ConnectedClients)
|
||||
{
|
||||
if (c.Character != null && c.Character.Removed) { c.Character = null; }
|
||||
c.UpdateSoundPosition();
|
||||
}
|
||||
|
||||
@@ -664,6 +674,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
|
||||
@@ -674,6 +685,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;
|
||||
@@ -837,7 +873,7 @@ namespace Barotrauma.Networking
|
||||
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
|
||||
{
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash.ShortHash + ")" +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
@@ -1051,11 +1087,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;
|
||||
@@ -1326,7 +1364,6 @@ namespace Barotrauma.Networking
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
});*/
|
||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||
reloadSub: true,
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
}
|
||||
|
||||
@@ -1406,9 +1443,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession.Submarine.IsFileCorrupted)
|
||||
if (GameMain.GameSession.Submarine.Info.IsFileCorrupted)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Name}\".");
|
||||
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Info.Name}\".");
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
@@ -1498,8 +1535,8 @@ namespace Barotrauma.Networking
|
||||
bool requiredContentPackagesInstalled = inc.ReadBoolean();
|
||||
|
||||
var matchingSub =
|
||||
Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
|
||||
new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false);
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
|
||||
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash, tryLoad: false);
|
||||
|
||||
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
|
||||
serverSubmarines.Add(matchingSub);
|
||||
@@ -1533,9 +1570,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
|
||||
@@ -1546,8 +1585,10 @@ namespace Barotrauma.Networking
|
||||
Name = name,
|
||||
PreferredJob = preferredJob,
|
||||
CharacterID = characterID,
|
||||
Karma = karma,
|
||||
Muted = muted,
|
||||
InGame = inGame,
|
||||
HasPermissions = hasPermissions,
|
||||
AllowKicking = allowKicking
|
||||
});
|
||||
}
|
||||
@@ -1575,7 +1616,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);
|
||||
@@ -2028,15 +2071,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
case FileTransferType.Submarine:
|
||||
new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
|
||||
var newSub = new Submarine(transfer.FilePath);
|
||||
var newSub = new SubmarineInfo(transfer.FilePath);
|
||||
if (newSub.IsFileCorrupted) { return; }
|
||||
|
||||
var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
|
||||
foreach (Submarine existingSub in existingSubs)
|
||||
var existingSubs = SubmarineInfo.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
|
||||
foreach (SubmarineInfo existingSub in existingSubs)
|
||||
{
|
||||
existingSub.Dispose();
|
||||
}
|
||||
Submarine.AddToSavedSubs(newSub);
|
||||
SubmarineInfo.AddToSavedSubs(newSub);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -2045,8 +2088,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SubList.Content.Children;
|
||||
|
||||
var subElement = subListChildren.FirstOrDefault(c =>
|
||||
((Submarine)c.UserData).Name == newSub.Name &&
|
||||
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||
((SubmarineInfo)c.UserData).Name == newSub.Name &&
|
||||
((SubmarineInfo)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||
if (subElement == null) continue;
|
||||
|
||||
subElement.GetChild<GUITextBlock>().TextColor = new Color(subElement.GetChild<GUITextBlock>().TextColor, 1.0f);
|
||||
@@ -2074,17 +2117,17 @@ namespace Barotrauma.Networking
|
||||
if (campaign == null) { return; }
|
||||
|
||||
GameMain.GameSession.SavePath = transfer.FilePath;
|
||||
if (GameMain.GameSession.Submarine == null)
|
||||
if (GameMain.GameSession.SubmarineInfo == null)
|
||||
{
|
||||
var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath);
|
||||
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDoc.Root.GetAttributeString("submarine", "")) + ".sub";
|
||||
GameMain.GameSession.Submarine = new Submarine(subPath, "");
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
|
||||
}
|
||||
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
|
||||
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
|
||||
if (GameMain.GameSession?.Submarine?.Name != null)
|
||||
GameMain.GameSession?.SubmarineInfo?.CheckSubsLeftBehind();
|
||||
if (GameMain.GameSession?.SubmarineInfo?.Name != null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.Submarine);
|
||||
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.SubmarineInfo);
|
||||
}
|
||||
campaign.LastSaveID = campaign.PendingSaveID;
|
||||
|
||||
@@ -2119,8 +2162,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) { return false; }
|
||||
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
if (permittedConsoleCommands.Any(c => c.ToLowerInvariant() == commandName)) { return true; }
|
||||
if (permittedConsoleCommands.Any(c => c.Equals(commandName, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
|
||||
//check aliases
|
||||
foreach (DebugConsole.Command command in DebugConsole.Commands)
|
||||
@@ -2371,7 +2413,7 @@ namespace Barotrauma.Networking
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void SetupNewCampaign(Submarine sub, string saveName, string mapSeed)
|
||||
public void SetupNewCampaign(SubmarineInfo sub, string saveName, string mapSeed)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSetupFrame.Visible = false;
|
||||
|
||||
@@ -2537,6 +2579,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)
|
||||
@@ -2580,7 +2627,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)
|
||||
{
|
||||
@@ -2626,8 +2673,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)
|
||||
@@ -2740,73 +2785,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))
|
||||
@@ -2820,14 +2898,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,7 +3010,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
if (GameMain.GameSession?.Submarine != null)
|
||||
{
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Name);
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
@@ -2952,8 +3032,8 @@ namespace Barotrauma.Networking
|
||||
errorLines.Add(" " + DebugConsole.Messages[i].Time + " - " + DebugConsole.Messages[i].Text);
|
||||
}
|
||||
|
||||
string filePath = "event_error_log_client_" + Name + "_" + ToolBox.RemoveInvalidFileNameChars(DateTime.UtcNow.ToShortTimeString() + ".log");
|
||||
filePath = Path.Combine(ServerLog.SavePath, filePath);
|
||||
string filePath = "event_error_log_client_" + Name + "_" + DateTime.UtcNow.ToShortTimeString() + ".log";
|
||||
filePath = Path.Combine(ServerLog.SavePath, ToolBox.RemoveInvalidFileNameChars(filePath));
|
||||
|
||||
if (!Directory.Exists(ServerLog.SavePath))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -137,8 +137,9 @@ 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)
|
||||
{
|
||||
|
||||
@@ -204,8 +204,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
|
||||
for (int i=0;i<100;i++)
|
||||
{
|
||||
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
|
||||
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
|
||||
if (packet.HasValue)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -9,9 +11,19 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public GUIButton LogFrame;
|
||||
private GUIListBox listBox;
|
||||
private GUIButton reverseButton;
|
||||
|
||||
private string msgFilter;
|
||||
|
||||
private bool reverseOrder = false;
|
||||
|
||||
private bool OnReverseClicked(GUIButton btn, object obj)
|
||||
{
|
||||
SetMessageReversal(!reverseOrder);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CreateLogFrame()
|
||||
{
|
||||
LogFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
|
||||
@@ -80,7 +92,17 @@ namespace Barotrauma.Networking
|
||||
GUI.KeyboardDispatcher.Subscriber = searchBox;
|
||||
filterArea.RectTransform.MinSize = new Point(0, filterArea.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
|
||||
listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), rightColumn.RectTransform));
|
||||
GUILayoutGroup listBoxLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.95f), rightColumn.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.0f
|
||||
};
|
||||
|
||||
reverseButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), listBoxLayout.RectTransform), style: "UIToggleButtonVertical");
|
||||
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
|
||||
reverseButton.OnClicked = OnReverseClicked;
|
||||
|
||||
listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), listBoxLayout.RectTransform));
|
||||
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.05f), rightColumn.RectTransform), TextManager.Get("Close"))
|
||||
{
|
||||
@@ -107,7 +129,7 @@ namespace Barotrauma.Networking
|
||||
msgFilter = "";
|
||||
}
|
||||
|
||||
public void AssignLogFrame(GUIListBox inListBox, GUIComponent tickBoxContainer, GUITextBox searchBox)
|
||||
public void AssignLogFrame(GUIButton inReverseButton, GUIListBox inListBox, GUIComponent tickBoxContainer, GUITextBox searchBox)
|
||||
{
|
||||
searchBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
@@ -144,6 +166,10 @@ namespace Barotrauma.Networking
|
||||
inListBox.ClearChildren();
|
||||
listBox = inListBox;
|
||||
|
||||
reverseButton = inReverseButton;
|
||||
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
|
||||
reverseButton.OnClicked = OnReverseClicked;
|
||||
|
||||
var currLines = lines.ToList();
|
||||
foreach (LogMessage line in currLines)
|
||||
{
|
||||
@@ -158,8 +184,34 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
float prevSize = listBox.BarSize;
|
||||
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
||||
line.Text, wrap: true, font: GUI.SmallFont)
|
||||
GUIFrame textContainer = null;
|
||||
|
||||
Anchor anchor = Anchor.TopLeft;
|
||||
Pivot pivot = Pivot.TopLeft;
|
||||
if (line.RichData != null)
|
||||
{
|
||||
foreach (var data in line.RichData)
|
||||
{
|
||||
UInt64 id = 0;
|
||||
if (!UInt64.TryParse(data.Metadata, out id)) { return; }
|
||||
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
|
||||
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client != null && client.Karma < 40.0f)
|
||||
{
|
||||
textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
||||
style: null, color: new Color(0xff111155))
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
anchor = Anchor.CenterLeft;
|
||||
pivot = Pivot.CenterLeft;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), (textContainer ?? listBox.Content).RectTransform, anchor, pivot),
|
||||
line.RichData, line.SanitizedText, wrap: true, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = messageColor[line.Type],
|
||||
Visible = !msgTypeHidden[(int)line.Type],
|
||||
@@ -167,6 +219,38 @@ namespace Barotrauma.Networking
|
||||
UserData = line
|
||||
};
|
||||
|
||||
if (textContainer != null)
|
||||
{
|
||||
textContainer.RectTransform.NonScaledSize = new Point(textContainer.RectTransform.NonScaledSize.X, textBlock.RectTransform.NonScaledSize.Y + 5);
|
||||
textBlock.SetTextPos();
|
||||
textBlock.RectTransform.Resize(textContainer.RectTransform.NonScaledSize);
|
||||
}
|
||||
|
||||
if (reverseOrder)
|
||||
{
|
||||
textBlock.RectTransform.SetAsFirstChild();
|
||||
}
|
||||
|
||||
if (line.RichData != null)
|
||||
{
|
||||
foreach (var data in line.RichData)
|
||||
{
|
||||
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
|
||||
{
|
||||
Data = data,
|
||||
OnClick = (component, area) =>
|
||||
{
|
||||
UInt64 id = 0;
|
||||
if (!UInt64.TryParse(area.Data.Metadata, out id)) { return; }
|
||||
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
|
||||
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client == null) { return; }
|
||||
GameMain.NetLobbyScreen.SelectPlayer(client);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ((prevSize == 1.0f && listBox.BarScroll == 0.0f) || (prevSize < 1.0f && listBox.BarScroll == 1.0f)) listBox.BarScroll = 1.0f;
|
||||
}
|
||||
|
||||
@@ -195,6 +279,16 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetMessageReversal(bool reverse)
|
||||
{
|
||||
if (reverseOrder == reverse) { return; }
|
||||
|
||||
reverseOrder = reverse;
|
||||
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
|
||||
|
||||
listBox.Content.RectTransform.ReverseChildren();
|
||||
}
|
||||
|
||||
public bool ClearFilter(GUIComponent button, object obj)
|
||||
{
|
||||
var searchBox = button.UserData as GUITextBox;
|
||||
|
||||
@@ -571,6 +571,9 @@ namespace Barotrauma.Networking
|
||||
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
|
||||
|
||||
var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
|
||||
GetPropertyData("DisableBotConversations").AssignGUIComponent(disableBotConversationsBox);
|
||||
|
||||
/*var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||
|
||||
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||
|
||||
@@ -10,11 +10,14 @@ using RestSharp.Contrib;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml;
|
||||
using Color = Microsoft.Xna.Framework.Color;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Barotrauma.Steam
|
||||
{
|
||||
static partial class SteamManager
|
||||
{
|
||||
private static Dictionary<Steamworks.Data.PublishedFileId, Task> modCopiesInProgress = new Dictionary<Steamworks.Data.PublishedFileId, Task>();
|
||||
|
||||
private static void InitializeProjectSpecific()
|
||||
{
|
||||
if (isInitialized) { return; }
|
||||
@@ -35,6 +38,11 @@ namespace Barotrauma.Steam
|
||||
popularTags.Insert(i, commonness.Key);
|
||||
i++;
|
||||
}
|
||||
|
||||
LogSteamworksNetworkingDelegate = LogSteamworksNetworking;
|
||||
|
||||
IntPtr logSteamworksNetworkingPtr = Marshal.GetFunctionPointerForDelegate(LogSteamworksNetworkingDelegate);
|
||||
Steamworks.SteamNetworkingUtils.SetDebugOutputFunction(Steamworks.Data.DebugOutputType.Everything, logSteamworksNetworkingPtr);
|
||||
}
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
@@ -61,22 +69,17 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
public static bool NetworkingDebugLog = false;
|
||||
|
||||
private static Steamworks.Data.FSteamNetworkingSocketsDebugOutput LogSteamworksNetworkingDelegate;
|
||||
|
||||
private static void LogSteamworksNetworking(Steamworks.Data.DebugOutputType nType, string pszMsg)
|
||||
{
|
||||
if (NetworkingDebugLog) { DebugConsole.NewMessage($"({nType}) {pszMsg}", Color.Orange); }
|
||||
}
|
||||
|
||||
private static void UpdateProjectSpecific(float deltaTime)
|
||||
{
|
||||
for (int i=0;i<(ugcResultPageTasks?.Count ?? 0);i++)
|
||||
{
|
||||
var task = ugcResultPageTasks[i];
|
||||
if (task.IsCompleted)
|
||||
{
|
||||
if (!task.IsCompletedSuccessfully)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to retrieve Steam Workshop page info: TaskStatus = "+task.Status.ToString());
|
||||
}
|
||||
ugcResultPageTasks.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ugcSubscriptionTasks != null)
|
||||
{
|
||||
var ugcSubscriptionKeys = ugcSubscriptionTasks.Keys.ToList();
|
||||
@@ -525,7 +528,37 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Task> ugcResultPageTasks;
|
||||
private static async Task<List<Steamworks.Ugc.Item>> GetWorkshopItemsAsync(Steamworks.Ugc.Query query, int clampResults = 0, Predicate<Steamworks.Ugc.Item> itemPredicate=null)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
List<Steamworks.Ugc.Item> retVal = new List<Steamworks.Ugc.Item>();
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
if (itemPredicate != null)
|
||||
{
|
||||
retVal.AddRange(resultPage.Value.Entries.Where(it => itemPredicate(it)));
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal.AddRange(resultPage.Value.Entries);
|
||||
}
|
||||
|
||||
if (clampResults > 0 && retVal.Count >= clampResults)
|
||||
{
|
||||
retVal = retVal.Take(clampResults).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
pageIndex++;
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static void GetSubscribedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
|
||||
{
|
||||
@@ -535,30 +568,9 @@ namespace Barotrauma.Steam
|
||||
.RankedByTotalUniqueSubscriptions()
|
||||
.WhereUserSubscribed()
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
if (requireTags != null) { query = query.WithTags(requireTags); }
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
|
||||
}
|
||||
|
||||
public static void GetPopularWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, int amount, List<string> requireTags = null)
|
||||
@@ -570,65 +582,40 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) => {
|
||||
var entries = task.Result;
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
//count the number of each unique tag
|
||||
foreach (var item in entries)
|
||||
{
|
||||
var entries = resultPage.Value.Entries.ToList();
|
||||
//count the number of each unique tag
|
||||
foreach (var item in entries)
|
||||
foreach (string tag in item.Tags)
|
||||
{
|
||||
foreach (string tag in item.Tags)
|
||||
if (string.IsNullOrEmpty(tag)) { continue; }
|
||||
string caseInvariantTag = tag.ToLowerInvariant();
|
||||
if (!tagCommonness.ContainsKey(caseInvariantTag))
|
||||
{
|
||||
if (string.IsNullOrEmpty(tag)) { continue; }
|
||||
string caseInvariantTag = tag.ToLowerInvariant();
|
||||
if (!tagCommonness.ContainsKey(caseInvariantTag))
|
||||
{
|
||||
tagCommonness[caseInvariantTag] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tagCommonness[caseInvariantTag]++;
|
||||
}
|
||||
tagCommonness[caseInvariantTag] = 1;
|
||||
}
|
||||
}
|
||||
//populate the popularTags list with tags sorted by commonness
|
||||
popularTags.Clear();
|
||||
foreach (KeyValuePair<string, int> tagCommonnessKVP in tagCommonness)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < popularTags.Count &&
|
||||
tagCommonness[popularTags[i]] > tagCommonnessKVP.Value)
|
||||
else
|
||||
{
|
||||
i++;
|
||||
tagCommonness[caseInvariantTag]++;
|
||||
}
|
||||
popularTags.Insert(i, tagCommonnessKVP.Key);
|
||||
}
|
||||
|
||||
var nonSubscribedItems = entries.Where(it => !it.IsSubscribed);
|
||||
if (nonSubscribedItems.Count() > (amount-processedResults))
|
||||
{
|
||||
nonSubscribedItems = nonSubscribedItems.Take(amount - processedResults);
|
||||
}
|
||||
|
||||
onItemsFound?.Invoke(nonSubscribedItems.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount && processedResults < amount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
//populate the popularTags list with tags sorted by commonness
|
||||
popularTags.Clear();
|
||||
foreach (KeyValuePair<string, int> tagCommonnessKVP in tagCommonness)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < popularTags.Count &&
|
||||
tagCommonness[popularTags[i]] > tagCommonnessKVP.Value)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
popularTags.Insert(i, tagCommonnessKVP.Key);
|
||||
}
|
||||
onItemsFound?.Invoke(task.Result);
|
||||
});
|
||||
}
|
||||
|
||||
public static void GetPublishedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
|
||||
@@ -641,28 +628,7 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, Task> ugcSubscriptionTasks;
|
||||
@@ -926,7 +892,7 @@ namespace Barotrauma.Steam
|
||||
/// <summary>
|
||||
/// Enables a workshop item by moving it to the game folder.
|
||||
/// </summary>
|
||||
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg)
|
||||
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
|
||||
{
|
||||
if (!(item?.IsInstalled ?? false))
|
||||
{
|
||||
@@ -952,10 +918,18 @@ namespace Barotrauma.Steam
|
||||
|
||||
if (ContentPackage.List.Any(cp => cp.Path.CleanUpPath() == newContentPackagePath.CleanUpPath()))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorSamePathInstalled",
|
||||
new string[] { "[itemname]", "[itempath]" },
|
||||
new string[] { item?.Title, Path.GetDirectoryName(newContentPackagePath) });
|
||||
return false;
|
||||
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorSamePathInstalled",
|
||||
new string[] { "[itemname]", "[itempath]" },
|
||||
new string[] { item?.Title, Path.GetDirectoryName(newContentPackagePath) });
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!contentPackage.IsCompatible())
|
||||
@@ -972,57 +946,116 @@ namespace Barotrauma.Steam
|
||||
return false;
|
||||
}
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
Task<string> newTask = null;
|
||||
|
||||
CopyWorkShopItem(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite, out errorMsg);
|
||||
|
||||
var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
|
||||
lock (modCopiesInProgress)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url,
|
||||
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
|
||||
};
|
||||
|
||||
foreach (ContentFile contentFile in newPackage.Files)
|
||||
{
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, true);
|
||||
if (modCopiesInProgress.ContainsKey(item.Value.Id))
|
||||
{
|
||||
if (!modCopiesInProgress[item.Value.Id].IsCompleted &&
|
||||
!modCopiesInProgress[item.Value.Id].IsFaulted &&
|
||||
!modCopiesInProgress[item.Value.Id].IsCanceled)
|
||||
{
|
||||
errorMsg = ""; return true;
|
||||
}
|
||||
modCopiesInProgress.Remove(item.Value.Id);
|
||||
}
|
||||
newTask = CopyWorkShopItemAsync(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite);
|
||||
modCopiesInProgress.Add(item.Value.Id, newTask);
|
||||
}
|
||||
|
||||
TaskPool.Add(newTask,
|
||||
contentPackage,
|
||||
(task, cp) =>
|
||||
{
|
||||
if (task.IsFaulted || task.IsCanceled)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\"", task.Exception);
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(task.Result))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\": {task.Result}");
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(newPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(newPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url,
|
||||
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
|
||||
};
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
foreach (ContentFile contentFile in newPackage.Files)
|
||||
{
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, cp, true);
|
||||
}
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
Submarine.RefreshSavedSubs();
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
|
||||
if (selectContentPackage)
|
||||
{
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(newPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(newPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
SubmarineInfo.RefreshSavedSubs();
|
||||
}
|
||||
}
|
||||
else if (!suppressInstallNotif)
|
||||
{
|
||||
GameMain.MainMenuScreen?.SetEnableModsNotification(true);
|
||||
}
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Green);
|
||||
|
||||
});
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CopyWorkShopItem(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite, out string errorMsg)
|
||||
/// <summary>
|
||||
/// Asynchronously copies a Workshop item into the Mods folder.
|
||||
/// </summary>
|
||||
/// <returns>Returns an empty string on success, otherwise returns an error message.</returns>
|
||||
private async static Task<string> CopyWorkShopItemAsync(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite)
|
||||
{
|
||||
errorMsg = "";
|
||||
await Task.Yield();
|
||||
|
||||
string targetPath = Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage));
|
||||
string copyingPath = Path.Combine(targetPath, CopyIndicatorFileName);
|
||||
|
||||
string errorMsg = "";
|
||||
if (contentPackage.GameVersion > new Version(0, 9, 1, 0))
|
||||
{
|
||||
SaveUtil.CopyFolder(item?.Directory, Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage)), copySubDirs: true, overwriteExisting: true);
|
||||
return true;
|
||||
Directory.CreateDirectory(targetPath);
|
||||
File.WriteAllText(copyingPath, "TEMPORARY FILE");
|
||||
|
||||
SaveUtil.CopyFolder(item?.Directory, targetPath, copySubDirs: true, overwriteExisting: true);
|
||||
|
||||
File.Delete(copyingPath);
|
||||
return "";
|
||||
}
|
||||
|
||||
var allPackageFiles = Directory.GetFiles(item?.Directory, "*", SearchOption.AllDirectories);
|
||||
@@ -1042,7 +1075,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, newContentPackagePath });
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
@@ -1053,84 +1086,79 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, contentFile.Path });
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
return errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
Directory.CreateDirectory(targetPath);
|
||||
File.WriteAllText(copyingPath, "TEMPORARY FILE");
|
||||
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
{
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
contentFile.Path = contentFile.Path.CleanUpPath();
|
||||
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
|
||||
if (!File.Exists(sourceFile))
|
||||
{
|
||||
contentFile.Path = contentFile.Path.CleanUpPath();
|
||||
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
|
||||
if (!File.Exists(sourceFile))
|
||||
string[] splitPath = contentFile.Path.Split('/');
|
||||
if (splitPath.Length >= 2 && splitPath[0] == "Mods")
|
||||
{
|
||||
string[] splitPath = contentFile.Path.Split('/');
|
||||
if (splitPath.Length >= 2 && splitPath[0] == "Mods")
|
||||
{
|
||||
sourceFile = Path.Combine(item?.Directory, string.Join("/", splitPath.Skip(2)));
|
||||
}
|
||||
sourceFile = Path.Combine(item?.Directory, string.Join("/", splitPath.Skip(2)));
|
||||
}
|
||||
}
|
||||
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, false);
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage,
|
||||
contentFile.Type != ContentType.Submarine);
|
||||
|
||||
|
||||
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
|
||||
if (!ContentPackage.IsModFilePathAllowed(contentFile))
|
||||
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
|
||||
if (!ContentPackage.IsModFilePathAllowed(contentFile))
|
||||
{
|
||||
//the content package is trying to copy a file to a prohibited path, which is not allowed
|
||||
if (File.Exists(sourceFile))
|
||||
{
|
||||
//the content package is trying to copy a file to a prohibited path, which is not allowed
|
||||
if (File.Exists(sourceFile))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
|
||||
return false;
|
||||
}
|
||||
//not trying to copy anything, so this is a reference to an external file
|
||||
//if the external file doesn't exist, we cannot enable the package
|
||||
else if (!File.Exists(contentFile.Path))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return false;
|
||||
}
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
|
||||
return errorMsg;
|
||||
}
|
||||
//not trying to copy anything, so this is a reference to an external file
|
||||
//if the external file doesn't exist, we cannot enable the package
|
||||
else if (!File.Exists(contentFile.Path))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return errorMsg;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (!File.Exists(sourceFile))
|
||||
{
|
||||
if (File.Exists(contentFile.Path))
|
||||
{
|
||||
//the file is already present in the game folder, all good
|
||||
continue;
|
||||
}
|
||||
else if (!File.Exists(sourceFile))
|
||||
else
|
||||
{
|
||||
if (File.Exists(contentFile.Path))
|
||||
{
|
||||
//the file is already present in the game folder, all good
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//file not present in either the mod or the game folder -> cannot enable the package
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return false;
|
||||
}
|
||||
//file not present in either the mod or the game folder -> cannot enable the package
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
//make sure the destination directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: true);
|
||||
}
|
||||
|
||||
foreach (string nonContentFile in nonContentFiles)
|
||||
{
|
||||
string sourceFile = Path.Combine(item?.Directory, nonContentFile);
|
||||
if (!File.Exists(sourceFile)) { continue; }
|
||||
string destinationPath = CorrectContentFilePath(nonContentFile, contentPackage, false);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
|
||||
}
|
||||
//make sure the destination directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
foreach (string nonContentFile in nonContentFiles)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " {" + e.Message + "}";
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
string sourceFile = Path.Combine(item?.Directory, nonContentFile);
|
||||
if (!File.Exists(sourceFile)) { continue; }
|
||||
string destinationPath = CorrectContentFilePath(nonContentFile, contentPackage, false);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
|
||||
}
|
||||
|
||||
return true;
|
||||
File.Delete(copyingPath);
|
||||
return "";
|
||||
}
|
||||
|
||||
private static bool CheckFileEquality(string filePath1, string filePath2)
|
||||
@@ -1149,6 +1177,47 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveMods(Func<ContentPackage, bool> predicate, bool delete = true)
|
||||
{
|
||||
var toRemove = ContentPackage.List.Where(predicate).ToList();
|
||||
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
|
||||
foreach (var cp in packagesToDeselect)
|
||||
{
|
||||
if (cp.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.DeselectContentPackage(cp);
|
||||
}
|
||||
}
|
||||
|
||||
if (delete)
|
||||
{
|
||||
foreach (var cp in toRemove)
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = Path.GetDirectoryName(cp.Path);
|
||||
if (Directory.Exists(path)) { Directory.Delete(path, true); }
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
|
||||
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
|
||||
|
||||
ContentPackage.SortContentPackages();
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables a workshop item by removing the files from the game folder.
|
||||
/// </summary>
|
||||
@@ -1173,44 +1242,11 @@ namespace Barotrauma.Steam
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
try
|
||||
{
|
||||
|
||||
var toRemove = ContentPackage.List.Where(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl).ToList();
|
||||
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
|
||||
foreach (var cp in packagesToDeselect)
|
||||
{
|
||||
if (cp.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.DeselectContentPackage(cp);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var cp in toRemove)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(Path.GetDirectoryName(cp.Path), true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
|
||||
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
|
||||
|
||||
ContentPackage.SortContentPackages();
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message;
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message + "\n" + e.StackTrace;
|
||||
if (!noLog)
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
|
||||
@@ -1219,6 +1255,8 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, false, null);
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
@@ -1314,7 +1352,7 @@ namespace Barotrauma.Steam
|
||||
return upToDate;
|
||||
}
|
||||
|
||||
public static async Task<bool> AutoUpdateWorkshopItems()
|
||||
public static async Task<bool> AutoUpdateWorkshopItemsAsync()
|
||||
{
|
||||
if (!isInitialized) { return false; }
|
||||
|
||||
@@ -1322,60 +1360,104 @@ namespace Barotrauma.Steam
|
||||
.WhereUserSubscribed()
|
||||
.WithLongDescription();
|
||||
|
||||
DateTime startTime = DateTime.Now;
|
||||
DateTime endTime = startTime + new TimeSpan(0, 0, 30);
|
||||
List<Steamworks.Ugc.Item> items = await GetWorkshopItemsAsync(query);
|
||||
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
//remove mods that the player is no longer subscribed to
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && !items.Any(it => it.Id == GetWorkshopItemIDFromUrl(cp.SteamWorkshopUrl)));
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
|
||||
List<string> updateNotifications = new List<string>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (DateTime.Now > endTime)
|
||||
try
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var item in resultPage.Value.Entries)
|
||||
{
|
||||
try
|
||||
if (!item.IsInstalled) { continue; }
|
||||
|
||||
bool installedSuccessfully = false;
|
||||
string errorMsg;
|
||||
if (!CheckWorkshopItemEnabled(item))
|
||||
{
|
||||
if (!item.IsInstalled || !CheckWorkshopItemEnabled(item) || CheckWorkshopItemUpToDate(item)) { continue; }
|
||||
if (!UpdateWorkshopItem(item, out string errorMsg))
|
||||
installedSuccessfully = EnableWorkShopItem(item, true, out errorMsg);
|
||||
}
|
||||
else if (!CheckWorkshopItemUpToDate(item))
|
||||
{
|
||||
installedSuccessfully = UpdateWorkshopItem(item, out errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!installedSuccessfully)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
string errorId = errorMsg;
|
||||
if (!GUIMessageBox.MessageBoxes.Any(m => m.UserData as string == errorId))
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }))
|
||||
{
|
||||
UserData = errorId
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
updateNotifications.Add(TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
string errorId = e.Message;
|
||||
if (!GUIMessageBox.MessageBoxes.Any(m => m.UserData as string == errorId))
|
||||
{
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }));
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }))
|
||||
{
|
||||
UserData = errorId
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: potential race condition
|
||||
new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }));
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (updateNotifications.Count > 0)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
while (updateNotifications.Count > 0)
|
||||
{
|
||||
int notificationsPerMsgBox = 20;
|
||||
new GUIMessageBox("", string.Join('\n', updateNotifications.Take(notificationsPerMsgBox)),
|
||||
relativeSize: new Microsoft.Xna.Framework.Vector2(0.5f, 0.0f),
|
||||
minSize: new Microsoft.Xna.Framework.Point(600, 0));
|
||||
updateNotifications.RemoveRange(0, Math.Min(notificationsPerMsgBox, updateNotifications.Count));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<Task> tasks;
|
||||
lock (modCopiesInProgress)
|
||||
{
|
||||
tasks = modCopiesInProgress.Values.ToList();
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1383,7 +1465,10 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = "";
|
||||
if (!(item?.IsInstalled ?? false)) { return false; }
|
||||
if (!DisableWorkShopItem(item, false, out errorMsg)) { return false; }
|
||||
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
|
||||
{
|
||||
if (!DisableWorkShopItem(item, false, out errorMsg)) { return false; }
|
||||
}
|
||||
if (!EnableWorkShopItem(item, allowFileOverwrite: false, errorMsg: out errorMsg)) { return false; }
|
||||
|
||||
return true;
|
||||
@@ -1391,8 +1476,9 @@ namespace Barotrauma.Steam
|
||||
|
||||
private static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage)
|
||||
{
|
||||
string packageName = contentPackage.Name;
|
||||
string packageName = contentPackage.Name.Trim();
|
||||
packageName = ToolBox.RemoveInvalidFileNameChars(packageName);
|
||||
while (packageName.Last() == '.') { packageName = packageName.Substring(0, packageName.Length-1); }
|
||||
//packageName = packageName + "_" + GetWorkshopItemIDFromUrl(contentPackage.SteamWorkshopUrl);
|
||||
|
||||
return Path.Combine("Mods", packageName, MetadataFileName);
|
||||
@@ -1421,7 +1507,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
private static void CorrectContentFileCopy(ContentPackage package, string src, string dest, bool overwrite)
|
||||
{
|
||||
if (Path.GetExtension(src).ToLowerInvariant() == ".xml")
|
||||
if (Path.GetExtension(src).Equals(".xml", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(src);
|
||||
if (doc != null)
|
||||
@@ -1471,7 +1557,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
if (checkIfFileExists)
|
||||
{
|
||||
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.ToLowerInvariant() == splitPath[1].ToLowerInvariant());
|
||||
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.Equals(splitPath[1], StringComparison.OrdinalIgnoreCase));
|
||||
if (otherContentPackage != null)
|
||||
{
|
||||
string otherPackageName = Path.GetDirectoryName(otherContentPackage.Path);
|
||||
@@ -1483,7 +1569,8 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
}
|
||||
newPath = Path.Combine(packageName, string.Join("/", splitPath.Skip(2)));
|
||||
splitPath = splitPath.Skip(Math.Clamp(splitPath.Length-1, 0, 2)).ToArray();
|
||||
newPath = Path.Combine(packageName, string.Join("/", splitPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -149,9 +149,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
|
||||
short[] prevUncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
|
||||
bool prevCaptured = true;
|
||||
int captureTimer;
|
||||
|
||||
void UpdateCapture()
|
||||
{
|
||||
short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
|
||||
Array.Copy(uncompressedBuffer, 0, prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
|
||||
Array.Clear(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
|
||||
while (capturing)
|
||||
{
|
||||
int alcError;
|
||||
@@ -202,6 +208,21 @@ namespace Barotrauma.Networking
|
||||
bool allowEnqueue = false;
|
||||
if (GameMain.WindowActive)
|
||||
{
|
||||
ForceLocal = captureTimer > 0 ? ForceLocal : false;
|
||||
bool pttDown = false;
|
||||
if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) &&
|
||||
GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
pttDown = true;
|
||||
if (PlayerInput.KeyDown(InputType.LocalVoice))
|
||||
{
|
||||
ForceLocal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ForceLocal = false;
|
||||
}
|
||||
}
|
||||
if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity)
|
||||
{
|
||||
if (dB > GameMain.Config.NoiseGateThreshold)
|
||||
@@ -211,25 +232,38 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk)
|
||||
{
|
||||
if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null)
|
||||
if (pttDown)
|
||||
{
|
||||
allowEnqueue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowEnqueue)
|
||||
if (allowEnqueue || captureTimer > 0)
|
||||
{
|
||||
LastEnqueueAudio = DateTime.Now;
|
||||
//encode audio and enqueue it
|
||||
lock (buffers)
|
||||
{
|
||||
if (!prevCaptured) //enqueue the previous buffer if not sent to avoid cutoff
|
||||
{
|
||||
int compressedCountPrev = VoipConfig.Encoder.Encode(prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE);
|
||||
EnqueueBuffer(compressedCountPrev);
|
||||
}
|
||||
int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE);
|
||||
EnqueueBuffer(compressedCount);
|
||||
}
|
||||
captureTimer -= (VoipConfig.BUFFER_SIZE * 1000) / VoipConfig.FREQUENCY;
|
||||
if (allowEnqueue)
|
||||
{
|
||||
captureTimer = GameMain.Config.VoiceChatCutoffPrevention;
|
||||
}
|
||||
prevCaptured = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
captureTimer = 0;
|
||||
prevCaptured = false;
|
||||
//enqueue silence
|
||||
lock (buffers)
|
||||
{
|
||||
|
||||
@@ -85,20 +85,20 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
if (queue.Read(msg))
|
||||
Client client = gameClient.ConnectedClients.Find(c => c.VoipQueue == queue);
|
||||
if (queue.Read(msg, discardData: client.Muted || client.MutedLocally))
|
||||
{
|
||||
Client client = gameClient.ConnectedClients.Find(c => c.VoipQueue == queue);
|
||||
if (client.Muted || client.MutedLocally) { return; }
|
||||
|
||||
if (client.VoipSound == null)
|
||||
{
|
||||
DebugConsole.Log("Recreating voipsound " + queueId);
|
||||
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
|
||||
client.VoipSound = new VoipSound(client.Name, GameMain.SoundManager, client.VoipQueue);
|
||||
}
|
||||
|
||||
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
|
||||
{
|
||||
var messageType = ChatMessage.CanUseRadio(client.Character, out WifiComponent radio) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
WifiComponent radio = null;
|
||||
var messageType = !client.VoipQueue.ForceLocal && ChatMessage.CanUseRadio(client.Character, out radio) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||
|
||||
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio;
|
||||
|
||||
@@ -61,10 +61,10 @@ namespace Barotrauma
|
||||
|
||||
foreach (GUIComponent comp in listBox.Content.Children)
|
||||
{
|
||||
if (comp.FindChild("votes") is GUITextBlock voteText) comp.RemoveChild(voteText);
|
||||
if (comp.FindChild("votes") is GUITextBlock voteText) { comp.RemoveChild(voteText); }
|
||||
}
|
||||
|
||||
if (clients == null) return;
|
||||
if (clients == null) { return; }
|
||||
|
||||
List<Pair<object, int>> voteList = GetVoteList(voteType, clients);
|
||||
foreach (Pair<object, int> votable in voteList)
|
||||
@@ -73,7 +73,7 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case VoteType.StartRound:
|
||||
if (clients == null) return;
|
||||
if (clients == null) { return; }
|
||||
foreach (Client client in clients)
|
||||
{
|
||||
var clientReady = GameMain.NetLobbyScreen.PlayerList.Content.FindChild(client)?.FindChild("clientready");
|
||||
@@ -113,18 +113,18 @@ namespace Barotrauma
|
||||
switch (voteType)
|
||||
{
|
||||
case VoteType.Sub:
|
||||
Submarine sub = data as Submarine;
|
||||
if (sub == null) return;
|
||||
SubmarineInfo sub = data as SubmarineInfo;
|
||||
if (sub == null) { return; }
|
||||
|
||||
msg.Write(sub.Name);
|
||||
break;
|
||||
case VoteType.Mode:
|
||||
GameModePreset gameMode = data as GameModePreset;
|
||||
if (gameMode == null) return;
|
||||
if (gameMode == null) { return; }
|
||||
msg.Write(gameMode.Identifier);
|
||||
break;
|
||||
case VoteType.EndRound:
|
||||
if (!(data is bool)) return;
|
||||
if (!(data is bool)) { return; }
|
||||
msg.Write((bool)data);
|
||||
break;
|
||||
case VoteType.Kick:
|
||||
@@ -153,12 +153,12 @@ namespace Barotrauma
|
||||
{
|
||||
int votes = inc.ReadByte();
|
||||
string subName = inc.ReadString();
|
||||
List<Submarine> serversubs = new List<Submarine>();
|
||||
List<SubmarineInfo> serversubs = new List<SubmarineInfo>();
|
||||
foreach (GUIComponent item in GameMain.NetLobbyScreen?.SubList?.Content?.Children)
|
||||
{
|
||||
if (item.UserData != null && item.UserData is Submarine) serversubs.Add(item.UserData as Submarine);
|
||||
if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); }
|
||||
}
|
||||
Submarine sub = serversubs.FirstOrDefault(sm => sm.Name == subName);
|
||||
SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName);
|
||||
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,18 @@ namespace Barotrauma.Particles
|
||||
|
||||
public string OriginalName { get { return Name; } }
|
||||
|
||||
public string Identifier { get { return Name.ToLowerInvariant(); } }
|
||||
private string _identifier;
|
||||
public string Identifier
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_identifier == null)
|
||||
{
|
||||
_identifier = Name.ToLowerInvariant();
|
||||
}
|
||||
return _identifier;
|
||||
}
|
||||
}
|
||||
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
@@ -46,7 +57,7 @@ namespace Barotrauma.Particles
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "sprite")
|
||||
if (subElement.Name.ToString().Equals("sprite", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Sprites.Add(new Sprite(subElement));
|
||||
}
|
||||
|
||||
@@ -108,7 +108,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
public readonly bool CopyEntityAngle;
|
||||
|
||||
public readonly bool DrawOnTop;
|
||||
public bool DrawOnTop => forceDrawOnTop || ParticlePrefab.DrawOnTop;
|
||||
private readonly bool forceDrawOnTop;
|
||||
|
||||
public ParticleEmitterPrefab(XElement element)
|
||||
{
|
||||
@@ -150,6 +151,12 @@ namespace Barotrauma.Particles
|
||||
{
|
||||
DistanceMin = DistanceMax = element.GetAttributeFloat("distance", 0.0f);
|
||||
}
|
||||
if (DistanceMax < DistanceMin)
|
||||
{
|
||||
var temp = DistanceMin;
|
||||
DistanceMin = DistanceMax;
|
||||
DistanceMax = temp;
|
||||
}
|
||||
|
||||
if (element.Attribute("velocity") == null)
|
||||
{
|
||||
@@ -160,13 +167,19 @@ namespace Barotrauma.Particles
|
||||
{
|
||||
VelocityMin = VelocityMax = element.GetAttributeFloat("velocity", 0.0f);
|
||||
}
|
||||
if (VelocityMax < VelocityMin)
|
||||
{
|
||||
var temp = VelocityMin;
|
||||
VelocityMin = VelocityMax;
|
||||
VelocityMax = temp;
|
||||
}
|
||||
|
||||
EmitInterval = element.GetAttributeFloat("emitinterval", 0.0f);
|
||||
ParticlesPerSecond = element.GetAttributeInt("particlespersecond", 0);
|
||||
ParticleAmount = element.GetAttributeInt("particleamount", 0);
|
||||
HighQualityCollisionDetection = element.GetAttributeBool("highqualitycollisiondetection", false);
|
||||
CopyEntityAngle = element.GetAttributeBool("copyentityangle", false);
|
||||
DrawOnTop = element.GetAttributeBool("drawontop", false);
|
||||
forceDrawOnTop = element.GetAttributeBool("drawontop", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,14 +228,7 @@ namespace Barotrauma.Particles
|
||||
if (inSub.HasValue)
|
||||
{
|
||||
bool isOutside = particle.CurrentHull == null;
|
||||
if (particle.DrawOnTop)
|
||||
{
|
||||
if (isOutside != inSub.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (isOutside == inSub.Value)
|
||||
if (!particle.DrawOnTop && isOutside == inSub.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -199,6 +199,9 @@ namespace Barotrauma.Particles
|
||||
[Editable, Serialize(DrawTargetType.Air, false, description: "Should the particle be rendered in air, water or both.")]
|
||||
public DrawTargetType DrawTarget { get; private set; }
|
||||
|
||||
[Editable, Serialize(false, false, description: "Should the particle be always rendered on top of entities?")]
|
||||
public bool DrawOnTop { get; private set; }
|
||||
|
||||
[Editable, Serialize(ParticleBlendState.AlphaBlend, false, description: "The type of blending to use when rendering the particle.")]
|
||||
public ParticleBlendState BlendState { get; private set; }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user