Merge branch 'dev'
# Conflicts: # Barotrauma/BarotraumaClient/LinuxClient.csproj # Barotrauma/BarotraumaClient/MacClient.csproj # Barotrauma/BarotraumaClient/WindowsClient.csproj # Barotrauma/BarotraumaServer/LinuxServer.csproj # Barotrauma/BarotraumaServer/MacServer.csproj # Barotrauma/BarotraumaServer/WindowsServer.csproj # Barotrauma/BarotraumaShared/changelog.txt
This commit is contained in:
@@ -6,7 +6,7 @@ using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class Camera
|
||||
public class Camera : IDisposable
|
||||
{
|
||||
public static bool FollowSub = true;
|
||||
|
||||
@@ -147,15 +147,19 @@ namespace Barotrauma
|
||||
position = Vector2.Zero;
|
||||
|
||||
CreateMatrices();
|
||||
// TODO: Needs to unregister if ever destroy cameras.
|
||||
// TODO: this has the potential to cause a resource leak
|
||||
// by sneakily creating a reference to cameras that we might
|
||||
// fail to release.
|
||||
GameMain.Instance.ResolutionChanged += CreateMatrices;
|
||||
|
||||
UpdateTransform(false);
|
||||
}
|
||||
|
||||
~Camera()
|
||||
private bool disposed = false;
|
||||
public void Dispose()
|
||||
{
|
||||
GameMain.Instance.ResolutionChanged -= CreateMatrices;
|
||||
if (!disposed) { GameMain.Instance.ResolutionChanged -= CreateMatrices; }
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public Vector2 TargetPos { get; set; }
|
||||
|
||||
@@ -400,7 +400,7 @@ namespace Barotrauma
|
||||
|
||||
partial void UpdateControlled(float deltaTime, Camera cam)
|
||||
{
|
||||
if (controlled != this) return;
|
||||
if (controlled != this) { return; }
|
||||
|
||||
ControlLocalPlayer(deltaTime, cam);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Items.Components;
|
||||
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;
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Barotrauma
|
||||
disguisedSkinColor = idCard.StoredOwnerAppearance.SkinColor;
|
||||
}
|
||||
|
||||
partial void LoadAttachmentSprites(bool omitJob)
|
||||
partial void LoadAttachmentSprites()
|
||||
{
|
||||
if (attachmentSprites == null)
|
||||
{
|
||||
@@ -280,14 +280,6 @@ namespace Barotrauma
|
||||
Head.BeardElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Beard)));
|
||||
Head.MoustacheElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Moustache)));
|
||||
Head.HairElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Hair)));
|
||||
if (omitJob)
|
||||
{
|
||||
JobPrefab.NoJobElement?.GetChildElement("PortraitClothing")?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Job?.Prefab.ClothingElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't work if the head's source rect does not start at 0,0.
|
||||
@@ -988,11 +980,6 @@ namespace Barotrauma
|
||||
HeadSelectionList = null;
|
||||
}
|
||||
}
|
||||
|
||||
~AppearanceCustomizationMenu()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +551,7 @@ namespace Barotrauma
|
||||
{
|
||||
bool hasOwner = inc.ReadBoolean();
|
||||
int ownerId = hasOwner ? inc.ReadByte() : -1;
|
||||
float humanPrefabHealthMultiplier = inc.ReadSingle();
|
||||
int balance = inc.ReadInt32();
|
||||
int rewardDistribution = inc.ReadRangedInteger(0, 100);
|
||||
byte teamID = inc.ReadByte();
|
||||
@@ -573,6 +574,7 @@ namespace Barotrauma
|
||||
{
|
||||
character.MerchantIdentifier = inc.ReadIdentifier();
|
||||
}
|
||||
character.HumanPrefabHealthMultiplier = humanPrefabHealthMultiplier;
|
||||
character.Wallet.Balance = balance;
|
||||
character.Wallet.RewardDistribution = rewardDistribution;
|
||||
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||
@@ -649,6 +651,8 @@ namespace Barotrauma
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
GameMain.LightManager.LosAlpha = 1f;
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignCharacterDiscarded = false;
|
||||
|
||||
character.memInput.Clear();
|
||||
character.memState.Clear();
|
||||
character.memLocalState.Clear();
|
||||
|
||||
@@ -6,7 +6,6 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -1345,6 +1344,7 @@ namespace Barotrauma
|
||||
{
|
||||
UserData = item,
|
||||
DisabledColor = Color.White * 0.1f,
|
||||
PlaySoundOnSelect = false,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (!(userdata is ItemPrefab itemPrefab)) { return false; }
|
||||
@@ -1352,6 +1352,7 @@ namespace Barotrauma
|
||||
if (item == null) { return false; }
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == selectedLimbIndex);
|
||||
item.ApplyTreatment(Character.Controlled, Character, targetLimb);
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -2008,8 +2009,27 @@ namespace Barotrauma
|
||||
DisplayedVitality = Vitality;
|
||||
}
|
||||
|
||||
partial void UpdateSkinTint()
|
||||
{
|
||||
if (!Character.IsVisible) { return; }
|
||||
FaceTint = DefaultFaceTint;
|
||||
BodyTint = Color.TransparentBlack;
|
||||
|
||||
if (!(Character?.Params?.Health.ApplyAfflictionColors ?? false)) { return; }
|
||||
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
var affliction = kvp.Key;
|
||||
Color faceTint = affliction.GetFaceTint();
|
||||
if (faceTint.A > FaceTint.A) { FaceTint = faceTint; }
|
||||
Color bodyTint = affliction.GetBodyTint();
|
||||
if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; }
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateLimbAfflictionOverlays()
|
||||
{
|
||||
if (!Character.IsVisible) { return; }
|
||||
foreach (Limb limb in Character.AnimController.Limbs)
|
||||
{
|
||||
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }
|
||||
|
||||
@@ -58,21 +58,19 @@ namespace Barotrauma
|
||||
|
||||
public class OutfitPreview
|
||||
{
|
||||
/// <summary>
|
||||
/// Pair.First = sprite, Pair.Second = draw offset
|
||||
/// </summary>
|
||||
public readonly List<Pair<Sprite, Vector2>> Sprites;
|
||||
public readonly List<(Sprite sprite, Vector2 drawOffset)> Sprites;
|
||||
|
||||
public Vector2 Dimensions;
|
||||
|
||||
public OutfitPreview()
|
||||
{
|
||||
Sprites = new List<Pair<Sprite, Vector2>>();
|
||||
Sprites = new List<(Sprite sprite, Vector2 drawOffset)>();
|
||||
Dimensions = Vector2.One;
|
||||
}
|
||||
|
||||
public void AddSprite(Sprite sprite, Vector2 drawOffset)
|
||||
{
|
||||
Sprites.Add(new Pair<Sprite, Vector2>(sprite, drawOffset));
|
||||
Sprites.Add((sprite, drawOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,14 +224,14 @@ namespace Barotrauma
|
||||
public float DamageOverlayStrength
|
||||
{
|
||||
get { return damageOverlayStrength; }
|
||||
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||
}
|
||||
|
||||
private float burnOverLayStrength;
|
||||
public float BurnOverlayStrength
|
||||
{
|
||||
get { return burnOverLayStrength; }
|
||||
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||
}
|
||||
|
||||
public string HitSoundTag => Params?.Sound?.Tag;
|
||||
@@ -279,7 +279,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < Params.decorativeSpriteParams.Count; i++)
|
||||
{
|
||||
var param = Params.decorativeSpriteParams[i];
|
||||
var decorativeSprite = new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param));
|
||||
var decorativeSprite = new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param, ref _texturePath));
|
||||
DecorativeSprites.Add(decorativeSprite);
|
||||
int groupID = decorativeSprite.RandomGroupID;
|
||||
if (!DecorativeSpriteGroups.ContainsKey(groupID))
|
||||
@@ -295,13 +295,13 @@ namespace Barotrauma
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
Sprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.normalSpriteParams));
|
||||
Sprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.normalSpriteParams, ref _texturePath));
|
||||
break;
|
||||
case "damagedsprite":
|
||||
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
|
||||
case "damagedsprite":
|
||||
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams, ref _damagedTexturePath));
|
||||
break;
|
||||
case "conditionalsprite":
|
||||
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null));
|
||||
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null, ref _texturePath));
|
||||
ConditionalSprites.Add(conditionalSprite);
|
||||
if (conditionalSprite.DeformableSprite != null)
|
||||
{
|
||||
@@ -311,7 +311,7 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case "deformablesprite":
|
||||
_deformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams));
|
||||
_deformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams, ref _texturePath));
|
||||
var deformations = CreateDeformations(subElement);
|
||||
Deformations.AddRange(deformations);
|
||||
NonConditionalDeformations.AddRange(deformations);
|
||||
@@ -435,33 +435,33 @@ namespace Barotrauma
|
||||
{
|
||||
Sprite.Remove();
|
||||
var source = Sprite.SourceElement;
|
||||
Sprite = new Sprite(source, file: GetSpritePath(source, Params.normalSpriteParams));
|
||||
Sprite = new Sprite(source, file: GetSpritePath(source, Params.normalSpriteParams, ref _texturePath));
|
||||
}
|
||||
if (_deformSprite != null)
|
||||
{
|
||||
_deformSprite.Remove();
|
||||
var source = _deformSprite.Sprite.SourceElement;
|
||||
_deformSprite = new DeformableSprite(source, filePath: GetSpritePath(source, Params.deformSpriteParams));
|
||||
_deformSprite = new DeformableSprite(source, filePath: GetSpritePath(source, Params.deformSpriteParams, ref _texturePath));
|
||||
}
|
||||
if (DamagedSprite != null)
|
||||
{
|
||||
DamagedSprite.Remove();
|
||||
var source = DamagedSprite.SourceElement;
|
||||
DamagedSprite = new Sprite(source, file: GetSpritePath(source, Params.damagedSpriteParams));
|
||||
DamagedSprite = new Sprite(source, file: GetSpritePath(source, Params.damagedSpriteParams, ref _damagedTexturePath));
|
||||
}
|
||||
for (int i = 0; i < ConditionalSprites.Count; i++)
|
||||
{
|
||||
var conditionalSprite = ConditionalSprites[i];
|
||||
var source = conditionalSprite.ActiveSprite.SourceElement;
|
||||
conditionalSprite.Remove();
|
||||
ConditionalSprites[i] = new ConditionalSprite(source, character, file: GetSpritePath(source, null));
|
||||
ConditionalSprites[i] = new ConditionalSprite(source, character, file: GetSpritePath(source, null, ref _texturePath));
|
||||
}
|
||||
for (int i = 0; i < DecorativeSprites.Count; i++)
|
||||
{
|
||||
var decorativeSprite = DecorativeSprites[i];
|
||||
decorativeSprite.Remove();
|
||||
var source = decorativeSprite.Sprite.SourceElement;
|
||||
DecorativeSprites[i] = new DecorativeSprite(source, file: GetSpritePath(source, Params.decorativeSpriteParams[i]));
|
||||
DecorativeSprites[i] = new DecorativeSprite(source, file: GetSpritePath(source, Params.decorativeSpriteParams[i], ref _texturePath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,16 +472,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private string _texturePath;
|
||||
private string GetSpritePath(ContentXElement element, SpriteParams spriteParams)
|
||||
private string _damagedTexturePath;
|
||||
private string GetSpritePath(ContentXElement element, SpriteParams spriteParams, ref string path)
|
||||
{
|
||||
if (_texturePath == null)
|
||||
if (path == null)
|
||||
{
|
||||
if (spriteParams != null)
|
||||
{
|
||||
ContentPath texturePath =
|
||||
character.Params.VariantFile?.Root?.GetAttributeContentPath("texture", character.Prefab.ContentPackage)
|
||||
?? ContentPath.FromRaw(character.Prefab.ContentPackage, spriteParams.GetTexturePath());
|
||||
_texturePath = GetSpritePath(texturePath);
|
||||
path = GetSpritePath(texturePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -489,10 +490,10 @@ namespace Barotrauma
|
||||
texturePath = texturePath.IsNullOrWhiteSpace()
|
||||
? ContentPath.FromRaw(character.Prefab.ContentPackage, ragdoll.RagdollParams.Texture)
|
||||
: texturePath;
|
||||
_texturePath = GetSpritePath(texturePath);
|
||||
path = GetSpritePath(texturePath);
|
||||
}
|
||||
}
|
||||
return _texturePath;
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -625,12 +626,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!body.Enabled) { return; }
|
||||
|
||||
if (!IsDead)
|
||||
{
|
||||
DamageOverlayStrength -= deltaTime;
|
||||
BurnOverlayStrength -= deltaTime;
|
||||
}
|
||||
else
|
||||
if (IsDead)
|
||||
{
|
||||
var spriteParams = Params.GetSprite();
|
||||
if (spriteParams != null && spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
|
||||
@@ -688,7 +684,7 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null, bool disableDeformations = false)
|
||||
{
|
||||
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
|
||||
float brightness = Math.Max(1.0f - burnOverLayStrength, 0.2f);
|
||||
var spriteParams = Params.GetSprite();
|
||||
if (spriteParams == null) { return; }
|
||||
|
||||
@@ -831,32 +827,6 @@ namespace Barotrauma
|
||||
{
|
||||
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||
}
|
||||
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
|
||||
{
|
||||
DamagedSprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color * Math.Min(damageOverlayStrength, 1.0f), activeSprite.Origin,
|
||||
-body.DrawRotation,
|
||||
Scale, spriteEffect, activeSprite.Depth - (depthStep * 90));
|
||||
}
|
||||
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, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * 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)), c,
|
||||
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
|
||||
depth: activeSprite.Depth - (depthStep * 100));
|
||||
}
|
||||
float step = depthStep;
|
||||
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
||||
if (Params.MirrorHorizontally)
|
||||
@@ -925,6 +895,36 @@ namespace Barotrauma
|
||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||
depthStep += step;
|
||||
}
|
||||
if (!Hide && onlyDrawable == null)
|
||||
{
|
||||
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, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * 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)), c,
|
||||
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
|
||||
depth: activeSprite.Depth - depthStep);
|
||||
depthStep += step;
|
||||
}
|
||||
if (damageOverlayStrength > 0.0f && DamagedSprite != null)
|
||||
{
|
||||
DamagedSprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color * damageOverlayStrength, activeSprite.Origin,
|
||||
-body.DrawRotation,
|
||||
Scale, spriteEffect, activeSprite.Depth - depthStep * Math.Max(1, WearingItems.Count * 2)); // Multiply by 2 to get rid of z-fighting with some clothing combos
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveFile(File file)
|
||||
{
|
||||
if (HasFile(file))
|
||||
{
|
||||
files.Remove(file);
|
||||
DiscardHashAndInstallTime();
|
||||
}
|
||||
}
|
||||
|
||||
public void DiscardHashAndInstallTime()
|
||||
{
|
||||
ExpectedHash = null;
|
||||
@@ -144,7 +153,7 @@ namespace Barotrauma
|
||||
=> rootElement.Add(new XAttribute(name, value.ToString() ?? ""));
|
||||
|
||||
addRootAttribute("name", Name);
|
||||
addRootAttribute("modversion", ModVersion);
|
||||
if (!ModVersion.IsNullOrEmpty()) { addRootAttribute("modversion", ModVersion); }
|
||||
addRootAttribute("corepackage", IsCore);
|
||||
if (SteamWorkshopId != 0) { addRootAttribute("steamworkshopid", SteamWorkshopId); }
|
||||
addRootAttribute("gameversion", GameMain.Version);
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Barotrauma.Steam;
|
||||
using Barotrauma.IO;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class ModMerger
|
||||
{
|
||||
public static void AskMerge(ContentPackage[] mods)
|
||||
{
|
||||
ErrorIfNonLocal(mods);
|
||||
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("MergeModsHeader"), "", relativeSize: (0.5f, 0.8f),
|
||||
buttons: new LocalizedString[] { TextManager.Get("ConfirmModMerge"), TextManager.Get("Cancel") });
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
|
||||
var desc = new GUITextBlock(new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform), TextManager.Get("MergeModsDesc"));
|
||||
var modsList = new GUIListBox(new RectTransform((1.0f, 0.5f), msgBox.Content.RectTransform))
|
||||
{
|
||||
OnSelected = (component, o) => false,
|
||||
HoverCursor = CursorState.Default
|
||||
};
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
new GUITextBlock(new RectTransform((1.0f, 0.11f), modsList.Content.RectTransform), mod.Name)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
var footer = new GUITextBlock(new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform), TextManager.Get("MergeModsFooter"));
|
||||
var resultName = new GUITextBox(new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform))
|
||||
{
|
||||
Text = (mods.Count(m => m.Files.Length > 1)==1)
|
||||
? mods.First(m => m.Files.Length > 1).Name
|
||||
: ""
|
||||
};
|
||||
|
||||
void flashText()
|
||||
{
|
||||
resultName!.Select();
|
||||
resultName.Flash(GUIStyle.Red);
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (button, o) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(resultName.Text))
|
||||
{
|
||||
flashText();
|
||||
return false;
|
||||
}
|
||||
string targetDir = $"{ContentPackage.LocalModsDir}/{resultName.Text}";
|
||||
|
||||
bool dirMatches(ContentPackage mod)
|
||||
=> mod.Dir.CleanUpPathCrossPlatform(correctFilenameCase: false)
|
||||
.Equals(targetDir, StringComparison.OrdinalIgnoreCase);
|
||||
if (ContentPackageManager.LocalPackages.Any(dirMatches)
|
||||
&& !mods.Any(dirMatches))
|
||||
{
|
||||
flashText();
|
||||
return false;
|
||||
}
|
||||
|
||||
MergeMods(mods, resultName.Text);
|
||||
msgBox.Close();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static void MergeMods(ContentPackage[] mods, string resultName)
|
||||
{
|
||||
ModProject resultProject = new ModProject
|
||||
{
|
||||
Name = resultName
|
||||
};
|
||||
|
||||
string targetDir = $"{ContentPackage.LocalModsDir}/{resultName}";
|
||||
Directory.CreateDirectory(targetDir);
|
||||
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(mod.Dir, "*", System.IO.SearchOption.AllDirectories)
|
||||
.Select(f => f.CleanUpPathCrossPlatform(correctFilenameCase: false)))
|
||||
{
|
||||
if (Path.GetFileName(file).Equals(ContentPackage.FileListFileName, StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
string targetFilePath = file[mod.Dir.Length..];
|
||||
if (targetFilePath.StartsWith("/") || targetFilePath.StartsWith("\\"))
|
||||
{
|
||||
targetFilePath = targetFilePath[1..];
|
||||
}
|
||||
|
||||
targetFilePath = Path.Combine(targetDir, targetFilePath).CleanUpPathCrossPlatform(correctFilenameCase: false);
|
||||
//DebugConsole.NewMessage(targetFilePath);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetFilePath)!);
|
||||
File.Copy(file, targetFilePath, overwrite: true);
|
||||
|
||||
var oldFileInProject = resultProject.Files.FirstOrDefault(f
|
||||
=> f.Path.Equals(targetFilePath, StringComparison.OrdinalIgnoreCase));
|
||||
if (oldFileInProject != null)
|
||||
{
|
||||
resultProject.RemoveFile(oldFileInProject);
|
||||
}
|
||||
|
||||
var fileInMod = mod.Files.Find(f => f.Path == file);
|
||||
if (fileInMod != null)
|
||||
{
|
||||
var newFileInProject = ModProject.File.FromPath(targetFilePath, fileInMod.GetType());
|
||||
resultProject.AddFile(newFileInProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
resultProject.Save(Path.Combine(targetDir, ContentPackage.FileListFileName));
|
||||
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
Directory.Delete(mod.Dir);
|
||||
}
|
||||
(SettingsMenu.Instance!.WorkshopMenu as MutableWorkshopMenu)!.PopulateInstalledModLists(forceRefreshEnabled: true, refreshDisabled: true);
|
||||
}
|
||||
|
||||
private static void ErrorIfNonLocal(ContentPackage[] mods)
|
||||
{
|
||||
var nonLocal = mods.Where(m => !ContentPackageManager.LocalPackages.Contains(m)).ToArray();
|
||||
if (nonLocal.Any())
|
||||
{
|
||||
throw new Exception($"{string.Join(", ", nonLocal.Select(m => m.Name))} are not local mods");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -9,9 +8,7 @@ using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Directory = Barotrauma.IO.Directory;
|
||||
using File = Barotrauma.IO.File;
|
||||
using Path = Barotrauma.IO.Path;
|
||||
using Barotrauma.IO;
|
||||
|
||||
namespace Barotrauma.Transition
|
||||
{
|
||||
@@ -258,13 +255,13 @@ namespace Barotrauma.Transition
|
||||
{
|
||||
string[] getFiles(string path, string pattern)
|
||||
=> Directory.Exists(path)
|
||||
? Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly)
|
||||
? Directory.GetFiles(path, pattern, System.IO.SearchOption.TopDirectoryOnly)
|
||||
: Array.Empty<string>();
|
||||
|
||||
subs = getFiles(oldSubsPath, "*.sub");
|
||||
itemAssemblies = getFiles(oldItemAssembliesPath, "*.xml");
|
||||
|
||||
string[] allOldMods = Directory.GetDirectories(oldModsPath, "*", SearchOption.TopDirectoryOnly);
|
||||
string[] allOldMods = Directory.GetDirectories(oldModsPath, "*", System.IO.SearchOption.TopDirectoryOnly);
|
||||
|
||||
var publishedItems = await SteamManager.Workshop.GetPublishedItems();
|
||||
foreach (var modDir in allOldMods)
|
||||
@@ -359,7 +356,7 @@ namespace Barotrauma.Transition
|
||||
else
|
||||
{
|
||||
//copying a mod: we have a neat method for that!
|
||||
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath);
|
||||
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath, SteamManager.Workshop.ShouldCorrectPaths.Yes);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (isOpen)
|
||||
{
|
||||
frame.AddToGUIUpdateList();
|
||||
frame.AddToGUIUpdateList(order: 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ namespace Barotrauma
|
||||
isOpen = false;
|
||||
GUI.ForceMouseOn(null);
|
||||
textBox.Deselect();
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
|
||||
if (isOpen)
|
||||
@@ -209,7 +210,7 @@ namespace Barotrauma
|
||||
isOpen = !isOpen;
|
||||
if (isOpen)
|
||||
{
|
||||
textBox.Select();
|
||||
textBox.Select(ignoreSelectSound: true);
|
||||
AddToGUIUpdateList();
|
||||
}
|
||||
else
|
||||
@@ -217,6 +218,7 @@ namespace Barotrauma
|
||||
GUI.ForceMouseOn(null);
|
||||
textBox.Deselect();
|
||||
}
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
|
||||
private static bool IsCommandPermitted(string command, GameClient client)
|
||||
@@ -1714,9 +1716,47 @@ namespace Barotrauma
|
||||
//check missing mission texts
|
||||
foreach (var missionPrefab in MissionPrefab.Prefabs)
|
||||
{
|
||||
Identifier missionId = (missionPrefab.ConfigElement.GetAttribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty));
|
||||
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
||||
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
||||
Identifier missionId = missionPrefab.ConfigElement.GetAttribute("textidentifier") == null ?
|
||||
missionPrefab.Identifier :
|
||||
missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty);
|
||||
|
||||
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("name", Identifier.Empty)))
|
||||
{
|
||||
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
|
||||
if (missionPrefab.Type == MissionType.Combat)
|
||||
{
|
||||
addIfMissing($"MissionDescriptionNeutral.{missionId}".ToIdentifier(), language);
|
||||
addIfMissing($"MissionDescription1.{missionId}".ToIdentifier(), language);
|
||||
addIfMissing($"MissionDescription2.{missionId}".ToIdentifier(), language);
|
||||
addIfMissing($"MissionTeam1.{missionId}".ToIdentifier(), language);
|
||||
addIfMissing($"MissionTeam2.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("description", Identifier.Empty)))
|
||||
{
|
||||
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("successmessage", Identifier.Empty)))
|
||||
{
|
||||
addIfMissing($"missionsuccess.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
//only check failure message if there's something defined in the xml (otherwise we just use the generic "missionfailed" text)
|
||||
if (missionPrefab.ConfigElement.GetAttribute("failuremessage") != null &&
|
||||
!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("failuremessage", Identifier.Empty)))
|
||||
{
|
||||
addIfMissing($"missionfailure.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i<missionPrefab.Messages.Length; i++)
|
||||
{
|
||||
if (missionPrefab.Messages[i].IsNullOrWhiteSpace())
|
||||
{
|
||||
addIfMissing($"MissionMessage{i}.{missionId}".ToIdentifier(), language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Type itemComponentType in typeof(ItemComponent).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ItemComponent))))
|
||||
@@ -2503,7 +2543,7 @@ namespace Barotrauma
|
||||
var entity = MapEntity.mapEntityList[i] as ISerializableEntity;
|
||||
if (entity != null)
|
||||
{
|
||||
List<Pair<object, SerializableProperty>> allProperties = new List<Pair<object, SerializableProperty>>();
|
||||
List<(object obj, SerializableProperty property)> allProperties = new List<(object obj, SerializableProperty property)>();
|
||||
|
||||
if (entity is Item item)
|
||||
{
|
||||
@@ -2518,14 +2558,14 @@ namespace Barotrauma
|
||||
|
||||
for (int k = 0; k < properties.Count; k++)
|
||||
{
|
||||
allProperties.Add(new Pair<object, SerializableProperty>(entity, properties[k]));
|
||||
allProperties.Add((entity, properties[k]));
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < allProperties.Count; j++)
|
||||
{
|
||||
var property = allProperties[j].Second;
|
||||
string propertyName = (allProperties[j].First.GetType().Name + "." + property.PropertyInfo.Name).ToLowerInvariant();
|
||||
var property = allProperties[j].property;
|
||||
string propertyName = (allProperties[j].obj.GetType().Name + "." + property.PropertyInfo.Name).ToLowerInvariant();
|
||||
LocalizedString displayName = TextManager.Get($"sp.{propertyName}.name");
|
||||
if (displayName.IsNullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -308,7 +308,7 @@ namespace Barotrauma
|
||||
AlwaysOverrideCursor = true
|
||||
};
|
||||
|
||||
LocalizedString translatedText = TextManager.Get(text);
|
||||
LocalizedString translatedText = TextManager.Get(text).Fallback(text);
|
||||
|
||||
if (speaker?.Info != null && drawChathead)
|
||||
{
|
||||
@@ -335,7 +335,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (string option in options)
|
||||
{
|
||||
var btn = new GUIButton(new RectTransform(new Vector2(0.9f, 0.01f), textContent.RectTransform), TextManager.Get(option), style: "ListBoxElement");
|
||||
var btn = new GUIButton(new RectTransform(new Vector2(0.9f, 0.01f), textContent.RectTransform), TextManager.Get(option).Fallback(option), style: "ListBoxElement");
|
||||
btn.TextBlock.TextAlignment = Alignment.CenterLeft;
|
||||
btn.TextColor = btn.HoverTextColor = GUIStyle.Green;
|
||||
btn.TextBlock.Wrap = true;
|
||||
|
||||
@@ -20,14 +20,12 @@ namespace Barotrauma
|
||||
if (targetId == Entity.NullEntityID) { continue; }
|
||||
Entity target = Entity.FindEntityByID(targetId);
|
||||
if (target == null) { continue; }
|
||||
existingTargets.Add(target);
|
||||
allTargets.Add(target);
|
||||
}
|
||||
ushort spawnedTargetsCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < spawnedTargetsCount; i++)
|
||||
{
|
||||
var enemy = Character.ReadSpawnData(msg);
|
||||
existingTargets.Add(enemy);
|
||||
allTargets.Add(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ namespace Barotrauma
|
||||
public const int ToggleButtonWidthRaw = 30;
|
||||
private int popupMessageOffset;
|
||||
|
||||
private GUIDropDown ChatModeDropDown { get; set; }
|
||||
|
||||
public ChatBox(GUIComponent parent, bool isSinglePlayer)
|
||||
{
|
||||
this.IsSinglePlayer = isSinglePlayer;
|
||||
@@ -107,6 +109,7 @@ namespace Barotrauma
|
||||
|
||||
var buttonLeft = new GUIButton(new RectTransform(new Vector2(0.1f, 0.8f), channelSettingsContent.RectTransform), style: "DeviceButton")
|
||||
{
|
||||
PlaySoundOnSelect = false,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
@@ -150,6 +153,7 @@ namespace Barotrauma
|
||||
|
||||
var buttonRight = new GUIButton(new RectTransform(new Vector2(0.1f, 0.8f), channelSettingsContent.RectTransform), style: "DeviceButton")
|
||||
{
|
||||
PlaySoundOnSelect = false,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
@@ -178,6 +182,7 @@ namespace Barotrauma
|
||||
TextColor = new Color(51, 59, 46),
|
||||
SelectedTextColor = GUIStyle.Green,
|
||||
UserData = i,
|
||||
PlaySoundOnSelect = false,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
@@ -223,7 +228,53 @@ namespace Barotrauma
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
InputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft),
|
||||
var bottomContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var dropdownRt = new RectTransform(new Vector2(0.1f, 1.0f), bottomContainer.RectTransform)
|
||||
{
|
||||
// The chat mode selection dropdown will take a maximum of 45% of the horizontal space
|
||||
MaxSize = new Point((int)(0.45f * bottomContainer.RectTransform.NonScaledSize.X), int.MaxValue)
|
||||
};
|
||||
var chatModes = new ChatMode[] { ChatMode.Local, ChatMode.Radio };
|
||||
ChatModeDropDown = new GUIDropDown(dropdownRt, elementCount: chatModes.Length, dropAbove: true)
|
||||
{
|
||||
OnSelected = (component, userdata) =>
|
||||
{
|
||||
GameMain.ActiveChatMode = (ChatMode)userdata;
|
||||
if (InputBox != null && InputBox.Text.StartsWith(RadioChatString) && GameMain.ActiveChatMode == ChatMode.Local)
|
||||
{
|
||||
string text = InputBox.Text;
|
||||
InputBox.Text = text.Remove(0, RadioChatString.Length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
float longestDropDownOption = 0.0f;
|
||||
foreach (ChatMode mode in chatModes)
|
||||
{
|
||||
var text = TextManager.Get($"chatmode.{mode}");
|
||||
ChatModeDropDown.AddItem(text, userData: mode);
|
||||
if (ChatModeDropDown.ListBox.Content.GetChildByUserData(mode) is GUITextBlock textBlock)
|
||||
{
|
||||
if (textBlock.TextSize.X > longestDropDownOption)
|
||||
{
|
||||
longestDropDownOption = textBlock.TextSize.X;
|
||||
}
|
||||
}
|
||||
}
|
||||
ChatModeDropDown.SelectItem(GameMain.ActiveChatMode);
|
||||
|
||||
float minDropDownWidth = longestDropDownOption + ChatModeDropDown.Padding.X +
|
||||
(ChatModeDropDown.DropDownIcon?.RectTransform.NonScaledSize.X ?? 0) +
|
||||
(ChatModeDropDown.DropDownIcon?.RectTransform.AbsoluteOffset.X ?? 0) * 2;
|
||||
ChatModeDropDown.RectTransform.MinSize = new Point(
|
||||
Math.Max((int)minDropDownWidth, ChatModeDropDown.RectTransform.MinSize.X),
|
||||
ChatModeDropDown.RectTransform.MinSize.Y);
|
||||
|
||||
InputBox = new GUITextBox(new RectTransform(new Vector2(0.9f, 1.0f), bottomContainer.RectTransform),
|
||||
style: "ChatTextBox")
|
||||
{
|
||||
OverflowClip = true,
|
||||
@@ -236,6 +287,11 @@ namespace Barotrauma
|
||||
InputBox.OnDeselected += (gui, Keys) =>
|
||||
{
|
||||
ChatManager.Clear();
|
||||
if (GUIFrame.IsParentOf(GUI.MouseOn))
|
||||
{
|
||||
CloseAfterMessageSent = false;
|
||||
return;
|
||||
}
|
||||
ChatMessage.GetChatMessageCommand(InputBox.Text, out var message);
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
@@ -245,8 +301,6 @@ namespace Barotrauma
|
||||
CloseAfterMessageSent = false;
|
||||
}
|
||||
}
|
||||
|
||||
//gui.Text = "";
|
||||
};
|
||||
|
||||
var chatSendButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.7f), InputBox.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight), style: "GUIButtonToggleRight");
|
||||
@@ -303,6 +357,10 @@ namespace Barotrauma
|
||||
{
|
||||
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Private];
|
||||
}
|
||||
else if (GameMain.ActiveChatMode == ChatMode.Radio)
|
||||
{
|
||||
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Radio];
|
||||
}
|
||||
else
|
||||
{
|
||||
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
|
||||
@@ -357,10 +415,15 @@ namespace Barotrauma
|
||||
CanBeFocused = true,
|
||||
ForceUpperCase = ForceUpperCase.No,
|
||||
UserData = message.SenderClient,
|
||||
PlaySoundOnSelect = false,
|
||||
OnClicked = (_, o) =>
|
||||
{
|
||||
if (!(o is Client client)) { return false; }
|
||||
GameMain.NetLobbyScreen?.SelectPlayer(client);
|
||||
if (GameMain.NetLobbyScreen != null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.SelectPlayer(client);
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
OnSecondaryClicked = (_, o) =>
|
||||
@@ -542,6 +605,25 @@ namespace Barotrauma
|
||||
showNewMessagesButton.Visible = false;
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(InputType.ToggleChatMode) && GUI.KeyboardDispatcher.Subscriber == null && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mode = GameMain.ActiveChatMode switch
|
||||
{
|
||||
ChatMode.Local => ChatMode.Radio,
|
||||
ChatMode.Radio => ChatMode.Local,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
ChatModeDropDown.SelectItem(mode);
|
||||
// TODO: Play a sound?
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error toggling chat mode: not implemented for current mode \"{GameMain.ActiveChatMode}\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (ToggleButton != null)
|
||||
{
|
||||
ToggleButton.Selected = ToggleOpen;
|
||||
@@ -692,5 +774,70 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySelectionInputs() => ApplySelectionInputs(InputBox, true, ChatKeyStates.GetChatKeyStates());
|
||||
|
||||
public struct ChatKeyStates
|
||||
{
|
||||
public bool ActiveChatKeyHit { get; set; }
|
||||
public bool LocalChatKeyHit { get; set; }
|
||||
public bool RadioChatKeyHit { get; set; }
|
||||
public bool AnyHit => ActiveChatKeyHit || LocalChatKeyHit || RadioChatKeyHit;
|
||||
|
||||
private ChatKeyStates(bool active, bool local, bool radio)
|
||||
{
|
||||
ActiveChatKeyHit = active;
|
||||
LocalChatKeyHit = local;
|
||||
RadioChatKeyHit = radio;
|
||||
}
|
||||
|
||||
public static ChatKeyStates GetChatKeyStates()
|
||||
{
|
||||
return new ChatKeyStates(PlayerInput.KeyHit(InputType.ActiveChat),
|
||||
PlayerInput.KeyHit(InputType.Chat),
|
||||
PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100));
|
||||
}
|
||||
|
||||
public (bool active, bool local, bool radio) Deconstruct()
|
||||
{
|
||||
return (ActiveChatKeyHit, LocalChatKeyHit, RadioChatKeyHit);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySelectionInputs(GUITextBox inputBox, bool selectInputBox, ChatKeyStates chatKeyStates)
|
||||
{
|
||||
inputBox ??= InputBox;
|
||||
var (activeChatKeyHit, localChatKeyHit, radioChatKeyHit) = chatKeyStates.Deconstruct();
|
||||
if (localChatKeyHit || (activeChatKeyHit && GameMain.ActiveChatMode == ChatMode.Local))
|
||||
{
|
||||
ChatModeDropDown.SelectItem(ChatMode.Local);
|
||||
inputBox.AddToGUIUpdateList();
|
||||
GUIFrame.Flash(Color.DarkGreen, 0.5f);
|
||||
if (!ToggleOpen)
|
||||
{
|
||||
CloseAfterMessageSent = !ToggleOpen;
|
||||
ToggleOpen = true;
|
||||
}
|
||||
if (selectInputBox)
|
||||
{
|
||||
inputBox.Select(inputBox.Text.Length);
|
||||
}
|
||||
}
|
||||
else if (radioChatKeyHit || (activeChatKeyHit && GameMain.ActiveChatMode == ChatMode.Radio))
|
||||
{
|
||||
ChatModeDropDown.SelectItem(ChatMode.Radio);
|
||||
inputBox.AddToGUIUpdateList();
|
||||
GUIFrame.Flash(Color.YellowGreen, 0.5f);
|
||||
if (!ToggleOpen)
|
||||
{
|
||||
CloseAfterMessageSent = !ToggleOpen;
|
||||
ToggleOpen = true;
|
||||
}
|
||||
if (selectInputBox)
|
||||
{
|
||||
inputBox.Select(inputBox.Text.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,18 @@ namespace Barotrauma
|
||||
return Sprites.ContainsKey(state) ? Sprites[state]?.First()?.Sprite : null;
|
||||
}
|
||||
|
||||
public void GetSize(XElement element)
|
||||
public void RefreshSize()
|
||||
{
|
||||
Width = null;
|
||||
Height = null;
|
||||
GetSize(Element);
|
||||
foreach (var childStyle in ChildStyles.Values)
|
||||
{
|
||||
childStyle.RefreshSize();
|
||||
}
|
||||
}
|
||||
|
||||
private void GetSize(XElement element)
|
||||
{
|
||||
Point size = new Point(0, 0);
|
||||
foreach (var subElement in element.Elements())
|
||||
|
||||
@@ -193,12 +193,13 @@ namespace Barotrauma
|
||||
};
|
||||
validateHiresButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaigncrew.validate"))
|
||||
{
|
||||
ClickSound = GUISoundType.HireRepairClick,
|
||||
ClickSound = GUISoundType.ConfirmTransaction,
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
OnClicked = (b, o) => ValidateHires(PendingHires, true)
|
||||
};
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemoveAllPendingHires()
|
||||
@@ -403,6 +404,7 @@ namespace Barotrauma
|
||||
{
|
||||
var hireButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
@@ -429,6 +431,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementRemoveButton")
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemovePendingHire(o as CharacterInfo)
|
||||
|
||||
@@ -182,7 +182,10 @@ namespace Barotrauma
|
||||
window = new GUIFrame(new RectTransform(Vector2.One * 0.8f, backgroundFrame.RectTransform, Anchor.Center));
|
||||
|
||||
var horizontalLayout = new GUILayoutGroup(new RectTransform(Vector2.One * 0.9f, window.RectTransform, Anchor.Center), true);
|
||||
sidebar = new GUIListBox(new RectTransform(new Vector2(0.29f, 1.0f), horizontalLayout.RectTransform));
|
||||
sidebar = new GUIListBox(new RectTransform(new Vector2(0.29f, 1.0f), horizontalLayout.RectTransform))
|
||||
{
|
||||
PlaySoundOnSelect = true
|
||||
};
|
||||
|
||||
var drives = System.IO.DriveInfo.GetDrives();
|
||||
foreach (var drive in drives)
|
||||
@@ -241,6 +244,7 @@ namespace Barotrauma
|
||||
|
||||
fileList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.85f), fileListLayout.RectTransform))
|
||||
{
|
||||
PlaySoundOnSelect = true,
|
||||
OnSelected = (child, userdata) =>
|
||||
{
|
||||
if (userdata is null) { return false; }
|
||||
|
||||
@@ -24,15 +24,17 @@ namespace Barotrauma
|
||||
ChatMessage,
|
||||
RadioMessage,
|
||||
DeadMessage,
|
||||
Click,
|
||||
Select,
|
||||
PickItem,
|
||||
PickItemFail,
|
||||
DropItem,
|
||||
PopupMenu,
|
||||
DecreaseQuantity,
|
||||
IncreaseQuantity,
|
||||
HireRepairClick,
|
||||
UISwitch
|
||||
Decrease,
|
||||
Increase,
|
||||
UISwitch,
|
||||
TickBox,
|
||||
ConfirmTransaction,
|
||||
Cart,
|
||||
}
|
||||
|
||||
public enum CursorState
|
||||
@@ -301,6 +303,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float startY = 10.0f;
|
||||
float yStep = AdjustForTextScale(18) * yScale;
|
||||
if (GameMain.ShowFPS || GameMain.DebugDraw || GameMain.ShowPerf)
|
||||
{
|
||||
float y = startY;
|
||||
@@ -309,11 +312,38 @@ namespace Barotrauma
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
if (GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 1.0)
|
||||
{
|
||||
y += AdjustForTextScale(15) * yScale;
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
$"Physics: {GameMain.CurrentUpdateRate}",
|
||||
(GameMain.CurrentUpdateRate < Timing.FixedUpdateRate) ? Color.Red : Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
}
|
||||
if (GameMain.DebugDraw || GameMain.ShowPerf)
|
||||
{
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Active lights: " + Lights.LightManager.ActiveLightCount,
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Physics: " + GameMain.World.UpdateTime.TotalMilliseconds + " ms",
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += yStep;
|
||||
try
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.Count(b => b != null && b.Awake && b.Enabled)} awake, {GameMain.World.BodyList.Count(b => b != null && b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled)} dynamic)",
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
DebugConsole.AddWarning("Exception while rendering debug info. Physics bodies may have been created or removed while rendering.");
|
||||
}
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
|
||||
Color.Lerp(GUIStyle.Green, GUIStyle.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.ShowPerf)
|
||||
@@ -324,67 +354,53 @@ namespace Barotrauma
|
||||
"Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" +
|
||||
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
|
||||
GUIStyle.Green, Color.Black * 0.8f, font: GUIStyle.SmallFont);
|
||||
y += 15 * yScale;
|
||||
y += yStep;
|
||||
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: GUIStyle.Green);
|
||||
y += 50 * yScale;
|
||||
y += yStep * 4;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(x, y),
|
||||
"Update - Avg: " + GameMain.PerformanceCounter.UpdateTimeGraph.Average().ToString("0.00") + " ms" +
|
||||
" Max: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue().ToString("0.00") + " ms",
|
||||
Color.LightBlue, Color.Black * 0.8f, font: GUIStyle.SmallFont);
|
||||
y += 15 * yScale;
|
||||
y += yStep;
|
||||
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: Color.LightBlue);
|
||||
y += 50 * yScale;
|
||||
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
|
||||
y += yStep * 4;
|
||||
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers.OrderBy(i => i))
|
||||
{
|
||||
float elapsedMillisecs = GameMain.PerformanceCounter.GetAverageElapsedMillisecs(key);
|
||||
DrawString(spriteBatch, new Vector2(x, y),
|
||||
key + ": " + elapsedMillisecs.ToString("0.00"),
|
||||
Color.Lerp(Color.LightGreen, GUIStyle.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += 15 * yScale;
|
||||
foreach (string childKey in GameMain.PerformanceCounter.GetSavedPartialIdentifiers(key))
|
||||
{
|
||||
elapsedMillisecs = GameMain.PerformanceCounter.GetPartialAverageElapsedMillisecs(key, childKey);
|
||||
DrawString(spriteBatch, new Vector2(x + 15, y),
|
||||
childKey + ": " + elapsedMillisecs.ToString("0.00"),
|
||||
Color.Lerp(Color.LightGreen, GUIStyle.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += 15 * yScale;
|
||||
}
|
||||
}
|
||||
|
||||
int categoryDepth = key.Count(c => c == ':');
|
||||
//color the more fine-grained counters red more easily (ok for the whole Update to take a longer time than specific part of the update)
|
||||
float runningSlowThreshold = 10.0f / categoryDepth;
|
||||
DrawString(spriteBatch, new Vector2(x + categoryDepth * 15, y),
|
||||
key.Split(':').Last() + ": " + elapsedMillisecs.ToString("0.00"),
|
||||
ToolBox.GradientLerp(elapsedMillisecs / runningSlowThreshold, Color.LightGreen, GUIStyle.Yellow, GUIStyle.Orange, GUIStyle.Red, Color.Magenta), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += yStep;
|
||||
}
|
||||
if (Powered.Grids != null)
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(x, y), "Grids: " + Powered.Grids.Count, Color.LightGreen, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
y += 15 * yScale;
|
||||
y += yStep;
|
||||
}
|
||||
|
||||
if (Settings.EnableDiagnostics)
|
||||
{
|
||||
x += 20 * xScale;
|
||||
DrawString(spriteBatch, new Vector2(x, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContinuousPhysicsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + 15 * yScale), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + 30 * yScale), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.AddRemoveTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + 45 * yScale), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.NewContactsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + 60 * yScale), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContactsUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + 75 * yScale), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
x += yStep * 2;
|
||||
DrawString(spriteBatch, new Vector2(x, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContinuousPhysicsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + yStep), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + yStep * 2), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.AddRemoveTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + yStep * 3), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.NewContactsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + yStep * 4), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContactsUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
DrawString(spriteBatch, new Vector2(x, y + yStep * 5), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw && !Submarine.Unloading && !(Screen.Selected is RoundSummaryScreen))
|
||||
{
|
||||
float y = startY + 15 * yScale;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Physics: " + GameMain.World.UpdateTime,
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
y += 15 * yScale;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.Count(b => b != null && b.Awake && b.Enabled)} awake, {GameMain.World.BodyList.Count(b => b != null && b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled)} dynamic)",
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
float y = startY + yStep * 6;
|
||||
|
||||
if (Screen.Selected.Cam != null)
|
||||
{
|
||||
y += 15 * yScale;
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Camera pos: " + Screen.Selected.Cam.Position.ToPoint() + ", zoom: " + Screen.Selected.Cam.Zoom,
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
@@ -392,23 +408,18 @@ namespace Barotrauma
|
||||
|
||||
if (Submarine.MainSub != null)
|
||||
{
|
||||
y += 15 * yScale;
|
||||
y += yStep;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Sub pos: " + Submarine.MainSub.Position.ToPoint(),
|
||||
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
}
|
||||
|
||||
y += 20 * yScale;
|
||||
DrawString(spriteBatch, new Vector2(10, y),
|
||||
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
|
||||
Color.Lerp(GUIStyle.Green, GUIStyle.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
if (loadedSpritesText == null || DateTime.Now > loadedSpritesUpdateTime)
|
||||
{
|
||||
loadedSpritesText = "Loaded sprites: " + Sprite.LoadedSprites.Count() + "\n(" + Sprite.LoadedSprites.Select(s => s.FilePath).Distinct().Count() + " unique textures)";
|
||||
loadedSpritesUpdateTime = DateTime.Now + new TimeSpan(0, 0, seconds: 5);
|
||||
}
|
||||
y += 25 * yScale;
|
||||
y += yStep * 2;
|
||||
DrawString(spriteBatch, new Vector2(10, y), loadedSpritesText, Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
if (debugDrawSounds)
|
||||
@@ -416,21 +427,21 @@ namespace Barotrauma
|
||||
float soundTextY = 0;
|
||||
DrawString(spriteBatch, new Vector2(500, soundTextY),
|
||||
"Sounds (Ctrl+S to hide): ", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
soundTextY += 15 * yScale;
|
||||
soundTextY += yStep;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, soundTextY),
|
||||
"Current playback amplitude: " + GameMain.SoundManager.PlaybackAmplitude.ToString(), Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
soundTextY += 15 * yScale;
|
||||
soundTextY += yStep;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, soundTextY),
|
||||
"Compressed dynamic range gain: " + GameMain.SoundManager.CompressionDynamicRangeGain.ToString(), Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
|
||||
soundTextY += 15 * yScale;
|
||||
soundTextY += yStep;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, soundTextY),
|
||||
"Loaded sounds: " + GameMain.SoundManager.LoadedSoundCount + " (" + GameMain.SoundManager.UniqueLoadedSoundCount + " unique)", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
soundTextY += 15 * yScale;
|
||||
soundTextY += yStep;
|
||||
|
||||
for (int i = 0; i < SoundManager.SOURCE_COUNT; i++)
|
||||
{
|
||||
@@ -479,7 +490,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, soundTextY), soundStr, clr, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
soundTextY += 15 * yScale;
|
||||
soundTextY += yStep;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1981,7 +1992,7 @@ namespace Barotrauma
|
||||
var element = new GUIFrame(new RectTransform(new Vector2(0.22f, 1), inputArea.RectTransform) { MinSize = new Point(50, 0), MaxSize = new Point(150, 50) }, style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), element.RectTransform, Anchor.CenterLeft), RectComponentLabels[i], font: font, textAlignment: Alignment.CenterLeft);
|
||||
GUINumberInput numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight),
|
||||
GUINumberInput.NumberType.Int)
|
||||
NumberType.Int)
|
||||
{
|
||||
Font = font
|
||||
};
|
||||
@@ -2025,7 +2036,7 @@ namespace Barotrauma
|
||||
var element = new GUIFrame(new RectTransform(new Vector2(0.45f, 1), inputArea.RectTransform), style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), element.RectTransform, Anchor.CenterLeft), VectorComponentLabels[i], font: GUIStyle.SmallFont, textAlignment: Alignment.CenterLeft);
|
||||
GUINumberInput numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight),
|
||||
GUINumberInput.NumberType.Int)
|
||||
NumberType.Int)
|
||||
{
|
||||
Font = GUIStyle.SmallFont
|
||||
};
|
||||
@@ -2055,7 +2066,7 @@ namespace Barotrauma
|
||||
{
|
||||
var element = new GUIFrame(new RectTransform(new Vector2(0.45f, 1), inputArea.RectTransform), style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), element.RectTransform, Anchor.CenterLeft), VectorComponentLabels[i], font: font, textAlignment: Alignment.CenterLeft);
|
||||
GUINumberInput numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight), GUINumberInput.NumberType.Float) { Font = font };
|
||||
GUINumberInput numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight), NumberType.Float) { Font = font };
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
@@ -2369,7 +2380,7 @@ namespace Barotrauma
|
||||
CreateButton("PauseMenuResume", buttonContainer, null);
|
||||
CreateButton("PauseMenuSettings", buttonContainer, () => SettingsMenuOpen = true);
|
||||
|
||||
bool IsOutpostLevel() => GameMain.GameSession != null && Level.IsLoadedOutpost;
|
||||
bool IsFriendlyOutpostLevel() => GameMain.GameSession != null && Level.IsLoadedFriendlyOutpost;
|
||||
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession != null)
|
||||
{
|
||||
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
|
||||
@@ -2384,11 +2395,11 @@ namespace Barotrauma
|
||||
GameMain.GameSession.LoadPreviousSave();
|
||||
});
|
||||
|
||||
if (IsOutpostLevel())
|
||||
if (IsFriendlyOutpostLevel())
|
||||
{
|
||||
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToMainMenuVerification", action: () =>
|
||||
{
|
||||
if (IsOutpostLevel()) { GameMain.QuitToMainMenu(save: true); }
|
||||
if (IsFriendlyOutpostLevel()) { GameMain.QuitToMainMenu(save: true); }
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2401,7 +2412,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
|
||||
{
|
||||
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsOutpostLevel();
|
||||
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsFriendlyOutpostLevel();
|
||||
if (canSave)
|
||||
{
|
||||
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToServerLobbyVerification", action: () =>
|
||||
|
||||
@@ -111,6 +111,11 @@ namespace Barotrauma
|
||||
set { textBlock.SelectedTextColor = value; }
|
||||
}
|
||||
|
||||
public Color DisabledTextColor
|
||||
{
|
||||
get { return textBlock.DisabledTextColor; }
|
||||
}
|
||||
|
||||
public override float FlashTimer
|
||||
{
|
||||
get { return Frame.FlashTimer; }
|
||||
@@ -159,7 +164,9 @@ namespace Barotrauma
|
||||
private float pulseExpand;
|
||||
private bool flashed;
|
||||
|
||||
public GUISoundType ClickSound { get; set; } = GUISoundType.Click;
|
||||
public GUISoundType ClickSound { get; set; } = GUISoundType.Select;
|
||||
|
||||
public override bool PlaySoundOnSelect { get; set; } = true;
|
||||
|
||||
public GUIButton(RectTransform rectT, Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : this(rectT, new RawLString(""), textAlignment, style, color) { }
|
||||
|
||||
@@ -247,7 +254,10 @@ namespace Barotrauma
|
||||
}
|
||||
else if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
SoundPlayer.PlayUISound(ClickSound);
|
||||
if (PlaySoundOnSelect)
|
||||
{
|
||||
SoundPlayer.PlayUISound(ClickSound);
|
||||
}
|
||||
if (OnClicked != null)
|
||||
{
|
||||
if (OnClicked(this, UserData))
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Barotrauma
|
||||
{
|
||||
public class GUICanvas : RectTransform
|
||||
{
|
||||
private static readonly object mutex = new object();
|
||||
|
||||
protected GUICanvas() : base(size, parent: null) { }
|
||||
|
||||
private static GUICanvas _instance;
|
||||
@@ -39,22 +41,25 @@ namespace Barotrauma
|
||||
|
||||
private static void OnChildrenChanged(RectTransform _)
|
||||
{
|
||||
//add weak reference if we don't have one yet
|
||||
foreach (var child in _instance.Children)
|
||||
lock (mutex)
|
||||
{
|
||||
if (!_instance.childrenWeakRef.Any(c => c.TryGetTarget(out var existingChild) && existingChild == child))
|
||||
//add weak reference if we don't have one yet
|
||||
foreach (var child in _instance.Children)
|
||||
{
|
||||
_instance.childrenWeakRef.Add(new WeakReference<RectTransform>(child));
|
||||
if (!_instance.childrenWeakRef.Any(c => c.TryGetTarget(out var existingChild) && existingChild == child))
|
||||
{
|
||||
_instance.childrenWeakRef.Add(new WeakReference<RectTransform>(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
//get rid of strong references
|
||||
_instance.children.Clear();
|
||||
//remove dead children
|
||||
for (int i = _instance.childrenWeakRef.Count - 2; i >= 0; i--)
|
||||
{
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out var child) || child.Parent != _instance)
|
||||
//get rid of strong references
|
||||
_instance.children.Clear();
|
||||
//remove dead children
|
||||
for (int i = _instance.childrenWeakRef.Count - 2; i >= 0; i--)
|
||||
{
|
||||
_instance.childrenWeakRef.RemoveAt(i);
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out var child) || child.Parent != _instance)
|
||||
{
|
||||
_instance.childrenWeakRef.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,6 +383,8 @@ namespace Barotrauma
|
||||
|
||||
public bool ExternalHighlight = false;
|
||||
|
||||
public virtual bool PlaySoundOnSelect { get; set; } = false;
|
||||
|
||||
private RectTransform rectTransform;
|
||||
public RectTransform RectTransform
|
||||
{
|
||||
|
||||
@@ -113,7 +113,8 @@ namespace Barotrauma
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
ScrollBarVisible = false,
|
||||
Padding = hasHeader ? new Vector4(4, 0, 4, 4) : padding
|
||||
Padding = hasHeader ? new Vector4(4, 0, 4, 4) : padding,
|
||||
PlaySoundOnSelect = true
|
||||
};
|
||||
|
||||
foreach (var (option, size) in optionsAndSizes)
|
||||
@@ -290,7 +291,7 @@ namespace Barotrauma
|
||||
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
base.AddToGUIUpdateList(ignoreChildren, order);
|
||||
SubMenu?.AddToGUIUpdateList();
|
||||
SubMenu?.AddToGUIUpdateList(order: 2);
|
||||
}
|
||||
|
||||
public static void AddActiveToGUIUpdateList()
|
||||
@@ -300,7 +301,7 @@ namespace Barotrauma
|
||||
CurrentContextMenu = null;
|
||||
}
|
||||
|
||||
CurrentContextMenu?.AddToGUIUpdateList();
|
||||
CurrentContextMenu?.AddToGUIUpdateList(order: 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +160,10 @@ namespace Barotrauma
|
||||
listBox.ToolTip = value;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIImage DropDownIcon => icon;
|
||||
|
||||
public Vector4 Padding => button.TextBlock.Padding;
|
||||
|
||||
public GUIDropDown(RectTransform rectT, LocalizedString text = null, int elementCount = 4, string style = "", bool selectMultiple = false, bool dropAbove = false, Alignment textAlignment = Alignment.CenterLeft) : base(style, rectT)
|
||||
{
|
||||
@@ -183,7 +187,8 @@ namespace Barotrauma
|
||||
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, listAnchor, listPivot)
|
||||
{ IsFixedSize = false }, style: null)
|
||||
{
|
||||
Enabled = !selectMultiple
|
||||
Enabled = !selectMultiple,
|
||||
PlaySoundOnSelect = true,
|
||||
};
|
||||
if (!selectMultiple) { listBox.OnSelected = SelectItem; }
|
||||
GUIStyle.Apply(listBox, "GUIListBox", this);
|
||||
|
||||
@@ -309,6 +309,45 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override bool PlaySoundOnSelect { get; set; } = false;
|
||||
|
||||
public bool PlaySoundOnDragStop { get; set; } = false;
|
||||
|
||||
public GUISoundType? SoundOnDragStart { get; set; } = null;
|
||||
|
||||
public GUISoundType? SoundOnDragStop { get; set; } = null;
|
||||
|
||||
#region enums
|
||||
public enum Force
|
||||
{
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
|
||||
public enum AutoScroll
|
||||
{
|
||||
Enabled,
|
||||
Disabled
|
||||
}
|
||||
|
||||
public enum TakeKeyBoardFocus
|
||||
{
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
|
||||
public enum PlaySelectSound
|
||||
{
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
|
||||
private AutoScroll GetAutoScroll(bool b)
|
||||
{
|
||||
return b ? AutoScroll.Enabled : AutoScroll.Disabled;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <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, bool useMouseDownToSelect = false) : base(style, rectT)
|
||||
{
|
||||
@@ -396,7 +435,7 @@ namespace Barotrauma
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
public void Select(object userData, bool force = false, bool autoScroll = true)
|
||||
public void Select(object userData, Force force = Force.No, AutoScroll autoScroll = AutoScroll.Enabled)
|
||||
{
|
||||
var children = Content.Children;
|
||||
int i = 0;
|
||||
@@ -515,9 +554,12 @@ namespace Barotrauma
|
||||
/// Scrolls the list to the specific element.
|
||||
/// </summary>
|
||||
/// <param name="component"></param>
|
||||
public void ScrollToElement(GUIComponent component, bool playSound = true)
|
||||
public void ScrollToElement(GUIComponent component, PlaySelectSound playSelectSound = PlaySelectSound.No)
|
||||
{
|
||||
if (playSound) { SoundPlayer.PlayUISound(GUISoundType.Click); }
|
||||
if (playSelectSound == PlaySelectSound.Yes)
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
List<GUIComponent> children = Content.Children.ToList();
|
||||
int index = children.IndexOf(component);
|
||||
if (index < 0) { return; }
|
||||
@@ -573,9 +615,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private double lastDragStartTime;
|
||||
|
||||
private void StartDraggingElement(GUIComponent child)
|
||||
{
|
||||
DraggedElement = child;
|
||||
if (Timing.TotalTime > lastDragStartTime + 0.2f)
|
||||
{
|
||||
lastDragStartTime = Timing.TotalTime;
|
||||
SoundPlayer.PlayUISound(SoundOnDragStart);
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateDragging()
|
||||
@@ -586,6 +635,10 @@ namespace Barotrauma
|
||||
var draggedElem = draggedElement;
|
||||
OnRearranged?.Invoke(this, draggedElem.UserData);
|
||||
DraggedElement = null;
|
||||
if (PlaySoundOnDragStop)
|
||||
{
|
||||
SoundPlayer.PlayUISound(SoundOnDragStop);
|
||||
}
|
||||
RepositionChildren();
|
||||
if (AllSelected.Contains(draggedElem)) { return true; }
|
||||
}
|
||||
@@ -710,7 +763,7 @@ namespace Barotrauma
|
||||
int index = Content.Children.ToList().IndexOf(component);
|
||||
if (index >= 0)
|
||||
{
|
||||
Select(index, false, false, takeKeyBoardFocus: true);
|
||||
Select(index, autoScroll: AutoScroll.Disabled, takeKeyBoardFocus: TakeKeyBoardFocus.Yes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,7 +786,7 @@ namespace Barotrauma
|
||||
{
|
||||
ScrollToElement(child);
|
||||
}
|
||||
Select(i, autoScroll: false, takeKeyBoardFocus: true);
|
||||
Select(i, autoScroll: AutoScroll.Disabled, takeKeyBoardFocus: TakeKeyBoardFocus.Yes, playSelectSound: PlaySelectSound.Yes);
|
||||
}
|
||||
|
||||
if (CurrentDragMode != DragMode.NoDragging
|
||||
@@ -929,14 +982,13 @@ namespace Barotrauma
|
||||
if (ClampScrollToElements)
|
||||
{
|
||||
bool scrollDown = Math.Clamp(PlayerInput.ScrollWheelSpeed, 0, 1) > 0;
|
||||
|
||||
if (scrollDown)
|
||||
{
|
||||
SelectPrevious(takeKeyBoardFocus: true);
|
||||
SelectPrevious(takeKeyBoardFocus: TakeKeyBoardFocus.Yes, playSelectSound: PlaySelectSound.Yes);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectNext(takeKeyBoardFocus: true);
|
||||
SelectNext(takeKeyBoardFocus: TakeKeyBoardFocus.Yes, playSelectSound: PlaySelectSound.Yes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -964,7 +1016,7 @@ namespace Barotrauma
|
||||
return FindScrollableParentListBox(target.Parent);
|
||||
}
|
||||
|
||||
public void SelectNext(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
public void SelectNext(Force force = Force.No, AutoScroll autoScroll = AutoScroll.Enabled, TakeKeyBoardFocus takeKeyBoardFocus = TakeKeyBoardFocus.No, PlaySelectSound playSelectSound = PlaySelectSound.No)
|
||||
{
|
||||
int index = SelectedIndex + 1;
|
||||
while (index < Content.CountChildren)
|
||||
@@ -972,10 +1024,10 @@ namespace Barotrauma
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
Select(index, force, GetAutoScroll(!SmoothScroll && autoScroll == AutoScroll.Enabled), takeKeyBoardFocus, playSelectSound);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
ScrollToElement(child);
|
||||
ScrollToElement(child, playSelectSound);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -983,7 +1035,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectPrevious(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
public void SelectPrevious(Force force = Force.No, AutoScroll autoScroll = AutoScroll.Enabled, TakeKeyBoardFocus takeKeyBoardFocus = TakeKeyBoardFocus.No, PlaySelectSound playSelectSound = PlaySelectSound.No)
|
||||
{
|
||||
int index = SelectedIndex - 1;
|
||||
while (index >= 0)
|
||||
@@ -991,10 +1043,10 @@ namespace Barotrauma
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
Select(index, force, GetAutoScroll(!SmoothScroll && autoScroll == AutoScroll.Enabled), takeKeyBoardFocus, playSelectSound);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
ScrollToElement(child);
|
||||
ScrollToElement(child, playSelectSound);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1002,7 +1054,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void Select(int childIndex, bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
public void Select(int childIndex, Force force = Force.No, AutoScroll autoScroll = AutoScroll.Enabled, TakeKeyBoardFocus takeKeyBoardFocus = TakeKeyBoardFocus.No, PlaySelectSound playSelectSound = PlaySelectSound.No)
|
||||
{
|
||||
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
|
||||
|
||||
@@ -1013,7 +1065,7 @@ namespace Barotrauma
|
||||
if (OnSelected != null)
|
||||
{
|
||||
// TODO: The callback is called twice, fix this!
|
||||
wasSelected = force || OnSelected(child, child.UserData);
|
||||
wasSelected = force == Force.Yes || OnSelected(child, child.UserData);
|
||||
}
|
||||
|
||||
if (!wasSelected) { return; }
|
||||
@@ -1055,7 +1107,7 @@ namespace Barotrauma
|
||||
|
||||
// Ensure that the selected element is visible. This may not be the case, if the selection is run from code. (e.g. if we have two list boxes that are synced)
|
||||
// TODO: This method only works when moving one item up/down (e.g. when using the up and down arrows)
|
||||
if (autoScroll)
|
||||
if (autoScroll == AutoScroll.Enabled)
|
||||
{
|
||||
if (ScrollBar.IsHorizontal)
|
||||
{
|
||||
@@ -1086,11 +1138,19 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// If one of the children is the subscriber, we don't want to register, because it will unregister the child.
|
||||
if (takeKeyBoardFocus && CanTakeKeyBoardFocus && RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
if (takeKeyBoardFocus == TakeKeyBoardFocus.Yes && CanTakeKeyBoardFocus && RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
{
|
||||
Selected = true;
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
}
|
||||
|
||||
// List box child components can be parents to other components that can play sounds when selected (e.g. store elements)
|
||||
// so the list box shouldn't play the Select sound if the GUI.MouseOn component has a sound to play
|
||||
if (playSelectSound == PlaySelectSound.Yes && PlaySoundOnSelect && !child.PlaySoundOnSelect &&
|
||||
(GUI.MouseOn == null || GUI.MouseOn.Parent == Content || !GUI.MouseOn.PlaySoundOnSelect))
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
}
|
||||
|
||||
public void Select(IEnumerable<GUIComponent> children)
|
||||
@@ -1293,16 +1353,16 @@ namespace Barotrauma
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Down:
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectNext(playSelectSound: PlaySelectSound.Yes); }
|
||||
break;
|
||||
case Keys.Up:
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectPrevious(playSelectSound: PlaySelectSound.Yes); }
|
||||
break;
|
||||
case Keys.Left:
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectPrevious(playSelectSound: PlaySelectSound.Yes); }
|
||||
break;
|
||||
case Keys.Right:
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(playSelectSound: PlaySelectSound.Yes); }
|
||||
break;
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
|
||||
@@ -7,11 +7,6 @@ namespace Barotrauma
|
||||
{
|
||||
class GUINumberInput : GUIComponent
|
||||
{
|
||||
public enum NumberType
|
||||
{
|
||||
Int, Float
|
||||
}
|
||||
|
||||
public delegate void OnValueEnteredHandler(GUINumberInput numberInput);
|
||||
public OnValueEnteredHandler OnValueEntered;
|
||||
|
||||
@@ -187,7 +182,7 @@ namespace Barotrauma
|
||||
public float valueStep;
|
||||
|
||||
private float pressedTimer;
|
||||
private float pressedDelay = 0.5f;
|
||||
private readonly float pressedDelay = 0.5f;
|
||||
private bool IsPressedTimerRunning { get { return pressedTimer > 0; } }
|
||||
|
||||
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null, bool hidePlusMinusButtons = false) : base(style, rectT)
|
||||
@@ -233,6 +228,7 @@ namespace Barotrauma
|
||||
var buttonArea = new GUIFrame(new RectTransform(new Vector2(_relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight), style: null);
|
||||
PlusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), style: null);
|
||||
GUIStyle.Apply(PlusButton, "PlusButton", this);
|
||||
PlusButton.ClickSound = GUISoundType.Increase;
|
||||
PlusButton.OnButtonDown += () =>
|
||||
{
|
||||
pressedTimer = pressedDelay;
|
||||
@@ -254,6 +250,7 @@ namespace Barotrauma
|
||||
|
||||
MinusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), style: null);
|
||||
GUIStyle.Apply(MinusButton, "MinusButton", this);
|
||||
MinusButton.ClickSound = GUISoundType.Decrease;
|
||||
MinusButton.OnButtonDown += () =>
|
||||
{
|
||||
pressedTimer = pressedDelay;
|
||||
@@ -428,8 +425,8 @@ namespace Barotrauma
|
||||
intValue = Math.Min(intValue, MaxValueInt.Value);
|
||||
UpdateText();
|
||||
}
|
||||
PlusButton.Enabled = intValue < MaxValueInt;
|
||||
MinusButton.Enabled = intValue > MinValueInt;
|
||||
PlusButton.Enabled = MaxValueInt == null || intValue < MaxValueInt;
|
||||
MinusButton.Enabled = MinValueInt == null || intValue > MinValueInt;
|
||||
}
|
||||
|
||||
private void UpdateText()
|
||||
|
||||
@@ -98,7 +98,6 @@ namespace Barotrauma
|
||||
foreach (var subElement in element.Elements().Reverse())
|
||||
{
|
||||
if (subElement.NameAsIdentifier() != "override") { continue; }
|
||||
|
||||
if (subElement.GetAttributeBool("iscjk", false))
|
||||
{
|
||||
return new ScalableFont(subElement, GameMain.Instance.GraphicsDevice);
|
||||
@@ -111,8 +110,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameSettings.CurrentConfig.Language == subElement.GetAttributeIdentifier("language", "").ToLanguageIdentifier())
|
||||
if (IsValidOverride(subElement))
|
||||
{
|
||||
return subElement.GetAttributeContentPath("file")?.Value;
|
||||
}
|
||||
@@ -125,8 +123,7 @@ namespace Barotrauma
|
||||
//check if any of the language override fonts want to override the font size as well
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameSettings.CurrentConfig.Language == subElement.GetAttributeIdentifier("language", "").ToLanguageIdentifier())
|
||||
if (IsValidOverride(subElement))
|
||||
{
|
||||
uint overrideFontSize = GetFontSize(subElement, 0);
|
||||
if (overrideFontSize > 0) { return (uint)Math.Round(overrideFontSize * GameSettings.CurrentConfig.Graphics.TextScale); }
|
||||
@@ -149,8 +146,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameSettings.CurrentConfig.Language == subElement.GetAttributeIdentifier("language", "").ToLanguageIdentifier())
|
||||
if (IsValidOverride(subElement))
|
||||
{
|
||||
return subElement.GetAttributeBool("dynamicloading", false);
|
||||
}
|
||||
@@ -162,14 +158,20 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (GameSettings.CurrentConfig.Language == subElement.GetAttributeIdentifier("language", "").ToLanguageIdentifier())
|
||||
if (IsValidOverride(subElement))
|
||||
{
|
||||
return subElement.GetAttributeBool("iscjk", false);
|
||||
}
|
||||
}
|
||||
return element.GetAttributeBool("iscjk", false);
|
||||
}
|
||||
|
||||
private bool IsValidOverride(XElement element)
|
||||
{
|
||||
if (!element.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { return false; }
|
||||
var languages = element.GetAttributeIdentifierArray("language", Array.Empty<Identifier>());
|
||||
return languages.Any(l => l.ToLanguageIdentifier() == GameSettings.CurrentConfig.Language);
|
||||
}
|
||||
}
|
||||
|
||||
public class GUIFont : GUISelector<GUIFontPrefab>
|
||||
|
||||
@@ -322,9 +322,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!enabled || !PlayerInput.PrimaryMouseButtonDown()) { return false; }
|
||||
if (barSize >= 1.0f) { return false; }
|
||||
|
||||
DraggingBar = this;
|
||||
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace Barotrauma
|
||||
public readonly static PrefabCollection<GUIComponentStyle> ComponentStyles = new PrefabCollection<GUIComponentStyle>();
|
||||
|
||||
public readonly static GUIFont Font = new GUIFont("Font");
|
||||
public readonly static GUIFont GlobalFont = new GUIFont("GlobalFont");
|
||||
public readonly static GUIFont UnscaledSmallFont = new GUIFont("UnscaledSmallFont");
|
||||
public readonly static GUIFont SmallFont = new GUIFont("SmallFont");
|
||||
public readonly static GUIFont LargeFont = new GUIFont("LargeFont");
|
||||
@@ -142,10 +141,6 @@ namespace Barotrauma
|
||||
public readonly static GUIColor HealthBarColorMedium = new GUIColor("HealthBarColorMedium");
|
||||
public readonly static GUIColor HealthBarColorHigh = new GUIColor("HealthBarColorHigh");
|
||||
|
||||
public readonly static GUIColor EquipmentIndicatorNotEquipped = new GUIColor("EquipmentIndicatorNotEquipped");
|
||||
public readonly static GUIColor EquipmentIndicatorEquipped = new GUIColor("EquipmentIndicatorEquipped");
|
||||
public readonly static GUIColor EquipmentIndicatorRunningOut = new GUIColor("EquipmentIndicatorRunningOut");
|
||||
|
||||
public static Point ItemFrameMargin => new Point(50, 56).Multiply(GUI.SlicedSpriteScale);
|
||||
public static Point ItemFrameOffset => new Point(0, 3).Multiply(GUI.SlicedSpriteScale);
|
||||
|
||||
@@ -159,7 +154,7 @@ namespace Barotrauma
|
||||
|
||||
public static void Apply(GUIComponent targetComponent, Identifier styleName, GUIComponent parent = null)
|
||||
{
|
||||
GUIComponentStyle componentStyle = null;
|
||||
GUIComponentStyle componentStyle;
|
||||
if (parent != null)
|
||||
{
|
||||
GUIComponentStyle parentStyle = parent.Style;
|
||||
@@ -212,5 +207,21 @@ namespace Barotrauma
|
||||
return ItemQualityColorNormal;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RecalculateFonts()
|
||||
{
|
||||
foreach (var font in Fonts.Values)
|
||||
{
|
||||
font.Prefabs.ForEach(p => p.LoadFont());
|
||||
}
|
||||
}
|
||||
|
||||
public static void RecalculateSizeRestrictions()
|
||||
{
|
||||
foreach (var componentStyle in ComponentStyles)
|
||||
{
|
||||
componentStyle.RefreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace Barotrauma
|
||||
public TextGetterHandler TextGetter;
|
||||
|
||||
public bool Wrap;
|
||||
private bool playerInput;
|
||||
|
||||
public bool RoundToNearestPixel = true;
|
||||
|
||||
@@ -287,8 +286,7 @@ namespace Barotrauma
|
||||
/// If the rectT height is set 0, the height is calculated from the text.
|
||||
/// </summary>
|
||||
public GUITextBlock(RectTransform rectT, RichString text, Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null,
|
||||
bool playerInput = false)
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||
: base(style, rectT)
|
||||
{
|
||||
if (color.HasValue)
|
||||
@@ -307,7 +305,6 @@ namespace Barotrauma
|
||||
this.textAlignment = textAlignment;
|
||||
this.Wrap = wrap;
|
||||
this.Text = text ?? "";
|
||||
this.playerInput = playerInput;
|
||||
if (rectT.Rect.Height == 0 && !text.IsNullOrEmpty())
|
||||
{
|
||||
CalculateHeightFromText();
|
||||
|
||||
@@ -251,6 +251,8 @@ namespace Barotrauma
|
||||
|
||||
public bool Readonly { get; set; }
|
||||
|
||||
public override bool PlaySoundOnSelect { get; set; } = true;
|
||||
|
||||
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
|
||||
: base(style, rectT)
|
||||
@@ -261,7 +263,7 @@ namespace Barotrauma
|
||||
this.color = color ?? Color.White;
|
||||
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
||||
GUIStyle.Apply(frame, style == "" ? "GUITextBox" : style);
|
||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text ?? "", textColor, font, textAlignment, wrap, playerInput: true);
|
||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text ?? "", textColor, font, textAlignment, wrap);
|
||||
GUIStyle.Apply(textBlock, "", this);
|
||||
if (font != null) { textBlock.Font = font; }
|
||||
CaretEnabled = true;
|
||||
@@ -350,7 +352,7 @@ namespace Barotrauma
|
||||
caretPosDirty = false;
|
||||
}
|
||||
|
||||
public void Select(int forcedCaretIndex = -1)
|
||||
public void Select(int forcedCaretIndex = -1, bool ignoreSelectSound = false)
|
||||
{
|
||||
skipUpdate = true;
|
||||
if (memento.Current == null)
|
||||
@@ -360,9 +362,14 @@ namespace Barotrauma
|
||||
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
|
||||
CalculateCaretPos();
|
||||
ClearSelection();
|
||||
bool wasSelected = selected;
|
||||
selected = true;
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
OnSelected?.Invoke(this, Keys.None);
|
||||
if (!wasSelected && PlaySoundOnSelect && !ignoreSelectSound)
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deselect()
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUITickBox : GUIComponent
|
||||
{
|
||||
private GUILayoutGroup layoutGroup;
|
||||
private GUIFrame box;
|
||||
private GUITextBlock text;
|
||||
private readonly GUILayoutGroup layoutGroup;
|
||||
private readonly GUIFrame box;
|
||||
private readonly GUITextBlock text;
|
||||
|
||||
public delegate bool OnSelectedHandler(GUITickBox obj);
|
||||
public OnSelectedHandler OnSelected;
|
||||
@@ -129,6 +127,12 @@ namespace Barotrauma
|
||||
set { text.Text = value; }
|
||||
}
|
||||
|
||||
public float ContentWidth { get; private set; }
|
||||
|
||||
public GUISoundType SoundType { private get; set; } = GUISoundType.TickBox;
|
||||
|
||||
public override bool PlaySoundOnSelect { get; set; } = true;
|
||||
|
||||
public GUITickBox(RectTransform rectT, LocalizedString label, GUIFont font = null, string style = "") : base(null, rectT)
|
||||
{
|
||||
CanBeFocused = true;
|
||||
@@ -180,6 +184,7 @@ namespace Barotrauma
|
||||
box.RectTransform.MinSize = new Point(Rect.Height);
|
||||
box.RectTransform.Resize(box.RectTransform.MinSize);
|
||||
text.SetTextPos();
|
||||
ContentWidth = box.Rect.Width + text.Padding.X + text.TextSize.X + text.Padding.Z;
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
@@ -209,6 +214,10 @@ namespace Barotrauma
|
||||
{
|
||||
Selected = true;
|
||||
}
|
||||
if (PlaySoundOnSelect)
|
||||
{
|
||||
SoundPlayer.PlayUISound(SoundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isSelected)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace Barotrauma
|
||||
get { return inventoryTopY; }
|
||||
set
|
||||
{
|
||||
if (value == inventoryTopY) return;
|
||||
if (value == inventoryTopY) { return; }
|
||||
inventoryTopY = value;
|
||||
CreateAreas();
|
||||
}
|
||||
@@ -90,8 +91,6 @@ namespace Barotrauma
|
||||
if (GameMain.Instance != null)
|
||||
{
|
||||
GameMain.Instance.ResolutionChanged += CreateAreas;
|
||||
#warning TODO: reimplement
|
||||
//GameSettings.CurrentConfig.OnHUDScaleChanged += CreateAreas;
|
||||
CreateAreas();
|
||||
CharacterInfo.Init();
|
||||
}
|
||||
@@ -122,7 +121,17 @@ namespace Barotrauma
|
||||
|
||||
//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 * 1.58f);
|
||||
int healthBarWidth = BottomRightInfoArea.Width;
|
||||
|
||||
var healthBarChildStyles = GUIStyle.GetComponentStyle("CharacterHealthBar")?.ChildStyles;
|
||||
if (healthBarChildStyles!= null && healthBarChildStyles.TryGetValue("GUIFrame".ToIdentifier(), out var style))
|
||||
{
|
||||
if (style.Sprites.TryGetValue(GUIComponent.ComponentState.None, out var uiSprites) && uiSprites.FirstOrDefault() is { } uiSprite)
|
||||
{
|
||||
// The default health bar uses a sliced sprite so let's make sure the health bar area is calculated accordingly
|
||||
healthBarWidth += (int)(uiSprite.NonSliceSize.X * Math.Min(GUI.Scale, 1f));
|
||||
}
|
||||
}
|
||||
int healthBarHeight = (int)(50f * GUI.Scale);
|
||||
HealthBarArea = new Rectangle(BottomRightInfoArea.Right - healthBarWidth + (int)Math.Floor(1 / GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + GUI.IntScale(10), healthBarWidth, healthBarHeight);
|
||||
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
|
||||
|
||||
@@ -569,6 +569,7 @@ namespace Barotrauma
|
||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterRight);
|
||||
GUIButton healButton = new GUIButton(new RectTransform(new Vector2(0.33f, 1f), buttonLayout.RectTransform), TextManager.Get("medicalclinic.heal"))
|
||||
{
|
||||
ClickSound = GUISoundType.ConfirmTransaction,
|
||||
Enabled = medicalClinic.PendingHeals.Any() && medicalClinic.GetBalance() >= medicalClinic.GetTotalCost(),
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
@@ -595,6 +596,7 @@ namespace Barotrauma
|
||||
|
||||
GUIButton clearButton = new GUIButton(new RectTransform(new Vector2(0.33f, 1f), buttonLayout.RectTransform), TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
button.Enabled = false;
|
||||
@@ -657,6 +659,7 @@ namespace Barotrauma
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUILayoutGroup parentLayout = new GUILayoutGroup(new RectTransform(Vector2.One, backgroundFrame.RectTransform), isHorizontal: true) { Stretch = true };
|
||||
|
||||
if (!(affliction.Prefab is { } prefab)) { return; }
|
||||
@@ -676,13 +679,14 @@ namespace Barotrauma
|
||||
GUIFrame textContainer = new GUIFrame(new RectTransform(new Vector2(0.6f, 1f), textLayout.RectTransform), style: null);
|
||||
GUITextBlock afflictionName = new GUITextBlock(new RectTransform(Vector2.One, textContainer.RectTransform), name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.LargeFont)
|
||||
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
Padding = Vector4.Zero
|
||||
};
|
||||
|
||||
GUIButton healButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), style: "CrewManagementRemoveButton")
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
button.Enabled = false;
|
||||
@@ -746,12 +750,12 @@ namespace Barotrauma
|
||||
|
||||
ClosePopup();
|
||||
|
||||
GUIFrame mainFrame = new GUIFrame(new RectTransform(new Vector2(0.28f, 0.45f), container.RectTransform)
|
||||
GUIFrame mainFrame = new GUIFrame(new RectTransform(new Vector2(0.28f, 0.5f), container.RectTransform)
|
||||
{
|
||||
ScreenSpaceOffset = location.ToPoint()
|
||||
});
|
||||
|
||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), mainFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.01f, Stretch = true };
|
||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), mainFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.01f, Stretch = true };
|
||||
|
||||
if (mainFrame.Rect.Bottom > GameMain.GraphicsHeight)
|
||||
{
|
||||
@@ -765,6 +769,7 @@ namespace Barotrauma
|
||||
|
||||
GUIButton treatAllButton = new GUIButton(new RectTransform(new Vector2(1f, 0.2f), mainLayout.RectTransform), TextManager.Get("medicalclinic.treatall"))
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
Font = GUIStyle.SubHeadingFont,
|
||||
Visible = false
|
||||
};
|
||||
@@ -819,7 +824,9 @@ namespace Barotrauma
|
||||
if (!(affliction.Prefab is { } prefab)) { return ImmutableArray<GUIComponent>.Empty; }
|
||||
|
||||
GUIFrame backgroundFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), parent.RectTransform), style: "ListBoxElement");
|
||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), backgroundFrame.RectTransform, Anchor.Center))
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), backgroundFrame.RectTransform, Anchor.BottomCenter), style: "HorizontalLine");
|
||||
|
||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), backgroundFrame.RectTransform, Anchor.Center))
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
@@ -862,15 +869,32 @@ namespace Barotrauma
|
||||
|
||||
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), mainLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUILayoutGroup bottomTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), bottomLayout.RectTransform));
|
||||
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), ToolBox.LimitString(prefab.Description, GUIStyle.Font, GUI.IntScale(64)), wrap: true)
|
||||
GUILayoutGroup bottomTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), bottomLayout.RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.6f), bottomTextLayout.RectTransform), prefab.Description, font: GUIStyle.SmallFont, wrap: true)
|
||||
{
|
||||
ToolTip = prefab.Description
|
||||
};
|
||||
bool truncated = false;
|
||||
while (descriptionBlock.TextSize.Y > descriptionBlock.Rect.Height && descriptionBlock.WrappedText.Contains('\n'))
|
||||
{
|
||||
var split = descriptionBlock.WrappedText.Value.Split('\n');
|
||||
descriptionBlock.Text = string.Join('\n', split.Take(split.Length - 1));
|
||||
truncated = true;
|
||||
}
|
||||
if (truncated)
|
||||
{
|
||||
descriptionBlock.Text += "...";
|
||||
}
|
||||
|
||||
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), font: GUIStyle.LargeFont);
|
||||
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.25f), bottomTextLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), font: GUIStyle.SubHeadingFont);
|
||||
|
||||
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton");
|
||||
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
ClickSound = GUISoundType.Cart
|
||||
};
|
||||
|
||||
ImmutableArray<GUIComponent> elementsToDisable = ImmutableArray.Create<GUIComponent>(prefabBlock, backgroundFrame, icon, vitalityBlock, severityBlock, buyButton, descriptionBlock, priceBlock);
|
||||
|
||||
@@ -923,6 +947,7 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
#warning TODO: this doesn't seem like the right place for this, and it's not clear from the method signature how this differs from ToolBox.LimitString
|
||||
public static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray<GUILayoutGroup>? layoutGroups = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text)) { return; }
|
||||
|
||||
@@ -46,9 +46,7 @@ namespace Barotrauma
|
||||
private int buyTotal, sellTotal, sellFromSubTotal;
|
||||
|
||||
private GUITextBlock storeNameBlock;
|
||||
private GUITextBlock merchantBalanceBlock;
|
||||
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
||||
private GUIImage sellValueChangeArrow;
|
||||
private GUITextBlock reputationEffectBlock;
|
||||
private GUIDropDown sortingDropDown;
|
||||
private GUITextBox searchBox;
|
||||
private GUILayoutGroup categoryButtonContainer;
|
||||
@@ -376,41 +374,29 @@ namespace Barotrauma
|
||||
AutoScaleVertical = true,
|
||||
ForceUpperCase = ForceUpperCase.Yes
|
||||
};
|
||||
merchantBalanceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform),
|
||||
"", font: GUIStyle.SubHeadingFont)
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform), "",
|
||||
color: Color.White, font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () =>
|
||||
{
|
||||
merchantBalanceBlock.TextColor = ActiveStore?.BalanceColor ?? Color.Red;
|
||||
return GetMerchantBalanceText();
|
||||
}
|
||||
TextGetter = () => GetMerchantBalanceText()
|
||||
};
|
||||
|
||||
// Item sell value ------------------------------------------------
|
||||
var sellValueContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
||||
var reputationEffectContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
||||
{
|
||||
CanBeFocused = true,
|
||||
RelativeSpacing = 0.005f
|
||||
RelativeSpacing = 0.005f,
|
||||
ToolTip = TextManager.Get("campaignstore.reputationtooltip")
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform),
|
||||
TextManager.Get("campaignstore.sellvalue"), font: GUIStyle.Font, textAlignment: Alignment.BottomLeft)
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), reputationEffectContainer.RectTransform),
|
||||
TextManager.Get("reputationmodifier"), font: GUIStyle.Font, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
ForceUpperCase = ForceUpperCase.Yes
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
};
|
||||
|
||||
var valueChangeGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
float blockWidth = GUI.IsFourByThree() ? 0.32f : 0.28f;
|
||||
Point blockMaxSize = new Point((int)(GameSettings.CurrentConfig.Graphics.TextScale * 60), valueChangeGroup.Rect.Height);
|
||||
currentSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
||||
"", font: GUIStyle.SubHeadingFont)
|
||||
reputationEffectBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), reputationEffectContainer.RectTransform), "", font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
@@ -419,64 +405,27 @@ namespace Barotrauma
|
||||
{
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
int balanceAfterTransaction = activeTab switch
|
||||
Color textColor = GUIStyle.ColorReputationNeutral;
|
||||
string sign = "";
|
||||
int reputationModifier = (int)MathF.Round((CurrentLocation.GetStoreReputationModifier(activeTab == StoreTab.Buy) - 1) * 100);
|
||||
if (reputationModifier > 0)
|
||||
{
|
||||
StoreTab.Buy => ActiveStore.Balance + buyTotal,
|
||||
StoreTab.Sell => ActiveStore.Balance - sellTotal,
|
||||
StoreTab.SellSub => ActiveStore.Balance - sellFromSubTotal,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
if (balanceAfterTransaction != ActiveStore.Balance)
|
||||
{
|
||||
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
|
||||
if (ActiveStore.ActiveBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
|
||||
{
|
||||
string tooltipTag = newStatus.SellPriceModifier > ActiveStore.ActiveBalanceStatus.SellPriceModifier ?
|
||||
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
|
||||
sellValueContainer.ToolTip = TextManager.Get(tooltipTag);
|
||||
currentSellValueBlock.TextColor = newStatus.Color;
|
||||
sellValueChangeArrow.Color = newStatus.Color;
|
||||
sellValueChangeArrow.Visible = true;
|
||||
newSellValueBlock.TextColor = newStatus.Color;
|
||||
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
}
|
||||
textColor = IsBuying ? GUIStyle.ColorReputationLow : GUIStyle.ColorReputationHigh;
|
||||
sign = "+";
|
||||
}
|
||||
sellValueContainer.ToolTip = TextManager.Get("campaignstore.sellvaluetooltip");
|
||||
currentSellValueBlock.TextColor = ActiveStore.BalanceColor;
|
||||
sellValueChangeArrow.Visible = false;
|
||||
newSellValueBlock.Text = null;
|
||||
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
else if (reputationModifier < 0)
|
||||
{
|
||||
textColor = IsBuying ? GUIStyle.ColorReputationHigh : GUIStyle.ColorReputationLow;
|
||||
}
|
||||
reputationEffectBlock.TextColor = textColor;
|
||||
return $"{sign}{reputationModifier}%";
|
||||
}
|
||||
else
|
||||
{
|
||||
sellValueContainer.ToolTip = null;
|
||||
sellValueChangeArrow.Visible = false;
|
||||
newSellValueBlock.Text = null;
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
};
|
||||
Vector4 newPadding = currentSellValueBlock.Padding;
|
||||
newPadding.Z = 0;
|
||||
currentSellValueBlock.Padding = newPadding;
|
||||
float relativeHeight = 0.45f;
|
||||
float relativeWidth = (relativeHeight * valueChangeGroup.Rect.Height) / valueChangeGroup.Rect.Width;
|
||||
sellValueChangeArrow = new GUIImage(new RectTransform(new Vector2(relativeWidth, relativeHeight), valueChangeGroup.RectTransform), "StoreArrow", scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Visible = false
|
||||
};
|
||||
newSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
||||
"", font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f
|
||||
};
|
||||
newPadding = newSellValueBlock.Padding;
|
||||
newPadding.X = 0;
|
||||
newSellValueBlock.Padding = newPadding;
|
||||
|
||||
// Store mode buttons ------------------------------------------------
|
||||
var modeButtonFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.4f / 14.0f), storeContent.RectTransform), style: null);
|
||||
@@ -707,7 +656,7 @@ namespace Barotrauma
|
||||
SetConfirmButtonBehavior();
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(0.35f, 1.0f), buttonContainer.RectTransform), TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ClickSound = GUISoundType.DecreaseQuantity,
|
||||
ClickSound = GUISoundType.Cart,
|
||||
Enabled = HasActiveTabPermissions(),
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
OnClicked = (button, userData) =>
|
||||
@@ -1597,7 +1546,7 @@ namespace Barotrauma
|
||||
{
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, containingTab),
|
||||
@@ -1618,8 +1567,6 @@ namespace Barotrauma
|
||||
}
|
||||
AddToShoppingCrate(purchasedItem, quantity: numberInput.IntValue - purchasedItem.Quantity);
|
||||
};
|
||||
amountInput.PlusButton.ClickSound = GUISoundType.IncreaseQuantity;
|
||||
amountInput.MinusButton.ClickSound = GUISoundType.DecreaseQuantity;
|
||||
frame.HoverColor = frame.SelectedColor = Color.Transparent;
|
||||
}
|
||||
|
||||
@@ -1673,7 +1620,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreAddToCrateButton")
|
||||
{
|
||||
ClickSound = GUISoundType.IncreaseQuantity,
|
||||
ClickSound = GUISoundType.Cart,
|
||||
Enabled = !forceDisable && pi.Quantity > 0,
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
UserData = "addbutton",
|
||||
@@ -1684,7 +1631,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreRemoveFromCrateButton")
|
||||
{
|
||||
ClickSound = GUISoundType.DecreaseQuantity,
|
||||
ClickSound = GUISoundType.Cart,
|
||||
Enabled = !forceDisable,
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
UserData = "removebutton",
|
||||
@@ -2127,11 +2074,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (IsBuying)
|
||||
{
|
||||
confirmButton.ClickSound = GUISoundType.ConfirmTransaction;
|
||||
confirmButton.Text = TextManager.Get("CampaignStore.Purchase");
|
||||
confirmButton.OnClicked = (b, o) => BuyItems();
|
||||
}
|
||||
else
|
||||
{
|
||||
confirmButton.ClickSound = GUISoundType.Select;
|
||||
confirmButton.Text = TextManager.Get("CampaignStoreTab.Sell");
|
||||
confirmButton.OnClicked = (b, o) =>
|
||||
{
|
||||
@@ -2139,6 +2088,7 @@ namespace Barotrauma
|
||||
TextManager.Get("FireWarningHeader"),
|
||||
TextManager.Get("CampaignStore.SellWarningText"),
|
||||
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
confirmDialog.Buttons[0].ClickSound = GUISoundType.ConfirmTransaction;
|
||||
confirmDialog.Buttons[0].OnClicked = (b, o) => SellItems();
|
||||
confirmDialog.Buttons[0].OnClicked += confirmDialog.Close;
|
||||
confirmDialog.Buttons[1].OnClicked = confirmDialog.Close;
|
||||
@@ -2258,7 +2208,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
updateStopwatch.Stop();
|
||||
GameMain.PerformanceCounter.AddPartialElapsedTicks("GameSessionUpdate", "StoreUpdate", updateStopwatch.ElapsedTicks);
|
||||
GameMain.PerformanceCounter.AddElapsedTicks("Update:GameSession:Store", updateStopwatch.ElapsedTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Barotrauma
|
||||
private GUITextBlock descriptionTextBlock;
|
||||
private int selectionIndicatorThickness;
|
||||
private GUIImage listBackground;
|
||||
private GUITickBox transferItemsTickBox;
|
||||
private GUITextBlock itemTransferReminderBlock;
|
||||
|
||||
private readonly List<SubmarineInfo> subsToShow;
|
||||
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
||||
@@ -61,6 +63,23 @@ namespace Barotrauma
|
||||
public GUIButton previewButton;
|
||||
}
|
||||
|
||||
private bool TransferItemsOnSwitch
|
||||
{
|
||||
get
|
||||
{
|
||||
return transferItemsOnSwitch;
|
||||
}
|
||||
set
|
||||
{
|
||||
transferItemsOnSwitch = value;
|
||||
if (transferItemsTickBox != null)
|
||||
{
|
||||
transferItemsTickBox.Selected = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool transferItemsOnSwitch = true;
|
||||
|
||||
public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent)
|
||||
{
|
||||
if (GameMain.GameSession.Campaign == null) { return; }
|
||||
@@ -149,11 +168,12 @@ namespace Barotrauma
|
||||
GUIListBox descriptionFrame = new GUIListBox(new RectTransform(new Vector2(0.59f, 1f), infoFrame.RectTransform), style: null) { Padding = new Vector4(HUDLayoutSettings.Padding / 2f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding / 2f) };
|
||||
descriptionTextBlock = new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionFrame.Content.RectTransform), string.Empty, font: GUIStyle.Font, wrap: true) { CanBeFocused = false };
|
||||
|
||||
GUILayoutGroup buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.075f), content.RectTransform), childAnchor: Anchor.CenterRight) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
GUILayoutGroup bottomContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.075f), content.RectTransform, Anchor.CenterRight), childAnchor: Anchor.CenterRight) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
float transferInfoFrameWidth = 1.0f;
|
||||
|
||||
if (closeAction != null)
|
||||
{
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), TextManager.Get("Close"), style: "GUIButtonFreeScale")
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), bottomContainer.RectTransform), TextManager.Get("Close"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
@@ -161,11 +181,33 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
transferInfoFrameWidth -= closeButton.RectTransform.RelativeSize.X;
|
||||
}
|
||||
|
||||
if (purchaseService) confirmButtonAlt = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseOnlyText, style: "GUIButtonFreeScale");
|
||||
confirmButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseService ? purchaseAndSwitchText : deliveryFee > 0 ? deliveryText : switchText, style: "GUIButtonFreeScale");
|
||||
if (purchaseService)
|
||||
{
|
||||
confirmButtonAlt = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), bottomContainer.RectTransform), purchaseOnlyText, style: "GUIButtonFreeScale");
|
||||
transferInfoFrameWidth -= confirmButtonAlt.RectTransform.RelativeSize.X;
|
||||
}
|
||||
confirmButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), bottomContainer.RectTransform), purchaseService ? purchaseAndSwitchText : deliveryFee > 0 ? deliveryText : switchText, style: "GUIButtonFreeScale");
|
||||
SetConfirmButtonState(false);
|
||||
transferInfoFrameWidth -= confirmButton.RectTransform.RelativeSize.X;
|
||||
GUIFrame transferInfoFrame = new GUIFrame(new RectTransform(new Vector2(transferInfoFrameWidth, 1.0f), bottomContainer.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
transferItemsTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 1.0f), transferInfoFrame.RectTransform, Anchor.CenterRight), TextManager.Get("transferitems"), font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
Selected = TransferItemsOnSwitch,
|
||||
Visible = false,
|
||||
OnSelected = (tb) => transferItemsOnSwitch = tb.Selected
|
||||
};
|
||||
transferItemsTickBox.RectTransform.Resize(new Point(Math.Min((int)transferItemsTickBox.ContentWidth, transferInfoFrame.Rect.Width), transferItemsTickBox.Rect.Height));
|
||||
itemTransferReminderBlock = new GUITextBlock(new RectTransform(Vector2.One, transferInfoFrame.RectTransform, Anchor.CenterRight), null)
|
||||
{
|
||||
TextAlignment = Alignment.CenterRight,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
pageIndicatorHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.5f), submarineControlsGroup.RectTransform), style: null);
|
||||
pageIndicator = GUIStyle.GetComponentStyle("GUIPageIndicator").GetDefaultSprite();
|
||||
@@ -272,7 +314,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSubmarineDisplay(bool updateSubs)
|
||||
public void RefreshSubmarineDisplay(bool updateSubs, bool setTransferOptionToTrue = false)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
@@ -286,6 +328,10 @@ namespace Barotrauma
|
||||
{
|
||||
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
|
||||
}
|
||||
if (setTransferOptionToTrue)
|
||||
{
|
||||
TransferItemsOnSwitch = true;
|
||||
}
|
||||
if (updateSubs)
|
||||
{
|
||||
UpdateSubmarines();
|
||||
@@ -401,6 +447,10 @@ namespace Barotrauma
|
||||
{
|
||||
SelectSubmarine(null, Rectangle.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateItemTransferInfoFrame();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSubmarines()
|
||||
@@ -553,6 +603,40 @@ namespace Barotrauma
|
||||
selectedSubmarineIndicator.RectTransform.NonScaledSize = Point.Zero;
|
||||
SetConfirmButtonState(false);
|
||||
}
|
||||
|
||||
UpdateItemTransferInfoFrame();
|
||||
}
|
||||
|
||||
private void UpdateItemTransferInfoFrame()
|
||||
{
|
||||
if (selectedSubmarine != null)
|
||||
{
|
||||
var pendingSub = GameMain.GameSession?.Campaign?.PendingSubmarineSwitch;
|
||||
if (Submarine.MainSub?.Info?.Name == selectedSubmarine.Name && pendingSub == null)
|
||||
{
|
||||
transferItemsTickBox.Visible = false;
|
||||
itemTransferReminderBlock.Visible = false;
|
||||
}
|
||||
else if (pendingSub?.Name == selectedSubmarine.Name)
|
||||
{
|
||||
transferItemsTickBox.Visible = false;
|
||||
itemTransferReminderBlock.Text = GameMain.GameSession.Campaign.TransferItemsOnSubSwitch ?
|
||||
TextManager.Get("itemtransferenabledreminder") :
|
||||
TextManager.Get("itemtransferdisabledreminder");
|
||||
itemTransferReminderBlock.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
transferItemsTickBox.Selected = TransferItemsOnSwitch;
|
||||
transferItemsTickBox.Visible = true;
|
||||
itemTransferReminderBlock.Visible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transferItemsTickBox.Visible = false;
|
||||
itemTransferReminderBlock.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConfirmButtonState(bool state)
|
||||
@@ -614,24 +698,27 @@ namespace Barotrauma
|
||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName),
|
||||
("[amount]", deliveryFee.ToString()),
|
||||
("[currencyname]", currencyName)), messageBoxOptions);
|
||||
msgBox.Buttons[0].ClickSound = GUISoundType.ConfirmTransaction;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("switchsubmarineheader"), TextManager.GetWithVariables("switchsubmarinetext",
|
||||
var text = TextManager.GetWithVariables("switchsubmarinetext",
|
||||
("[submarinename1]", CurrentOrPendingSubmarine().DisplayName),
|
||||
("[submarinename2]", selectedSubmarine.DisplayName)), messageBoxOptions);
|
||||
("[submarinename2]", selectedSubmarine.DisplayName));
|
||||
text += GetItemTransferText();
|
||||
msgBox = new GUIMessageBox(TextManager.Get("switchsubmarineheader"), text, messageBoxOptions);
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, TransferItemsOnSwitch, deliveryFee);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.SwitchSub);
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, TransferItemsOnSwitch, Networking.VoteType.SwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -653,23 +740,25 @@ namespace Barotrauma
|
||||
|
||||
if (!purchaseOnly)
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), TextManager.GetWithVariables("purchaseandswitchsubmarinetext",
|
||||
var text = TextManager.GetWithVariables("purchaseandswitchsubmarinetext",
|
||||
("[submarinename1]", selectedSubmarine.DisplayName),
|
||||
("[amount]", selectedSubmarine.Price.ToString()),
|
||||
("[currencyname]", currencyName),
|
||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName)), messageBoxOptions);
|
||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName));
|
||||
text += GetItemTransferText();
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), text, messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, TransferItemsOnSwitch, 0);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseAndSwitchSub);
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, TransferItemsOnSwitch, Networking.VoteType.PurchaseAndSwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -690,14 +779,20 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseSub);
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, false, Networking.VoteType.PurchaseSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].ClickSound = GUISoundType.ConfirmTransaction;
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalizedString GetItemTransferText()
|
||||
{
|
||||
return "\n\n" + TextManager.Get(TransferItemsOnSwitch ? "itemswillbetransferred" : "itemswontbetransferred");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,47 +54,65 @@ namespace Barotrauma
|
||||
|
||||
private ushort currentPing;
|
||||
private readonly Character character;
|
||||
private readonly bool hasCharacter;
|
||||
private readonly bool wasCharacterAlive;
|
||||
private readonly GUITextBlock textBlock;
|
||||
private readonly GUIFrame frame;
|
||||
|
||||
private readonly GUIImage permissionIcon;
|
||||
|
||||
public LinkedGUI(Client client, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock, GUIImage permissionIcon)
|
||||
public LinkedGUI(Client client, GUIFrame frame, GUITextBlock textBlock, GUIImage permissionIcon)
|
||||
{
|
||||
this.Client = client;
|
||||
this.textBlock = textBlock;
|
||||
this.frame = frame;
|
||||
this.hasCharacter = hasCharacter;
|
||||
this.permissionIcon = permissionIcon;
|
||||
character = client?.Character;
|
||||
wasCharacterAlive = client?.Character != null && !client.Character.IsDead;
|
||||
}
|
||||
|
||||
public LinkedGUI(Character character, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
|
||||
public LinkedGUI(Character character, GUIFrame frame, GUITextBlock textBlock)
|
||||
{
|
||||
this.character = character;
|
||||
this.textBlock = textBlock;
|
||||
this.frame = frame;
|
||||
this.hasCharacter = hasCharacter;
|
||||
wasCharacterAlive = character != null && !character.IsDead;
|
||||
}
|
||||
|
||||
public bool HasMultiplayerCharacterChanged()
|
||||
{
|
||||
if (Client == null) { return false; }
|
||||
bool characterState = Client.Character != null;
|
||||
if (characterState && Client.Character.IsDead) characterState = false;
|
||||
return hasCharacter != characterState;
|
||||
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
if (Client.Character != character)
|
||||
{
|
||||
DebugConsole.Log($"Refreshing tab menu crew list (client \"{Client.Name}\"'s character changed from \"{character?.Name ?? "null"}\" to \"{Client.Character?.Name ?? "null"}\")");
|
||||
}
|
||||
}
|
||||
return Client.Character != character;
|
||||
}
|
||||
|
||||
public bool HasMultiplayerCharacterDied()
|
||||
{
|
||||
if (Client == null || !hasCharacter || Client.Character == null) { return false; }
|
||||
return Client.Character.IsDead;
|
||||
}
|
||||
|
||||
public bool HasAICharacterDied()
|
||||
public bool HasCharacterDied()
|
||||
{
|
||||
if (character == null) { return false; }
|
||||
return character.IsDead;
|
||||
bool isAlive = !(character?.IsDead ?? true);
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
if (wasCharacterAlive && !isAlive)
|
||||
{
|
||||
DebugConsole.Log(Client == null ?
|
||||
$"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" died)" :
|
||||
$"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" died)");
|
||||
}
|
||||
else if (!wasCharacterAlive && isAlive)
|
||||
{
|
||||
DebugConsole.Log(Client == null ?
|
||||
|
||||
$"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" came back to life)" :
|
||||
$"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" came back to life)");
|
||||
}
|
||||
}
|
||||
return isAlive != wasCharacterAlive;
|
||||
}
|
||||
|
||||
public void TryPingRefresh()
|
||||
@@ -207,7 +225,7 @@ namespace Barotrauma
|
||||
{
|
||||
linkedGUIList[i].TryPingRefresh();
|
||||
linkedGUIList[i].TryPermissionIconRefresh(GetPermissionIcon(linkedGUIList[i].Client));
|
||||
if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasMultiplayerCharacterDied() || linkedGUIList[i].HasAICharacterDied())
|
||||
if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasCharacterDied())
|
||||
{
|
||||
RemoveCurrentElements();
|
||||
CreateMultiPlayerList(true);
|
||||
@@ -219,10 +237,11 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < linkedGUIList.Count; i++)
|
||||
{
|
||||
if (linkedGUIList[i].HasAICharacterDied())
|
||||
if (linkedGUIList[i].HasCharacterDied())
|
||||
{
|
||||
RemoveCurrentElements();
|
||||
CreateSinglePlayerList(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,6 +316,10 @@ namespace Barotrauma
|
||||
|
||||
var balanceFrame = new GUIFrame(new RectTransform(new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style: "InnerFrame");
|
||||
GUITextBlock balanceText = new GUITextBlock(new RectTransform(Vector2.One, balanceFrame.RectTransform), string.Empty, textAlignment: Alignment.Right);
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
balanceText.ToolTip = TextManager.Get("bankdescription");
|
||||
}
|
||||
GUIFrame bottomDisclaimerFrame = new GUIFrame(new RectTransform(new Vector2(contentFrameSize.X, 0.1f), infoFrame.RectTransform)
|
||||
{
|
||||
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
||||
@@ -337,7 +360,7 @@ namespace Barotrauma
|
||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
||||
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
||||
{
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null;
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null || GameMain.Client?.CharacterInfo != null;
|
||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||
{
|
||||
SelectInfoFrameTab(InfoFrameTab.Crew);
|
||||
@@ -430,7 +453,8 @@ namespace Barotrauma
|
||||
GUIListBox crewList = new GUIListBox(new RectTransform(crewListSize, content.RectTransform))
|
||||
{
|
||||
Padding = new Vector4(2, 5, 0, 0),
|
||||
AutoHideScrollBar = false
|
||||
AutoHideScrollBar = false,
|
||||
PlaySoundOnSelect = true
|
||||
};
|
||||
crewList.UpdateDimensions();
|
||||
|
||||
@@ -560,7 +584,7 @@ namespace Barotrauma
|
||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
||||
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead, textBlock: null));
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame, textBlock: null));
|
||||
}
|
||||
|
||||
private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
|
||||
@@ -657,7 +681,7 @@ namespace Barotrauma
|
||||
if (client != null)
|
||||
{
|
||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame, true,
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||
permissionIcon));
|
||||
}
|
||||
@@ -668,12 +692,12 @@ namespace Barotrauma
|
||||
|
||||
if (character is AICharacter)
|
||||
{
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead,
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedGUIList.Add(new LinkedGUI(client: null, frame, true, textBlock: null, permissionIcon: null));
|
||||
linkedGUIList.Add(new LinkedGUI(client: null, frame, textBlock: null, permissionIcon: null));
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
|
||||
{
|
||||
@@ -718,7 +742,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame, false,
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||
permissionIcon));
|
||||
|
||||
@@ -775,19 +799,27 @@ namespace Barotrauma
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUIFrame(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
ToolTip = TextManager.Get("walletdescription")
|
||||
};
|
||||
|
||||
if (character.IsBot) { return; }
|
||||
|
||||
Sprite walletSprite = GUIStyle.CrewWalletIconSmall.Value.Sprite;
|
||||
|
||||
GUIImage icon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), walletSprite, scaleToFit: true);
|
||||
GUIImage icon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), walletSprite, scaleToFit: true) { CanBeFocused = false };
|
||||
GUITextBlock walletBlock = new GUITextBlock(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), string.Empty, textAlignment: Alignment.Right, font: GUIStyle.Font)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
Padding = Vector4.Zero
|
||||
Padding = Vector4.Zero,
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUIImage largeIcon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), walletSprite, scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false
|
||||
};
|
||||
@@ -897,8 +929,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 stringOffset = GUIStyle.GlobalFont.MeasureString(inLobbyString) / 2f;
|
||||
GUIStyle.GlobalFont.DrawString(spriteBatch, inLobbyString, area.Center.ToVector2() - stringOffset, Color.White);
|
||||
Vector2 stringOffset = GUIStyle.Font.MeasureString(inLobbyString) / 2f;
|
||||
GUIStyle.Font.DrawString(spriteBatch, inLobbyString, area.Center.ToVector2() - stringOffset, Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,16 +1003,25 @@ namespace Barotrauma
|
||||
float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
|
||||
GUILayoutGroup headerTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get("crewwallet.wallet"), font: GUIStyle.LargeFont);
|
||||
GUIFrame walletTooltipFrame = new GUIFrame(new RectTransform(Vector2.One, headerLayout.RectTransform), style: null)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
ToolTip = TextManager.Get("walletdescription")
|
||||
};
|
||||
GUITextBlock moneyBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
||||
|
||||
GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform));
|
||||
GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true);
|
||||
GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
||||
GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), string.Empty, textAlignment: Alignment.BottomRight);
|
||||
GUIFrame salaryTooltipFrame = new GUIFrame(new RectTransform(Vector2.One, middleLayout.RectTransform), style: null)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
ToolTip = TextManager.Get("crewwallet.salary.tooltip")
|
||||
};
|
||||
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
||||
GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f)
|
||||
{
|
||||
ToolTip = TextManager.Get("crewwallet.salary.tooltip"),
|
||||
Range = new Vector2(0, 1),
|
||||
BarScrollValue = targetWallet.RewardDistribution / 100f,
|
||||
Step = 0.01f,
|
||||
@@ -1024,7 +1065,7 @@ namespace Barotrauma
|
||||
GUIButton centerButton = new GUIButton(new RectTransform(new Vector2(1f), centerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight, anchor: Anchor.Center), style: "GUIButtonTransferArrow");
|
||||
|
||||
GUILayoutGroup inputLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), paddedTransferMenuLayout.RectTransform), childAnchor: Anchor.Center);
|
||||
GUINumberInput transferAmountInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), inputLayout.RectTransform), GUINumberInput.NumberType.Int, hidePlusMinusButtons: true)
|
||||
GUINumberInput transferAmountInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), inputLayout.RectTransform), NumberType.Int, hidePlusMinusButtons: true)
|
||||
{
|
||||
MinValueInt = 0
|
||||
};
|
||||
@@ -1050,149 +1091,195 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Identifier eventIdentifier = nameof(CreateWalletFrame).ToIdentifier();
|
||||
|
||||
ToggleTransferMenuIcon(transferMenuButton, open: isTransferMenuOpen);
|
||||
ToggleCenterButton(centerButton, isSending);
|
||||
|
||||
|
||||
if (!(Character.Controlled is { } myCharacter))
|
||||
{
|
||||
salarySlider.Enabled = false;
|
||||
transferAmountInput.Enabled = false;
|
||||
centerButton.Enabled = false;
|
||||
confirmButton.Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
|
||||
salarySlider.Enabled = hasMoneyPermissions;
|
||||
Wallet otherWallet;
|
||||
GameMain.Client?.OnPermissionChanged.RegisterOverwriteExisting(eventIdentifier, e => UpdateWalletInterface(registerEvents: false));
|
||||
UpdateWalletInterface(registerEvents: true);
|
||||
|
||||
switch (hasMoneyPermissions)
|
||||
void UpdateWalletInterface(bool registerEvents)
|
||||
{
|
||||
case true:
|
||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||
otherWallet = campaign.Bank;
|
||||
break;
|
||||
case false when character == myCharacter:
|
||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||
otherWallet = campaign.Bank;
|
||||
isSending = true;
|
||||
ToggleCenterButton(centerButton, isSending);
|
||||
break;
|
||||
default:
|
||||
rightName.Text = myCharacter.Name;
|
||||
otherWallet = campaign.PersonalWallet;
|
||||
break;
|
||||
}
|
||||
|
||||
MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
|
||||
updateButtonText();
|
||||
if (!hasMoneyPermissions)
|
||||
{
|
||||
if (character != Character.Controlled)
|
||||
if (!(Character.Controlled is { } myCharacter))
|
||||
{
|
||||
centerButton.Enabled = centerButton.CanBeFocused = false;
|
||||
salarySlider.Enabled = false;
|
||||
transferAmountInput.Enabled = false;
|
||||
centerButton.Enabled = false;
|
||||
confirmButton.Enabled = false;
|
||||
return;
|
||||
}
|
||||
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
||||
}
|
||||
|
||||
leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||
bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
|
||||
salarySlider.Enabled = hasMoneyPermissions;
|
||||
|
||||
UpdateAllInputs();
|
||||
switch (hasMoneyPermissions)
|
||||
{
|
||||
case true:
|
||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||
otherWallet = campaign.Bank;
|
||||
break;
|
||||
case false when character == myCharacter:
|
||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||
otherWallet = campaign.Bank;
|
||||
isSending = true;
|
||||
ToggleCenterButton(centerButton, isSending);
|
||||
break;
|
||||
default:
|
||||
rightName.Text = myCharacter.Name;
|
||||
otherWallet = campaign.PersonalWallet;
|
||||
break;
|
||||
}
|
||||
|
||||
MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
|
||||
|
||||
UpdatedConfirmButtonText();
|
||||
|
||||
if (!hasMoneyPermissions)
|
||||
{
|
||||
if (character != Character.Controlled)
|
||||
{
|
||||
centerButton.Enabled = centerButton.CanBeFocused = false;
|
||||
}
|
||||
|
||||
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
||||
}
|
||||
|
||||
leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||
|
||||
centerButton.OnClicked = (btn, o) =>
|
||||
{
|
||||
isSending = !isSending;
|
||||
updateButtonText();
|
||||
ToggleCenterButton(btn, isSending);
|
||||
UpdateAllInputs();
|
||||
return true;
|
||||
};
|
||||
|
||||
void updateButtonText()
|
||||
{
|
||||
confirmButton.Text = TextManager.Get(hasMoneyPermissions || isSending ? "confirm" : "crewwallet.requestmoney");
|
||||
}
|
||||
if (!registerEvents) { return; }
|
||||
|
||||
transferAmountInput.OnValueChanged = input =>
|
||||
{
|
||||
UpdateInputs();
|
||||
};
|
||||
|
||||
transferAmountInput.OnValueEntered = input =>
|
||||
{
|
||||
UpdateAllInputs();
|
||||
};
|
||||
|
||||
Identifier eventIdentifier = nameof(CreateWalletFrame).ToIdentifier();
|
||||
campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
|
||||
{
|
||||
if (e.Wallet == targetWallet)
|
||||
centerButton.OnClicked = (btn, o) =>
|
||||
{
|
||||
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
|
||||
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
||||
isSending = !isSending;
|
||||
UpdatedConfirmButtonText();
|
||||
ToggleCenterButton(btn, isSending);
|
||||
UpdateAllInputs();
|
||||
return true;
|
||||
};
|
||||
|
||||
transferAmountInput.OnValueChanged = input =>
|
||||
{
|
||||
UpdateInputs();
|
||||
};
|
||||
|
||||
transferAmountInput.OnValueEntered = input =>
|
||||
{
|
||||
UpdateAllInputs();
|
||||
};
|
||||
|
||||
resetButton.OnClicked = (button, o) =>
|
||||
{
|
||||
transferAmountInput.IntValue = 0;
|
||||
UpdateAllInputs();
|
||||
return true;
|
||||
};
|
||||
|
||||
confirmButton.OnClicked = (button, o) =>
|
||||
{
|
||||
int amount = transferAmountInput.IntValue;
|
||||
if (amount == 0) { return false; }
|
||||
|
||||
Option<Character> target1 = Option<Character>.Some(character),
|
||||
target2 = otherWallet == campaign.Bank ? Option<Character>.None() : Option<Character>.Some(myCharacter);
|
||||
if (isSending) { (target1, target2) = (target2, target1); }
|
||||
|
||||
SendTransaction(target1, target2, amount);
|
||||
isTransferMenuOpen = false;
|
||||
ToggleTransferMenuIcon(transferMenuButton, isTransferMenuOpen);
|
||||
return true;
|
||||
};
|
||||
|
||||
campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
|
||||
{
|
||||
if (e.Wallet == targetWallet)
|
||||
{
|
||||
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
|
||||
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
||||
}
|
||||
|
||||
UpdateAllInputs();
|
||||
});
|
||||
|
||||
registeredEvents.Add(eventIdentifier);
|
||||
|
||||
void UpdatedConfirmButtonText()
|
||||
{
|
||||
confirmButton.Text = TextManager.Get(hasMoneyPermissions || isSending ? "confirm" : "crewwallet.requestmoney");
|
||||
}
|
||||
UpdateAllInputs();
|
||||
});
|
||||
registeredEvents.Add(eventIdentifier);
|
||||
|
||||
resetButton.OnClicked = (button, o) =>
|
||||
{
|
||||
transferAmountInput.IntValue = 0;
|
||||
UpdateAllInputs();
|
||||
return true;
|
||||
};
|
||||
|
||||
confirmButton.OnClicked = (button, o) =>
|
||||
{
|
||||
int amount = transferAmountInput.IntValue;
|
||||
if (amount == 0) { return false; }
|
||||
|
||||
Option<Character> target1 = Option<Character>.Some(character),
|
||||
target2 = otherWallet == campaign.Bank ? Option<Character>.None() : Option<Character>.Some(myCharacter);
|
||||
if (isSending) { (target1, target2) = (target2, target1); }
|
||||
|
||||
SendTransaction(target1, target2, amount);
|
||||
isTransferMenuOpen = false;
|
||||
ToggleTransferMenuIcon(transferMenuButton, isTransferMenuOpen);
|
||||
return true;
|
||||
};
|
||||
|
||||
void UpdateAllInputs()
|
||||
{
|
||||
UpdateInputs();
|
||||
UpdateMaxInput();
|
||||
}
|
||||
|
||||
void UpdateInputs()
|
||||
{
|
||||
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
||||
if (transferAmountInput.IntValue == 0)
|
||||
void UpdateAllInputs()
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
|
||||
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
||||
UpdateInputs();
|
||||
UpdateMaxInput();
|
||||
}
|
||||
else if (isSending)
|
||||
|
||||
void UpdateInputs()
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
||||
rightBalance.TextColor = GUIStyle.Blue;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
||||
leftBalance.TextColor = GUIStyle.Red;
|
||||
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
||||
if (transferAmountInput.IntValue == 0)
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
|
||||
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
||||
}
|
||||
else if (isSending)
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
||||
rightBalance.TextColor = GUIStyle.Blue;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
||||
leftBalance.TextColor = GUIStyle.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
||||
rightBalance.TextColor = GUIStyle.Red;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
||||
leftBalance.TextColor = GUIStyle.Blue;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
void UpdateMaxInput()
|
||||
{
|
||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
||||
rightBalance.TextColor = GUIStyle.Red;
|
||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
||||
leftBalance.TextColor = GUIStyle.Blue;
|
||||
int maxValue = isSending ? targetWallet.Balance : otherWallet.Balance;
|
||||
transferAmountInput.MaxValueInt = maxValue;
|
||||
|
||||
transferAmountInput.Enabled = true;
|
||||
transferAmountInput.ToolTip = string.Empty;
|
||||
|
||||
if (!hasMoneyPermissions && GameMain.Client?.ServerSettings is { } serverSettings)
|
||||
{
|
||||
transferAmountInput.MaxValueInt = Math.Min(maxValue, serverSettings.MaximumMoneyTransferRequest);
|
||||
if (serverSettings.MaximumMoneyTransferRequest <= 0)
|
||||
{
|
||||
transferAmountInput.Enabled = false;
|
||||
transferAmountInput.ToolTip = TextManager.Get("wallettransferrequestdisabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMaxInput()
|
||||
void SetRewardText(int value, GUITextBlock block)
|
||||
{
|
||||
transferAmountInput.MaxValueInt = isSending ? targetWallet.Balance : otherWallet.Balance;
|
||||
var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.None());
|
||||
LocalizedString tooltip = string.Empty;
|
||||
block.TextColor = GUIStyle.TextColorNormal;
|
||||
|
||||
if (sum > 100)
|
||||
{
|
||||
tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}"));
|
||||
block.TextColor = GUIStyle.Orange;
|
||||
}
|
||||
|
||||
LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}");
|
||||
|
||||
block.Text = text;
|
||||
block.ToolTip = RichString.Rich(tooltip);
|
||||
}
|
||||
|
||||
static void ToggleTransferMenuIcon(GUIButton btn, bool open)
|
||||
@@ -1235,24 +1322,6 @@ namespace Barotrauma
|
||||
transfer.Write(msg);
|
||||
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
void SetRewardText(int value, GUITextBlock block)
|
||||
{
|
||||
var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.None());
|
||||
LocalizedString tooltip = string.Empty;
|
||||
block.TextColor = GUIStyle.TextColorNormal;
|
||||
|
||||
if (sum > 100)
|
||||
{
|
||||
tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}"));
|
||||
block.TextColor = GUIStyle.Orange;
|
||||
}
|
||||
|
||||
LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}");
|
||||
|
||||
block.Text = text;
|
||||
block.ToolTip = RichString.Rich(tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
|
||||
@@ -1490,10 +1559,10 @@ namespace Barotrauma
|
||||
RichString missionReputationString = RichString.Rich(reputationText, wrapMissionText(GUIStyle.Font));
|
||||
RichString missionDescriptionString = RichString.Rich(descriptionText, wrapMissionText(GUIStyle.Font));
|
||||
|
||||
Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString);
|
||||
Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString);
|
||||
Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString);
|
||||
Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString);
|
||||
Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString.SanitizedValue);
|
||||
Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString.SanitizedValue);
|
||||
Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString.SanitizedValue);
|
||||
Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString.SanitizedValue);
|
||||
|
||||
float ySize = missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y + missionReputationSize.Y + missionTextGroup.AbsoluteSpacing * 4;
|
||||
bool displayDifficulty = mission.Difficulty.HasValue;
|
||||
@@ -1740,9 +1809,6 @@ namespace Barotrauma
|
||||
talentButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter == null) { return; }
|
||||
|
||||
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = GUI.IntScale(15);
|
||||
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
||||
@@ -1762,13 +1828,20 @@ namespace Barotrauma
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||
}
|
||||
|
||||
/*Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter == null) { return; }
|
||||
|
||||
if (controlledCharacter.Info is null)
|
||||
{
|
||||
DebugConsole.ThrowError("No character info found for talent UI");
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
CharacterInfo info = controlledCharacter?.Info ?? GameMain.Client?.CharacterInfo;
|
||||
if (info == null) { return; }
|
||||
|
||||
Job job = info.Job;
|
||||
|
||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
@@ -1776,9 +1849,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
|
||||
|
||||
CharacterInfo info = controlledCharacter.Info;
|
||||
Job job = info.Job;
|
||||
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
||||
{
|
||||
@@ -1787,25 +1858,30 @@ namespace Barotrauma
|
||||
});
|
||||
|
||||
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), talentInfoLayoutGroup.RectTransform)) { RelativeSpacing = 0.05f };
|
||||
|
||||
|
||||
Vector2 nameSize = GUIStyle.SubHeadingFont.MeasureString(info.Name);
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont) { TextColor = job.Prefab.UIColor };
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
|
||||
nameBlock.RectTransform.NonScaledSize = nameSize.Pad(nameBlock.Padding).ToPoint();
|
||||
|
||||
Vector2 jobSize = GUIStyle.SmallFont.MeasureString(job.Name);
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
|
||||
if (!info.OmitJobInMenus)
|
||||
{
|
||||
nameBlock.TextColor = job.Prefab.UIColor;
|
||||
Vector2 jobSize = GUIStyle.SmallFont.MeasureString(job.Name);
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
|
||||
}
|
||||
|
||||
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + info.PersonalityTrait.Name.Replace(" ", "")));
|
||||
Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString);
|
||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
|
||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||
|
||||
GUIFrame endocrineFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
|
||||
GUIFrame talentsOutsideTreeFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
|
||||
|
||||
if (!(GameMain.NetworkMember is null))
|
||||
{
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), endocrineFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), talentsOutsideTreeFrame.RectTransform, Anchor.TopLeft),
|
||||
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
@@ -1844,6 +1920,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
|
||||
characterSettingsFrame!.Visible = false;
|
||||
talentFrameMain.Visible = true;
|
||||
return true;
|
||||
@@ -1852,13 +1929,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<TalentPrefab> endocrineTalents = info.GetEndocrineTalents().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
|
||||
IEnumerable<TalentPrefab> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
|
||||
|
||||
if (endocrineTalents.Count() > 0)
|
||||
if (talentsOutsideTree.Count() > 0)
|
||||
{
|
||||
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), endocrineFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
|
||||
//TODO: replace with something more generic
|
||||
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), talentsOutsideTreeFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
|
||||
{
|
||||
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", endocrineTalents.Select(e => e.DisplayName))}"
|
||||
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", talentsOutsideTree.Select(e => e.DisplayName))}"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1870,49 +1948,55 @@ namespace Barotrauma
|
||||
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
|
||||
|
||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
CreateTalentSkillList(controlledCharacter, info, skillListBox);
|
||||
|
||||
if (!TalentTree.JobTalentTrees.TryGet(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
||||
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
if (controlledCharacter != null)
|
||||
{
|
||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||
if (!TalentTree.JobTalentTrees.TryGet(info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
selectedTalents = info.GetUnlockedTalentsInTree().ToList();
|
||||
|
||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
||||
|
||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground");
|
||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
|
||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground")
|
||||
{
|
||||
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||
};
|
||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||
};
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
|
||||
if (subTree.TalentOptionStages.Count <= i) { continue; }
|
||||
|
||||
if (subTree.TalentOptionStages.Count > i)
|
||||
{
|
||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||
|
||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
foreach (TalentPrefab talent in talentOption.Talents.OrderBy(t => t.Identifier))
|
||||
@@ -1929,6 +2013,7 @@ namespace Barotrauma
|
||||
ToolTip = RichString.Rich(talent.DisplayName + "\n\n" + talent.Description),
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
Enabled = controlledCharacter != null,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
@@ -1961,7 +2046,7 @@ namespace Barotrauma
|
||||
},
|
||||
};
|
||||
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = Color.Transparent;
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = talentButton.DisabledColor = Color.Transparent;
|
||||
|
||||
GUIComponent iconImage;
|
||||
if (talent.Icon is null)
|
||||
@@ -1971,6 +2056,7 @@ namespace Barotrauma
|
||||
OutlineColor = GUIStyle.Red,
|
||||
TextColor = GUIStyle.Red,
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
@@ -1979,63 +2065,63 @@ namespace Barotrauma
|
||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor * 0.5f,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
|
||||
iconImage.Enabled = talentButton.Enabled;
|
||||
talentButtons.Add((talentButton, iconImage));
|
||||
}
|
||||
|
||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
}
|
||||
}
|
||||
}
|
||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||
|
||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
||||
{
|
||||
IsHorizontal = true,
|
||||
};
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
||||
{
|
||||
IsHorizontal = true,
|
||||
};
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true,
|
||||
ToolTip = TextManager.Get("experiencetooltip")
|
||||
};
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true,
|
||||
ToolTip = TextManager.Get("experiencetooltip")
|
||||
};
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||
|
||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ResetTalentSelection
|
||||
};
|
||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ResetTalentSelection
|
||||
};
|
||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
}
|
||||
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
||||
private void CreateTalentSkillList(Character character, CharacterInfo info, GUIListBox parent)
|
||||
{
|
||||
parent.Content.ClearChildren();
|
||||
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||
foreach (Skill skill in character.Info.Job.GetSkills())
|
||||
foreach (Skill skill in info.Job.GetSkills())
|
||||
{
|
||||
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
||||
|
||||
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value)));
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
||||
|
||||
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
||||
float modifiedSkillLevel = character?.GetSkillLevel(skill.Identifier) ?? skill.Level;
|
||||
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
||||
{
|
||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
||||
@@ -2129,7 +2215,7 @@ namespace Barotrauma
|
||||
talentButton.icon.HoverColor = hoverColor;
|
||||
}
|
||||
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
CreateTalentSkillList(controlledCharacter, controlledCharacter.Info, skillListBox);
|
||||
}
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
@@ -2157,6 +2243,7 @@ namespace Barotrauma
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter?.Info == null) { return false; }
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace Barotrauma
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of fixed area around the slice area
|
||||
/// </summary>
|
||||
public Point NonSliceSize { get; set; }
|
||||
|
||||
public bool MaintainAspectRatio
|
||||
{
|
||||
get;
|
||||
@@ -72,6 +77,7 @@ namespace Barotrauma
|
||||
maxBorderScale = element.GetAttributeFloat("minborderscale", 10.0f);
|
||||
|
||||
Rectangle slice = new Rectangle((int)sliceVec.X, (int)sliceVec.Y, (int)(sliceVec.Z - sliceVec.X), (int)(sliceVec.W - sliceVec.Y));
|
||||
NonSliceSize = new Point(Sprite.SourceRect.Width - slice.Width, Sprite.SourceRect.Height - slice.Height);
|
||||
|
||||
Slices = new Rectangle[9];
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ namespace Barotrauma
|
||||
button.Enabled = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, overrideConfirmButtonSound: GUISoundType.ConfirmTransaction);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,7 +497,7 @@ namespace Barotrauma
|
||||
button.Enabled = false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, overrideConfirmButtonSound: GUISoundType.ConfirmTransaction);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -539,7 +539,7 @@ namespace Barotrauma
|
||||
GameMain.Client?.SendCampaignState();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, overrideConfirmButtonSound: GUISoundType.ConfirmTransaction);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -589,7 +589,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
||||
new GUITextBlock(rectT(1, 0, textLayout), TextManager.FormatCurrency(price));
|
||||
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = PlayerBalance >= price && !isDisabled, OnClicked = onPressed };
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { Enabled = PlayerBalance >= price && !isDisabled, OnClicked = onPressed };
|
||||
contentLayout.Recalculate();
|
||||
buyButtonLayout.Recalculate();
|
||||
|
||||
@@ -622,7 +622,8 @@ namespace Barotrauma
|
||||
PadBottom = true,
|
||||
SelectTop = true,
|
||||
ClampScrollToElements = true,
|
||||
Spacing = 8
|
||||
Spacing = 8,
|
||||
PlaySoundOnSelect = true
|
||||
};
|
||||
|
||||
Dictionary<UpgradeCategory, List<UpgradePrefab>> upgrades = new Dictionary<UpgradeCategory, List<UpgradePrefab>>();
|
||||
@@ -1123,7 +1124,10 @@ namespace Barotrauma
|
||||
{
|
||||
priceText.Text = string.Empty;
|
||||
}
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: buttonStyle) { Enabled = false };
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: buttonStyle)
|
||||
{
|
||||
Enabled = false
|
||||
};
|
||||
if (upgradePrefab != null)
|
||||
{
|
||||
var increaseText = new GUITextBlock(rectT(1, 0.2f, buyButtonLayout), "", textAlignment: Alignment.Center);
|
||||
@@ -1212,7 +1216,7 @@ namespace Barotrauma
|
||||
Campaign.UpgradeManager.PurchaseUpgrade(prefab, category);
|
||||
GameMain.Client?.SendCampaignState();
|
||||
return true;
|
||||
});
|
||||
}, overrideConfirmButtonSound: GUISoundType.ConfirmTransaction);
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -1400,7 +1404,7 @@ namespace Barotrauma
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonClicked() && selectedUpgradeTab == UpgradeTab.Upgrade && currentStoreLayout != null)
|
||||
{
|
||||
ScrollToCategory(data => data.Category.IsWallUpgrade);
|
||||
ScrollToCategory(data => data.Category.IsWallUpgrade, GUIListBox.PlaySelectSound.Yes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1682,7 +1686,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollToCategory(Predicate<CategoryData> predicate)
|
||||
private void ScrollToCategory(Predicate<CategoryData> predicate, GUIListBox.PlaySelectSound playSelectSound = GUIListBox.PlaySelectSound.No)
|
||||
{
|
||||
if (currentStoreLayout == null) { return; }
|
||||
|
||||
@@ -1690,7 +1694,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (child.UserData is CategoryData data && predicate(data))
|
||||
{
|
||||
currentStoreLayout.ScrollToElement(child);
|
||||
currentStoreLayout.ScrollToElement(child, playSelectSound);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Barotrauma
|
||||
private Color SubmarineColor => GUIStyle.Orange;
|
||||
private Point createdForResolution;
|
||||
|
||||
public static VotingInterface CreateSubmarineVotingInterface(Client starter, SubmarineInfo info, VoteType type, float votingTime)
|
||||
public static VotingInterface CreateSubmarineVotingInterface(Client starter, SubmarineInfo info, VoteType type, bool transferItems, float votingTime)
|
||||
{
|
||||
if (starter == null || info == null) { return null; }
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Barotrauma
|
||||
getMaxVotes = () => GameMain.NetworkMember?.Voting?.GetVoteCountMax(type) ?? 0,
|
||||
};
|
||||
subVoting.onVoteEnd = () => subVoting.SendSubmarineVoteEndMessage(info, type);
|
||||
subVoting.SetSubmarineVotingText(starter, info, type);
|
||||
subVoting.SetSubmarineVotingText(starter, info, transferItems, type);
|
||||
subVoting.Initialize(starter, type);
|
||||
return subVoting;
|
||||
}
|
||||
@@ -160,19 +160,21 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#region Submarine Voting
|
||||
private void SetSubmarineVotingText(Client starter, SubmarineInfo info, VoteType type)
|
||||
|
||||
private void SetSubmarineVotingText(Client starter, SubmarineInfo info, bool transferItems, VoteType type)
|
||||
{
|
||||
string name = starter.Name;
|
||||
JobPrefab prefab = starter?.Character?.Info?.Job?.Prefab;
|
||||
Color nameColor = prefab != null ? prefab.UIColor : Color.White;
|
||||
string characterRichString = $"‖color:{nameColor.R},{nameColor.G},{nameColor.B}‖{name}‖color:end‖";
|
||||
string submarineRichString = $"‖color:{SubmarineColor.R},{SubmarineColor.G},{SubmarineColor.B}‖{info.DisplayName}‖color:end‖";
|
||||
|
||||
string tag = string.Empty;
|
||||
LocalizedString text = string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
text = TextManager.GetWithVariables("submarinepurchaseandswitchvote",
|
||||
tag = transferItems ? "submarinepurchaseandswitchwithitemsvote" : "submarinepurchaseandswitchvote";
|
||||
text = TextManager.GetWithVariables(tag,
|
||||
("[playername]", characterRichString),
|
||||
("[submarinename]", submarineRichString),
|
||||
("[amount]", info.Price.ToString()),
|
||||
@@ -189,7 +191,8 @@ namespace Barotrauma
|
||||
int deliveryFee = SubmarineSelection.DeliveryFeePerDistanceTravelled * GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
text = TextManager.GetWithVariables("submarineswitchfeevote",
|
||||
tag = transferItems ? "submarineswitchwithitemsfeevote" : "submarineswitchfeevote";
|
||||
text = TextManager.GetWithVariables(tag,
|
||||
("[playername]", characterRichString),
|
||||
("[submarinename]", submarineRichString),
|
||||
("[locationname]", endLocation.Name),
|
||||
@@ -198,13 +201,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
text = TextManager.GetWithVariables("submarineswitchnofeevote",
|
||||
tag = transferItems ? "submarineswitchwithitemsnofeevote" : "submarineswitchnofeevote";
|
||||
text = TextManager.GetWithVariables(tag,
|
||||
("[playername]", characterRichString),
|
||||
("[submarinename]", submarineRichString));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
votingOnText = RichString.Rich(text);
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,8 @@ namespace Barotrauma
|
||||
public static bool CancelQuickStart;
|
||||
#endif
|
||||
|
||||
public static ChatMode ActiveChatMode { get; set; } = ChatMode.Radio;
|
||||
|
||||
public GameMain(string[] args)
|
||||
{
|
||||
Content.RootDirectory = "Content";
|
||||
@@ -280,9 +282,9 @@ namespace Barotrauma
|
||||
screen.OnFileDropped(filePath, extension);
|
||||
}
|
||||
|
||||
public void ApplyGraphicsSettings()
|
||||
public void ApplyGraphicsSettings(bool recalculateFontsAndStyles = false)
|
||||
{
|
||||
void updateConfig()
|
||||
static void updateConfig()
|
||||
{
|
||||
var config = GameSettings.CurrentConfig;
|
||||
config.Graphics.Width = GraphicsWidth;
|
||||
@@ -321,6 +323,12 @@ namespace Barotrauma
|
||||
|
||||
defaultViewport = GraphicsDevice.Viewport;
|
||||
|
||||
if (recalculateFontsAndStyles)
|
||||
{
|
||||
GUIStyle.RecalculateFonts();
|
||||
GUIStyle.RecalculateSizeRestrictions();
|
||||
}
|
||||
|
||||
ResolutionChanged?.Invoke();
|
||||
}
|
||||
|
||||
@@ -546,6 +554,10 @@ namespace Barotrauma
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
#if DEBUG
|
||||
LevelGenerationParams.CheckValidity();
|
||||
#endif
|
||||
|
||||
MainMenuScreen.Select();
|
||||
|
||||
foreach (Identifier steamError in SteamManager.InitializationErrors)
|
||||
@@ -920,7 +932,7 @@ namespace Barotrauma
|
||||
updateCount++;
|
||||
|
||||
sw.Stop();
|
||||
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
|
||||
PerformanceCounter.AddElapsedTicks("Update", sw.ElapsedTicks);
|
||||
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||
}
|
||||
|
||||
@@ -939,6 +951,23 @@ namespace Barotrauma
|
||||
Timing.Accumulator = 0.0f;
|
||||
}
|
||||
|
||||
private void FixRazerCortex()
|
||||
{
|
||||
#if WINDOWS
|
||||
//Razer Cortex's overlay is broken.
|
||||
//For whatever reason, it messes up the blendstate and,
|
||||
//because MonoGame reasonably assumes that you don't need
|
||||
//to touch it if you're setting it to the exact same one
|
||||
//you were already using, it doesn't fix Razer's mess.
|
||||
//Therefore, we need to change the blendstate TWICE:
|
||||
//once to force MonoGame to change it, and then again to
|
||||
//use the blendstate we actually want.
|
||||
var oldBlendState = GraphicsDevice.BlendState;
|
||||
GraphicsDevice.BlendState = oldBlendState == BlendState.Opaque ? BlendState.NonPremultiplied : BlendState.Opaque;
|
||||
GraphicsDevice.BlendState = oldBlendState;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when the game should draw itself.
|
||||
/// </summary>
|
||||
@@ -946,7 +975,9 @@ namespace Barotrauma
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
|
||||
FixRazerCortex();
|
||||
|
||||
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds;
|
||||
|
||||
if (Timing.FrameLimit > 0)
|
||||
@@ -1003,7 +1034,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
|
||||
PerformanceCounter.AddElapsedTicks("Draw", sw.ElapsedTicks);
|
||||
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||
}
|
||||
|
||||
@@ -1039,7 +1070,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedFriendlyOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
||||
{
|
||||
spCampaign.Map.CurrentLocation.AddStock(spCampaign.CargoManager.SoldItems);
|
||||
spCampaign.CargoManager.ClearSoldItemsProjSpecific();
|
||||
@@ -1164,7 +1195,7 @@ namespace Barotrauma
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportgithubform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
|
||||
{
|
||||
UserData = "https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md",
|
||||
UserData = "https://github.com/Regalis11/Barotrauma/issues/new/choose",
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
ShowOpenUrlInWebBrowserPrompt(userdata as string);
|
||||
|
||||
@@ -81,7 +81,6 @@ namespace Barotrauma
|
||||
: this(isSinglePlayer)
|
||||
{
|
||||
AddCharacterElements(element);
|
||||
ActiveOrdersElement = element.GetChildElement("activeorders");
|
||||
}
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
@@ -148,9 +147,10 @@ namespace Barotrauma
|
||||
string msgCommand = ChatMessage.GetChatMessageCommand(text, out string msg);
|
||||
// add to local history
|
||||
ChatBox.ChatManager.Store(text);
|
||||
WifiComponent headset = null;
|
||||
ChatMessageType messageType =
|
||||
((msgCommand == "r" || msgCommand == "radio") && ChatMessage.CanUseRadio(Character.Controlled, out headset)) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
bool isUsingRadioMode = GameMain.ActiveChatMode == ChatMode.Radio;
|
||||
bool containsRadioCommand = msgCommand == "r" || msgCommand == "radio";
|
||||
bool canUseRadio = ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent headset);
|
||||
ChatMessageType messageType = ((isUsingRadioMode && msgCommand == "") || containsRadioCommand) && canUseRadio ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
AddSinglePlayerChatMessage(
|
||||
Character.Controlled.Info.Name,
|
||||
msg, messageType,
|
||||
@@ -1554,40 +1554,9 @@ namespace Barotrauma
|
||||
{
|
||||
ChatBox.Update(deltaTime);
|
||||
ChatBox.InputBox.Visible = Character.Controlled != null;
|
||||
|
||||
if (!DebugConsole.IsOpen && ChatBox.InputBox.Visible && GUI.KeyboardDispatcher.Subscriber == null)
|
||||
if (!DebugConsole.IsOpen && ChatBox.InputBox.Visible && GUI.KeyboardDispatcher.Subscriber == null && !ChatBox.InputBox.Selected)
|
||||
{
|
||||
if (PlayerInput.KeyHit(InputType.Chat) && !ChatBox.InputBox.Selected)
|
||||
{
|
||||
ChatBox.InputBox.AddToGUIUpdateList();
|
||||
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
|
||||
if (!ChatBox.ToggleOpen)
|
||||
{
|
||||
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
|
||||
ChatBox.ToggleOpen = true;
|
||||
}
|
||||
ChatBox.InputBox.Select(ChatBox.InputBox.Text.Length);
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(InputType.RadioChat) && !ChatBox.InputBox.Selected)
|
||||
{
|
||||
if (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100)
|
||||
{
|
||||
ChatBox.InputBox.AddToGUIUpdateList();
|
||||
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
|
||||
if (!ChatBox.ToggleOpen)
|
||||
{
|
||||
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
|
||||
ChatBox.ToggleOpen = true;
|
||||
}
|
||||
|
||||
if (!ChatBox.InputBox.Text.StartsWith(ChatBox.RadioChatString))
|
||||
{
|
||||
ChatBox.InputBox.Text = ChatBox.RadioChatString;
|
||||
}
|
||||
ChatBox.InputBox.Select(ChatBox.InputBox.Text.Length);
|
||||
}
|
||||
}
|
||||
ChatBox.ApplySelectionInputs();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1609,7 +1578,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (character == Character.Controlled && crewList.SelectedComponent != characterComponent)
|
||||
{
|
||||
crewList.Select(character, force: true);
|
||||
crewList.Select(character, GUIListBox.Force.Yes);
|
||||
}
|
||||
// Icon colors might change based on the target so we check if they need to be updated
|
||||
if (GetCurrentOrderIconList(characterComponent) is GUIListBox currentOrderIconList)
|
||||
@@ -3661,9 +3630,9 @@ namespace Barotrauma
|
||||
crewList.ClearChildren();
|
||||
}
|
||||
|
||||
public void Save(XElement parentElement)
|
||||
public XElement Save(XElement parentElement)
|
||||
{
|
||||
XElement element = new XElement("crew");
|
||||
var element = new XElement("crew");
|
||||
for (int i = 0; i < characterInfos.Count; i++)
|
||||
{
|
||||
var ci = characterInfos[i];
|
||||
@@ -3674,8 +3643,8 @@ namespace Barotrauma
|
||||
infoElement.Add(new XAttribute("crewlistindex", ci.CrewListIndex));
|
||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||
}
|
||||
SaveActiveOrders(element);
|
||||
parentElement.Add(element);
|
||||
parentElement?.Add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
public static void ClientReadActiveOrders(IReadMessage inc)
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Barotrauma
|
||||
|
||||
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged)
|
||||
{
|
||||
if (Owner is Some<Character> { Value: var character })
|
||||
{
|
||||
if (!character.IsPlayer) { return; }
|
||||
}
|
||||
|
||||
CampaignMode campaign = GameMain.GameSession?.Campaign;
|
||||
WalletChangedData data = new WalletChangedData
|
||||
{
|
||||
|
||||
@@ -587,196 +587,78 @@ namespace Barotrauma
|
||||
//static because we may need to instantiate the campaign if it hasn't been done yet
|
||||
public static void ClientRead(IReadMessage msg)
|
||||
{
|
||||
NetFlags requiredFlags = (NetFlags)msg.ReadUInt16();
|
||||
|
||||
bool isFirstRound = msg.ReadBoolean();
|
||||
byte campaignID = msg.ReadByte();
|
||||
UInt16 updateID = msg.ReadUInt16();
|
||||
UInt16 saveID = msg.ReadUInt16();
|
||||
string mapSeed = msg.ReadString();
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
|
||||
byte selectedMissionCount = msg.ReadByte();
|
||||
List<int> selectedMissionIndices = new List<int>();
|
||||
for (int i = 0; i < selectedMissionCount; i++)
|
||||
{
|
||||
selectedMissionIndices.Add(msg.ReadByte());
|
||||
}
|
||||
|
||||
ushort ownedSubCount = msg.ReadUInt16();
|
||||
List<ushort> ownedSubIndices = new List<ushort>();
|
||||
for (int i = 0; i < ownedSubCount; i++)
|
||||
{
|
||||
ownedSubIndices.Add(msg.ReadUInt16());
|
||||
}
|
||||
|
||||
bool allowDebugTeleport = msg.ReadBoolean();
|
||||
float? reputation = null;
|
||||
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
|
||||
|
||||
Dictionary<Identifier, float> factionReps = new Dictionary<Identifier, float>();
|
||||
byte factionsCount = msg.ReadByte();
|
||||
for (int i = 0; i < factionsCount; i++)
|
||||
{
|
||||
factionReps.Add(msg.ReadIdentifier(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
bool forceMapUI = msg.ReadBoolean();
|
||||
|
||||
bool purchasedHullRepairs = msg.ReadBoolean();
|
||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||
|
||||
byte missionCount = msg.ReadByte();
|
||||
var availableMissions = new List<(Identifier Identifier, byte ConnectionIndex)>();
|
||||
for (int i = 0; i < missionCount; i++)
|
||||
{
|
||||
Identifier missionIdentifier = msg.ReadIdentifier();
|
||||
byte connectionIndex = msg.ReadByte();
|
||||
availableMissions.Add((missionIdentifier, connectionIndex));
|
||||
}
|
||||
|
||||
var storeBalances = new Dictionary<Identifier, UInt16>();
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
byte storeCount = msg.ReadByte();
|
||||
for (int i = 0; i < storeCount; i++)
|
||||
{
|
||||
Identifier identifier = msg.ReadIdentifier();
|
||||
UInt16 storeBalance = msg.ReadUInt16();
|
||||
storeBalances.Add(identifier, storeBalance);
|
||||
}
|
||||
}
|
||||
|
||||
var buyCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||
var subSellCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||
var purchasedItems = ReadPurchasedItems(msg, sender: null);
|
||||
var soldItems = ReadSoldItems(msg);
|
||||
|
||||
ushort pendingUpgradeCount = msg.ReadUInt16();
|
||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||
for (int i = 0; i < pendingUpgradeCount; i++)
|
||||
{
|
||||
Identifier upgradeIdentifier = msg.ReadIdentifier();
|
||||
UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier);
|
||||
Identifier categoryIdentifier = msg.ReadIdentifier();
|
||||
UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier);
|
||||
int upgradeLevel = msg.ReadByte();
|
||||
if (prefab == null || category == null) { continue; }
|
||||
pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||
}
|
||||
|
||||
ushort purchasedItemSwapCount = msg.ReadUInt16();
|
||||
List<PurchasedItemSwap> purchasedItemSwaps = new List<PurchasedItemSwap>();
|
||||
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||
{
|
||||
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||
Identifier itemToInstallIdentifier = msg.ReadIdentifier();
|
||||
ItemPrefab itemToInstall = itemToInstallIdentifier.IsEmpty ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||
if (!(Entity.FindEntityByID(itemToRemoveID) is Item itemToRemove)) { continue; }
|
||||
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
}
|
||||
|
||||
bool hasCharacterData = msg.ReadBoolean();
|
||||
CharacterInfo myCharacterInfo = null;
|
||||
if (hasCharacterData)
|
||||
{
|
||||
myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
|
||||
}
|
||||
bool refreshCampaignUI = false;
|
||||
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID)
|
||||
{
|
||||
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);
|
||||
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Unsure, mapSeed);
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty, mapSeed);
|
||||
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
|
||||
campaign.CampaignID = campaignID;
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
|
||||
//server has a newer save file
|
||||
if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID))
|
||||
{
|
||||
campaign.PendingSaveID = saveID;
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID))
|
||||
{
|
||||
campaign.SuppressStateSending = true;
|
||||
campaign.IsFirstRound = isFirstRound;
|
||||
if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID)) { campaign.PendingSaveID = saveID; }
|
||||
campaign.IsFirstRound = isFirstRound;
|
||||
|
||||
//we need to have the latest save file to display location/mission/store
|
||||
if (campaign.LastSaveID == saveID)
|
||||
if (requiredFlags.HasFlag(NetFlags.Misc))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (Misc)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool purchasedHullRepairs = msg.ReadBoolean();
|
||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||
if (ShouldApply(NetFlags.Misc, id, requireUpToDateSave: false))
|
||||
{
|
||||
refreshCampaignUI = campaign.PurchasedHullRepairs != purchasedHullRepairs ||
|
||||
campaign.PurchasedItemRepairs != purchasedItemRepairs ||
|
||||
campaign.PurchasedLostShuttles != purchasedLostShuttles;
|
||||
campaign.PurchasedHullRepairs = purchasedHullRepairs;
|
||||
campaign.PurchasedItemRepairs = purchasedItemRepairs;
|
||||
campaign.PurchasedLostShuttles = purchasedLostShuttles;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.MapAndMissions))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (MapAndMissions)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool forceMapUI = msg.ReadBoolean();
|
||||
bool allowDebugTeleport = msg.ReadBoolean();
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
|
||||
byte missionCount = msg.ReadByte();
|
||||
var availableMissions = new List<(Identifier Identifier, byte ConnectionIndex)>();
|
||||
for (int i = 0; i < missionCount; i++)
|
||||
{
|
||||
Identifier missionIdentifier = msg.ReadIdentifier();
|
||||
byte connectionIndex = msg.ReadByte();
|
||||
availableMissions.Add((missionIdentifier, connectionIndex));
|
||||
}
|
||||
|
||||
byte selectedMissionCount = msg.ReadByte();
|
||||
List<int> selectedMissionIndices = new List<int>();
|
||||
for (int i = 0; i < selectedMissionCount; i++)
|
||||
{
|
||||
selectedMissionIndices.Add(msg.ReadByte());
|
||||
}
|
||||
|
||||
if (ShouldApply(NetFlags.MapAndMissions, id, requireUpToDateSave: true))
|
||||
{
|
||||
campaign.ForceMapUI = forceMapUI;
|
||||
|
||||
UpgradeStore.WaitForServerUpdate = false;
|
||||
|
||||
campaign.Map.AllowDebugTeleport = allowDebugTeleport;
|
||||
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
||||
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
campaign.Map.SelectMission(selectedMissionIndices);
|
||||
|
||||
GameMain.GameSession.OwnedSubmarines.Clear();
|
||||
foreach (int ownedSubIndex in ownedSubIndices)
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[ownedSubIndex];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.Add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
campaign.Map.AllowDebugTeleport = allowDebugTeleport;
|
||||
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
|
||||
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
|
||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||
campaign.CargoManager.SetSoldItems(soldItems);
|
||||
foreach (var balance in storeBalances)
|
||||
{
|
||||
if (campaign.Map.CurrentLocation.GetStore(balance.Key) is { } store)
|
||||
{
|
||||
store.Balance = balance.Value;
|
||||
}
|
||||
}
|
||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
{
|
||||
if (purchasedItemSwap.ItemToInstall == null)
|
||||
{
|
||||
campaign.UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove, force: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
campaign.UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, force: true);
|
||||
}
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||
{
|
||||
item.PendingItemSwap = null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (identifier, rep) in factionReps)
|
||||
{
|
||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier == identifier);
|
||||
if (faction?.Reputation != null)
|
||||
{
|
||||
faction.Reputation.SetReputation(rep);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\".");
|
||||
}
|
||||
}
|
||||
|
||||
if (reputation.HasValue)
|
||||
{
|
||||
campaign.Map.CurrentLocation.Reputation.SetReputation(reputation.Value);
|
||||
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||
}
|
||||
|
||||
foreach (var availableMission in availableMissions)
|
||||
{
|
||||
MissionPrefab missionPrefab = MissionPrefab.Prefabs.Find(mp => mp.Identifier == availableMission.Identifier);
|
||||
@@ -800,36 +682,269 @@ namespace Barotrauma
|
||||
campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection);
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
|
||||
bool shouldRefresh = campaign.PurchasedHullRepairs != purchasedHullRepairs ||
|
||||
campaign.PurchasedItemRepairs != purchasedItemRepairs ||
|
||||
campaign.PurchasedLostShuttles != purchasedLostShuttles;
|
||||
|
||||
campaign.PurchasedHullRepairs = purchasedHullRepairs;
|
||||
campaign.PurchasedItemRepairs = purchasedItemRepairs;
|
||||
campaign.PurchasedLostShuttles = purchasedLostShuttles;
|
||||
|
||||
if (shouldRefresh)
|
||||
{
|
||||
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||
}
|
||||
|
||||
if (myCharacterInfo != null)
|
||||
{
|
||||
GameMain.Client.CharacterInfo = myCharacterInfo;
|
||||
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
|
||||
campaign.Map.SelectMission(selectedMissionIndices);
|
||||
ReadStores(msg, apply: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
|
||||
ReadStores(msg, apply: false);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.SubList))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (SubList)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
ushort ownedSubCount = msg.ReadUInt16();
|
||||
List<ushort> ownedSubIndices = new List<ushort>();
|
||||
for (int i = 0; i < ownedSubCount; i++)
|
||||
{
|
||||
ownedSubIndices.Add(msg.ReadUInt16());
|
||||
}
|
||||
|
||||
campaign.lastUpdateID = updateID;
|
||||
campaign.SuppressStateSending = false;
|
||||
if (ShouldApply(NetFlags.SubList, id, requireUpToDateSave: false))
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.Clear();
|
||||
foreach (int ownedSubIndex in ownedSubIndices)
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[ownedSubIndex];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.Add(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.UpgradeManager))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (UpgradeManager)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
|
||||
ushort pendingUpgradeCount = msg.ReadUInt16();
|
||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||
for (int i = 0; i < pendingUpgradeCount; i++)
|
||||
{
|
||||
Identifier upgradeIdentifier = msg.ReadIdentifier();
|
||||
UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier);
|
||||
Identifier categoryIdentifier = msg.ReadIdentifier();
|
||||
UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier);
|
||||
int upgradeLevel = msg.ReadByte();
|
||||
if (prefab == null || category == null) { continue; }
|
||||
pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||
}
|
||||
|
||||
ushort purchasedItemSwapCount = msg.ReadUInt16();
|
||||
List<PurchasedItemSwap> purchasedItemSwaps = new List<PurchasedItemSwap>();
|
||||
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||
{
|
||||
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||
Identifier itemToInstallIdentifier = msg.ReadIdentifier();
|
||||
ItemPrefab itemToInstall = itemToInstallIdentifier.IsEmpty ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||
if (!(Entity.FindEntityByID(itemToRemoveID) is Item itemToRemove)) { continue; }
|
||||
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
}
|
||||
|
||||
if (!Submarine.Unloading && !(Submarine.MainSub is { Loading: true }) &&
|
||||
ShouldApply(NetFlags.UpgradeManager, id, requireUpToDateSave: true))
|
||||
{
|
||||
UpgradeStore.WaitForServerUpdate = false;
|
||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
{
|
||||
if (purchasedItemSwap.ItemToInstall == null)
|
||||
{
|
||||
campaign.UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove, force: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
campaign.UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, force: true);
|
||||
}
|
||||
}
|
||||
foreach (Item item in Item.ItemList.ToList())
|
||||
{
|
||||
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||
{
|
||||
item.PendingItemSwap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.ItemsInBuyCrate))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (ItemsInBuyCrate)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
var buyCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||
if (ShouldApply(NetFlags.ItemsInBuyCrate, id, requireUpToDateSave: true))
|
||||
{
|
||||
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
|
||||
campaign.SetLastUpdateIdForFlag(NetFlags.ItemsInBuyCrate, id);
|
||||
ReadStores(msg, apply: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStores(msg, apply: false);
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.ItemsInSellFromSubCrate))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (ItemsInSellFromSubCrate)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
var subSellCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||
if (ShouldApply(NetFlags.ItemsInSellFromSubCrate, id, requireUpToDateSave: true))
|
||||
{
|
||||
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
|
||||
campaign.SetLastUpdateIdForFlag(NetFlags.ItemsInSellFromSubCrate, id);
|
||||
ReadStores(msg, apply: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStores(msg, apply: false);
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.PurchasedItems))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (PuchasedItems)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
var purchasedItems = ReadPurchasedItems(msg, sender: null);
|
||||
if (ShouldApply(NetFlags.PurchasedItems, id, requireUpToDateSave: true))
|
||||
{
|
||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||
campaign.SetLastUpdateIdForFlag(NetFlags.PurchasedItems, id);
|
||||
ReadStores(msg, apply: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStores(msg, apply: false);
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.SoldItems))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (SoldItems)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
var soldItems = ReadSoldItems(msg);
|
||||
if (ShouldApply(NetFlags.SoldItems, id, requireUpToDateSave: true))
|
||||
{
|
||||
campaign.CargoManager.SetSoldItems(soldItems);
|
||||
campaign.SetLastUpdateIdForFlag(NetFlags.SoldItems, id);
|
||||
ReadStores(msg, apply: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStores(msg, apply: false);
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.Reputation))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (Reputation)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
float? reputation = null;
|
||||
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
|
||||
Dictionary<Identifier, float> factionReps = new Dictionary<Identifier, float>();
|
||||
byte factionsCount = msg.ReadByte();
|
||||
for (int i = 0; i < factionsCount; i++)
|
||||
{
|
||||
factionReps.Add(msg.ReadIdentifier(), msg.ReadSingle());
|
||||
}
|
||||
if (ShouldApply(NetFlags.Reputation, id, requireUpToDateSave: true))
|
||||
{
|
||||
if (reputation.HasValue)
|
||||
{
|
||||
campaign.Map.CurrentLocation.Reputation.SetReputation(reputation.Value);
|
||||
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||
}
|
||||
foreach (var (identifier, rep) in factionReps)
|
||||
{
|
||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier == identifier);
|
||||
if (faction?.Reputation != null)
|
||||
{
|
||||
faction.Reputation.SetReputation(rep);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.CharacterInfo))
|
||||
{
|
||||
DebugConsole.Log("Received campaign update (CharacterInfo)");
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool hasCharacterData = msg.ReadBoolean();
|
||||
CharacterInfo myCharacterInfo = null;
|
||||
if (hasCharacterData)
|
||||
{
|
||||
myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
|
||||
}
|
||||
if (ShouldApply(NetFlags.CharacterInfo, id, requireUpToDateSave: true))
|
||||
{
|
||||
if (myCharacterInfo != null)
|
||||
{
|
||||
GameMain.Client.CharacterInfo = myCharacterInfo;
|
||||
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
campaign.SuppressStateSending = true;
|
||||
//we need to have the latest save file to display location/mission/store
|
||||
if (campaign.LastSaveID == saveID)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
if (refreshCampaignUI)
|
||||
{
|
||||
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||
}
|
||||
campaign.SuppressStateSending = false;
|
||||
|
||||
bool ShouldApply(NetFlags flag, UInt16 id, bool requireUpToDateSave)
|
||||
{
|
||||
if (NetIdUtils.IdMoreRecent(id, campaign.GetLastUpdateIdForFlag(flag)) &&
|
||||
(!requireUpToDateSave || saveID == campaign.LastSaveID))
|
||||
{
|
||||
campaign.SetLastUpdateIdForFlag(flag, id);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadStores(IReadMessage msg, bool apply)
|
||||
{
|
||||
var storeBalances = new Dictionary<Identifier, UInt16>();
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
byte storeCount = msg.ReadByte();
|
||||
for (int i = 0; i < storeCount; i++)
|
||||
{
|
||||
Identifier identifier = msg.ReadIdentifier();
|
||||
UInt16 storeBalance = msg.ReadUInt16();
|
||||
storeBalances.Add(identifier, storeBalance);
|
||||
}
|
||||
}
|
||||
if (apply)
|
||||
{
|
||||
foreach (var balance in storeBalances)
|
||||
{
|
||||
if (campaign.Map?.CurrentLocation?.GetStore(balance.Key) is { } store)
|
||||
{
|
||||
store.Balance = balance.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void ClientReadCrew(IReadMessage msg)
|
||||
|
||||
@@ -35,11 +35,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (CrewManager.ChatBox != null)
|
||||
{
|
||||
CrewManager.ChatBox.Update(deltaTime);
|
||||
}
|
||||
|
||||
CrewManager.ChatBox?.Update(deltaTime);
|
||||
CrewManager.UpdateReports();
|
||||
}
|
||||
|
||||
@@ -58,12 +54,12 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Instantiates a new single player campaign
|
||||
/// </summary>
|
||||
private SinglePlayerCampaign(string mapSeed, CampaignSettings settings) : base(GameModePreset.SinglePlayerCampaign)
|
||||
private SinglePlayerCampaign(string mapSeed, CampaignSettings settings) : base(GameModePreset.SinglePlayerCampaign, settings)
|
||||
{
|
||||
CampaignMetadata = new CampaignMetadata(this);
|
||||
UpgradeManager = new UpgradeManager(this);
|
||||
map = new Map(this, mapSeed, settings);
|
||||
Settings = settings;
|
||||
map = new Map(this, mapSeed);
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||
{
|
||||
for (int i = 0; i < jobPrefab.InitialCount; i++)
|
||||
@@ -79,7 +75,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Loads a previously saved single player campaign from XML
|
||||
/// </summary>
|
||||
private SinglePlayerCampaign(XElement element) : base(GameModePreset.SinglePlayerCampaign)
|
||||
private SinglePlayerCampaign(XElement element) : base(GameModePreset.SinglePlayerCampaign, CampaignSettings.Empty)
|
||||
{
|
||||
IsFirstRound = false;
|
||||
|
||||
@@ -87,14 +83,15 @@ namespace Barotrauma
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "campaignsettings":
|
||||
case CampaignSettings.LowerCaseSaveElementName:
|
||||
Settings = new CampaignSettings(subElement);
|
||||
break;
|
||||
case "crew":
|
||||
GameMain.GameSession.CrewManager = new CrewManager(subElement, true);
|
||||
ActiveOrdersElement = subElement.GetChildElement("activeorders");
|
||||
break;
|
||||
case "map":
|
||||
map = Map.Load(this, subElement, Settings);
|
||||
map = Map.Load(this, subElement);
|
||||
break;
|
||||
case "metadata":
|
||||
CampaignMetadata = new CampaignMetadata(this, subElement);
|
||||
@@ -162,21 +159,14 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Start a completely new single player campaign
|
||||
/// </summary>
|
||||
public static SinglePlayerCampaign StartNew(string mapSeed, SubmarineInfo selectedSub, CampaignSettings settings)
|
||||
{
|
||||
var campaign = new SinglePlayerCampaign(mapSeed, settings);
|
||||
return campaign;
|
||||
}
|
||||
public static SinglePlayerCampaign StartNew(string mapSeed, CampaignSettings startingSettings) => new SinglePlayerCampaign(mapSeed, startingSettings);
|
||||
|
||||
/// <summary>
|
||||
/// Load a previously saved single player campaign from xml
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
public static SinglePlayerCampaign Load(XElement element)
|
||||
{
|
||||
return new SinglePlayerCampaign(element);
|
||||
}
|
||||
public static SinglePlayerCampaign Load(XElement element) => new SinglePlayerCampaign(element);
|
||||
|
||||
private void InitUI()
|
||||
{
|
||||
@@ -242,11 +232,10 @@ namespace Barotrauma
|
||||
crewDead = false;
|
||||
endTimer = 5.0f;
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
if (petsElement != null)
|
||||
{
|
||||
PetBehavior.LoadPets(petsElement);
|
||||
}
|
||||
CrewManager.LoadActiveOrders();
|
||||
LoadPets();
|
||||
LoadActiveOrders();
|
||||
|
||||
CargoManager.InitPurchasedIDCards();
|
||||
|
||||
GUI.DisableSavingIndicatorDelayed();
|
||||
}
|
||||
@@ -461,41 +450,8 @@ namespace Barotrauma
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
||||
{
|
||||
Submarine.MainSub = leavingSub;
|
||||
GameMain.GameSession.Submarine = leavingSub;
|
||||
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
||||
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
||||
foreach (Submarine sub in subsToLeaveBehind)
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
|
||||
if (PendingSubmarineSwitch != null)
|
||||
{
|
||||
SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo;
|
||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
||||
|
||||
for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines[i].Name == previousSub.Name)
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines[i] = previousSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
PendingSubmarineSwitch = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -766,11 +722,10 @@ namespace Barotrauma
|
||||
c.Info.SaveOrderData();
|
||||
}
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
modeElement.Add(petsElement);
|
||||
SavePets(modeElement);
|
||||
var crewManagerElement = CrewManager.Save(modeElement);
|
||||
SaveActiveOrders(crewManagerElement);
|
||||
|
||||
CrewManager.Save(modeElement);
|
||||
CampaignMetadata.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
|
||||
@@ -102,29 +102,11 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman");
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
|
||||
|
||||
var revolver = FindOrGiveItem(captain, "revolver".ToIdentifier());
|
||||
revolver.Unequip(captain);
|
||||
captain.Inventory.RemoveItem(revolver);
|
||||
|
||||
var captainscap =
|
||||
captain.Inventory.FindItemByIdentifier("captainscap1".ToIdentifier()) ??
|
||||
captain.Inventory.FindItemByIdentifier("captainscap2".ToIdentifier()) ??
|
||||
captain.Inventory.FindItemByIdentifier("captainscap3".ToIdentifier());
|
||||
|
||||
if (captainscap != null)
|
||||
foreach (Item item in captain.Inventory.AllItemsMod)
|
||||
{
|
||||
captainscap.Unequip(captain);
|
||||
captain.Inventory.RemoveItem(captainscap);
|
||||
}
|
||||
|
||||
var captainsuniform =
|
||||
captain.Inventory.FindItemByIdentifier("captainsuniform1".ToIdentifier()) ??
|
||||
captain.Inventory.FindItemByIdentifier("captainsuniform2".ToIdentifier()) ??
|
||||
captain.Inventory.FindItemByIdentifier("captainsuniform3".ToIdentifier());
|
||||
if (captainsuniform != null)
|
||||
{
|
||||
captainsuniform.Unequip(captain);
|
||||
captain.Inventory.RemoveItem(captainsuniform);
|
||||
if (item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(captain);
|
||||
captain.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var steerOrder = OrderPrefab.Prefabs["steer"];
|
||||
|
||||
@@ -105,21 +105,12 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
doctor = Character.Controlled;
|
||||
|
||||
var bandages = FindOrGiveItem(doctor, "antibleeding1".ToIdentifier());
|
||||
bandages.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(bandages);
|
||||
|
||||
var syringegun = FindOrGiveItem(doctor, "syringegun".ToIdentifier());
|
||||
syringegun.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(syringegun);
|
||||
|
||||
var antibiotics = FindOrGiveItem(doctor, "antibiotics".ToIdentifier());
|
||||
antibiotics.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(antibiotics);
|
||||
|
||||
var morphine = FindOrGiveItem(doctor, "antidama1".ToIdentifier());
|
||||
morphine.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(morphine);
|
||||
foreach (Item item in doctor.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(doctor);
|
||||
doctor.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>();
|
||||
doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>();
|
||||
@@ -260,7 +251,7 @@ namespace Barotrauma.Tutorials
|
||||
yield return new WaitForSeconds(2.0f);
|
||||
}*/
|
||||
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Medical supplies objective
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Medical supplies objective
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
@@ -131,9 +131,12 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
engineer = Character.Controlled;
|
||||
|
||||
var toolbelt = FindOrGiveItem(engineer, "toolbelt".ToIdentifier());
|
||||
toolbelt.Unequip(engineer);
|
||||
engineer.Inventory.RemoveItem(toolbelt);
|
||||
foreach (Item item in engineer.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(engineer);
|
||||
engineer.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
|
||||
engineer_repairIcon = repairOrder.SymbolSprite;
|
||||
@@ -278,7 +281,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!engineer_equipmentObjectiveSensor.MotionDetected);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(0.5f, false);
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Retrieve equipment
|
||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Retrieve equipment
|
||||
bool firstSlotRemoved = false;
|
||||
bool secondSlotRemoved = false;
|
||||
bool thirdSlotRemoved = false;
|
||||
|
||||
@@ -160,13 +160,12 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
mechanic = Character.Controlled;
|
||||
|
||||
var toolbelt = FindOrGiveItem(mechanic, "toolbelt".ToIdentifier());
|
||||
toolbelt.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(toolbelt);
|
||||
|
||||
var crowbar = FindOrGiveItem(mechanic, "crowbar".ToIdentifier());
|
||||
crowbar.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(crowbar);
|
||||
foreach (Item item in mechanic.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
|
||||
mechanic_repairIcon = repairOrder.SymbolSprite;
|
||||
@@ -297,7 +296,10 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
|
||||
if (mechanic_brokenhull_1 != null)
|
||||
{
|
||||
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
|
||||
}
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
@@ -334,7 +336,7 @@ namespace Barotrauma.Tutorials
|
||||
yield return new WaitForSeconds(0.0f, false);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Equipment & inventory objective
|
||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Equipment & inventory objective
|
||||
SetHighlight(mechanic_equipmentCabinet.Item, true);
|
||||
bool firstSlotRemoved = false;
|
||||
bool secondSlotRemoved = false;
|
||||
@@ -377,7 +379,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
// Room 3
|
||||
do { yield return null; } while (!mechanic_weldingObjectiveSensor.MotionDetected);
|
||||
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Welding objective
|
||||
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Welding objective
|
||||
do
|
||||
{
|
||||
if (!mechanic.HasEquippedItem("divingmask".ToIdentifier()))
|
||||
@@ -413,7 +415,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
} while (mechanic_workingPump.FlowPercentage >= 0 || !mechanic_workingPump.IsActive); // Highlight until draining
|
||||
SetHighlight(mechanic_workingPump.Item, false);
|
||||
do { yield return null; } while (mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
|
||||
do { yield return null; } while (mechanic_brokenhull_1 != null && mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
|
||||
RemoveCompletedObjective(3);
|
||||
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective3");
|
||||
|
||||
|
||||
@@ -141,36 +141,12 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
officer = Character.Controlled;
|
||||
|
||||
var handcuffs = FindOrGiveItem(officer, "handcuffs".ToIdentifier());
|
||||
handcuffs.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(handcuffs);
|
||||
|
||||
var stunbaton = FindOrGiveItem(officer, "stunbaton".ToIdentifier());
|
||||
stunbaton.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(stunbaton);
|
||||
|
||||
var smg = FindOrGiveItem(officer, "smg".ToIdentifier());
|
||||
smg.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(smg);
|
||||
|
||||
var divingknife = FindOrGiveItem(officer, "divingknife".ToIdentifier());
|
||||
divingknife.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(divingknife);
|
||||
|
||||
var steroids = FindOrGiveItem(officer, "steroids".ToIdentifier());
|
||||
steroids.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(steroids);
|
||||
|
||||
var ballistichelmet =
|
||||
officer.Inventory.FindItemByIdentifier("ballistichelmet1".ToIdentifier()) ??
|
||||
officer.Inventory.FindItemByIdentifier("ballistichelmet2".ToIdentifier()) ??
|
||||
FindOrGiveItem(officer, "ballistichelmet3".ToIdentifier());
|
||||
ballistichelmet.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(ballistichelmet);
|
||||
|
||||
var bodyarmor = FindOrGiveItem(officer, "bodyarmor".ToIdentifier());
|
||||
bodyarmor.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(bodyarmor);
|
||||
foreach (Item item in officer.Inventory.AllItemsMod)
|
||||
{
|
||||
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("mobileradio")) { continue; }
|
||||
item.Unequip(officer);
|
||||
officer.Inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
var gunOrder = OrderPrefab.Prefabs["operateweapons"];
|
||||
officer_gunIcon = gunOrder.SymbolSprite;
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Tutorials
|
||||
{
|
||||
@@ -106,7 +103,7 @@ namespace Barotrauma.Tutorials
|
||||
Character.Controlled = character;
|
||||
character.GiveJobItems(null);
|
||||
|
||||
var idCard = character.Inventory.FindItemByIdentifier("idcard".ToIdentifier());
|
||||
var idCard = character.Inventory.FindItemByTag("identitycard".ToIdentifier());
|
||||
if (idCard == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
||||
@@ -228,6 +225,8 @@ namespace Barotrauma.Tutorials
|
||||
{
|
||||
CoroutineManager.StopCoroutines(tutorialCoroutine);
|
||||
}
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
ContentRunning = false;
|
||||
infoBox = null;
|
||||
}
|
||||
else if (Character.Controlled.IsDead)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Barotrauma
|
||||
UserListData = "ReadyUserList",
|
||||
ReadySpriteData = "ReadySprite";
|
||||
|
||||
private int lastSecond;
|
||||
private int lastSecond = 1;
|
||||
|
||||
private GUIMessageBox? msgBox;
|
||||
private GUIMessageBox? resultsBox;
|
||||
@@ -44,7 +44,7 @@ namespace Barotrauma
|
||||
msgBox = new GUIMessageBox(readyCheckHeader, readyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true };
|
||||
|
||||
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.125f), msgBox.Content.RectTransform), childAnchor: Anchor.Center);
|
||||
new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), time / endTime, GUIStyle.Orange) { UserData = TimerData };
|
||||
new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), 0.0f, GUIStyle.Orange) { UserData = TimerData };
|
||||
|
||||
// Yes
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
@@ -116,17 +116,18 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateBar()
|
||||
{
|
||||
double elapsedTime = (DateTime.Now - startTime).TotalSeconds;
|
||||
if (msgBox != null && !msgBox.Closed && GUIMessageBox.MessageBoxes.Contains(msgBox))
|
||||
{
|
||||
if (msgBox.FindChild(TimerData, true) is GUIProgressBar bar)
|
||||
{
|
||||
bar.BarSize = time / endTime;
|
||||
bar.BarSize = (float)(elapsedTime / (endTime - startTime).TotalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
// play click sound after a second has passed
|
||||
int second = (int) Math.Ceiling(time);
|
||||
if (second < lastSecond)
|
||||
int second = (int)Math.Ceiling(elapsedTime);
|
||||
if (second > lastSecond)
|
||||
{
|
||||
if (msgBox != null && !msgBox.Closed)
|
||||
{
|
||||
@@ -156,7 +157,8 @@ namespace Barotrauma
|
||||
bool isOwn = false;
|
||||
byte authorId = 0;
|
||||
|
||||
float duration = inc.ReadSingle();
|
||||
long startTime = inc.ReadInt64();
|
||||
long endTime = inc.ReadInt64();
|
||||
string author = inc.ReadString();
|
||||
bool hasAuthor = inc.ReadBoolean();
|
||||
|
||||
@@ -173,7 +175,9 @@ namespace Barotrauma
|
||||
clients.Add(inc.ReadByte());
|
||||
}
|
||||
|
||||
ReadyCheck rCheck = new ReadyCheck(clients, duration);
|
||||
ReadyCheck rCheck = new ReadyCheck(clients,
|
||||
DateTimeOffset.FromUnixTimeSeconds(startTime).LocalDateTime,
|
||||
DateTimeOffset.FromUnixTimeSeconds(endTime).LocalDateTime);
|
||||
crewManager.ActiveReadyCheck = rCheck;
|
||||
|
||||
if (isOwn)
|
||||
@@ -192,12 +196,10 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case ReadyCheckState.Update:
|
||||
float time = inc.ReadSingle();
|
||||
ReadyStatus newState = (ReadyStatus) inc.ReadByte();
|
||||
byte targetId = inc.ReadByte();
|
||||
if (crewManager.ActiveReadyCheck != null)
|
||||
{
|
||||
crewManager.ActiveReadyCheck.time = time;
|
||||
crewManager.ActiveReadyCheck?.UpdateState(targetId, newState);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -64,7 +64,6 @@ namespace Barotrauma
|
||||
public Vector2[] SlotPositions;
|
||||
public static Point SlotSize;
|
||||
public static int Spacing;
|
||||
public static int HideButtonWidth;
|
||||
|
||||
private Layout layout;
|
||||
public Layout CurrentLayout
|
||||
@@ -77,64 +76,11 @@ namespace Barotrauma
|
||||
SetSlotPositions(layout);
|
||||
}
|
||||
}
|
||||
public bool Hidden { get; set; }
|
||||
|
||||
private bool hidePersonalSlots;
|
||||
private float hidePersonalSlotsState;
|
||||
private GUIButton hideButton;
|
||||
|
||||
private Rectangle personalSlotArea;
|
||||
|
||||
public bool HidePersonalSlots
|
||||
{
|
||||
get { return hidePersonalSlots; }
|
||||
}
|
||||
|
||||
public Rectangle PersonalSlotArea
|
||||
{
|
||||
get { return personalSlotArea; }
|
||||
}
|
||||
|
||||
private readonly GUIImage[] indicators = new GUIImage[5];
|
||||
private readonly int[] indicatorIndices = new int[5];
|
||||
private Vector2 indicatorSpriteSize;
|
||||
private GUILayoutGroup indicatorGroup;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
Hidden = true;
|
||||
|
||||
hideButton = new GUIButton(new RectTransform(new Point((int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f)), HUDLayoutSettings.BottomRightInfoArea.Height), GUI.Canvas)
|
||||
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
|
||||
"", style: "EquipmentToggleButton");
|
||||
|
||||
indicatorGroup = new GUILayoutGroup(new RectTransform(Point.Zero, hideButton.RectTransform)) { IsHorizontal = false };
|
||||
indicatorGroup.ChildAnchor = Anchor.TopCenter;
|
||||
indicatorSpriteSize = GUIStyle.GetComponentStyle("EquipmentIndicatorDivingSuit").GetDefaultSprite().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");
|
||||
|
||||
indicatorIndices[0] = FindLimbSlot(InvSlotType.OuterClothes);
|
||||
indicatorIndices[1] = FindLimbSlot(InvSlotType.Card);
|
||||
indicatorIndices[2] = FindLimbSlot(InvSlotType.InnerClothes);
|
||||
indicatorIndices[3] = FindLimbSlot(InvSlotType.Head);
|
||||
indicatorIndices[4] = FindLimbSlot(InvSlotType.Headset);
|
||||
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
indicators[i].CanBeFocused = false;
|
||||
}
|
||||
|
||||
hideButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||
{
|
||||
hidePersonalSlots = !hidePersonalSlots;
|
||||
return true;
|
||||
};
|
||||
hidePersonalSlots = false;
|
||||
|
||||
SlotPositions = new Vector2[SlotTypes.Length];
|
||||
CurrentLayout = Layout.Default;
|
||||
SetSlotPositions(layout);
|
||||
@@ -271,25 +217,6 @@ 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();
|
||||
@@ -302,13 +229,9 @@ 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;
|
||||
|
||||
hideButton.Visible = false;
|
||||
|
||||
if (visualSlots == null) { CreateSlots(); }
|
||||
if (visualSlots.None()) { return; }
|
||||
|
||||
@@ -320,7 +243,7 @@ namespace Barotrauma
|
||||
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s) && s != InvSlotType.HealthInterface);
|
||||
|
||||
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
|
||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
|
||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing;
|
||||
|
||||
//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);
|
||||
@@ -343,16 +266,6 @@ namespace Barotrauma
|
||||
x += SlotSize.X + Spacing;
|
||||
}
|
||||
}
|
||||
|
||||
if (hideButtonSlotIndex > -1)
|
||||
{
|
||||
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
|
||||
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 = Screen.Selected != GameMain.SubEditorScreen || !GameMain.SubEditorScreen.WiringMode;
|
||||
|
||||
SetIndicatorSizes();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Layout.Right:
|
||||
@@ -525,6 +438,7 @@ namespace Barotrauma
|
||||
if (!AccessibleWhenAlive && !character.IsDead && !AccessibleByOwner)
|
||||
{
|
||||
syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
|
||||
doubleClickedItems.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -532,58 +446,13 @@ namespace Barotrauma
|
||||
|
||||
bool hoverOnInventory = GUI.MouseOn == null &&
|
||||
((selectedSlot != null && selectedSlot.IsSubSlot) || (DraggingItems.Any() && (DraggingSlot == null || !DraggingSlot.MouseOn())));
|
||||
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
|
||||
|
||||
if (layout == Layout.Default && (Screen.Selected != GameMain.SubEditorScreen || Screen.Selected is SubEditorScreen editor && editor.WiringMode))
|
||||
{
|
||||
if (hideButton.Visible)
|
||||
{
|
||||
hideButton.AddToGUIUpdateList();
|
||||
hideButton.UpdateManually(deltaTime, alsoChildren: true);
|
||||
|
||||
hidePersonalSlotsState = hidePersonalSlots ?
|
||||
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
|
||||
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
|
||||
|
||||
bool personalSlotsMoving = hidePersonalSlotsState > 0 && hidePersonalSlotsState < 1f;
|
||||
for (int i = 0; i < visualSlots.Length; i++)
|
||||
{
|
||||
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
|
||||
if (HidePersonalSlots)
|
||||
{
|
||||
if (selectedSlot?.Slot == visualSlots[i]) { selectedSlot = null; }
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == visualSlots[i]);
|
||||
}
|
||||
visualSlots[i].IsMoving = personalSlotsMoving;
|
||||
visualSlots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CharacterHealth.OpenHealthWindow != null) { hoverOnInventory = true; }
|
||||
|
||||
if (hoverOnInventory) { HideTimer = 0.5f; }
|
||||
if (HideTimer > 0.0f) { HideTimer -= deltaTime; }
|
||||
|
||||
UpdateSlotInput();
|
||||
|
||||
//force personal slots open if an item is running out of battery/fuel/oxygen/etc
|
||||
if (hidePersonalSlots)
|
||||
{
|
||||
for (int i = 0; i < visualSlots.Length; i++)
|
||||
{
|
||||
var item = slots[i].FirstOrDefault();
|
||||
if (item?.OwnInventory != null && item.OwnInventory.Capacity == 1 && PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
var containedItem = item.OwnInventory.AllItems.FirstOrDefault();
|
||||
if (containedItem != null &&
|
||||
containedItem.Condition > 0.0f &&
|
||||
containedItem.Condition / containedItem.MaxCondition < 0.15f)
|
||||
{
|
||||
hidePersonalSlots = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hideSubInventories.Clear();
|
||||
//remove highlighted subinventory slots that can no longer be accessed
|
||||
highlightedSubInventorySlots.RemoveWhere(s =>
|
||||
@@ -652,8 +521,6 @@ 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);
|
||||
|
||||
@@ -798,40 +665,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEquipmentIndicators()
|
||||
{
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
if (indicatorIndices[i] < 0) { continue; }
|
||||
Item item = slots[indicatorIndices[i]].FirstOrDefault();
|
||||
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, GUIStyle.EquipmentIndicatorRunningOut, GUIStyle.EquipmentIndicatorEquipped);
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUIStyle.EquipmentIndicatorRunningOut;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUIStyle.EquipmentIndicatorEquipped;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indicators[i].Color = GUIStyle.EquipmentIndicatorNotEquipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List<SlotReference> hideSubInventories, bool isEquippedSubInventory)
|
||||
{
|
||||
@@ -931,7 +764,7 @@ namespace Barotrauma
|
||||
// Move the item from the subinventory to the selected container
|
||||
return QuickUseAction.PutToContainer;
|
||||
}
|
||||
else
|
||||
else if (character.Inventory.AccessibleWhenAlive || character.Inventory.AccessibleByOwner)
|
||||
{
|
||||
// Take from the subinventory and place it in the character's main inventory if no target container is selected
|
||||
return QuickUseAction.TakeFromContainer;
|
||||
@@ -941,6 +774,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isEquippable = item.AllowedSlots.Any(s => s != InvSlotType.Any);
|
||||
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
|
||||
if (selectedContainer != null &&
|
||||
selectedContainer.Inventory != null &&
|
||||
@@ -959,14 +793,16 @@ namespace Barotrauma
|
||||
}
|
||||
else if (character.SelectedBy?.Inventory != null &&
|
||||
Character.Controlled == character.SelectedBy &&
|
||||
!character.SelectedBy.Inventory.Locked &&
|
||||
!character.SelectedBy.Inventory.Locked &&
|
||||
(character.SelectedBy.Inventory.AccessibleWhenAlive || character.SelectedBy.Inventory.AccessibleByOwner) &&
|
||||
allowInventorySwap)
|
||||
{
|
||||
return QuickUseAction.TakeFromCharacter;
|
||||
}
|
||||
else if (character.HeldItems.Any(i =>
|
||||
i.OwnInventory != null &&
|
||||
((i.OwnInventory.CanBePut(item) && allowInventorySwap) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
||||
i.OwnInventory != null &&
|
||||
/*disallow putting into equipped item if the item is equippable (equip as the quick action instead)*/
|
||||
((i.OwnInventory.CanBePut(item) && (allowInventorySwap || !isEquippable)) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
||||
{
|
||||
return QuickUseAction.PutToEquippedItem;
|
||||
}
|
||||
@@ -1129,11 +965,18 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case QuickUseAction.PutToEquippedItem:
|
||||
|
||||
foreach (Item heldItem in character.HeldItems)
|
||||
{
|
||||
if (heldItem.OwnInventory == null) { continue; }
|
||||
//don't allow swapping if we're moving items into an item with 1 slot holding a stack of items
|
||||
//(in that case, the quick action should just fill up the stack)
|
||||
bool disallowSwapping =
|
||||
heldItem.OwnInventory.Capacity == 1 &&
|
||||
heldItem.OwnInventory.GetItemAt(0)?.Prefab == item.Prefab &&
|
||||
heldItem.OwnInventory.GetItemsAt(0).Count() > 1;
|
||||
if (heldItem.OwnInventory.TryPutItem(item, Character.Controlled) ||
|
||||
(heldItem.OwnInventory.Capacity == 1 && heldItem.OwnInventory.TryPutItem(item, 0, allowSwapping: true, allowCombine: false, user: Character.Controlled)))
|
||||
(heldItem.OwnInventory.Capacity == 1 && heldItem.OwnInventory.TryPutItem(item, 0, allowSwapping: !disallowSwapping, allowCombine: false, user: Character.Controlled)))
|
||||
{
|
||||
success = true;
|
||||
for (int j = 0; j < capacity; j++)
|
||||
@@ -1195,11 +1038,6 @@ namespace Barotrauma
|
||||
|
||||
DrawSlot(spriteBatch, this, visualSlots[i], slots[i].FirstOrDefault(), i, drawItem, SlotTypes[i]);
|
||||
}
|
||||
|
||||
if (hideButton != null && hideButton.Visible && !Locked)
|
||||
{
|
||||
hideButton.DrawManually(spriteBatch, alsoChildren: true);
|
||||
}
|
||||
|
||||
VisualSlot highlightedQuickUseSlot = null;
|
||||
Rectangle inventoryArea = Rectangle.Empty;
|
||||
|
||||
@@ -43,6 +43,31 @@ namespace Barotrauma.Items.Components
|
||||
corners[2] = center + new Vector2(shadowSize.X, shadowSize.Y) / 2;
|
||||
corners[3] = center + new Vector2(shadowSize.X, -shadowSize.Y) / 2;
|
||||
|
||||
if (IsHorizontal)
|
||||
{
|
||||
if (item.FlippedX)
|
||||
{
|
||||
Vector2 itemCenter = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2);
|
||||
for (int i = 0; i < corners.Length; i++)
|
||||
{
|
||||
corners[i].X = itemCenter.X * 2 - corners[i].X;
|
||||
}
|
||||
Array.Reverse(corners);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.FlippedY)
|
||||
{
|
||||
Vector2 itemCenter = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2);
|
||||
for (int i = 0; i < corners.Length; i++)
|
||||
{
|
||||
corners[i].Y = itemCenter.Y * 2 - corners[i].Y;
|
||||
}
|
||||
Array.Reverse(corners);
|
||||
}
|
||||
}
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
@@ -66,6 +91,9 @@ namespace Barotrauma.Items.Components
|
||||
rect.Height = (int)(rect.Height * (1.0f - openState));
|
||||
}
|
||||
|
||||
//only merge the door's convex hull with overlapping wall segments if it's fully open or fully closed
|
||||
//it's the heaviest part of changing the convex hull, and doesn't need to be done while the door is still in motion
|
||||
bool mergeOverlappingSegments = openState <= 0.0f || openState >= 1.0f;
|
||||
if (Window.Height > 0 && Window.Width > 0)
|
||||
{
|
||||
if (IsHorizontal)
|
||||
@@ -88,7 +116,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
convexHull2.Enabled = true;
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2), mergeOverlappingSegments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +140,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
convexHull2.Enabled = true;
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2), mergeOverlappingSegments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +155,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
convexHull.Enabled = true;
|
||||
convexHull.SetVertices(GetConvexHullCorners(rect));
|
||||
convexHull.SetVertices(GetConvexHullCorners(rect), mergeOverlappingSegments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,69 +188,68 @@ namespace Barotrauma.Items.Components
|
||||
if (stuck > 0.0f && weldedSprite != null)
|
||||
{
|
||||
Vector2 weldSpritePos = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2.0f) + shakePos;
|
||||
if (item.Submarine != null) weldSpritePos += item.Submarine.DrawPosition;
|
||||
if (item.Submarine != null) { weldSpritePos += item.Submarine.DrawPosition; }
|
||||
weldSpritePos.Y = -weldSpritePos.Y;
|
||||
|
||||
weldedSprite.Draw(spriteBatch,
|
||||
weldSpritePos, item.SpriteColor * (stuck / 100.0f), scale: item.Scale);
|
||||
}
|
||||
|
||||
if (openState >= 1.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (openState >= 1.0f) { return; }
|
||||
|
||||
Vector2 pos;
|
||||
if (IsHorizontal)
|
||||
{
|
||||
Vector2 pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2) + shakePos;
|
||||
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (brokenSprite == null || !IsBroken)
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
|
||||
(int) doorSprite.SourceRect.Y,
|
||||
(int) (doorSprite.size.X * (1.0f - openState)), (int) doorSprite.size.Y),
|
||||
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||
}
|
||||
|
||||
if (brokenSprite != null && item.Health < item.MaxCondition)
|
||||
{
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
|
||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
|
||||
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
|
||||
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None,
|
||||
brokenSprite.Depth);
|
||||
}
|
||||
pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2);
|
||||
if (item.FlippedX) { pos.X += (int)(doorSprite.size.X * item.Scale * openState); }
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 pos = new Vector2(item.Rect.Center.X, item.Rect.Y) + shakePos;
|
||||
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (brokenSprite == null || !IsBroken)
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||
new Rectangle(doorSprite.SourceRect.X,
|
||||
(int) (doorSprite.SourceRect.Y + doorSprite.size.Y * openState),
|
||||
(int) doorSprite.size.X, (int) (doorSprite.size.Y * (1.0f - openState))),
|
||||
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||
}
|
||||
|
||||
if (brokenSprite != null && item.Health < item.MaxCondition)
|
||||
{
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition, 1.0f) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
|
||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
|
||||
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
|
||||
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None, brokenSprite.Depth);
|
||||
}
|
||||
pos = new Vector2(item.Rect.Center.X, item.Rect.Y);
|
||||
if (item.FlippedY) { pos.Y -= (int)(doorSprite.size.Y * item.Scale * openState); }
|
||||
}
|
||||
|
||||
pos += shakePos;
|
||||
if (item.Submarine != null) { pos += item.Submarine.DrawPosition; }
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (brokenSprite == null || !IsBroken)
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||
getSourceRect(doorSprite, openState, IsHorizontal),
|
||||
color, 0.0f, doorSprite.Origin, item.Scale, item.SpriteEffects, doorSprite.Depth);
|
||||
}
|
||||
|
||||
if (brokenSprite != null && item.Health < item.MaxCondition)
|
||||
{
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition) : Vector2.One;
|
||||
if (IsHorizontal) { scale.X = 1; } else { scale.Y = 1; }
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
|
||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||
getSourceRect(brokenSprite, openState, IsHorizontal),
|
||||
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, item.SpriteEffects,
|
||||
brokenSprite.Depth);
|
||||
}
|
||||
|
||||
static Rectangle getSourceRect(Sprite sprite, float openState, bool horizontal)
|
||||
{
|
||||
if (horizontal)
|
||||
{
|
||||
return new Rectangle(
|
||||
(int)(sprite.SourceRect.X + sprite.size.X * openState),
|
||||
sprite.SourceRect.Y,
|
||||
(int)(sprite.size.X * (1.0f - openState)),
|
||||
(int)sprite.size.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Rectangle(
|
||||
sprite.SourceRect.X,
|
||||
(int)(sprite.SourceRect.Y + sprite.size.Y * openState),
|
||||
(int)sprite.size.X,
|
||||
(int)(sprite.size.Y * (1.0f - openState)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnFailedToOpen()
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f), parent), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), label);
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), GUINumberInput.NumberType.Int) { IntValue = defaultValue };
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), NumberType.Int) { IntValue = defaultValue };
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f), parent), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), label);
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), GUINumberInput.NumberType.Float) { FloatValue = defaultValue, DecimalsToDisplay = 2 };
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), NumberType.Float) { FloatValue = defaultValue, DecimalsToDisplay = 2 };
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ namespace Barotrauma.Items.Components
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
float value = values[i];
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f / values.Length, 1f), layout.RectTransform), GUINumberInput.NumberType.Float)
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f / values.Length, 1f), layout.RectTransform), NumberType.Float)
|
||||
{
|
||||
FloatValue = value, DecimalsToDisplay = 2,
|
||||
MinValueFloat = min,
|
||||
|
||||
@@ -116,12 +116,6 @@ namespace Barotrauma.Items.Components
|
||||
loadAttachments(Attachments, disguisedBeardElement, WearableType.Beard);
|
||||
loadAttachments(Attachments, disguisedMoustacheElement, WearableType.Moustache);
|
||||
loadAttachments(Attachments, disguisedHairElement, WearableType.Hair);
|
||||
|
||||
loadAttachments(Attachments,
|
||||
characterInfo.OmitJobInPortraitClothing
|
||||
? JobPrefab.NoJobElement?.GetChildElement("PortraitClothing")
|
||||
: JobPrefab?.ClothingElement,
|
||||
WearableType.JobIndicator);
|
||||
}
|
||||
|
||||
HairColor = hairColor;
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace Barotrauma.Items.Components
|
||||
private float lastMuffleCheckTime;
|
||||
private ItemSound loopingSound;
|
||||
private SoundChannel loopingSoundChannel;
|
||||
private List<SoundChannel> playingOneshotSoundChannels = new List<SoundChannel>();
|
||||
private readonly List<SoundChannel> playingOneshotSoundChannels = new List<SoundChannel>();
|
||||
public ItemComponent ReplacedBy;
|
||||
|
||||
public ItemComponent GetReplacementOrThis()
|
||||
@@ -211,13 +211,16 @@ namespace Barotrauma.Items.Components
|
||||
return ReplacedBy?.GetReplacementOrThis() ?? this;
|
||||
}
|
||||
|
||||
public bool NeedsSoundUpdate()
|
||||
{
|
||||
if (hasSoundsOfType[(int)ActionType.Always]) { return true; }
|
||||
if (loopingSoundChannel != null && loopingSoundChannel.IsPlaying) { return true; }
|
||||
if (playingOneshotSoundChannels.Count > 0) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public void UpdateSounds()
|
||||
{
|
||||
if (!isActive || item.Condition <= 0.0f)
|
||||
{
|
||||
StopSounds(ActionType.OnActive);
|
||||
}
|
||||
|
||||
if (loopingSound != null && loopingSoundChannel != null && loopingSoundChannel.IsPlaying)
|
||||
{
|
||||
if (Timing.TotalTime > lastMuffleCheckTime + 0.2f)
|
||||
@@ -280,6 +283,7 @@ namespace Barotrauma.Items.Components
|
||||
loopingSound.RoundSound.GetRandomFrequencyMultiplier(),
|
||||
SoundPlayer.ShouldMuffleSound(Character.Controlled, item.WorldPosition, loopingSound.Range, Character.Controlled?.CurrentHull));
|
||||
loopingSoundChannel.Looping = true;
|
||||
item.CheckNeedsSoundUpdate(this);
|
||||
//TODO: tweak
|
||||
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
|
||||
loopingSoundChannel.Far = loopingSound.Range;
|
||||
@@ -298,7 +302,6 @@ namespace Barotrauma.Items.Components
|
||||
loopingSound = null;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,6 +336,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
PlaySound(matchingSounds[index], item.WorldPosition);
|
||||
item.CheckNeedsSoundUpdate(this);
|
||||
}
|
||||
}
|
||||
private void PlaySound(ItemSound itemSound, Vector2 position)
|
||||
@@ -401,7 +405,7 @@ namespace Barotrauma.Items.Components
|
||||
float newVolume;
|
||||
try
|
||||
{
|
||||
newVolume = property.GetFloatValue(this);
|
||||
newVolume = Math.Min(property.GetFloatValue(this), 1.0f);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -280,9 +280,9 @@ namespace Barotrauma.Items.Components
|
||||
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
|
||||
if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
|
||||
|
||||
if (Math.Abs(item.Rotation) > 0.01f)
|
||||
if (Math.Abs(item.RotationRad) > 0.01f)
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(MathHelper.ToRadians(-item.Rotation));
|
||||
Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos - item.DrawPosition, transform) + item.DrawPosition;
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
|
||||
@@ -56,9 +56,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 pos = item.DrawPosition;
|
||||
if (item.Submarine != null) { pos -= item.Submarine.DrawPosition; }
|
||||
Light.Position = pos;
|
||||
Light.Position = item.Position;
|
||||
}
|
||||
PhysicsBody body = Light.ParentBody;
|
||||
if (body != null)
|
||||
@@ -68,7 +66,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Light.Rotation = -Rotation - MathHelper.ToRadians(item.Rotation);
|
||||
Light.Rotation = -Rotation - item.RotationRad;
|
||||
Light.LightSpriteEffect = item.SpriteEffects;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
@@ -78,7 +79,7 @@ namespace Barotrauma.Items.Components
|
||||
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
|
||||
{
|
||||
TextBlock = { AutoScaleHorizontal = true },
|
||||
OnClicked = ToggleActive
|
||||
OnClicked = OnActivateButtonClicked
|
||||
};
|
||||
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
||||
TextManager.Get("DeconstructorNoPower"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
||||
@@ -164,7 +165,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
activateButton.Enabled = outputsFound;
|
||||
activateButton.Enabled = outputsFound || !InputContainer.Inventory.IsEmpty();
|
||||
activateButton.Text = TextManager.Get(ActivateButtonText);
|
||||
};
|
||||
}
|
||||
@@ -236,8 +237,19 @@ namespace Barotrauma.Items.Components
|
||||
inSufficientPowerWarning.Visible = IsActive && !hasPower;
|
||||
}
|
||||
|
||||
private bool ToggleActive(GUIButton button, object obj)
|
||||
private bool OnActivateButtonClicked(GUIButton button, object obj)
|
||||
{
|
||||
var disallowedItem = inputContainer.Inventory.FindItem(i => !i.AllowDeconstruct, recursive: false);
|
||||
if (disallowedItem != null && !DeconstructItemsSimultaneously)
|
||||
{
|
||||
int index = inputContainer.Inventory.FindIndex(disallowedItem);
|
||||
if (index >= 0 && index < inputContainer.Inventory.visualSlots.Length)
|
||||
{
|
||||
var slot = inputContainer.Inventory.visualSlots[index];
|
||||
slot?.ShowBorderHighlight(GUIStyle.Red, 0.1f, 0.9f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
pendingState = !IsActive;
|
||||
@@ -247,7 +259,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
SetActive(!IsActive, Character.Controlled);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
itemList = new GUIListBox(new RectTransform(new Vector2(1f, 0.9f), paddedItemFrame.RectTransform), style: null)
|
||||
{
|
||||
PlaySoundOnSelect = true,
|
||||
OnSelected = (component, userdata) =>
|
||||
{
|
||||
selectedItem = userdata as FabricationRecipe;
|
||||
|
||||
@@ -333,6 +333,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(Vector2.One, searchAutoComplete.RectTransform))
|
||||
{
|
||||
PlaySoundOnSelect = true,
|
||||
OnSelected = (component, o) =>
|
||||
{
|
||||
if (o is ItemPrefab prefab)
|
||||
@@ -613,7 +614,7 @@ namespace Barotrauma.Items.Components
|
||||
if (hullData.Distort)
|
||||
{
|
||||
hullData.ReceivedOxygenAmount = Rand.Range(0.0f, 100.0f);
|
||||
hullData.ReceivedWaterAmount = Rand.Range(0.0f, 1.0f);
|
||||
hullData.ReceivedWaterAmount = Rand.Range(0.0f, 100.0f);
|
||||
}
|
||||
hullData.DistortionTimer = Rand.Range(1.0f, 10.0f);
|
||||
}
|
||||
@@ -681,7 +682,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
var sprite = GUIStyle.UIGlowSolidCircular.Value?.Sprite;
|
||||
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
|
||||
if (sprite != null)
|
||||
if (sprite != null && ShowHullIntegrity)
|
||||
{
|
||||
Vector2 spriteSize = sprite.size;
|
||||
Rectangle worldBorders = item.Submarine.GetDockedBorders();
|
||||
@@ -744,11 +745,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (key == Keys.Down)
|
||||
{
|
||||
listBox.SelectNext(true, autoScroll: true);
|
||||
listBox.SelectNext(force: GUIListBox.Force.Yes, playSelectSound: GUIListBox.PlaySelectSound.Yes);
|
||||
}
|
||||
else if (key == Keys.Up)
|
||||
{
|
||||
listBox.SelectPrevious(true, autoScroll: true);
|
||||
listBox.SelectPrevious(force: GUIListBox.Force.Yes, playSelectSound: GUIListBox.PlaySelectSound.Yes);
|
||||
}
|
||||
else if (key == Keys.Enter)
|
||||
{
|
||||
@@ -782,7 +783,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (component.Visible && first)
|
||||
{
|
||||
listBox.Select(i, force: true, autoScroll: false);
|
||||
listBox.Select(i, GUIListBox.Force.Yes, GUIListBox.AutoScroll.Disabled);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
@@ -1014,13 +1015,13 @@ namespace Barotrauma.Items.Components
|
||||
hullData.HullWaterAmount = 0.0f;
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
hullData.HullWaterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
|
||||
hullData.HullWaterAmount += WaterDetector.GetWaterPercentage(linkedHull);
|
||||
}
|
||||
hullData.HullWaterAmount /= hullData.LinkedHulls.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
hullData.HullWaterAmount = Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
|
||||
hullData.HullWaterAmount = WaterDetector.GetWaterPercentage(hull);
|
||||
}
|
||||
|
||||
float gapOpenSum = 0.0f;
|
||||
@@ -1052,8 +1053,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
LocalizedString line3 = waterAmount == null ?
|
||||
TextManager.Get("MiniMapWaterLevelUnavailable") :
|
||||
TextManager.AddPunctuation(':', TextManager.Get("MiniMapWaterLevel"), (int)Math.Round(waterAmount.Value * 100.0f) + "%");
|
||||
Color line3Color = waterAmount == null ? GUIStyle.Red : Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)waterAmount);
|
||||
TextManager.AddPunctuation(':', TextManager.Get("MiniMapWaterLevel"), (int)Math.Round(waterAmount.Value) + "%");
|
||||
Color line3Color = waterAmount == null ? GUIStyle.Red : Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)waterAmount / 100.0f);
|
||||
|
||||
SetTooltip(borderComponent.Rect.Center, header, line1, line2, line3, line1Color, line2Color, line3Color);
|
||||
}
|
||||
@@ -1188,7 +1189,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (hullsVisible && hullData.HullWaterAmount is { } waterAmount)
|
||||
{
|
||||
if (!RequireWaterDetectors) { waterAmount = hull.WaterPercentage / 100.0f; }
|
||||
if (!RequireWaterDetectors) { waterAmount = WaterDetector.GetWaterPercentage(hull); }
|
||||
waterAmount /= 100.0f;
|
||||
if (hullFrame.Rect.Height * waterAmount > 1.0f)
|
||||
{
|
||||
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
|
||||
@@ -1327,7 +1329,7 @@ namespace Barotrauma.Items.Components
|
||||
pos.X += inflate;
|
||||
pos.Y += inflate;
|
||||
|
||||
sprite.Draw(spriteBatch, pos, item.SpriteColor, sprite.Origin, MathHelper.ToRadians(item.Rotation), spriteScale, item.SpriteEffects);
|
||||
sprite.Draw(spriteBatch, pos, item.SpriteColor, sprite.Origin, item.RotationRad, spriteScale, item.SpriteEffects);
|
||||
|
||||
void DrawAdditionalSprite(Vector2 basePos, Sprite addSprite, float rotation)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
GuiFrame = selectionUI.GuiFrame;
|
||||
selectionUI.RefreshSubmarineDisplay(true);
|
||||
selectionUI.RefreshSubmarineDisplay(true, setTransferOptionToTrue: true);
|
||||
IsActive = true;
|
||||
return base.Select(character);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
float rotationRad = MathHelper.ToRadians(item.Rotation);
|
||||
if (FlowPercentage < 0.0f)
|
||||
{
|
||||
foreach (var (position, emitter) in pumpOutEmitters)
|
||||
@@ -142,8 +141,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//only emit "pump out" particles when underwater
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? item.RotationRad : -item.RotationRad);
|
||||
float angle = -item.RotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
@@ -163,8 +162,8 @@ namespace Barotrauma.Items.Components
|
||||
foreach (var (position, emitter) in pumpInEmitters)
|
||||
{
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? item.RotationRad : -item.RotationRad);
|
||||
float angle = -item.RotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
|
||||
@@ -1367,6 +1367,15 @@ namespace Barotrauma.Items.Components
|
||||
pingRadius, prevPingRadius,
|
||||
250.0f, 150.0f, range, pingStrength, passive);
|
||||
}
|
||||
if (pingSource.Y - Level.Loaded.BottomPos < range)
|
||||
{
|
||||
CreateBlipsForLine(
|
||||
new Vector2(pingSource.X - range, Level.Loaded.BottomPos),
|
||||
new Vector2(pingSource.X + range, Level.Loaded.BottomPos),
|
||||
pingSource, transducerPos,
|
||||
pingRadius, prevPingRadius,
|
||||
250.0f, 150.0f, range, pingStrength, passive);
|
||||
}
|
||||
|
||||
List<Voronoi2.VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
|
||||
foreach (Voronoi2.VoronoiCell cell in cells)
|
||||
|
||||
@@ -927,6 +927,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
bool autoPilot = msg.ReadBoolean();
|
||||
bool dockingButtonClicked = msg.ReadBoolean();
|
||||
ushort userID = msg.ReadUInt16();
|
||||
|
||||
Vector2 newSteeringInput = steeringInput;
|
||||
Vector2 newTargetVelocity = targetVelocity;
|
||||
float newSteeringAdjustSpeed = steeringAdjustSpeed;
|
||||
@@ -935,7 +937,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (dockingButtonClicked)
|
||||
{
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
item.SendSignal(new Signal("1", sender: Entity.FindEntityByID(userID) as Character), "toggle_docking");
|
||||
}
|
||||
|
||||
if (autoPilot)
|
||||
|
||||
@@ -40,8 +40,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private LightComponent lightComponent;
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
for (var i = 0; i < GrowableSeeds.Length; i++)
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
#endif
|
||||
|
||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private List<ParticleEmitter> particleEmitterHitStructure = new List<ParticleEmitter>();
|
||||
private List<ParticleEmitter> particleEmitterHitCharacter = new List<ParticleEmitter>();
|
||||
private List<Pair<RelatedItem, ParticleEmitter>> particleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private readonly List<ParticleEmitter> particleEmitterHitStructure = new List<ParticleEmitter>();
|
||||
private readonly List<ParticleEmitter> particleEmitterHitCharacter = new List<ParticleEmitter>();
|
||||
private readonly List<(RelatedItem relatedItem, ParticleEmitter emitter)> particleEmitterHitItem = new List<(RelatedItem relatedItem, ParticleEmitter emitter)>();
|
||||
|
||||
private float prevProgressBarState;
|
||||
private Item prevProgressBarTarget = null;
|
||||
@@ -46,10 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
Identifier[] excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifiers", Array.Empty<Identifier>());
|
||||
if (excludedIdentifiers.Length == 0) { excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifier", Array.Empty<Identifier>()); }
|
||||
|
||||
particleEmitterHitItem.Add(
|
||||
new Pair<RelatedItem, ParticleEmitter>(
|
||||
new RelatedItem(identifiers, excludedIdentifiers),
|
||||
new ParticleEmitter(subElement)));
|
||||
particleEmitterHitItem.Add((new RelatedItem(identifiers, excludedIdentifiers), new ParticleEmitter(subElement)));
|
||||
break;
|
||||
case "particleemitterhitstructure":
|
||||
particleEmitterHitStructure.Add(new ParticleEmitter(subElement));
|
||||
@@ -139,11 +136,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
||||
foreach (var emitter in particleEmitterHitItem)
|
||||
foreach ((RelatedItem relatedItem, ParticleEmitter emitter) in particleEmitterHitItem)
|
||||
{
|
||||
if (!emitter.First.MatchesItem(targetItem)) { continue; }
|
||||
if (!relatedItem.MatchesItem(targetItem)) { continue; }
|
||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -419,7 +418,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!GameMain.IsMultiplayer) { RepairBoost(qteSuccess); }
|
||||
|
||||
SoundPlayer.PlayUISound(qteSuccess ? GUISoundType.IncreaseQuantity : GUISoundType.DecreaseQuantity);
|
||||
SoundPlayer.PlayUISound(qteSuccess ? GUISoundType.Increase : GUISoundType.Decrease);
|
||||
|
||||
//on failure during cooldown reset cursor to beginning
|
||||
if (!qteSuccess && qteCooldown > 0.0f) { qteTimer = QteDuration; }
|
||||
|
||||
@@ -92,6 +92,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (target == null || target.Removed) { return; }
|
||||
if (target.ParentInventory != null) { return; }
|
||||
if (source is Limb limb && limb.Removed) { return; }
|
||||
if (source is Entity e && e.Removed) { return; }
|
||||
|
||||
Vector2 startPos = GetSourcePos();
|
||||
startPos.Y = -startPos.Y;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
|
||||
int totalWireCount = 0;
|
||||
foreach (Connection c in panel.Connections)
|
||||
{
|
||||
totalWireCount += c.Wires.Count(w => w != null);
|
||||
totalWireCount += c.Wires.Count;
|
||||
}
|
||||
|
||||
Wire equippedWire = null;
|
||||
@@ -87,8 +87,8 @@ namespace Barotrauma.Items.Components
|
||||
(DraggingConnected.Connections[0] == null && DraggingConnected.Connections[1] == null) ||
|
||||
(DraggingConnected.Connections.Contains(c) && DraggingConnected.Connections.Contains(null)))
|
||||
{
|
||||
int linkIndex = c.FindWireIndex(DraggingConnected.Item);
|
||||
if (linkIndex > -1 || panel.DisconnectedWires.Contains(DraggingConnected))
|
||||
var linkedWire = c.FindWireByItem(DraggingConnected.Item);
|
||||
if (linkedWire != null || panel.DisconnectedWires.Contains(DraggingConnected))
|
||||
{
|
||||
Inventory.DraggingItems.Clear();
|
||||
Inventory.DraggingItems.Add(DraggingConnected.Item);
|
||||
@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
|
||||
c.DrawWires(spriteBatch, panel, rightPos, rightWirePos, mouseInRect, equippedWire, wireInterval);
|
||||
}
|
||||
rightPos.Y += connectorIntervalLeft;
|
||||
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
||||
rightWirePos.Y += c.Wires.Count * wireInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -121,7 +121,7 @@ namespace Barotrauma.Items.Components
|
||||
c.DrawWires(spriteBatch, panel, leftPos, leftWirePos, mouseInRect, equippedWire, wireInterval);
|
||||
}
|
||||
leftPos.Y += connectorIntervalRight;
|
||||
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
||||
leftWirePos.Y += c.Wires.Count * wireInterval;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,15 +228,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float connectorSpriteScale = (35.0f / connectionSprite.SourceRect.Width) * panel.Scale;
|
||||
|
||||
for (int i = 0; i < MaxWires; i++)
|
||||
foreach (var wire in wires)
|
||||
{
|
||||
if (wires[i] == null || wires[i].Hidden || (DraggingConnected == wires[i] && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
|
||||
if (wires[i].HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
||||
if (wire.Hidden || (DraggingConnected == wire && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
|
||||
if (wire.HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
||||
|
||||
Connection recipient = wires[i].OtherConnection(this);
|
||||
Connection recipient = wire.OtherConnection(this);
|
||||
LocalizedString label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
|
||||
if (wires[i].Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
|
||||
DrawWire(spriteBatch, wires[i], position, wirePosition, equippedWire, panel, label);
|
||||
if (wire.Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
|
||||
DrawWire(spriteBatch, wire, position, wirePosition, equippedWire, panel, label);
|
||||
|
||||
wirePosition.Y += wireInterval;
|
||||
}
|
||||
@@ -248,18 +248,17 @@ namespace Barotrauma.Items.Components
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
if ((GameMain.NetworkMember != null || panel.CheckCharacterSuccess(Character.Controlled)) &&
|
||||
Wires.Count(w => w != null) < MaxPlayerConnectableWires)
|
||||
Wires.Count < MaxPlayerConnectableWires)
|
||||
{
|
||||
//find an empty cell for the new connection
|
||||
int index = FindEmptyIndex();
|
||||
if (index > -1 && !Wires.Contains(DraggingConnected))
|
||||
if (WireSlotsAvailable() && !Wires.Contains(DraggingConnected))
|
||||
{
|
||||
bool alreadyConnected = DraggingConnected.IsConnectedTo(panel.Item);
|
||||
DraggingConnected.RemoveConnection(panel.Item);
|
||||
if (DraggingConnected.Connect(this, !alreadyConnected, true))
|
||||
{
|
||||
var otherConnection = DraggingConnected.OtherConnection(this);
|
||||
SetWire(index, DraggingConnected);
|
||||
ConnectWire(DraggingConnected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,7 +283,7 @@ namespace Barotrauma.Items.Components
|
||||
flashColor * (float)Math.Sin(FlashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), scale: connectorSpriteScale);
|
||||
}
|
||||
|
||||
if (Wires.Any(w => w != null && w != DraggingConnected && !w.Hidden && (!w.HiddenInGame || Screen.Selected != GameMain.GameScreen)))
|
||||
if (Wires.Any(w => w != DraggingConnected && !w.Hidden && (!w.HiddenInGame || Screen.Selected != GameMain.GameScreen)))
|
||||
{
|
||||
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
||||
screwSprites[screwIndex].Draw(spriteBatch, position, scale: connectorSpriteScale);
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
MoveConnectedWires(amount);
|
||||
@@ -147,9 +147,10 @@ namespace Barotrauma.Items.Components
|
||||
//because some of the wires connected to the panel may not exist yet
|
||||
long msgStartPos = msg.BitPosition;
|
||||
msg.ReadUInt16(); //user ID
|
||||
foreach (Connection connection in Connections)
|
||||
foreach (Connection _ in Connections)
|
||||
{
|
||||
for (int i = 0; i < connection.MaxWires; i++)
|
||||
uint wireCount = msg.ReadVariableUInt32();
|
||||
for (int i = 0; i < wireCount; i++)
|
||||
{
|
||||
msg.ReadUInt16();
|
||||
}
|
||||
@@ -173,9 +174,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void ApplyRemoteState(IReadMessage msg)
|
||||
{
|
||||
List<Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
|
||||
List<Wire> newWires = new List<Wire>();
|
||||
|
||||
List<Wire> prevWires = Connections.SelectMany(c => c.Wires).ToList();
|
||||
|
||||
ushort userID = msg.ReadUInt16();
|
||||
|
||||
if (userID == 0)
|
||||
@@ -195,7 +195,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (Connection connection in Connections)
|
||||
{
|
||||
for (int i = 0; i < connection.MaxWires; i++)
|
||||
HashSet<Wire> newWires = new HashSet<Wire>();
|
||||
uint wireCount = msg.ReadVariableUInt32();
|
||||
for (int i = 0; i < wireCount; i++)
|
||||
{
|
||||
ushort wireId = msg.ReadUInt16();
|
||||
|
||||
@@ -204,9 +206,18 @@ namespace Barotrauma.Items.Components
|
||||
if (wireComponent == null) { continue; }
|
||||
|
||||
newWires.Add(wireComponent);
|
||||
}
|
||||
|
||||
connection.SetWire(i, wireComponent);
|
||||
wireComponent.Connect(connection, false);
|
||||
Wire[] oldWires = connection.Wires.Where(w => !newWires.Contains(w)).ToArray();
|
||||
foreach (var wire in oldWires)
|
||||
{
|
||||
connection.DisconnectWire(wire);
|
||||
}
|
||||
|
||||
foreach (var wire in newWires.Where(w => !connection.Wires.Contains(w)).ToArray())
|
||||
{
|
||||
connection.ConnectWire(wire);
|
||||
wire.Connect(connection, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
|
||||
TextManager.Get(ciElement.Label).Fallback(ciElement.Label));
|
||||
if (!ciElement.IsIntegerInput)
|
||||
if (!ciElement.IsNumberInput)
|
||||
{
|
||||
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), ciElement.Signal, style: "GUITextBoxNoIcon")
|
||||
{
|
||||
@@ -77,29 +77,71 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
int.TryParse(ciElement.Signal, out int signal);
|
||||
var numberInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
GUINumberInput numberInput = null;
|
||||
if (ciElement.NumberType == NumberType.Float)
|
||||
{
|
||||
UserData = ciElement,
|
||||
MinValueInt = ciElement.NumberInputMin,
|
||||
MaxValueInt = ciElement.NumberInputMax,
|
||||
IntValue = Math.Clamp(signal, ciElement.NumberInputMin, ciElement.NumberInputMax)
|
||||
};
|
||||
//reset size restrictions set by the Style to make sure the elements can fit the interface
|
||||
numberInput.RectTransform.MinSize = numberInput.LayoutGroup.RectTransform.MinSize = new Point(0, 0);
|
||||
numberInput.RectTransform.MaxSize = numberInput.LayoutGroup.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
|
||||
numberInput.OnValueChanged += (ni) =>
|
||||
TryParseFloatInvariantCulture(ciElement.Signal, out float floatSignal);
|
||||
TryParseFloatInvariantCulture(ciElement.NumberInputMin, out float numberInputMin);
|
||||
TryParseFloatInvariantCulture(ciElement.NumberInputMax, out float numberInputMax);
|
||||
TryParseFloatInvariantCulture(ciElement.NumberInputStep, out float numberInputStep);
|
||||
numberInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), NumberType.Float)
|
||||
{
|
||||
UserData = ciElement,
|
||||
MinValueFloat = numberInputMin,
|
||||
MaxValueFloat = numberInputMax,
|
||||
FloatValue = Math.Clamp(floatSignal, numberInputMin, numberInputMax),
|
||||
DecimalsToDisplay = ciElement.NumberInputDecimalPlaces,
|
||||
valueStep = numberInputStep,
|
||||
OnValueChanged = (ni) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
ValueChanged(ni.UserData as CustomInterfaceElement, ni.FloatValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (ciElement.NumberType == NumberType.Int)
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
int.TryParse(ciElement.Signal, out int intSignal);
|
||||
int.TryParse(ciElement.NumberInputMin, out int numberInputMin);
|
||||
int.TryParse(ciElement.NumberInputMax, out int numberInputMax);
|
||||
TryParseFloatInvariantCulture(ciElement.NumberInputStep, out float numberInputStep);
|
||||
numberInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), NumberType.Int)
|
||||
{
|
||||
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
};
|
||||
uiElements.Add(numberInput);
|
||||
UserData = ciElement,
|
||||
MinValueInt = numberInputMin,
|
||||
MaxValueInt = numberInputMax,
|
||||
IntValue = Math.Clamp(intSignal, numberInputMin, numberInputMax),
|
||||
valueStep = numberInputStep,
|
||||
OnValueChanged = (ni) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ShowError($"Error creating a CustomInterface component: unexpected NumberType \"{(ciElement.NumberType.HasValue ? ciElement.NumberType.Value.ToString() : "none")}\"");
|
||||
}
|
||||
if (numberInput != null)
|
||||
{
|
||||
//reset size restrictions set by the Style to make sure the elements can fit the interface
|
||||
numberInput.RectTransform.MinSize = numberInput.LayoutGroup.RectTransform.MinSize = new Point(0, 0);
|
||||
numberInput.RectTransform.MaxSize = numberInput.LayoutGroup.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
|
||||
uiElements.Add(numberInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ciElement.ContinuousSignal)
|
||||
@@ -205,7 +247,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.HasPropertyName || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
|
||||
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Count > 0);
|
||||
if (visible) { visibleElementCount++; }
|
||||
if (uiElement.Visible != visible)
|
||||
{
|
||||
@@ -293,7 +335,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (uiElements[i] is GUINumberInput ni)
|
||||
{
|
||||
if (ni.InputType == GUINumberInput.NumberType.Int)
|
||||
if (ni.InputType == NumberType.Int)
|
||||
{
|
||||
int.TryParse(customInterfaceElementList[i].Signal, out int value);
|
||||
ni.IntValue = value;
|
||||
@@ -307,18 +349,28 @@ 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].HasPropertyName)
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
{
|
||||
if (!customInterfaceElementList[i].IsIntegerInput)
|
||||
if (!element.IsNumberInput)
|
||||
{
|
||||
msg.Write(((GUITextBox)uiElements[i]).Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(((GUINumberInput)uiElements[i]).IntValue.ToString());
|
||||
switch (element.NumberType)
|
||||
{
|
||||
case NumberType.Float:
|
||||
msg.Write(((GUINumberInput)uiElements[i]).FloatValue.ToString());
|
||||
break;
|
||||
case NumberType.Int:
|
||||
default:
|
||||
msg.Write(((GUINumberInput)uiElements[i]).IntValue.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (customInterfaceElementList[i].ContinuousSignal)
|
||||
else if (element.ContinuousSignal)
|
||||
{
|
||||
msg.Write(((GUITickBox)uiElements[i]).Selected);
|
||||
}
|
||||
@@ -333,29 +385,38 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
if (customInterfaceElementList[i].HasPropertyName)
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
{
|
||||
if (!customInterfaceElementList[i].IsIntegerInput)
|
||||
string newValue = msg.ReadString();
|
||||
if (!element.IsNumberInput)
|
||||
{
|
||||
TextChanged(customInterfaceElementList[i], msg.ReadString());
|
||||
TextChanged(element, newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
int.TryParse(msg.ReadString(), out int value);
|
||||
ValueChanged(customInterfaceElementList[i], value);
|
||||
switch (element.NumberType)
|
||||
{
|
||||
case NumberType.Int when int.TryParse(newValue, out int value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
case NumberType.Float when TryParseFloatInvariantCulture(newValue, out float value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool elementState = msg.ReadBoolean();
|
||||
if (customInterfaceElementList[i].ContinuousSignal)
|
||||
if (element.ContinuousSignal)
|
||||
{
|
||||
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||
TickBoxToggled(customInterfaceElementList[i], elementState);
|
||||
TickBoxToggled(element, elementState);
|
||||
}
|
||||
else if (elementState)
|
||||
{
|
||||
ButtonClicked(customInterfaceElementList[i]);
|
||||
ButtonClicked(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
layoutGroup.Recalculate();
|
||||
}
|
||||
|
||||
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
|
||||
@@ -100,7 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
GUITextBlock newBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
|
||||
"> " + input,
|
||||
textColor: color, wrap: true, font: UseMonospaceFont ? GUIStyle.MonospacedFont : GUIStyle.GlobalFont)
|
||||
textColor: color, wrap: true, font: UseMonospaceFont ? GUIStyle.MonospacedFont : GUIStyle.Font)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
@@ -526,7 +526,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
//only used in the sub editor, hence only in the client project
|
||||
if (!item.IsSelected) { return; }
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
widgets.Clear();
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private GUIMessageBox autodockingVerification;
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
//use the extents of the item as the draw size
|
||||
@@ -180,5 +182,10 @@ namespace Barotrauma.Items.Components
|
||||
Undock();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write((byte)allowOutpostAutoDocking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
LocalizedString description = item.Description;
|
||||
if (item.Prefab.Identifier == "idcard" || item.Tags.Contains("despawncontainer"))
|
||||
if (item.HasTag("identitycard") || item.HasTag("despawncontainer"))
|
||||
{
|
||||
string[] readTags = item.Tags.Split(',');
|
||||
string idName = null;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -6,13 +8,8 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -355,7 +352,7 @@ namespace Barotrauma
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? RotationRad : -RotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
@@ -379,17 +376,17 @@ namespace Barotrauma
|
||||
}
|
||||
if (color.A > 0)
|
||||
{
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, RotationRad, Scale, activeSprite.effects, depth);
|
||||
if (fadeInBrokenSprite != null)
|
||||
{
|
||||
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
|
||||
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, d);
|
||||
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, RotationRad, Scale, activeSprite.effects, d);
|
||||
}
|
||||
}
|
||||
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
|
||||
{
|
||||
Prefab.InfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, Prefab.InfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.001f);
|
||||
Prefab.DamagedInfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, Infector.HealthColor, Prefab.DamagedInfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.002f);
|
||||
Prefab.InfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, Prefab.InfectedSprite.Origin, RotationRad, Scale, activeSprite.effects, depth - 0.001f);
|
||||
Prefab.DamagedInfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, Infector.HealthColor, Prefab.DamagedInfectedSprite.Origin, RotationRad, Scale, activeSprite.effects, depth - 0.002f);
|
||||
}
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
@@ -397,11 +394,11 @@ namespace Barotrauma
|
||||
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
bool flipX = flippedX && Prefab.CanSpriteFlipX;
|
||||
bool flipY = flippedY && Prefab.CanSpriteFlipY;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flipX ^ flipY ? rotationRad : -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flipX ^ flipY ? RotationRad : -RotationRad) * Scale;
|
||||
if (flipX) { offset.X = -offset.X; }
|
||||
if (flipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
rotationRad + rot, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
|
||||
RotationRad + rot, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||
}
|
||||
}
|
||||
@@ -448,7 +445,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -RotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
var ca = (float)Math.Cos(-body.Rotation);
|
||||
@@ -469,7 +466,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -RotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
@@ -572,6 +569,18 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckNeedsSoundUpdate(ItemComponent ic)
|
||||
{
|
||||
if (ic.NeedsSoundUpdate())
|
||||
{
|
||||
if (!updateableComponents.Contains(ic))
|
||||
{
|
||||
updateableComponents.Add(ic);
|
||||
}
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSpriteStates(float deltaTime)
|
||||
{
|
||||
if (activeContainedSprite != null)
|
||||
@@ -720,7 +729,7 @@ namespace Barotrauma
|
||||
//remove identifiers from the available container tags
|
||||
//(otherwise the list will include many irrelevant options,
|
||||
//e.g. "weldingtool" because a welding fuel tank can be placed inside the container, etc)
|
||||
.Where(t => !ItemPrefab.Prefabs.Any(ip => ip.Identifier == t))
|
||||
.Where(t => !ItemPrefab.Prefabs.ContainsKey(t))
|
||||
.ToImmutableHashSet();
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1), tagsField.RectTransform, Anchor.TopRight), "...")
|
||||
{
|
||||
@@ -943,6 +952,7 @@ namespace Barotrauma
|
||||
|
||||
var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter))
|
||||
{
|
||||
PlaySoundOnSelect = true,
|
||||
OnSelected = (component, userData) =>
|
||||
{
|
||||
if (!(userData is Identifier)) { return true; }
|
||||
@@ -1174,7 +1184,7 @@ namespace Barotrauma
|
||||
texts.Clear();
|
||||
|
||||
string nameText = Name;
|
||||
if (Prefab.Identifier == "idcard" || Tags.Contains("despawncontainer"))
|
||||
if (Prefab.Tags.Contains("identitycard") || Tags.Contains("despawncontainer"))
|
||||
{
|
||||
string[] readTags = Tags.Split(',');
|
||||
string idName = null;
|
||||
|
||||
@@ -183,8 +183,21 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
Color branchColor = (branch.IsRoot || branch.IsRootGrowth) ? RootColor : Color.White;
|
||||
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
if (branch.DisconnectedFromRoot && branch.ParentBranch == null)
|
||||
{
|
||||
branchColor = Color.Yellow;
|
||||
}
|
||||
else if (branch.DisconnectedFromRoot)
|
||||
{
|
||||
branchColor = Color.Cyan;
|
||||
}
|
||||
else if (branch.ParentBranch == null)
|
||||
{
|
||||
branchColor = Color.Magenta;
|
||||
}
|
||||
#if DEBUG
|
||||
Vector2 basePos = Parent.WorldPosition;
|
||||
foreach (var (from, to) in debugSearchLines)
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma
|
||||
DrawArrow(FlowTargetHull, IsHorizontal ? rect.Height: rect.Width, Math.Abs(lerpedFlowForce.Length()), Color.Red * 0.3f);
|
||||
}
|
||||
|
||||
if (outsideCollisionBlocker.Enabled && Submarine != null)
|
||||
if (Submarine != null && outsideCollisionBlocker != null && outsideCollisionBlocker.Enabled)
|
||||
{
|
||||
var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape;
|
||||
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + Submarine.Position;
|
||||
|
||||
@@ -80,15 +80,17 @@ namespace Barotrauma
|
||||
}
|
||||
Vector2 center = new Vector2((minX + maxX) / 2.0f, (minY + maxY) / 2.0f);
|
||||
if (Submarine.MainSub != null) { center -= Submarine.MainSub.HiddenSubPosition; }
|
||||
center.X -= MathUtils.RoundTowardsClosest(center.X, Submarine.GridSize.X);
|
||||
center.Y -= MathUtils.RoundTowardsClosest(center.Y, Submarine.GridSize.Y);
|
||||
|
||||
Vector2 offsetFromGrid = new Vector2(
|
||||
MathUtils.RoundTowardsClosest(center.X, Submarine.GridSize.X) - center.X,
|
||||
MathUtils.RoundTowardsClosest(center.Y, Submarine.GridSize.Y) - center.Y - Submarine.GridSize.Y / 2);
|
||||
|
||||
MapEntity.SelectedList.Clear();
|
||||
assemblyEntities.ForEach(e => MapEntity.AddSelection(e));
|
||||
|
||||
foreach (MapEntity mapEntity in assemblyEntities)
|
||||
{
|
||||
mapEntity.Move(-center);
|
||||
mapEntity.Move(-center - offsetFromGrid);
|
||||
mapEntity.Submarine = Submarine.MainSub;
|
||||
var entityElement = mapEntity.Save(element);
|
||||
if (disabledEntities.Contains(mapEntity))
|
||||
|
||||
@@ -60,12 +60,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
IsDisposed = true;
|
||||
WallEdgeBuffer?.Dispose();
|
||||
@@ -482,12 +476,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
foreach (var vertexBuffer in vertexBuffers)
|
||||
{
|
||||
|
||||
@@ -230,14 +230,6 @@ namespace Barotrauma
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
|
||||
if (WaterEffect != null)
|
||||
{
|
||||
WaterEffect.Dispose();
|
||||
@@ -250,6 +242,5 @@ namespace Barotrauma
|
||||
basicEffect = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,7 +461,7 @@ namespace Barotrauma.Lights
|
||||
Matrix.CreateTranslation(-origin.X, -origin.Y, 0.0f) *
|
||||
Matrix.CreateRotationZ(amount) *
|
||||
Matrix.CreateTranslation(origin.X, origin.Y, 0.0f);
|
||||
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix);
|
||||
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix: rotationMatrix);
|
||||
}
|
||||
|
||||
private void CalculateDimensions()
|
||||
@@ -541,7 +541,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVertices(Vector2[] points, Matrix? rotationMatrix = null)
|
||||
public void SetVertices(Vector2[] points, bool mergeOverlappingSegments = true, Matrix? rotationMatrix = null)
|
||||
{
|
||||
Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");
|
||||
|
||||
@@ -594,13 +594,16 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (ParentEntity == null) { return; }
|
||||
|
||||
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
|
||||
if (chList != null)
|
||||
if (mergeOverlappingSegments)
|
||||
{
|
||||
overlappingHulls.Clear();
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
|
||||
if (chList != null)
|
||||
{
|
||||
MergeOverlappingSegments(ch);
|
||||
overlappingHulls.Clear();
|
||||
foreach (ConvexHull ch in chList.List)
|
||||
{
|
||||
MergeOverlappingSegments(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,18 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
class LightManager
|
||||
{
|
||||
/// <summary>
|
||||
/// How many light sources are allowed to recalculate their light volumes per frame.
|
||||
/// Pending calculations will be done on subsequent frames, starting from the light sources that have been waiting for a recalculation the longest.
|
||||
/// </summary>
|
||||
const int MaxLightVolumeRecalculationsPerFrame = 5;
|
||||
|
||||
/// <summary>
|
||||
/// If zoomed further out than this, characters no longer obstruct lights behind them.
|
||||
/// Improves performance, and isn't very noticeable if we do it after zoomed far out enough.
|
||||
/// </summary>
|
||||
const float ObstructLightsBehindCharactersZoomThreshold = 0.5f;
|
||||
|
||||
public static Entity ViewTarget { get; set; }
|
||||
|
||||
private float currLightMapScale;
|
||||
@@ -59,6 +71,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
private Vector2 losOffset;
|
||||
|
||||
private int recalculationCount;
|
||||
|
||||
public IEnumerable<LightSource> Lights
|
||||
{
|
||||
get { return lights; }
|
||||
@@ -151,6 +165,9 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
private readonly List<LightSource> activeLights = new List<LightSource>(capacity: 100);
|
||||
private readonly List<LightSource> activeLightsWithLightVolume = new List<LightSource>(capacity: 100);
|
||||
|
||||
public static int ActiveLightCount { get; private set; }
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
@@ -180,11 +197,13 @@ namespace Barotrauma.Lights
|
||||
Rectangle viewRect = cam.WorldView;
|
||||
viewRect.Y -= cam.WorldView.Height;
|
||||
//check which lights need to be drawn
|
||||
recalculationCount = 0;
|
||||
activeLights.Clear();
|
||||
foreach (LightSource light in lights)
|
||||
{
|
||||
if (!light.Enabled) { continue; }
|
||||
if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue) { continue; }
|
||||
|
||||
if (light.ParentBody != null)
|
||||
{
|
||||
light.ParentBody.UpdateDrawPosition();
|
||||
@@ -205,8 +224,44 @@ namespace Barotrauma.Lights
|
||||
range = Math.Max(Math.Max(spriteRange, targetSize), range);
|
||||
}
|
||||
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect)) { continue; }
|
||||
activeLights.Add(light);
|
||||
|
||||
light.Priority = lightPriority(range, light);
|
||||
|
||||
int i = 0;
|
||||
while (i < activeLights.Count && light.Priority < activeLights[i].Priority)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
activeLights.Insert(i, light);
|
||||
}
|
||||
ActiveLightCount = activeLights.Count;
|
||||
|
||||
float lightPriority(float range, LightSource light)
|
||||
{
|
||||
return
|
||||
range *
|
||||
((Character.Controlled?.Submarine != null && light.ParentSub == Character.Controlled?.Submarine) ? 2.0f : 1.0f) *
|
||||
(light.CastShadows ? 10.0f : 1.0f) *
|
||||
(light.LightSourceParams.OverrideLightSpriteAlpha ?? (light.Color.A / 255.0f));
|
||||
}
|
||||
|
||||
//find the lights with an active light volume
|
||||
activeLightsWithLightVolume.Clear();
|
||||
foreach (var activeLight in activeLights)
|
||||
{
|
||||
if (activeLight.Range < 1.0f || activeLight.Color.A < 1 || activeLight.CurrentBrightness <= 0.0f) { continue; }
|
||||
activeLightsWithLightVolume.Add(activeLight);
|
||||
}
|
||||
|
||||
//remove some lights with a light volume if there's too many of them
|
||||
if (activeLightsWithLightVolume.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit)
|
||||
{
|
||||
for (int i = GameSettings.CurrentConfig.Graphics.VisibleLightLimit; i < activeLightsWithLightVolume.Count; i++)
|
||||
{
|
||||
activeLights.Remove(activeLightsWithLightVolume[i]);
|
||||
}
|
||||
}
|
||||
activeLights.Sort((l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime));
|
||||
|
||||
//draw light sprites attached to characters
|
||||
//render into a separate rendertarget using alpha blending (instead of on top of everything else with alpha blending)
|
||||
@@ -235,7 +290,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (!light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
|
||||
}
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
@@ -243,14 +298,6 @@ namespace Barotrauma.Lights
|
||||
//draw a black rectangle on hulls to hide background lights behind subs
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
/*if (backgroundObstructor != null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
|
||||
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
|
||||
spriteBatch.End();
|
||||
}*/
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
|
||||
Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
|
||||
foreach (KeyValuePair<Hull, Rectangle> hull in visibleHulls)
|
||||
@@ -292,41 +339,44 @@ namespace Barotrauma.Lights
|
||||
|
||||
//draw characters to obstruct the highlighted items/characters and light sprites
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
if (cam.Zoom > ObstructLightsBehindCharactersZoomThreshold)
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (limb.DeformSprite != null) { continue; }
|
||||
limb.Draw(spriteBatch, cam, lightColor);
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
if (limb.DeformSprite != null) { continue; }
|
||||
limb.Draw(spriteBatch, cam, lightColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
spriteBatch.End();
|
||||
|
||||
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
|
||||
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
|
||||
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (limb.DeformSprite == null) { continue; }
|
||||
limb.Draw(spriteBatch, cam, lightColor);
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
if (limb.DeformSprite == null) { continue; }
|
||||
limb.Draw(spriteBatch, cam, lightColor);
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
@@ -344,7 +394,7 @@ namespace Barotrauma.Lights
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform, recalculationCount < MaxLightVolumeRecalculationsPerFrame, ref recalculationCount);
|
||||
}
|
||||
|
||||
lightEffect.World = transform;
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace Barotrauma.Lights
|
||||
private VertexPositionColorTexture[] vertices;
|
||||
private short[] indices;
|
||||
|
||||
private List<ConvexHullList> hullsInRange;
|
||||
private readonly List<ConvexHullList> hullsInRange;
|
||||
|
||||
public Texture2D texture;
|
||||
|
||||
@@ -246,9 +246,9 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
//when were the vertices of the light volume last calculated
|
||||
private float lastRecalculationTime;
|
||||
public float LastRecalculationTime { get; private set; }
|
||||
|
||||
private Dictionary<Submarine, Vector2> diffToSub;
|
||||
private readonly Dictionary<Submarine, Vector2> diffToSub;
|
||||
|
||||
private DynamicVertexBuffer lightVolumeBuffer;
|
||||
private DynamicIndexBuffer lightVolumeIndexBuffer;
|
||||
@@ -376,6 +376,8 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public float Priority;
|
||||
|
||||
private Vector2 lightTextureTargetSize;
|
||||
|
||||
public Vector2 LightTextureTargetSize
|
||||
@@ -423,7 +425,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
public bool Enabled = true;
|
||||
|
||||
private ISerializableEntity conditionalTarget;
|
||||
private readonly ISerializableEntity conditionalTarget;
|
||||
private readonly PropertyConditional.Comparison comparison;
|
||||
private readonly List<PropertyConditional> conditionals = new List<PropertyConditional>();
|
||||
|
||||
@@ -561,7 +563,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
foreach (var ch in chList.List)
|
||||
{
|
||||
if (ch.LastVertexChangeTime > lastRecalculationTime && !chList.IsHidden.Contains(ch))
|
||||
if (ch.LastVertexChangeTime > LastRecalculationTime && !chList.IsHidden.Contains(ch))
|
||||
{
|
||||
NeedsRecalculation = true;
|
||||
break;
|
||||
@@ -1289,7 +1291,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
//visualize light recalculations
|
||||
float timeSinceRecalculation = (float)Timing.TotalTime - lastRecalculationTime;
|
||||
float timeSinceRecalculation = (float)Timing.TotalTime - LastRecalculationTime;
|
||||
if (timeSinceRecalculation < 0.1f)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, GUIStyle.Red * (1.0f - timeSinceRecalculation * 10.0f), isFilled: true);
|
||||
@@ -1313,7 +1315,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform)
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform, bool allowRecalculation, ref int recalculationCount)
|
||||
{
|
||||
if (Range < 1.0f || Color.A < 1 || CurrentBrightness <= 0.0f) { return; }
|
||||
|
||||
@@ -1338,8 +1340,9 @@ namespace Barotrauma.Lights
|
||||
|
||||
CheckHullsInRange();
|
||||
|
||||
if (NeedsRecalculation)
|
||||
if (NeedsRecalculation && allowRecalculation)
|
||||
{
|
||||
recalculationCount++;
|
||||
var verts = FindRaycastHits();
|
||||
if (verts == null)
|
||||
{
|
||||
@@ -1352,7 +1355,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
CalculateLightVertices(verts);
|
||||
|
||||
lastRecalculationTime = (float)Timing.TotalTime;
|
||||
LastRecalculationTime = (float)Timing.TotalTime;
|
||||
NeedsRecalculation = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(this.Seed));
|
||||
Generate();
|
||||
Generate(GameMain.GameSession.GameMode is CampaignMode campaign ? campaign.Settings : CampaignSettings.Empty);
|
||||
InitProjectSpecific();
|
||||
return true;
|
||||
}
|
||||
@@ -642,11 +642,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw && location == HighlightedLocation && (!location.Discovered || !location.HasOutpost()))
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
if (location.Reputation != null)
|
||||
Vector2 dPos = pos;
|
||||
if (location == HighlightedLocation && (!location.Discovered || !location.HasOutpost()) && location.Reputation != null)
|
||||
{
|
||||
Vector2 dPos = pos;
|
||||
dPos.Y += 48;
|
||||
string name = $"Reputation: {location.Name}";
|
||||
Vector2 nameSize = GUIStyle.SmallFont.MeasureString(name);
|
||||
@@ -663,6 +663,8 @@ namespace Barotrauma
|
||||
GUI.DrawString(spriteBatch, dPos + (new Vector2(256, 32) / 2) - (repValueSize / 2), reputationValue, Color.White, Color.Black, font: GUIStyle.SubHeadingFont);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)dPos.X, (int)dPos.Y, 256, 32), Color.White);
|
||||
}
|
||||
dPos.Y += 48;
|
||||
GUI.DrawString(spriteBatch, dPos, $"Difficulty: {location.LevelData.Difficulty.FormatZeroDecimal()}", Color.White, Color.Black * 0.8f, 4, font: GUIStyle.SmallFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -977,7 +979,7 @@ namespace Barotrauma
|
||||
Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom;
|
||||
if (viewArea.Contains(center) && connection.Biome != null)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, center, connection.Biome.Identifier + " (" + connection.Difficulty + ")", Color.White);
|
||||
GUI.DrawString(spriteBatch, center, (connection.LevelData?.GenerationParams?.Identifier ?? connection.Biome.Identifier) + " (" + (int)connection.Difficulty + ")", Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,18 @@ namespace Barotrauma
|
||||
}
|
||||
catch (System.IO.FileNotFoundException e)
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\".";
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\" (file not found).";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
catch (System.IO.InvalidDataException e)
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\" (invalid data).";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:InvalidData" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
RoundSound newSound = new RoundSound(element, existingSound);
|
||||
|
||||
@@ -1,55 +1,61 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.RuinGeneration;
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Submarine : Entity, IServerPositionSync
|
||||
{
|
||||
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
|
||||
{
|
||||
Vector2 position = PlayerInput.MousePosition;
|
||||
position = cam.ScreenToWorld(position);
|
||||
|
||||
Vector2 worldGridPos = VectorToWorldGrid(position);
|
||||
|
||||
if (sub != null)
|
||||
{
|
||||
worldGridPos.X += sub.Position.X % GridSize.X;
|
||||
worldGridPos.Y += sub.Position.Y % GridSize.Y;
|
||||
}
|
||||
|
||||
return worldGridPos;
|
||||
}
|
||||
|
||||
//drawing ----------------------------------------------------
|
||||
private static readonly HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
|
||||
|
||||
private static double prevCullTime;
|
||||
private static Rectangle prevCullArea;
|
||||
/// <summary>
|
||||
/// Interval at which we force culled entites to be updated, regardless if the camera has moved
|
||||
/// </summary>
|
||||
private const float CullInterval = 0.25f;
|
||||
/// <summary>
|
||||
/// Margin applied around the view area when culling entities (i.e. entities that are this far outside the view are still considered visible)
|
||||
/// </summary>
|
||||
private const int CullMargin = 500;
|
||||
/// <summary>
|
||||
/// Update entity culling when any corner of the view has moved more than this
|
||||
/// </summary>
|
||||
private const int CullMoveThreshold = 50;
|
||||
|
||||
public static void CullEntities(Camera cam)
|
||||
{
|
||||
Rectangle camView = cam.WorldView;
|
||||
camView = new Rectangle(camView.X - CullMargin, camView.Y + CullMargin, camView.Width + CullMargin * 2, camView.Height + CullMargin * 2);
|
||||
|
||||
if (Math.Abs(camView.X - prevCullArea.X) < CullMoveThreshold &&
|
||||
Math.Abs(camView.Y - prevCullArea.Y) < CullMoveThreshold &&
|
||||
Math.Abs(camView.Right - prevCullArea.Right) < CullMoveThreshold &&
|
||||
Math.Abs(camView.Bottom - prevCullArea.Bottom) < CullMoveThreshold &&
|
||||
prevCullTime > Timing.TotalTime - CullInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
visibleSubs.Clear();
|
||||
foreach (Submarine sub in Loaded)
|
||||
{
|
||||
if (Level.Loaded != null && sub.WorldPosition.Y < Level.MaxEntityDepth) { continue; }
|
||||
|
||||
int margin = 500;
|
||||
Rectangle worldBorders = new Rectangle(
|
||||
sub.VisibleBorders.X + (int)sub.WorldPosition.X - margin,
|
||||
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y + margin,
|
||||
sub.VisibleBorders.Width + margin * 2,
|
||||
sub.VisibleBorders.Height + margin * 2);
|
||||
sub.VisibleBorders.X + (int)sub.WorldPosition.X,
|
||||
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y,
|
||||
sub.VisibleBorders.Width,
|
||||
sub.VisibleBorders.Height);
|
||||
|
||||
if (RectsOverlap(worldBorders, cam.WorldView))
|
||||
if (RectsOverlap(worldBorders, camView))
|
||||
{
|
||||
visibleSubs.Add(sub);
|
||||
}
|
||||
@@ -64,16 +70,22 @@ namespace Barotrauma
|
||||
visibleEntities.Clear();
|
||||
}
|
||||
|
||||
Rectangle worldView = cam.WorldView;
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
if (entity.Submarine != null)
|
||||
{
|
||||
if (!visibleSubs.Contains(entity.Submarine)) { continue; }
|
||||
}
|
||||
|
||||
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
|
||||
if (entity.IsVisible(camView)) { visibleEntities.Add(entity); }
|
||||
}
|
||||
|
||||
prevCullArea = camView;
|
||||
prevCullTime = Timing.TotalTime;
|
||||
}
|
||||
|
||||
public static void ForceVisibilityRecheck()
|
||||
{
|
||||
prevCullTime = 0;
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||
@@ -148,7 +160,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (predicate != null)
|
||||
{
|
||||
if (!predicate(e)) continue;
|
||||
if (!predicate(e)) { continue; }
|
||||
}
|
||||
float drawDepth = structure.GetDrawDepth();
|
||||
int i = 0;
|
||||
@@ -525,7 +537,7 @@ namespace Barotrauma
|
||||
Item.ItemList.Count(it2 => it2.linkedTo.Contains(item) && !item.linkedTo.Contains(it2));
|
||||
for (int i = 0; i < item.Connections.Count; i++)
|
||||
{
|
||||
int wireCount = item.Connections[i].Wires.Count(w => w != null);
|
||||
int wireCount = item.Connections[i].Wires.Count;
|
||||
if (doorLinks + wireCount > item.Connections[i].MaxWires)
|
||||
{
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
@@ -679,6 +691,22 @@ namespace Barotrauma
|
||||
return GameMain.LightManager.Lights.Count(l => l.CastShadows && !l.IsBackground) - disabledItemLightCount;
|
||||
}
|
||||
|
||||
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
|
||||
{
|
||||
Vector2 position = PlayerInput.MousePosition;
|
||||
position = cam.ScreenToWorld(position);
|
||||
|
||||
Vector2 worldGridPos = VectorToWorldGrid(position);
|
||||
|
||||
if (sub != null)
|
||||
{
|
||||
worldGridPos.X += sub.Position.X % GridSize.X;
|
||||
worldGridPos.Y += sub.Position.Y % GridSize.Y;
|
||||
}
|
||||
|
||||
return worldGridPos;
|
||||
}
|
||||
|
||||
public void ClientReadPosition(IReadMessage msg, float sendingTime)
|
||||
{
|
||||
var posInfo = PhysicsBody.ClientRead(msg, sendingTime, parentDebugName: Info.Name);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Barotrauma
|
||||
partial class SubmarineInfo : IDisposable
|
||||
{
|
||||
public Sprite PreviewImage;
|
||||
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
string previewImageData = SubmarineElement.GetAttributeString("previewimage", "");
|
||||
@@ -154,13 +154,13 @@ namespace Barotrauma
|
||||
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
|
||||
if (RecommendedCrewExperience != CrewExperienceLevel.Unknown)
|
||||
{
|
||||
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.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)
|
||||
TextManager.Get(RecommendedCrewExperience.ToIdentifier()), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Barotrauma
|
||||
class SubmarinePreview : IDisposable
|
||||
{
|
||||
private SpriteRecorder spriteRecorder;
|
||||
private SubmarineInfo submarineInfo;
|
||||
private readonly SubmarineInfo submarineInfo;
|
||||
private Camera camera;
|
||||
private Task loadTask;
|
||||
private volatile bool isDisposed;
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
instance?.Dispose();
|
||||
instance?.Dispose(); instance = null;
|
||||
}
|
||||
|
||||
private SubmarinePreview(SubmarineInfo subInfo)
|
||||
@@ -100,12 +100,16 @@ namespace Barotrauma
|
||||
GUIListBox specsContainer = null;
|
||||
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, innerPadded.RectTransform, Anchor.Center),
|
||||
(spriteBatch, component) => {
|
||||
(spriteBatch, component) =>
|
||||
{
|
||||
if (isDisposed) { return; }
|
||||
camera.UpdateTransform(interpolate: true, updateListener: false);
|
||||
Rectangle drawRect = new Rectangle(component.Rect.X + 1, component.Rect.Y + 1, component.Rect.Width - 2, component.Rect.Height - 2);
|
||||
RenderSubmarine(spriteBatch, drawRect, component);
|
||||
},
|
||||
(deltaTime, component) => {
|
||||
(deltaTime, component) =>
|
||||
{
|
||||
if (isDisposed) { return; }
|
||||
bool isMouseOnComponent = GUI.MouseOn == component;
|
||||
camera.MoveCamera(deltaTime, allowZoom: isMouseOnComponent, followSub: false);
|
||||
if (isMouseOnComponent &&
|
||||
@@ -294,8 +298,8 @@ namespace Barotrauma
|
||||
|
||||
private void BakeMapEntity(XElement element)
|
||||
{
|
||||
string identifier = element.GetAttributeString("identifier", "");
|
||||
if (string.IsNullOrEmpty(identifier)) { return; }
|
||||
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
if (identifier.IsEmpty) { return; }
|
||||
Rectangle rect = element.GetAttributeRect("rect", Rectangle.Empty);
|
||||
if (rect.Equals(Rectangle.Empty)) { return; }
|
||||
|
||||
@@ -308,7 +312,16 @@ namespace Barotrauma
|
||||
|
||||
float rotation = element.GetAttributeFloat("rotation", 0f);
|
||||
|
||||
MapEntityPrefab prefab = MapEntityPrefab.List.FirstOrDefault(p => p.Identifier == identifier);
|
||||
MapEntityPrefab prefab = null;
|
||||
if (element.Name.ToString().Equals("item", StringComparison.OrdinalIgnoreCase) &&
|
||||
ItemPrefab.Prefabs.TryGet(identifier, out ItemPrefab ip))
|
||||
{
|
||||
prefab = ip;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefab = MapEntityPrefab.List.FirstOrDefault(p => p.Identifier == identifier);
|
||||
}
|
||||
if (prefab == null) { return; }
|
||||
|
||||
var texture = prefab.Sprite.Texture;
|
||||
@@ -329,7 +342,6 @@ namespace Barotrauma
|
||||
|
||||
bool overrideSprite = false;
|
||||
ItemPrefab itemPrefab = prefab as ItemPrefab;
|
||||
StructurePrefab structurePrefab = prefab as StructurePrefab;
|
||||
if (itemPrefab != null)
|
||||
{
|
||||
BakeItemComponents(itemPrefab, rect, color, scale, rotation, depth, out overrideSprite);
|
||||
@@ -337,7 +349,7 @@ namespace Barotrauma
|
||||
|
||||
if (!overrideSprite)
|
||||
{
|
||||
if (structurePrefab != null)
|
||||
if (prefab is StructurePrefab structurePrefab)
|
||||
{
|
||||
ParseUpgrades(structurePrefab.ConfigElement, ref scale);
|
||||
|
||||
@@ -655,7 +667,8 @@ namespace Barotrauma
|
||||
previewFrame.RectTransform.Parent = null;
|
||||
previewFrame = null;
|
||||
}
|
||||
spriteRecorder?.Dispose();
|
||||
spriteRecorder?.Dispose(); spriteRecorder = null;
|
||||
camera?.Dispose(); camera = null;
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
@@ -9,14 +10,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)Type);
|
||||
msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.WriteRangedInteger((int)ChatMode, 0, Enum.GetValues(typeof(ChatMode)).Length - 1);
|
||||
msg.Write(Text);
|
||||
}
|
||||
|
||||
public static void ClientRead(IReadMessage msg)
|
||||
{
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadByte();
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
|
||||
string txt = "";
|
||||
string styleSetting = string.Empty;
|
||||
@@ -183,6 +185,11 @@ namespace Barotrauma.Networking
|
||||
break;
|
||||
default:
|
||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType, textColor: textColor);
|
||||
if (type == ChatMessageType.Radio && CanUseRadio(senderCharacter, out WifiComponent radio))
|
||||
{
|
||||
Signal s = new Signal(txt, sender: senderCharacter, source: radio.Item);
|
||||
radio.TransmitSignal(s, sentFromChat: true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
LastID = id;
|
||||
|
||||
@@ -146,26 +146,19 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
private bool disposed = false;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (WriteStream != null)
|
||||
{
|
||||
WriteStream.Flush();
|
||||
WriteStream.Close();
|
||||
WriteStream.Dispose();
|
||||
WriteStream = null;
|
||||
}
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
if (disposed) { return; }
|
||||
|
||||
if (WriteStream != null)
|
||||
{
|
||||
WriteStream.Flush();
|
||||
WriteStream.Close();
|
||||
WriteStream.Dispose();
|
||||
WriteStream = null;
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@@ -11,6 +12,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -182,6 +184,20 @@ namespace Barotrauma.Networking
|
||||
get { return ownerKey > 0 || steamP2POwner; }
|
||||
}
|
||||
|
||||
internal readonly struct PermissionChangedEvent
|
||||
{
|
||||
public readonly ClientPermissions NewPermissions;
|
||||
public readonly ImmutableArray<string> NewPermittedConsoleCommands;
|
||||
|
||||
public PermissionChangedEvent(ClientPermissions newPermissions, IReadOnlyList<string> newPermittedConsoleCommands)
|
||||
{
|
||||
NewPermissions = newPermissions;
|
||||
NewPermittedConsoleCommands = newPermittedConsoleCommands.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
||||
public readonly NamedEvent<PermissionChangedEvent> OnPermissionChanged = new NamedEvent<PermissionChangedEvent>();
|
||||
|
||||
public GameClient(string newName, string ip, UInt64 steamId, string serverName = null, int ownerKey = 0, bool steamP2POwner = false)
|
||||
{
|
||||
//TODO: gui stuff should probably not be here?
|
||||
@@ -570,7 +586,12 @@ namespace Barotrauma.Networking
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
#if DEBUG
|
||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.P)) return;
|
||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.P)) return;
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Home))
|
||||
{
|
||||
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, permittedConsoleCommands));
|
||||
}
|
||||
#endif
|
||||
|
||||
foreach (Client c in ConnectedClients)
|
||||
@@ -668,7 +689,7 @@ namespace Barotrauma.Networking
|
||||
if (ChildServerRelay.Process?.HasExited ?? true)
|
||||
{
|
||||
Disconnect();
|
||||
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text.Text == ChildServerRelay.CrashMessage))
|
||||
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text?.Text == ChildServerRelay.CrashMessage))
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
|
||||
msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
|
||||
@@ -803,7 +824,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
byte campaignID = inc.ReadByte();
|
||||
UInt16 campaignSaveID = inc.ReadUInt16();
|
||||
UInt16 campaignUpdateID = inc.ReadUInt16();
|
||||
Dictionary<MultiPlayerCampaign.NetFlags, UInt16> campaignUpdateIDs = new Dictionary<MultiPlayerCampaign.NetFlags, ushort>();
|
||||
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
campaignUpdateIDs[flag] = inc.ReadUInt16();
|
||||
}
|
||||
|
||||
IWriteMessage readyToStartMsg = new WriteOnlyMessage();
|
||||
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
|
||||
@@ -822,7 +847,7 @@ namespace Barotrauma.Networking
|
||||
campaign != null &&
|
||||
campaign.CampaignID == campaignID &&
|
||||
campaign.LastSaveID == campaignSaveID &&
|
||||
campaign.LastUpdateID == campaignUpdateID;
|
||||
campaignUpdateIDs.All(kvp => campaign.GetLastUpdateIdForFlag(kvp.Key) == kvp.Value);
|
||||
}
|
||||
readyToStartMsg.Write(readyToStart);
|
||||
|
||||
@@ -1019,40 +1044,25 @@ namespace Barotrauma.Networking
|
||||
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
|
||||
}
|
||||
|
||||
byte equalityCheckValueCount = inc.ReadByte();
|
||||
List<int> levelEqualityCheckValues = new List<int>();
|
||||
for (int i = 0; i < equalityCheckValueCount; i++)
|
||||
var levelEqualityCheckValues = new Dictionary<Level.LevelGenStage, int>();
|
||||
foreach (Level.LevelGenStage stage in Enum.GetValues(typeof(Level.LevelGenStage)).OfType<Level.LevelGenStage>().OrderBy(s => s))
|
||||
{
|
||||
levelEqualityCheckValues.Add(inc.ReadInt32());
|
||||
levelEqualityCheckValues.Add(stage, inc.ReadInt32());
|
||||
}
|
||||
|
||||
if (Level.Loaded.EqualityCheckValues.Count != levelEqualityCheckValues.Count)
|
||||
foreach (var stage in levelEqualityCheckValues.Keys)
|
||||
{
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
||||
" (client value count: " + Level.Loaded.EqualityCheckValues.Count +
|
||||
", level value count: " + levelEqualityCheckValues.Count +
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < equalityCheckValueCount; i++)
|
||||
if (Level.Loaded.EqualityCheckValues[stage] != levelEqualityCheckValues[stage])
|
||||
{
|
||||
if (Level.Loaded.EqualityCheckValues[i] != levelEqualityCheckValues[i])
|
||||
{
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
||||
" (client value #" + i + ": " + Level.Loaded.EqualityCheckValues[i] +
|
||||
", server value #" + i + ": " + levelEqualityCheckValues[i].ToString("X") +
|
||||
", level value count: " + levelEqualityCheckValues.Count +
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
||||
" (client value " + stage + ": " + Level.Loaded.EqualityCheckValues[stage].ToString("X") +
|
||||
", server value " + stage + ": " + levelEqualityCheckValues[stage].ToString("X") +
|
||||
", level value count: " + levelEqualityCheckValues.Count +
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1076,6 +1086,7 @@ namespace Barotrauma.Networking
|
||||
reconnectBox?.Close();
|
||||
reconnectBox = null;
|
||||
|
||||
GameMain.ModDownloadScreen.Reset();
|
||||
ContentPackageManager.EnabledPackages.Restore();
|
||||
|
||||
GUI.ClearCursorWait();
|
||||
@@ -1189,7 +1200,14 @@ namespace Barotrauma.Networking
|
||||
new LocalizedString[] { TextManager.Get("Cancel") });
|
||||
reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
|
||||
connected = false;
|
||||
|
||||
var prevContentPackages = clientPeer.ServerContentPackages;
|
||||
ConnectToServer(serverEndpoint, serverName);
|
||||
if (clientPeer != null)
|
||||
{
|
||||
//restore the previous list of content packages so we can reconnect immediately without having to recheck that the packages match
|
||||
clientPeer.ServerContentPackages = prevContentPackages;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1380,18 +1398,13 @@ namespace Barotrauma.Networking
|
||||
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
||||
{
|
||||
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
||||
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
|
||||
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
|
||||
{
|
||||
if (newPermissions == permissions) return;
|
||||
}
|
||||
|
||||
bool refreshCampaignUI = false;
|
||||
|
||||
if (permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
|
||||
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound))
|
||||
{
|
||||
refreshCampaignUI = true;
|
||||
}
|
||||
bool refreshCampaignUI = permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
|
||||
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound);
|
||||
|
||||
permissions = newPermissions;
|
||||
this.permittedConsoleCommands = new List<string>(permittedConsoleCommands);
|
||||
@@ -1430,7 +1443,7 @@ namespace Barotrauma.Networking
|
||||
if (newPermissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
var commandsLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform),
|
||||
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
|
||||
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
|
||||
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform));
|
||||
foreach (string permittedCommand in permittedConsoleCommands)
|
||||
{
|
||||
@@ -1469,6 +1482,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.RefreshEnabledElements();
|
||||
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, this.permittedConsoleCommands));
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
|
||||
@@ -1516,6 +1530,7 @@ namespace Barotrauma.Networking
|
||||
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
||||
serverSettings.AllowLinkingWifiToChat = inc.ReadBoolean();
|
||||
serverSettings.MaximumMoneyTransferRequest = inc.ReadInt32();
|
||||
bool usingShuttle = GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
GameMain.LightManager.LosMode = (LosMode)inc.ReadByte();
|
||||
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
@@ -1681,6 +1696,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (clientPeer == null)
|
||||
{
|
||||
DebugConsole.ThrowError("There was an error initializing the round (disconnected during the StartGame coroutine.)");
|
||||
roundInitStatus = RoundInitStatus.Error;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
|
||||
|
||||
DateTime? timeOut = null;
|
||||
@@ -1823,7 +1845,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
GameMain.GameScreen.Select();
|
||||
|
||||
AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
|
||||
// TODO: Re-enable the server message once it's been edited and translated
|
||||
//AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
@@ -2397,7 +2420,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
outmsg.Write(campaign.LastSaveID);
|
||||
outmsg.Write(campaign.CampaignID);
|
||||
outmsg.Write(campaign.LastUpdateID);
|
||||
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
outmsg.Write(campaign.GetLastUpdateIdForFlag(netFlag));
|
||||
}
|
||||
outmsg.Write(GameMain.NetLobbyScreen.CampaignCharacterDiscarded);
|
||||
}
|
||||
|
||||
@@ -2442,7 +2468,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
outmsg.Write(campaign.LastSaveID);
|
||||
outmsg.Write(campaign.CampaignID);
|
||||
outmsg.Write(campaign.LastUpdateID);
|
||||
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
outmsg.Write(campaign.GetLastUpdateIdForFlag(flag));
|
||||
}
|
||||
outmsg.Write(GameMain.NetLobbyScreen.CampaignCharacterDiscarded);
|
||||
}
|
||||
|
||||
@@ -2489,6 +2518,7 @@ namespace Barotrauma.Networking
|
||||
message,
|
||||
type,
|
||||
gameStarted && myCharacter != null ? myCharacter : null);
|
||||
chatMessage.ChatMode = GameMain.ActiveChatMode;
|
||||
|
||||
lastQueueChatMsgID++;
|
||||
chatMessage.NetStateID = lastQueueChatMsgID;
|
||||
@@ -2640,7 +2670,7 @@ namespace Barotrauma.Networking
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaign.CampaignID != campaignID)
|
||||
{
|
||||
string savePath = transfer.FilePath;
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Unsure);
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty);
|
||||
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
|
||||
campaign.CampaignID = campaignID;
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
@@ -2670,9 +2700,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
DebugConsole.Log("Campaign save received (" + GameMain.GameSession.SavePath + "), save ID " + campaign.LastSaveID);
|
||||
//decrement campaign update ID so the server will send us the latest data
|
||||
//decrement campaign update IDs so the server will send us the latest data
|
||||
//(as there may have been campaign updates after the save file was created)
|
||||
campaign.LastUpdateID--;
|
||||
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
campaign.SetLastUpdateIdForFlag(flag, (ushort)(campaign.GetLastUpdateIdForFlag(flag) - 1));
|
||||
}
|
||||
break;
|
||||
case FileTransferType.Mod:
|
||||
if (!(Screen.Selected is ModDownloadScreen)) { return; }
|
||||
@@ -2771,10 +2804,21 @@ namespace Barotrauma.Networking
|
||||
GameMain.GameSession = null;
|
||||
}
|
||||
|
||||
public void WriteCharacterInfo(IWriteMessage msg)
|
||||
public void SendCharacterInfo(string newName = null)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.UPDATE_CHARACTERINFO);
|
||||
WriteCharacterInfo(msg, newName);
|
||||
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
clientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void WriteCharacterInfo(IWriteMessage msg, string newName = null)
|
||||
{
|
||||
msg.Write(characterInfo == null);
|
||||
if (characterInfo == null) return;
|
||||
if (characterInfo == null) { return; }
|
||||
|
||||
msg.Write(newName ?? string.Empty);
|
||||
|
||||
msg.Write((byte)characterInfo.Head.Preset.TagSet.Count);
|
||||
foreach (Identifier tag in characterInfo.Head.Preset.TagSet)
|
||||
@@ -2820,18 +2864,18 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
#region Submarine Change Voting
|
||||
public void InitiateSubmarineChange(SubmarineInfo sub, VoteType voteType)
|
||||
public void InitiateSubmarineChange(SubmarineInfo sub, bool transferItems, VoteType voteType)
|
||||
{
|
||||
if (sub == null) { return; }
|
||||
Vote(voteType, sub);
|
||||
Vote(voteType, (sub, transferItems));
|
||||
}
|
||||
|
||||
public void ShowSubmarineChangeVoteInterface(Client starter, SubmarineInfo info, VoteType type, float timeOut)
|
||||
public void ShowSubmarineChangeVoteInterface(Client starter, SubmarineInfo info, VoteType type, bool transferItems, float timeOut)
|
||||
{
|
||||
if (info == null) { return; }
|
||||
if (votingInterface != null && votingInterface.VoteRunning) { return; }
|
||||
votingInterface?.Remove();
|
||||
votingInterface = VotingInterface.CreateSubmarineVotingInterface(starter, info, type, timeOut);
|
||||
votingInterface = VotingInterface.CreateSubmarineVotingInterface(starter, info, type, transferItems, timeOut);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -3010,7 +3054,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(mapSeed);
|
||||
msg.Write(sub.Name);
|
||||
msg.Write(sub.MD5Hash.StringRepresentation);
|
||||
settings.Serialize(msg);
|
||||
msg.Write(settings);
|
||||
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
@@ -3258,10 +3302,8 @@ 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 < 100);
|
||||
|
||||
if (chatKeyHit || radioKeyHit)
|
||||
var chatKeyStates = ChatBox.ChatKeyStates.GetChatKeyStates();
|
||||
if (chatKeyStates.AnyHit)
|
||||
{
|
||||
if (msgBox.Selected)
|
||||
{
|
||||
@@ -3272,34 +3314,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
if (chatKeyHit)
|
||||
{
|
||||
msgBox.AddToGUIUpdateList();
|
||||
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
|
||||
if (!chatBox.ToggleOpen)
|
||||
{
|
||||
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
|
||||
ChatBox.ToggleOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (radioKeyHit)
|
||||
{
|
||||
msgBox.AddToGUIUpdateList();
|
||||
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
|
||||
if (!chatBox.ToggleOpen)
|
||||
{
|
||||
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
|
||||
ChatBox.ToggleOpen = true;
|
||||
}
|
||||
|
||||
if (!msgBox.Text.StartsWith(ChatBox.RadioChatString))
|
||||
{
|
||||
msgBox.Text = ChatBox.RadioChatString;
|
||||
}
|
||||
}
|
||||
ChatBox.ApplySelectionInputs(msgBox, false, chatKeyStates);
|
||||
}
|
||||
|
||||
msgBox.Select(msgBox.Text.Length);
|
||||
}
|
||||
}
|
||||
@@ -3567,13 +3583,13 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
};
|
||||
|
||||
durationInputDays = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), GUINumberInput.NumberType.Int)
|
||||
durationInputDays = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueFloat = 1000
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), TextManager.Get("Days"));
|
||||
durationInputHours = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), GUINumberInput.NumberType.Int)
|
||||
durationInputHours = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueFloat = 24
|
||||
@@ -3680,7 +3696,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
|
||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", "
|
||||
+ string.Join("; ", Level.Loaded.EqualityCheckValues.Select(cv
|
||||
=> cv.Key + "=" + cv.Value.ToString("X"))));
|
||||
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
||||
errorLines.Add("Entities:");
|
||||
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip")
|
||||
};
|
||||
|
||||
var numInput = new GUINumberInput(new RectTransform(new Vector2(0.3f, 1.0f), container.RectTransform), GUINumberInput.NumberType.Int)
|
||||
var numInput = new GUINumberInput(new RectTransform(new Vector2(0.3f, 1.0f), container.RectTransform), NumberType.Int)
|
||||
{
|
||||
MinValueInt = min,
|
||||
MaxValueInt = max
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Barotrauma.Networking
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
@@ -6,7 +8,8 @@
|
||||
{
|
||||
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)ChatMessageType.Order);
|
||||
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.WriteRangedInteger((int)ChatMode.None, 0, Enum.GetValues(typeof(ChatMode)).Length - 1);
|
||||
WriteOrder(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public ImmutableArray<ServerContentPackage> ServerContentPackages { get; private set; } =
|
||||
public ImmutableArray<ServerContentPackage> ServerContentPackages { get; set; } =
|
||||
ImmutableArray<ServerContentPackage>.Empty;
|
||||
|
||||
public delegate void MessageCallback(IReadMessage message);
|
||||
|
||||
@@ -117,8 +117,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
|
||||
|
||||
//Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
|
||||
|
||||
if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
|
||||
timeout = Screen.Selected == GameMain.GameScreen ?
|
||||
NetworkConnection.TimeoutThresholdInGame :
|
||||
NetworkConnection.TimeoutThreshold;
|
||||
|
||||
|
||||
PacketHeader packetHeader = (PacketHeader)data[0];
|
||||
|
||||
if (!packetHeader.IsServerMessage()) { return; }
|
||||
@@ -373,12 +373,6 @@ namespace Barotrauma.Networking
|
||||
OnDisconnect?.Invoke(disableReconnect);
|
||||
}
|
||||
|
||||
~SteamP2PClientPeer()
|
||||
{
|
||||
OnDisconnect = null;
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
{
|
||||
Steamworks.P2PSend sendType;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user