Unstable 0.16.0.0
This commit is contained in:
@@ -1156,9 +1156,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnTalentGiven(string talentIdentifier)
|
||||
partial void OnTalentGiven(TalentPrefab talentPrefab)
|
||||
{
|
||||
AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()), GUI.Style.Yellow, playSound: this == Controlled);
|
||||
AddMessage(TextManager.Get("talentname." + talentPrefab.Identifier), GUI.Style.Yellow, playSound: this == Controlled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,6 +521,7 @@ namespace Barotrauma
|
||||
ch.SkinColor = skinColor;
|
||||
ch.HairColor = hairColor;
|
||||
ch.FacialHairColor = facialHairColor;
|
||||
ch.SetPersonalityTrait();
|
||||
if (ch.Job != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, float> skill in skillLevels)
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
{
|
||||
partial class AfflictionHusk : Affliction
|
||||
{
|
||||
private InfectionState? prevDisplayedMessage;
|
||||
partial void UpdateMessages()
|
||||
{
|
||||
if (Prefab is AfflictionPrefabHusk { SendMessages: false }) { return; }
|
||||
if (prevDisplayedMessage.HasValue && prevDisplayedMessage.Value == State) { return; }
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case InfectionState.Dormant:
|
||||
if (Strength < DormantThreshold * 0.5f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
GUI.AddMessage(TextManager.Get("HuskDormant"), GUI.Style.Red);
|
||||
break;
|
||||
case InfectionState.Transition:
|
||||
@@ -23,6 +30,7 @@
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prevDisplayedMessage = State;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +531,8 @@ namespace Barotrauma
|
||||
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
|
||||
if (bloodParticleTimer <= 0.0f)
|
||||
{
|
||||
Limb limb = targetLimb ?? Character.AnimController.MainLimb;
|
||||
|
||||
bool inWater = Character.AnimController.InWater;
|
||||
var drawTarget = inWater ? Particles.ParticlePrefab.DrawTargetType.Water : Particles.ParticlePrefab.DrawTargetType.Air;
|
||||
var emitter = Character.BloodEmitters.FirstOrDefault(e => e.Prefab.ParticlePrefab.DrawTarget == drawTarget || e.Prefab.ParticlePrefab.DrawTarget == Particles.ParticlePrefab.DrawTargetType.Both);
|
||||
@@ -543,13 +545,13 @@ namespace Barotrauma
|
||||
if (!inWater)
|
||||
{
|
||||
bloodParticleSize *= 2.0f;
|
||||
velocity = targetLimb.LinearVelocity * 100.0f;
|
||||
velocity = limb.LinearVelocity * 100.0f;
|
||||
}
|
||||
|
||||
// TODO: use the blood emitter?
|
||||
var blood = GameMain.ParticleManager.CreateParticle(
|
||||
inWater ? Character.Params.BleedParticleWater : Character.Params.BleedParticleAir,
|
||||
targetLimb.WorldPosition, velocity, 0.0f, Character.AnimController.CurrentHull);
|
||||
limb.WorldPosition, velocity, 0.0f, Character.AnimController.CurrentHull);
|
||||
|
||||
if (blood != null && !inWater)
|
||||
{
|
||||
@@ -1122,23 +1124,24 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public static Color GetAfflictionIconColor(AfflictionPrefab prefab, Affliction affliction)
|
||||
{
|
||||
return GetAfflictionIconColor(prefab, affliction.Strength);
|
||||
}
|
||||
|
||||
public static Color GetAfflictionIconColor(AfflictionPrefab prefab, float afflictionStrength)
|
||||
{
|
||||
// No specific colors, use generic
|
||||
if (prefab.IconColors == null)
|
||||
{
|
||||
if (prefab.IsBuff)
|
||||
{
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.BuffColorLow, GUI.Style.BuffColorMedium, GUI.Style.BuffColorHigh);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.DebuffColorLow, GUI.Style.DebuffColorMedium, GUI.Style.DebuffColorHigh);
|
||||
return ToolBox.GradientLerp(afflictionStrength / prefab.MaxStrength, GUI.Style.BuffColorLow, GUI.Style.BuffColorMedium, GUI.Style.BuffColorHigh);
|
||||
}
|
||||
|
||||
return ToolBox.GradientLerp(afflictionStrength / prefab.MaxStrength, GUI.Style.DebuffColorLow, GUI.Style.DebuffColorMedium, GUI.Style.DebuffColorHigh);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, prefab.IconColors);
|
||||
}
|
||||
|
||||
return ToolBox.GradientLerp(afflictionStrength / prefab.MaxStrength, prefab.IconColors);
|
||||
}
|
||||
|
||||
public static Color GetAfflictionIconColor(Affliction affliction) => GetAfflictionIconColor(affliction.Prefab, affliction);
|
||||
@@ -1153,7 +1156,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (afflictionsDirty())
|
||||
if (afflictionsDirty() || selectedLimb != currentDisplayedLimb)
|
||||
{
|
||||
var currentAfflictions = afflictions.Where(a => ShouldDisplayAfflictionOnLimb(a, selectedLimb)).Select(a => a.Key);
|
||||
CreateAfflictionInfos(currentAfflictions);
|
||||
|
||||
@@ -1120,7 +1120,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (Submarine.MainSub.SaveAs(Barotrauma.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
|
||||
if (Submarine.MainSub.TrySaveAs(Barotrauma.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
|
||||
{
|
||||
NewMessage("Sub saved", Color.Green);
|
||||
}
|
||||
@@ -2392,8 +2392,9 @@ namespace Barotrauma
|
||||
commands.Add(new Command("querylobbies", "Queries all SteamP2P lobbies", (args) =>
|
||||
{
|
||||
TaskPool.Add("DebugQueryLobbies",
|
||||
SteamManager.LobbyQueryRequest(), (t) => {
|
||||
var lobbies = ((Task<List<Steamworks.Data.Lobby>>)t).Result;
|
||||
SteamManager.LobbyQueryRequest(), (t) =>
|
||||
{
|
||||
t.TryGetResult(out List<Steamworks.Data.Lobby> lobbies);
|
||||
foreach (var lobby in lobbies)
|
||||
{
|
||||
NewMessage(lobby.GetData("name") + ", " + lobby.GetData("lobbyowner"), Color.Yellow);
|
||||
|
||||
@@ -60,7 +60,16 @@ namespace Barotrauma
|
||||
ushort id = msg.ReadUInt16();
|
||||
bool scanned = msg.ReadBoolean();
|
||||
Entity entity = Entity.FindEntityByID(id);
|
||||
scanTargets.Add(entity as WayPoint, scanned);
|
||||
if (!(entity is WayPoint wayPoint))
|
||||
{
|
||||
string errorMsg = $"Failed to find a waypoint in ScanMission.ClientReadScanTargetStatus. Entity {id} was {(entity?.ToString() ?? null)}";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ScanMission.ClientReadScanTargetStatus", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
scanTargets.Add(wayPoint, scanned);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using SharpFont;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -130,7 +132,7 @@ namespace Barotrauma
|
||||
/// <param name="charRanges">Character ranges between each even element with their corresponding odd element. Default is 0x20 to 0xFFFF.</param>
|
||||
/// <param name="texDims">Texture dimensions. Default is 512x512.</param>
|
||||
/// <param name="baseChar">Base character used to shift all other characters downwards when rendering. Defaults to T.</param>
|
||||
public void RenderAtlas(GraphicsDevice gd, uint[] charRanges = null, int texDims = 1024, uint baseChar = 0x54)
|
||||
private void RenderAtlas(GraphicsDevice gd, uint[] charRanges = null, int texDims = 1024, uint baseChar = 0x54)
|
||||
{
|
||||
if (DynamicLoading) { return; }
|
||||
|
||||
@@ -253,13 +255,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void DynamicRenderAtlas(GraphicsDevice gd, uint character, int texDims = 1024, uint baseChar = 0x54)
|
||||
private void DynamicRenderAtlas(GraphicsDevice gd, uint character, int texDims = 1024, uint baseChar = 0x54)
|
||||
=> DynamicRenderAtlas(gd, character.ToEnumerable(), texDims, baseChar);
|
||||
|
||||
private void DynamicRenderAtlas(GraphicsDevice gd, string str, int texDims = 1024, uint baseChar = 0x54)
|
||||
=> DynamicRenderAtlas(gd, str.Distinct().Select(c => (uint)c), texDims, baseChar);
|
||||
|
||||
private void DynamicRenderAtlas(GraphicsDevice gd, IEnumerable<uint> characters, int texDims = 1024, uint baseChar = 0x54)
|
||||
{
|
||||
if (System.Threading.Thread.CurrentThread != GameMain.MainThread)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
DynamicRenderAtlas(gd, character, texDims, baseChar);
|
||||
DynamicRenderAtlas(gd, characters, texDims, baseChar);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -271,7 +279,6 @@ namespace Barotrauma
|
||||
|
||||
lock (mutex)
|
||||
{
|
||||
if (texCoords.ContainsKey(character)) { return; }
|
||||
if (textures.Count == 0)
|
||||
{
|
||||
this.texDims = texDims;
|
||||
@@ -282,79 +289,90 @@ namespace Barotrauma
|
||||
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
|
||||
}
|
||||
|
||||
uint glyphIndex = face.GetCharIndex(character);
|
||||
if (glyphIndex == 0) { return; }
|
||||
|
||||
face.SetPixelSizes(0, size);
|
||||
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
|
||||
if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
|
||||
bool anyChanges = false;
|
||||
bool firstChar = true;
|
||||
foreach (var character in characters)
|
||||
{
|
||||
if (face.Glyph.Metrics.HorizontalAdvance > 0)
|
||||
if (texCoords.ContainsKey(character)) { continue; }
|
||||
|
||||
uint glyphIndex = face.GetCharIndex(character);
|
||||
if (glyphIndex == 0) { continue; }
|
||||
|
||||
face.SetPixelSizes(0, size);
|
||||
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
|
||||
if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
|
||||
{
|
||||
//glyph is empty, but char still applies advance
|
||||
GlyphData blankData = new GlyphData(
|
||||
advance: (float)face.Glyph.Metrics.HorizontalAdvance,
|
||||
texIndex: -1); //indicates no texture because the glyph is empty
|
||||
texCoords.Add(character, blankData);
|
||||
if (face.Glyph.Metrics.HorizontalAdvance > 0)
|
||||
{
|
||||
//glyph is empty, but char still applies advance
|
||||
GlyphData blankData = new GlyphData(
|
||||
advance: (float)face.Glyph.Metrics.HorizontalAdvance,
|
||||
texIndex: -1); //indicates no texture because the glyph is empty
|
||||
texCoords.Add(character, blankData);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//stacktrace doesn't really work that well when RenderGlyph throws an exception
|
||||
face.Glyph.RenderGlyph(RenderMode.Normal);
|
||||
bitmap = (byte[])face.Glyph.Bitmap.BufferData.Clone();
|
||||
glyphWidth = face.Glyph.Bitmap.Width;
|
||||
glyphHeight = bitmap.Length / glyphWidth;
|
||||
horizontalAdvance = face.Glyph.Metrics.HorizontalAdvance;
|
||||
drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop);
|
||||
|
||||
if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
|
||||
{
|
||||
throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions");
|
||||
}
|
||||
|
||||
currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2);
|
||||
if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1)
|
||||
{
|
||||
currentDynamicAtlasCoords.X = 0;
|
||||
currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY;
|
||||
currentDynamicAtlasNextY = 0;
|
||||
}
|
||||
//no more room in current texture atlas, create a new one
|
||||
if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1)
|
||||
{
|
||||
currentDynamicAtlasCoords.X = 0;
|
||||
currentDynamicAtlasCoords.Y = 0;
|
||||
currentDynamicAtlasNextY = 0;
|
||||
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
|
||||
currentDynamicPixelBuffer = null;
|
||||
}
|
||||
//stacktrace doesn't really work that well when RenderGlyph throws an exception
|
||||
face.Glyph.RenderGlyph(RenderMode.Normal);
|
||||
bitmap = (byte[])face.Glyph.Bitmap.BufferData.Clone();
|
||||
glyphWidth = face.Glyph.Bitmap.Width;
|
||||
glyphHeight = bitmap.Length / glyphWidth;
|
||||
horizontalAdvance = face.Glyph.Metrics.HorizontalAdvance;
|
||||
drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop);
|
||||
|
||||
GlyphData newData = new GlyphData(
|
||||
advance: (float)horizontalAdvance,
|
||||
texIndex: textures.Count - 1,
|
||||
texCoords: new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
|
||||
drawOffset: drawOffset
|
||||
);
|
||||
texCoords.Add(character, newData);
|
||||
|
||||
if (currentDynamicPixelBuffer == null)
|
||||
{
|
||||
currentDynamicPixelBuffer = new uint[texDims * texDims];
|
||||
textures[newData.TexIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
|
||||
}
|
||||
|
||||
for (int y = 0; y < glyphHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < glyphWidth; x++)
|
||||
if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
|
||||
{
|
||||
byte byteColor = bitmap[x + y * glyphWidth];
|
||||
currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
|
||||
throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions");
|
||||
}
|
||||
}
|
||||
textures[newData.TexIndex].SetData<uint>(currentDynamicPixelBuffer);
|
||||
|
||||
currentDynamicAtlasCoords.X += glyphWidth + 2;
|
||||
currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2);
|
||||
if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1)
|
||||
{
|
||||
currentDynamicAtlasCoords.X = 0;
|
||||
currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY;
|
||||
currentDynamicAtlasNextY = 0;
|
||||
}
|
||||
//no more room in current texture atlas, create a new one
|
||||
if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1)
|
||||
{
|
||||
if (!firstChar) { textures[^1].SetData<uint>(currentDynamicPixelBuffer); }
|
||||
currentDynamicAtlasCoords.X = 0;
|
||||
currentDynamicAtlasCoords.Y = 0;
|
||||
currentDynamicAtlasNextY = 0;
|
||||
textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
|
||||
currentDynamicPixelBuffer = null;
|
||||
}
|
||||
|
||||
GlyphData newData = new GlyphData(
|
||||
advance: (float)horizontalAdvance,
|
||||
texIndex: textures.Count - 1,
|
||||
texCoords: new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
|
||||
drawOffset: drawOffset
|
||||
);
|
||||
texCoords.Add(character, newData);
|
||||
|
||||
if (currentDynamicPixelBuffer == null)
|
||||
{
|
||||
currentDynamicPixelBuffer = new uint[texDims * texDims];
|
||||
textures[newData.TexIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
|
||||
}
|
||||
|
||||
for (int y = 0; y < glyphHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < glyphWidth; x++)
|
||||
{
|
||||
byte byteColor = bitmap[x + y * glyphWidth];
|
||||
currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
currentDynamicAtlasCoords.X += glyphWidth + 2;
|
||||
firstChar = false;
|
||||
anyChanges = true;
|
||||
}
|
||||
|
||||
if (anyChanges) { textures[^1].SetData<uint>(currentDynamicPixelBuffer); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,6 +392,10 @@ namespace Barotrauma
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
|
||||
{
|
||||
if (textures.Count == 0 && !DynamicLoading) { return; }
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, text);
|
||||
}
|
||||
|
||||
int lineNum = 0;
|
||||
Vector2 currentPos = position;
|
||||
@@ -390,10 +412,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
uint charIndex = text[i];
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, charIndex);
|
||||
}
|
||||
|
||||
GlyphData gd = GetGlyphData(charIndex);
|
||||
if (gd.TexIndex >= 0)
|
||||
@@ -417,6 +435,10 @@ namespace Barotrauma
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color)
|
||||
{
|
||||
if (textures.Count == 0 && !DynamicLoading) { return; }
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, text);
|
||||
}
|
||||
|
||||
Vector2 currentPos = position;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
@@ -429,10 +451,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
uint charIndex = text[i];
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, charIndex);
|
||||
}
|
||||
|
||||
GlyphData gd = GetGlyphData(charIndex);
|
||||
if (gd.TexIndex >= 0)
|
||||
@@ -452,6 +470,10 @@ namespace Barotrauma
|
||||
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth, List<RichTextData> richTextData, int rtdOffset = 0)
|
||||
{
|
||||
if (textures.Count == 0 && !DynamicLoading) { return; }
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, text);
|
||||
}
|
||||
|
||||
int lineNum = 0;
|
||||
Vector2 currentPos = position;
|
||||
@@ -472,10 +494,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
uint charIndex = text[i];
|
||||
if (DynamicLoading && !texCoords.ContainsKey(charIndex))
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, charIndex);
|
||||
}
|
||||
|
||||
Color currentTextColor;
|
||||
|
||||
@@ -626,6 +644,10 @@ namespace Barotrauma
|
||||
{
|
||||
retVal.Y = baseHeight;
|
||||
}
|
||||
if (DynamicLoading)
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, text);
|
||||
}
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
@@ -636,10 +658,6 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
uint charIndex = text[i];
|
||||
if (DynamicLoading && !texCoords.ContainsKey(charIndex))
|
||||
{
|
||||
DynamicRenderAtlas(graphicsDevice, charIndex);
|
||||
}
|
||||
|
||||
GlyphData gd = GetGlyphData(charIndex);
|
||||
currentLineX += gd.Advance;
|
||||
|
||||
@@ -44,12 +44,12 @@ namespace Barotrauma
|
||||
Waiting, // Hourglass
|
||||
WaitingBackground // Cursor + Hourglass
|
||||
}
|
||||
|
||||
|
||||
public static class GUI
|
||||
{
|
||||
public static GUICanvas Canvas => GUICanvas.Instance;
|
||||
public static CursorState MouseCursor = CursorState.Default;
|
||||
|
||||
|
||||
public static readonly SamplerState SamplerState = new SamplerState()
|
||||
{
|
||||
Filter = TextureFilter.Linear,
|
||||
@@ -116,14 +116,14 @@ namespace Barotrauma
|
||||
|
||||
public static float SlicedSpriteScale
|
||||
{
|
||||
get
|
||||
get
|
||||
{
|
||||
if (Math.Abs(1.0f - Scale) < 0.1f)
|
||||
{
|
||||
if (Math.Abs(1.0f - Scale) < 0.1f)
|
||||
{
|
||||
//don't scale if very close to the "reference resolution"
|
||||
return 1.0f;
|
||||
return 1.0f;
|
||||
}
|
||||
return Scale;
|
||||
return Scale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace Barotrauma
|
||||
t = new Texture2D(GraphicsDevice, 1, 1);
|
||||
t.SetData(new Color[] { Color.White });// fill the texture with white
|
||||
});
|
||||
|
||||
|
||||
SubmarineIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(452, 385, 182, 81), new Vector2(0.5f, 0.5f));
|
||||
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(393, 393, 49, 45), new Vector2(0.5f, 0.5f));
|
||||
SpeechBubbleIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(385, 449, 66, 60), new Vector2(0.5f, 0.5f));
|
||||
@@ -314,7 +314,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By default, all the gui elements are drawn automatically in the same order they appear on the update list.
|
||||
/// By default, all the gui elements are drawn automatically in the same order they appear on the update list.
|
||||
/// </summary>
|
||||
public static void Draw(Camera cam, SpriteBatch spriteBatch)
|
||||
{
|
||||
@@ -706,11 +706,11 @@ namespace Barotrauma
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate, effect: GameMain.GameScreen.PostProcessEffect);
|
||||
|
||||
float scale = Math.Max(
|
||||
(float)GameMain.GraphicsWidth / backgroundSprite.SourceRect.Width,
|
||||
(float)GameMain.GraphicsWidth / backgroundSprite.SourceRect.Width,
|
||||
(float)GameMain.GraphicsHeight / backgroundSprite.SourceRect.Height) * 1.1f;
|
||||
float paddingX = backgroundSprite.SourceRect.Width * scale - GameMain.GraphicsWidth;
|
||||
float paddingY = backgroundSprite.SourceRect.Height * scale - GameMain.GraphicsHeight;
|
||||
|
||||
|
||||
double noiseT = (Timing.TotalTime * 0.02f);
|
||||
Vector2 pos = new Vector2((float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0.5f) - 0.5f);
|
||||
pos = new Vector2(pos.X * paddingX, pos.Y * paddingY);
|
||||
@@ -719,7 +719,7 @@ namespace Barotrauma
|
||||
new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2 + pos,
|
||||
null, Color.White, 0.0f, backgroundSprite.size / 2,
|
||||
scale, SpriteEffects.None, 0.0f);
|
||||
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
@@ -759,8 +759,8 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
additions.Enqueue(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -786,7 +786,7 @@ namespace Barotrauma
|
||||
component.Children.ForEach(c => RemoveFromUpdateList(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearUpdateList()
|
||||
@@ -900,7 +900,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUIMessageBox.VisibleBox.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -941,7 +941,7 @@ namespace Barotrauma
|
||||
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
|
||||
}
|
||||
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) ||
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) ||
|
||||
(prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld() && !Inventory.DraggingItems.Any()))
|
||||
{
|
||||
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
|
||||
@@ -967,7 +967,7 @@ namespace Barotrauma
|
||||
return MouseOn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static CursorState UpdateMouseCursorState(GUIComponent c)
|
||||
{
|
||||
lock (mutex)
|
||||
@@ -994,7 +994,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (Wire.DraggingWire != null) { return CursorState.Dragging; }
|
||||
}
|
||||
|
||||
|
||||
if (c == null || c is GUICustomComponent)
|
||||
{
|
||||
switch (Screen.Selected)
|
||||
@@ -1027,7 +1027,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (c != null && c.Visible)
|
||||
{
|
||||
if (c.AlwaysOverrideCursor) { return c.HoverCursor; }
|
||||
@@ -1036,20 +1036,20 @@ namespace Barotrauma
|
||||
// And this is of course picked up as clickable area.
|
||||
// There has to be a better way of checking this but for now this works.
|
||||
var monitorRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
|
||||
|
||||
var parent = FindInteractParent(c);
|
||||
|
||||
|
||||
if (c.Enabled)
|
||||
{
|
||||
// Some parent elements take priority
|
||||
// but not when the child is a GUIButton or GUITickBox
|
||||
if (!(parent is GUIButton) && !(parent is GUIListBox) ||
|
||||
if (!(parent is GUIButton) && !(parent is GUIListBox) ||
|
||||
(c is GUIButton) || (c is GUITickBox))
|
||||
{
|
||||
if (!c.Rect.Equals(monitorRect)) { return c.HoverCursor; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Children in list boxes can be interacted with despite not having
|
||||
// a GUIButton inside of them so instead of hard coding we check if
|
||||
// the children can be interacted with by checking their hover state
|
||||
@@ -1084,7 +1084,7 @@ namespace Barotrauma
|
||||
{
|
||||
// Health menus
|
||||
if (character.CharacterHealth.MouseOnElement) { return CursorState.Hand; }
|
||||
|
||||
|
||||
if (character.SelectedCharacter != null)
|
||||
{
|
||||
if (character.SelectedCharacter.CharacterHealth.MouseOnElement)
|
||||
@@ -1096,7 +1096,7 @@ namespace Barotrauma
|
||||
// Character is hovering over an item placed in the world
|
||||
if (character.FocusedItem != null) { return CursorState.Hand; }
|
||||
}
|
||||
|
||||
|
||||
return CursorState.Default;
|
||||
|
||||
static GUIComponent FindInteractParent(GUIComponent component)
|
||||
@@ -1130,7 +1130,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool ContainsMouse(GUIComponent component)
|
||||
{
|
||||
// If component has a mouse rectangle then use that, if not use it's physical rect
|
||||
@@ -1138,7 +1138,7 @@ namespace Barotrauma
|
||||
component.MouseRect.Contains(PlayerInput.MousePosition) :
|
||||
component.Rect.Contains(PlayerInput.MousePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1153,8 +1153,8 @@ namespace Barotrauma
|
||||
{
|
||||
MouseCursor = CursorState.Waiting;
|
||||
var timeOut = DateTime.Now + new TimeSpan(0, 0, waitSeconds);
|
||||
while (DateTime.Now < timeOut)
|
||||
{
|
||||
while (DateTime.Now < timeOut)
|
||||
{
|
||||
if (endCondition != null)
|
||||
{
|
||||
try
|
||||
@@ -1163,13 +1163,13 @@ namespace Barotrauma
|
||||
}
|
||||
catch { break; }
|
||||
}
|
||||
yield return CoroutineStatus.Running;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
if (MouseCursor == CursorState.Waiting) { MouseCursor = CursorState.Default; }
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void ClearCursorWait()
|
||||
{
|
||||
lock (mutex)
|
||||
@@ -1208,7 +1208,7 @@ namespace Barotrauma
|
||||
{
|
||||
debugDrawMetadataOffset--;
|
||||
}
|
||||
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Down))
|
||||
{
|
||||
debugDrawMetadataOffset++;
|
||||
@@ -1240,17 +1240,20 @@ namespace Barotrauma
|
||||
debugDrawMetadataOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
HandlePersistingElements(deltaTime);
|
||||
RefreshUpdateList();
|
||||
UpdateMouseOn();
|
||||
Debug.Assert(updateList.Count == updateListSet.Count);
|
||||
updateList.ForEach(c => c.UpdateAuto(deltaTime));
|
||||
foreach (var c in updateList)
|
||||
{
|
||||
c.UpdateAuto(deltaTime);
|
||||
}
|
||||
UpdateMessages(deltaTime);
|
||||
UpdateSavingIndicator(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateMessages(float deltaTime)
|
||||
@@ -1281,17 +1284,16 @@ namespace Barotrauma
|
||||
//only the first message (the currently visible one) is updated at a time
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (!msg.WorldSpace) { continue; }
|
||||
msg.Timer -= deltaTime;
|
||||
msg.Pos += msg.Velocity * deltaTime;
|
||||
msg.Timer -= deltaTime;
|
||||
msg.Pos += msg.Velocity * deltaTime;
|
||||
}
|
||||
|
||||
messages.RemoveAll(m => m.Timer <= 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void UpdateSavingIndicator(float deltaTime)
|
||||
@@ -1628,7 +1630,7 @@ namespace Barotrauma
|
||||
|
||||
private static void DrawMessages(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (messages.Count == 0) return;
|
||||
if (messages.Count == 0) { return; }
|
||||
|
||||
bool useScissorRect = messages.Any(m => !m.WorldSpace);
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
@@ -1647,7 +1649,7 @@ namespace Barotrauma
|
||||
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos + Vector2.One, Color.Black, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos, msg.Color, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (useScissorRect)
|
||||
@@ -1656,11 +1658,11 @@ namespace Barotrauma
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||
}
|
||||
|
||||
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (!msg.WorldSpace) { continue; }
|
||||
|
||||
|
||||
if (cam != null)
|
||||
{
|
||||
float alpha = 1.0f;
|
||||
@@ -1669,7 +1671,7 @@ namespace Barotrauma
|
||||
Vector2 drawPos = cam.WorldToScreen(msg.DrawPos);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + Vector2.One, Color.Black * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos, msg.Color * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
messages.RemoveAll(m => m.Timer <= 0.0f);
|
||||
@@ -1770,7 +1772,7 @@ namespace Barotrauma
|
||||
{
|
||||
int textureWidth = Math.Max(radius * 2, 1);
|
||||
int textureHeight = Math.Max(height + radius * 2, 1);
|
||||
|
||||
|
||||
Color[] data = new Color[textureWidth * textureHeight];
|
||||
|
||||
// Colour the entire texture transparent first.
|
||||
@@ -1880,9 +1882,9 @@ namespace Barotrauma
|
||||
/// Creates multiple elements with relative size and positions them automatically.
|
||||
/// </summary>
|
||||
public static List<T> CreateElements<T>(int count, Vector2 relativeSize, RectTransform parent, Func<RectTransform, T> constructor,
|
||||
Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null,
|
||||
int absoluteSpacing = 0, float relativeSpacing = 0, Func<int, int> extraSpacing = null,
|
||||
int startOffsetAbsolute = 0, float startOffsetRelative = 0, bool isHorizontal = false)
|
||||
Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null,
|
||||
int absoluteSpacing = 0, float relativeSpacing = 0, Func<int, int> extraSpacing = null,
|
||||
int startOffsetAbsolute = 0, float startOffsetRelative = 0, bool isHorizontal = false)
|
||||
where T : GUIComponent
|
||||
{
|
||||
return CreateElements(count, parent, constructor, relativeSize, null, anchor, pivot, minSize, maxSize, absoluteSpacing, relativeSpacing, extraSpacing, startOffsetAbsolute, startOffsetRelative, isHorizontal);
|
||||
@@ -1891,8 +1893,8 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Creates multiple elements with absolute size and positions them automatically.
|
||||
/// </summary>
|
||||
public static List<T> CreateElements<T>(int count, Point absoluteSize, RectTransform parent, Func<RectTransform, T> constructor,
|
||||
Anchor anchor = Anchor.TopLeft, Pivot? pivot = null,
|
||||
public static List<T> CreateElements<T>(int count, Point absoluteSize, RectTransform parent, Func<RectTransform, T> constructor,
|
||||
Anchor anchor = Anchor.TopLeft, Pivot? pivot = null,
|
||||
int absoluteSpacing = 0, float relativeSpacing = 0, Func<int, int> extraSpacing = null,
|
||||
int startOffsetAbsolute = 0, float startOffsetRelative = 0, bool isHorizontal = false)
|
||||
where T : GUIComponent
|
||||
@@ -1991,7 +1993,7 @@ namespace Barotrauma
|
||||
if (i == 0)
|
||||
numberInput.IntValue = value.X;
|
||||
else
|
||||
numberInput.IntValue = value.Y;
|
||||
numberInput.IntValue = value.Y;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
@@ -2028,6 +2030,16 @@ namespace Barotrauma
|
||||
return frame;
|
||||
}
|
||||
|
||||
public static void NotifyPrompt(string header, string body)
|
||||
{
|
||||
GUIMessageBox msgBox = new GUIMessageBox(header, body, new[] { TextManager.Get("Ok") }, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public static GUIMessageBox AskForConfirmation(string header, string body, Action onConfirm, Action onDeny = null)
|
||||
{
|
||||
string[] buttons = { TextManager.Get("Ok"), TextManager.Get("Cancel") };
|
||||
@@ -2051,6 +2063,32 @@ namespace Barotrauma
|
||||
return msgBox;
|
||||
}
|
||||
|
||||
public static GUIMessageBox PromptTextInput(string header, string body, Action<string> onConfirm)
|
||||
{
|
||||
string[] buttons = { TextManager.Get("Ok"), TextManager.Get("Cancel") };
|
||||
GUIMessageBox msgBox = new GUIMessageBox(header, string.Empty, buttons, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
||||
GUITextBox textBox = new GUITextBox(new RectTransform(Vector2.One, msgBox.Content.RectTransform), text: body)
|
||||
{
|
||||
OverflowClip = true
|
||||
};
|
||||
|
||||
// Cancel button
|
||||
msgBox.Buttons[1].OnClicked = delegate
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// Ok button
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
{
|
||||
onConfirm.Invoke(textBox.Text);
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
return msgBox;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Element positioning
|
||||
@@ -2210,7 +2248,7 @@ namespace Barotrauma
|
||||
if (disallowedAreas == null) { continue; }
|
||||
foreach (Rectangle rect2 in disallowedAreas)
|
||||
{
|
||||
if (!rect1.Intersects(rect2)) { continue; }
|
||||
if (!rect1.Intersects(rect2)) { continue; }
|
||||
intersections = true;
|
||||
|
||||
Point centerDiff = rect1.Center - rect2.Center;
|
||||
@@ -2330,8 +2368,8 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
CreateButton(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby" : "EndRound", buttonContainer,
|
||||
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
|
||||
CreateButton(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby" : "EndRound", buttonContainer,
|
||||
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
|
||||
action: () =>
|
||||
{
|
||||
GameMain.Client?.RequestRoundEnd(save: false);
|
||||
@@ -2448,7 +2486,10 @@ namespace Barotrauma
|
||||
|
||||
public static void ClearMessages()
|
||||
{
|
||||
messages.Clear();
|
||||
lock (mutex)
|
||||
{
|
||||
messages.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsFourByThree()
|
||||
|
||||
@@ -219,12 +219,6 @@ namespace Barotrauma
|
||||
|
||||
GUI.Style.ButtonPulse.Draw(spriteBatch, expandRect, ToolBox.GradientLerp(pulseExpand, Color.White, Color.White, Color.Transparent));
|
||||
}
|
||||
|
||||
if (UserData is string s && s == "ReadyCheckButton" && ReadyCheck.lastReadyCheck > DateTime.Now)
|
||||
{
|
||||
float progress = (ReadyCheck.lastReadyCheck - DateTime.Now).Seconds / 60.0f;
|
||||
Frame.Color = ToolBox.GradientLerp(progress, Color.White, GUI.Style.Red);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
|
||||
@@ -317,7 +317,10 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
selected = value;
|
||||
Children.ForEach(c => c.Selected = value);
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.Selected = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public virtual ComponentState State
|
||||
@@ -537,7 +540,10 @@ namespace Barotrauma
|
||||
//would be real nice to un-jank this some day
|
||||
ForceUpdate();
|
||||
ForceUpdate();
|
||||
foreach (var child in Children) { child.ForceLayoutRecalculation(); }
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.ForceLayoutRecalculation();
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceUpdate() => Update((float)Timing.Step);
|
||||
@@ -547,7 +553,10 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void UpdateChildren(float deltaTime, bool recursive)
|
||||
{
|
||||
RectTransform.Children.ForEach(c => c.GUIComponent.UpdateManually(deltaTime, recursive, recursive));
|
||||
foreach (var child in RectTransform.Children)
|
||||
{
|
||||
child.GUIComponent.UpdateManually(deltaTime, recursive, recursive);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -583,7 +592,10 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public virtual void DrawChildren(SpriteBatch spriteBatch, bool recursive)
|
||||
{
|
||||
RectTransform.Children.ForEach(c => c.GUIComponent.DrawManually(spriteBatch, recursive, recursive));
|
||||
foreach (RectTransform child in RectTransform.Children)
|
||||
{
|
||||
child.GUIComponent.DrawManually(spriteBatch, recursive, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
protected Color _currentColor;
|
||||
@@ -764,8 +776,8 @@ namespace Barotrauma
|
||||
{
|
||||
toolTipBlock = new GUITextBlock(new RectTransform(new Point(width, height), null), richTextData, toolTip, font: GUI.SmallFont, wrap: true, style: "GUIToolTip");
|
||||
toolTipBlock.RectTransform.NonScaledSize = new Point(
|
||||
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).X + padding.X + toolTipBlock.Padding.X + toolTipBlock.Padding.Z),
|
||||
(int)(GUI.SmallFont.MeasureString(toolTipBlock.WrappedText).Y + padding.Y + toolTipBlock.Padding.Y + toolTipBlock.Padding.W));
|
||||
(int)(toolTipBlock.Font.MeasureString(toolTipBlock.WrappedText).X + padding.X + toolTipBlock.Padding.X + toolTipBlock.Padding.Z),
|
||||
(int)(toolTipBlock.Font.MeasureString(toolTipBlock.WrappedText).Y + padding.Y + toolTipBlock.Padding.Y + toolTipBlock.Padding.W));
|
||||
toolTipBlock.userData = toolTip;
|
||||
}
|
||||
|
||||
|
||||
@@ -827,6 +827,13 @@ namespace Barotrauma
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child == ScrollBar || child == Content || child == ContentBackground) { continue; }
|
||||
|
||||
throw new InvalidOperationException($"Children were found in {nameof(GUIListBox)}, Add them to {nameof(GUIListBox)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateChildrenRect();
|
||||
@@ -837,7 +844,6 @@ namespace Barotrauma
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
|
||||
if (FadeElements)
|
||||
{
|
||||
foreach (var (component, _) in childVisible)
|
||||
|
||||
@@ -319,28 +319,29 @@ namespace Barotrauma
|
||||
AbsoluteSpacing = absoluteSpacing.Y,
|
||||
};
|
||||
|
||||
var bottomContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.3f), verticalLayoutGroup.RectTransform), style: null);
|
||||
|
||||
var tickBoxLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.67f, 1.0f), bottomContainer.RectTransform, anchor: Anchor.CenterLeft),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
var bottomContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.3f), verticalLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
var dontShowAgainTickBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1.0f), tickBoxLayoutGroup.RectTransform),
|
||||
var tickBoxLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.67f, 1.0f), bottomContainer.RectTransform, anchor: Anchor.CenterLeft))
|
||||
{
|
||||
CanBeFocused = true,
|
||||
Stretch = true
|
||||
};
|
||||
Vector2 tickBoxRelativeSize = new Vector2(1.0f, 0.5f);
|
||||
var dontShowAgainTickBox = new GUITickBox(new RectTransform(tickBoxRelativeSize, tickBoxLayoutGroup.RectTransform),
|
||||
TextManager.Get("hintmessagebox.dontshowagain"))
|
||||
{
|
||||
ToolTip = TextManager.Get("hintmessagebox.dontshowagaintooltip"),
|
||||
UserData = "dontshowagain"
|
||||
};
|
||||
|
||||
//var disableHintsTickBox = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), tickBoxLayoutGroup.RectTransform),
|
||||
// TextManager.Get("hintmessagebox.disablehints"))
|
||||
//{
|
||||
// ToolTip = TextManager.Get("hintmessagebox.disablehintstooltip"),
|
||||
// UserData = "disablehints"
|
||||
//};
|
||||
var disableHintsTickBox = new GUITickBox(new RectTransform(tickBoxRelativeSize, tickBoxLayoutGroup.RectTransform),
|
||||
TextManager.Get("hintmessagebox.disablehints"))
|
||||
{
|
||||
ToolTip = TextManager.Get("hintmessagebox.disablehintstooltip"),
|
||||
UserData = "disablehints"
|
||||
};
|
||||
|
||||
Buttons = new List<GUIButton>(1)
|
||||
{
|
||||
@@ -379,12 +380,16 @@ namespace Barotrauma
|
||||
upperContainerHeight = Math.Max(upperContainerHeight, Icon.Rect.Height);
|
||||
height += upperContainerHeight;
|
||||
height += absoluteSpacing.Y;
|
||||
height += (int)((bottomContainer.RectTransform.RelativeSize.Y / topHorizontalLayoutGroup.RectTransform.RelativeSize.Y) * upperContainerHeight);
|
||||
int bottomContainerHeight = dontShowAgainTickBox.Rect.Height + disableHintsTickBox.Rect.Height;
|
||||
height += bottomContainerHeight;
|
||||
height += absoluteSpacing.Y;
|
||||
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
|
||||
|
||||
InnerFrame.RectTransform.NonScaledSize = new Point(InnerFrame.Rect.Width, height);
|
||||
verticalLayoutGroup.RectTransform.NonScaledSize = GetVerticalLayoutGroupSize();
|
||||
float upperContainerRelativeHeight = (float)upperContainerHeight / (upperContainerHeight + bottomContainerHeight);
|
||||
topHorizontalLayoutGroup.RectTransform.RelativeSize = new Vector2(topHorizontalLayoutGroup.RectTransform.RelativeSize.X, upperContainerRelativeHeight);
|
||||
bottomContainer.RectTransform.RelativeSize = new Vector2(bottomContainer.RectTransform.RelativeSize.X, 1.0f - upperContainerRelativeHeight);
|
||||
verticalLayoutGroup.Recalculate();
|
||||
topHorizontalLayoutGroup.Recalculate();
|
||||
Content.Recalculate();
|
||||
|
||||
@@ -29,6 +29,12 @@ namespace Barotrauma
|
||||
ClampChildMouseRects(Content);
|
||||
}
|
||||
|
||||
public override void DrawChildren(SpriteBatch spriteBatch, bool recursive)
|
||||
{
|
||||
//do nothing (the children have to be drawn in the Draw method after the ScissorRectangle has been set)
|
||||
return;
|
||||
}
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
@@ -204,6 +204,12 @@ namespace Barotrauma
|
||||
set { textColor = value; }
|
||||
}
|
||||
|
||||
public Color DisabledTextColor
|
||||
{
|
||||
get => disabledTextColor;
|
||||
set => disabledTextColor = value;
|
||||
}
|
||||
|
||||
private Color? hoverTextColor;
|
||||
public Color HoverTextColor
|
||||
{
|
||||
@@ -303,6 +309,10 @@ namespace Barotrauma
|
||||
if (parseRichText)
|
||||
{
|
||||
RichTextData = Barotrauma.RichTextData.GetRichTextData(text, out text);
|
||||
if (RichTextData != null && RichTextData.Count == 0)
|
||||
{
|
||||
RichTextData = null;
|
||||
}
|
||||
}
|
||||
|
||||
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
|
||||
@@ -457,7 +467,7 @@ namespace Barotrauma
|
||||
while (size == Vector2.Zero)
|
||||
{
|
||||
try { size = Font.MeasureString(string.IsNullOrEmpty(text) ? " " : text); }
|
||||
catch { text = text.Substring(0, text.Length - 1); }
|
||||
catch { text = text.Length > 0 ? text.Substring(0, text.Length - 1) : ""; }
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
@@ -70,6 +70,8 @@ namespace Barotrauma
|
||||
private Vector2 selectionEndPos;
|
||||
private Vector2 selectionRectSize;
|
||||
|
||||
private GUICustomComponent caretAndSelectionRenderer;
|
||||
|
||||
private bool mouseHeldInside;
|
||||
|
||||
private readonly Memento<string> memento = new Memento<string>();
|
||||
@@ -178,8 +180,7 @@ namespace Barotrauma
|
||||
}
|
||||
set
|
||||
{
|
||||
base.ToolTip = value;
|
||||
textBlock.ToolTip = value;
|
||||
base.ToolTip = textBlock.ToolTip = caretAndSelectionRenderer.ToolTip = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +269,7 @@ namespace Barotrauma
|
||||
CaretEnabled = true;
|
||||
caretPosDirty = true;
|
||||
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, frame.RectTransform), onDraw: DrawCaretAndSelection);
|
||||
caretAndSelectionRenderer = new GUICustomComponent(new RectTransform(Vector2.One, frame.RectTransform), onDraw: DrawCaretAndSelection);
|
||||
|
||||
int clearButtonWidth = 0;
|
||||
if (createClearButton)
|
||||
|
||||
1056
Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs
Normal file
1056
Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -637,7 +637,15 @@ namespace Barotrauma
|
||||
|
||||
public bool IsParentOf(RectTransform rectT, bool recursive = true)
|
||||
{
|
||||
return children.Contains(rectT) || (recursive && children.Any(c => c.IsParentOf(rectT)));
|
||||
if (children.Contains(rectT)) { return true; }
|
||||
if (recursive)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (child.IsParentOf(rectT)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsChildOf(RectTransform rectT, bool recursive = true)
|
||||
|
||||
@@ -414,15 +414,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
subsToShow.AddRange(SubmarineInfo.SavedSubmarines.Where(s => s.IsCampaignCompatible && !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
subsToShow.AddRange(GameMain.NetLobbyScreen.CampaignSubmarines.Where(s => !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
|
||||
subsToShow.AddRange((GameMain.Client is null ? SubmarineInfo.SavedSubmarines : MultiPlayerCampaign.GetCampaignSubs())
|
||||
.Where(s => s.IsCampaignCompatible && !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
}
|
||||
|
||||
@@ -446,20 +439,11 @@ namespace Barotrauma
|
||||
|
||||
if (preview == null)
|
||||
{
|
||||
SubmarineInfo potentialMatch;
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
potentialMatch = GameMain.NetLobbyScreen.CampaignSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
SubmarineInfo potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
|
||||
preview = potentialMatch?.PreviewImage;
|
||||
|
||||
// Try from savedsubmarines with name comparison as a backup
|
||||
// Try name comparison as a backup
|
||||
if (preview == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == info.Name);
|
||||
|
||||
@@ -1543,30 +1543,12 @@ namespace Barotrauma
|
||||
GUITextBlock.AutoScaleAndNormalize(skillNames);
|
||||
}
|
||||
|
||||
private bool HasUnlockedAllTalents(Character controlledCharacter)
|
||||
{
|
||||
if (TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree))
|
||||
{
|
||||
foreach (TalentSubTree talentSubTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
foreach (TalentOption talentOption in talentSubTree.TalentOptionStages)
|
||||
{
|
||||
if (talentOption.Talents.None(t => controlledCharacter.HasTalent(t.Identifier)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateTalentButtons()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter?.Info == null) { return; }
|
||||
|
||||
bool unlockedAllTalents = HasUnlockedAllTalents(controlledCharacter);
|
||||
bool unlockedAllTalents = controlledCharacter.HasUnlockedAllTalents();
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
internal class UpgradeStore
|
||||
{
|
||||
public readonly struct CategoryData
|
||||
@@ -1688,7 +1687,7 @@ namespace Barotrauma
|
||||
|
||||
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign();
|
||||
|
||||
private static string FormatCurrency(int money, bool format = true)
|
||||
public static string FormatCurrency(int money, bool format = true)
|
||||
{
|
||||
return TextManager.GetWithVariable("CurrencyFormat", "[credits]", format ? string.Format(CultureInfo.InvariantCulture, "{0:N0}", money) : money.ToString());
|
||||
}
|
||||
|
||||
@@ -437,8 +437,8 @@ namespace Barotrauma
|
||||
TaskPool.Add("AutoUpdateWorkshopItemsAsync",
|
||||
SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
|
||||
{
|
||||
bool result = ((Task<bool>)task).Result;
|
||||
|
||||
if (!task.TryGetResult(out bool result)) { return; }
|
||||
|
||||
Config.WaitingForAutoUpdate = false;
|
||||
});
|
||||
|
||||
@@ -756,7 +756,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
CancelQuickStart |= PlayerInput.KeyDown(Keys.LeftShift);
|
||||
if (PlayerInput.KeyHit(Keys.LeftShift))
|
||||
{
|
||||
CancelQuickStart = !CancelQuickStart;
|
||||
}
|
||||
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled || Config.TestScreenEnabled) && FirstLoad && !CancelQuickStart)
|
||||
{
|
||||
|
||||
@@ -718,7 +718,7 @@ namespace Barotrauma
|
||||
/// Sets the character's current order (if it's close enough to receive messages from orderGiver) and
|
||||
/// displays the order in the crew UI
|
||||
/// </summary>
|
||||
public void SetCharacterOrder(Character character, Order order, string option, int priority, Character orderGiver, Hull targetHull = null)
|
||||
public void SetCharacterOrder(Character character, Order order, string option, int priority, Character orderGiver, Hull targetHull = null, bool isNewOrder = true)
|
||||
{
|
||||
if (order != null && order.TargetAllCharacters)
|
||||
{
|
||||
@@ -768,7 +768,7 @@ namespace Barotrauma
|
||||
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
orderGiver.Speak(order.GetChatMessage("", hull?.DisplayName, givingOrderToSelf: character == orderGiver), ChatMessageType.Order);
|
||||
orderGiver.Speak(order.GetChatMessage("", hull?.DisplayName, givingOrderToSelf: character == orderGiver, isNewOrder: isNewOrder), ChatMessageType.Order);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -784,7 +784,7 @@ namespace Barotrauma
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
character.SetOrder(order, option, priority, orderGiver, speak: orderGiver != character);
|
||||
string message = order?.GetChatMessage(character.Name, orderGiver?.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option, priority: priority);
|
||||
string message = order?.GetChatMessage(character.Name, orderGiver?.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option, isNewOrder: isNewOrder);
|
||||
orderGiver?.Speak(message);
|
||||
}
|
||||
else if (orderGiver != null)
|
||||
@@ -1071,7 +1071,7 @@ namespace Barotrauma
|
||||
var priority = Math.Max(CharacterInfo.HighestManualOrderPriority - orderList.Content.GetChildIndex(orderComponent), 1);
|
||||
if (orderInfo.ManualPriority == priority) { return; }
|
||||
var character = (Character)orderList.UserData;
|
||||
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled);
|
||||
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled, isNewOrder: false);
|
||||
}
|
||||
|
||||
private string CreateOrderTooltip(Order orderPrefab, string option, Entity targetEntity)
|
||||
@@ -2582,15 +2582,12 @@ namespace Barotrauma
|
||||
{
|
||||
contextualOrders.Remove(pumpOrderInfo);
|
||||
}
|
||||
if (contextualOrders.None())
|
||||
orderIdentifier = "cleanupitems";
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
orderIdentifier = "cleanupitems";
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false) || AIObjectiveCleanupItems.IsValidContainer(itemContext, Character.Controlled))
|
||||
{
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false) || AIObjectiveCleanupItems.IsValidContainer(itemContext, Character.Controlled))
|
||||
{
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
AddIgnoreOrder(itemContext);
|
||||
@@ -3523,16 +3520,6 @@ namespace Barotrauma
|
||||
InitRound();
|
||||
}
|
||||
|
||||
public void EndRound()
|
||||
{
|
||||
//remove characterinfos whose characters have been removed or killed
|
||||
characterInfos.RemoveAll(c => c.Character == null || c.Character.Removed || c.CauseOfDeath != null);
|
||||
|
||||
characters.Clear();
|
||||
crewList.ClearChildren();
|
||||
GUIContextMenu.CurrentContextMenu = null;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
characters.Clear();
|
||||
|
||||
@@ -242,6 +242,11 @@ namespace Barotrauma
|
||||
{
|
||||
ReadyCheckButton.RectTransform.ScreenSpaceOffset = endRoundButton.RectTransform.ScreenSpaceOffset;
|
||||
ReadyCheckButton.DrawManually(spriteBatch);
|
||||
if (ReadyCheck.ReadyCheckCooldown > DateTime.Now)
|
||||
{
|
||||
float progress = (ReadyCheck.ReadyCheckCooldown - DateTime.Now).Seconds / 60.0f;
|
||||
ReadyCheckButton.Color = ToolBox.GradientLerp(progress, Color.White, GUI.Style.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,6 +295,9 @@ namespace Barotrauma
|
||||
case InteractionType.Crew when GameMain.NetworkMember != null:
|
||||
CampaignUI.CrewManagement.SendCrewState(false);
|
||||
goto default;
|
||||
case InteractionType.MedicalClinic:
|
||||
CampaignUI.MedicalClinic.RequestLatestPending();
|
||||
goto default;
|
||||
default:
|
||||
ShowCampaignUI = true;
|
||||
CampaignUI.SelectTab(npc.CampaignInteractionType);
|
||||
@@ -319,6 +327,8 @@ namespace Barotrauma
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
MedicalClinic?.Update(deltaTime);
|
||||
|
||||
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData is RoundSummary);
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0;
|
||||
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0 && !Character.Controlled.HasUnlockedAllTalents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal partial class MedicalClinic
|
||||
{
|
||||
public enum RequestResult
|
||||
{
|
||||
Undecided,
|
||||
Success,
|
||||
Error,
|
||||
Timeout
|
||||
}
|
||||
|
||||
public readonly struct RequestAction<T>
|
||||
{
|
||||
public readonly Action<T> Callback;
|
||||
public readonly DateTimeOffset Timeout;
|
||||
|
||||
public RequestAction(Action<T> callback, DateTimeOffset timeout)
|
||||
{
|
||||
Callback = callback;
|
||||
Timeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct AfflictionRequest
|
||||
{
|
||||
public readonly RequestResult Result;
|
||||
public readonly ImmutableArray<NetAffliction> Afflictions;
|
||||
|
||||
public AfflictionRequest(RequestResult result, ImmutableArray<NetAffliction> afflictions)
|
||||
{
|
||||
Result = result;
|
||||
Afflictions = afflictions;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct PendingRequest
|
||||
{
|
||||
public readonly RequestResult Result;
|
||||
public readonly ImmutableArray<NetCrewMember> CrewMembers;
|
||||
|
||||
public PendingRequest(RequestResult result, ImmutableArray<NetCrewMember> crewMembers)
|
||||
{
|
||||
Result = result;
|
||||
CrewMembers = crewMembers;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct CallbackOnlyRequest
|
||||
{
|
||||
public readonly RequestResult Result;
|
||||
|
||||
public CallbackOnlyRequest(RequestResult result)
|
||||
{
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct HealRequest
|
||||
{
|
||||
public readonly RequestResult Result;
|
||||
public readonly HealRequestResult HealResult;
|
||||
|
||||
public HealRequest(RequestResult result, HealRequestResult healResult)
|
||||
{
|
||||
Result = result;
|
||||
HealResult = healResult;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<RequestAction<AfflictionRequest>> afflictionRequests = new List<RequestAction<AfflictionRequest>>();
|
||||
private readonly List<RequestAction<PendingRequest>> pendingHealRequests = new List<RequestAction<PendingRequest>>();
|
||||
private readonly List<RequestAction<CallbackOnlyRequest>> clearAllRequests = new List<RequestAction<CallbackOnlyRequest>>();
|
||||
private readonly List<RequestAction<HealRequest>> healAllRequests = new List<RequestAction<HealRequest>>();
|
||||
private readonly List<RequestAction<CallbackOnlyRequest>> addRequests = new List<RequestAction<CallbackOnlyRequest>>();
|
||||
private readonly List<RequestAction<CallbackOnlyRequest>> removeRequests = new List<RequestAction<CallbackOnlyRequest>>();
|
||||
|
||||
public void RequestAfflictions(CharacterInfo info, Action<AfflictionRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
#if DEBUG && LINUX
|
||||
if (Screen.Selected is TestScreen)
|
||||
{
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Success, TestAfflictions.ToImmutableArray()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(info is { Character: { CharacterHealth: { } health } }))
|
||||
{
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Error, ImmutableArray<NetAffliction>.Empty));
|
||||
return;
|
||||
}
|
||||
|
||||
ImmutableArray<NetAffliction> pendingAfflictions = GetAllAfflictions(health).ToImmutableArray();
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Success, pendingAfflictions));
|
||||
return;
|
||||
}
|
||||
|
||||
afflictionRequests.Add(new RequestAction<AfflictionRequest>(onReceived, GetTimeout()));
|
||||
SendAfflictionRequest(info);
|
||||
}
|
||||
|
||||
public void RequestLatestPending(Action<PendingRequest> onReceived)
|
||||
{
|
||||
// no need to worry about syncing when there's only one pair of eyes capable of looking at the UI
|
||||
if (GameMain.IsSingleplayer) { return; }
|
||||
|
||||
pendingHealRequests.Add(new RequestAction<PendingRequest>(onReceived, GetTimeout()));
|
||||
SendPendingRequest();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
DateTimeOffset now = DateTimeOffset.Now;
|
||||
UpdateQueue(afflictionRequests, now, onTimeout: callback => { callback(new AfflictionRequest(RequestResult.Timeout, ImmutableArray<NetAffliction>.Empty)); });
|
||||
UpdateQueue(pendingHealRequests, now, onTimeout: callback => { callback(new PendingRequest(RequestResult.Timeout, ImmutableArray<NetCrewMember>.Empty)); });
|
||||
UpdateQueue(healAllRequests, now, onTimeout: callback => { callback(new HealRequest(RequestResult.Timeout, HealRequestResult.Unknown)); });
|
||||
UpdateQueue(clearAllRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
UpdateQueue(addRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
UpdateQueue(removeRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
|
||||
void CallbackOnlyTimeout(Action<CallbackOnlyRequest> callback) { callback(new CallbackOnlyRequest(RequestResult.Timeout)); }
|
||||
}
|
||||
|
||||
public bool IsAfflictionPending(NetCrewMember character, NetAffliction affliction)
|
||||
{
|
||||
foreach (NetCrewMember crewMember in PendingHeals)
|
||||
{
|
||||
if (!crewMember.CharacterEquals(character)) { continue; }
|
||||
|
||||
return crewMember.Afflictions.Any(a => a.AfflictionEquals(affliction));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryDequeue<T>(List<RequestAction<T>> requestQueue, out Action<T> result)
|
||||
{
|
||||
RequestAction<T>? first = requestQueue.FirstOrNull();
|
||||
if (!(first is { } action))
|
||||
{
|
||||
result = _ => { };
|
||||
return false;
|
||||
}
|
||||
|
||||
requestQueue.Remove(action);
|
||||
result = action.Callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void UpdateQueue<T>(List<RequestAction<T>> requestQueue, DateTimeOffset now, Action<Action<T>> onTimeout)
|
||||
{
|
||||
HashSet<RequestAction<T>>? removals = null;
|
||||
foreach (RequestAction<T> action in requestQueue)
|
||||
{
|
||||
if (action.Timeout < now)
|
||||
{
|
||||
onTimeout.Invoke(action.Callback);
|
||||
|
||||
removals ??= new HashSet<RequestAction<T>>();
|
||||
removals.Add(action);
|
||||
}
|
||||
}
|
||||
|
||||
if (removals is null) { return; }
|
||||
|
||||
foreach (RequestAction<T> action in removals)
|
||||
{
|
||||
requestQueue.Remove(action);
|
||||
}
|
||||
}
|
||||
|
||||
// if you have more than 5000 ping there are probably more important things to worry about but hey just in case
|
||||
private static DateTimeOffset GetTimeout() => DateTimeOffset.Now.AddSeconds(5).AddMilliseconds(GetPing());
|
||||
|
||||
private static int GetPing()
|
||||
{
|
||||
if (GameMain.IsSingleplayer || !(GameMain.Client?.Name is { } ownName) || !(GameMain.NetworkMember?.ConnectedClients is { } clients)) { return 0; }
|
||||
|
||||
return (from client in clients where client.Name == ownName select client.Ping).FirstOrDefault();
|
||||
}
|
||||
|
||||
public void HealAllButtonAction(Action<HealRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
HealRequestResult result = HealAllPending();
|
||||
onReceived(new HealRequest(RequestResult.Success, HealAllPending()));
|
||||
if (result == HealRequestResult.Success)
|
||||
{
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
healAllRequests.Add(new RequestAction<HealRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void ClearAllButtonAction(Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
ClearPendingHeals();
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
clearAllRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.CLEAR_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
private void ClearRequstReceived()
|
||||
{
|
||||
ClearPendingHeals();
|
||||
if (TryDequeue(clearAllRequests, out var callback))
|
||||
{
|
||||
callback(new CallbackOnlyRequest(RequestResult.Success));
|
||||
}
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
private void HealRequestReceived(IReadMessage inc)
|
||||
{
|
||||
NetHealRequest request = INetSerializableStruct.Read<NetHealRequest>(inc);
|
||||
if (request.Result == HealRequestResult.Success)
|
||||
{
|
||||
HealAllPending(force: true);
|
||||
}
|
||||
|
||||
if (TryDequeue(healAllRequests, out var callback))
|
||||
{
|
||||
callback(new HealRequest(RequestResult.Success, request.Result));
|
||||
}
|
||||
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
public void AddPendingButtonAction(NetCrewMember crewMember, Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
InsertPendingCrewMember(crewMember);
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
addRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(crewMember, NetworkHeader.ADD_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void RemovePendingButtonAction(NetCrewMember crewMember, NetAffliction affliction, Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
RemovePendingAffliction(crewMember, affliction);
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
INetSerializableStruct removedAffliction = new NetRemovedAffliction
|
||||
{
|
||||
CrewMember = crewMember,
|
||||
Affliction = affliction
|
||||
};
|
||||
|
||||
removeRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(removedAffliction, NetworkHeader.REMOVE_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
private void NewAdditonReceived(IReadMessage inc, MessageFlag flag)
|
||||
{
|
||||
NetCrewMember crewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
InsertPendingCrewMember(crewMember);
|
||||
if (flag == MessageFlag.Response && TryDequeue(addRequests, out var callback))
|
||||
{
|
||||
callback(new CallbackOnlyRequest(RequestResult.Success));
|
||||
}
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
private void NewRemovalReceived(IReadMessage inc, MessageFlag flag)
|
||||
{
|
||||
NetRemovedAffliction removed = INetSerializableStruct.Read<NetRemovedAffliction>(inc);
|
||||
RemovePendingAffliction(removed.CrewMember, removed.Affliction);
|
||||
if (flag == MessageFlag.Response && TryDequeue(removeRequests, out var callback))
|
||||
{
|
||||
callback(new CallbackOnlyRequest(RequestResult.Success));
|
||||
}
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
private static void SendAfflictionRequest(CharacterInfo info)
|
||||
{
|
||||
INetSerializableStruct crewMember = new NetCrewMember
|
||||
{
|
||||
CharacterInfo = info,
|
||||
Afflictions = Array.Empty<NetAffliction>()
|
||||
};
|
||||
|
||||
ClientSend(crewMember, NetworkHeader.REQUEST_AFFLICTIONS, DeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
private static void SendPendingRequest()
|
||||
{
|
||||
ClientSend(null, NetworkHeader.REQUEST_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
private void AfflictionRequestReceived(IReadMessage inc)
|
||||
{
|
||||
NetCrewMember crewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
if (TryDequeue(afflictionRequests, out var callback))
|
||||
{
|
||||
RequestResult result = crewMember.CharacterInfoID == 0 ? RequestResult.Error : RequestResult.Success;
|
||||
callback(new AfflictionRequest(result, crewMember.Afflictions.ToImmutableArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private void PendingRequestReceived(IReadMessage inc)
|
||||
{
|
||||
NetPendingCrew pendingCrew = INetSerializableStruct.Read<NetPendingCrew>(inc);
|
||||
if (TryDequeue(pendingHealRequests, out var callback))
|
||||
{
|
||||
callback(new PendingRequest(RequestResult.Success, pendingCrew.CrewMembers.ToImmutableArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private static IWriteMessage StartSending()
|
||||
{
|
||||
IWriteMessage writeMessage = new WriteOnlyMessage();
|
||||
writeMessage.Write((byte)ClientPacketHeader.MEDICAL);
|
||||
return writeMessage;
|
||||
}
|
||||
|
||||
private static void ClientSend(INetSerializableStruct? netStruct, NetworkHeader header, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
IWriteMessage msg = StartSending();
|
||||
msg.Write((byte)header);
|
||||
netStruct?.Write(msg);
|
||||
GameMain.Client.ClientPeer?.Send(msg, deliveryMethod);
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
NetworkHeader header = (NetworkHeader)inc.ReadByte();
|
||||
MessageFlag flag = (MessageFlag)inc.ReadByte();
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case NetworkHeader.REQUEST_AFFLICTIONS:
|
||||
AfflictionRequestReceived(inc);
|
||||
break;
|
||||
case NetworkHeader.REQUEST_PENDING:
|
||||
PendingRequestReceived(inc);
|
||||
break;
|
||||
case NetworkHeader.ADD_PENDING:
|
||||
NewAdditonReceived(inc, flag);
|
||||
break;
|
||||
case NetworkHeader.REMOVE_PENDING:
|
||||
NewRemovalReceived(inc, flag);
|
||||
break;
|
||||
case NetworkHeader.HEAL_PENDING:
|
||||
HealRequestReceived(inc);
|
||||
break;
|
||||
case NetworkHeader.CLEAR_PENDING:
|
||||
ClearRequstReceived();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
||||
private GUIMessageBox? msgBox;
|
||||
private GUIMessageBox? resultsBox;
|
||||
|
||||
public static DateTime lastReadyCheck = DateTime.MinValue;
|
||||
public static DateTime ReadyCheckCooldown = DateTime.MinValue;
|
||||
|
||||
public static bool IsReadyCheck(GUIComponent? msgBox) => msgBox?.UserData as string == PromptData || msgBox?.UserData as string == ResultData;
|
||||
|
||||
@@ -273,10 +273,10 @@ namespace Barotrauma
|
||||
|
||||
public static void CreateReadyCheck()
|
||||
{
|
||||
if (lastReadyCheck < DateTime.Now)
|
||||
if (ReadyCheckCooldown < DateTime.Now)
|
||||
{
|
||||
#if !DEBUG
|
||||
lastReadyCheck = DateTime.Now.AddMinutes(1);
|
||||
ReadyCheckCooldown = DateTime.Now.AddMinutes(1);
|
||||
#endif
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte) ClientPacketHeader.READY_CHECK);
|
||||
@@ -285,7 +285,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
GUIMessageBox msgBox = new GUIMessageBox(readyCheckHeader, readyCheckPleaseWait((lastReadyCheck - DateTime.Now).Seconds), new[] { closeButton });
|
||||
GUIMessageBox msgBox = new GUIMessageBox(readyCheckHeader, readyCheckPleaseWait((ReadyCheckCooldown - DateTime.Now).Seconds), new[] { closeButton });
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
{
|
||||
msgBox.Close();
|
||||
|
||||
@@ -524,6 +524,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
#if !OSX
|
||||
var statisticsTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.045f), leftPanel.RectTransform), TextManager.Get("statisticsconsenttickbox"))
|
||||
{
|
||||
OnSelected = (GUITickBox tickBox) =>
|
||||
@@ -562,6 +563,8 @@ namespace Barotrauma
|
||||
statisticsTickBox.OnSelected = prevHandler;
|
||||
statisticsTickBox.Enabled = GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
|
||||
});
|
||||
#endif
|
||||
|
||||
|
||||
// right panel --------------------------------------
|
||||
|
||||
|
||||
@@ -504,6 +504,13 @@ namespace Barotrauma
|
||||
{
|
||||
HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
visualSlots[i].DrawOffset = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ControlInput(Camera cam)
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
case AreaShape.Circle:
|
||||
Vector2 center = item.WorldPosition;
|
||||
center.Y = -center.Y;
|
||||
center += SpawnAreaOffset;
|
||||
center.Y = -center.Y;
|
||||
spriteBatch.DrawCircle(center, SpawnAreaRadius, 32, GUI.Style.Red, thickness: 4f);
|
||||
|
||||
if (MaximumAmountRangePadding > 0f)
|
||||
@@ -51,8 +51,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
case AreaShape.Circle:
|
||||
Vector2 center = item.WorldPosition;
|
||||
center.Y = -center.Y;
|
||||
center += CrewAreaOffset;
|
||||
center.Y = -center.Y;
|
||||
spriteBatch.DrawCircle(center, CrewAreaRadius, 32, GUI.Style.Green);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -390,10 +390,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (SerializableProperties.TryGetValue(sound.VolumeProperty, out SerializableProperty property))
|
||||
{
|
||||
float newVolume = 0.0f;
|
||||
float newVolume;
|
||||
try
|
||||
{
|
||||
newVolume = (float)property.GetValue(this);
|
||||
newVolume = property.GetFloatValue(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
partial void SetLightSourceTransform()
|
||||
partial void SetLightSourceTransformProjSpecific()
|
||||
{
|
||||
if (ParentBody != null)
|
||||
{
|
||||
|
||||
@@ -6,21 +6,23 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Controller : ItemComponent
|
||||
{
|
||||
private bool chatBoxOriginalState;
|
||||
private bool isHUDsHidden;
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (focusTarget != null && character.ViewTarget == focusTarget)
|
||||
{
|
||||
foreach (ItemComponent ic in focusTarget.Components)
|
||||
{
|
||||
ic.DrawHUD(spriteBatch, character);
|
||||
if (ic.ShouldDrawHUD(character))
|
||||
{
|
||||
ic.DrawHUD(spriteBatch, character);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool crewAreaOriginalState;
|
||||
private bool chatBoxOriginalState;
|
||||
private bool isHUDsHidden;
|
||||
|
||||
partial void HideHUDs(bool value)
|
||||
{
|
||||
if (isHUDsHidden == value) { return; }
|
||||
|
||||
@@ -302,6 +302,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
HideEmptyItemListCategories();
|
||||
|
||||
if (selectedItem != null)
|
||||
{
|
||||
//reselect to recreate the info based on the new user's skills
|
||||
SelectItem(character, selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
@@ -343,13 +349,14 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Item it in availableItems)
|
||||
{
|
||||
if (it.ParentInventory == inputContainer.Inventory) { continue; }
|
||||
var rootContainer = it.GetRootContainer();
|
||||
if (rootContainer?.OwnInventory?.visualSlots == null) { continue; }
|
||||
int availableSlotIndex = rootContainer.OwnInventory.FindIndex(it.Container == rootContainer ? it : it.Container);
|
||||
var rootInventoryOwner = it.GetRootInventoryOwner();
|
||||
Inventory rootInventory = (rootInventoryOwner as Item)?.OwnInventory as Inventory ?? (rootInventoryOwner as Character)?.Inventory;
|
||||
if (rootInventory?.visualSlots == null) { continue; }
|
||||
int availableSlotIndex = rootInventory.FindIndex((it.Container != rootInventoryOwner ? it.Container : it) ?? it);
|
||||
if (availableSlotIndex < 0) { continue; }
|
||||
if (rootContainer.OwnInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
if (rootInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
{
|
||||
rootContainer.OwnInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
rootInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
if (slotIndex < inputContainer.Capacity)
|
||||
{
|
||||
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
@@ -406,9 +413,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
|
||||
}
|
||||
else if(requiredItem.MaxCondition < 1.0f)
|
||||
else if (requiredItem.MaxCondition < 1.0f)
|
||||
{
|
||||
toolTipText += " 0-" + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
|
||||
if (requiredItem.MaxCondition <= 0.0f)
|
||||
{
|
||||
toolTipText += " " + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
|
||||
}
|
||||
else
|
||||
{
|
||||
toolTipText += " 0-" + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
|
||||
}
|
||||
}
|
||||
else if (requiredItem.MaxCondition <= 0.0f)
|
||||
{
|
||||
@@ -524,16 +538,6 @@ namespace Barotrauma.Items.Components
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f };
|
||||
var paddedReqFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), selectedItemReqsFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f };
|
||||
|
||||
/*var itemIcon = selectedItem.TargetItem.InventoryIcon ?? selectedItem.TargetItem.sprite;
|
||||
if (itemIcon != null)
|
||||
{
|
||||
GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), paddedFrame.RectTransform),
|
||||
itemIcon, scaleToFit: true)
|
||||
{
|
||||
Color = selectedItem.TargetItem.InventoryIconColor
|
||||
};
|
||||
}*/
|
||||
|
||||
string itemName = GetRecipeNameAndAmount(selectedItem);
|
||||
string name = itemName;
|
||||
|
||||
@@ -732,8 +736,6 @@ namespace Barotrauma.Items.Components
|
||||
Character user = Entity.FindEntityByID(userID) as Character;
|
||||
|
||||
State = newState;
|
||||
timeUntilReady = newTimeUntilReady;
|
||||
|
||||
if (newState == FabricatorState.Stopped || itemIndex == -1)
|
||||
{
|
||||
CancelFabricating();
|
||||
@@ -747,6 +749,7 @@ namespace Barotrauma.Items.Components
|
||||
SelectItem(user, fabricationRecipes[itemIndex]);
|
||||
StartFabricating(fabricationRecipes[itemIndex], user);
|
||||
}
|
||||
timeUntilReady = newTimeUntilReady;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,9 +537,9 @@ namespace Barotrauma.Items.Components
|
||||
if (item.Submarine == null && displayedSubs.Count > 0 || // item not inside a sub anymore, but display is still showing subs
|
||||
item.Submarine is { } itemSub &&
|
||||
(
|
||||
!displayedSubs.Contains(itemSub) || // current sub not displayed
|
||||
itemSub.DockedTo.Any(s => !displayedSubs.Contains(s)) || // some of the docked subs not displayed
|
||||
displayedSubs.Any(s => s != itemSub && !itemSub.DockedTo.Contains(s)) // displaying a sub that shouldn't be displayed
|
||||
!displayedSubs.Contains(itemSub) || // current sub not displayed
|
||||
itemSub.DockedTo.Any(s => !displayedSubs.Contains(s) && itemSub.ConnectedDockingPorts[s].IsLocked) || // some of the docked subs not displayed
|
||||
displayedSubs.Any(s => s != itemSub && !itemSub.DockedTo.Contains(s)) // displaying a sub that shouldn't be displayed
|
||||
) ||
|
||||
prevResolution.X != GameMain.GraphicsWidth || prevResolution.Y != GameMain.GraphicsHeight || // resolution changed
|
||||
!submarineContainer.Children.Any()) // We lack a GUI
|
||||
@@ -1092,6 +1092,12 @@ namespace Barotrauma.Items.Components
|
||||
if (!(entity is Item it)) { continue; }
|
||||
if (!electricalChildren.TryGetValue(miniMapGuiComponent, out GUIComponent component)) { continue; }
|
||||
|
||||
if (entity.Removed)
|
||||
{
|
||||
component.Visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.Submarine == null || !hasPower)
|
||||
{
|
||||
component.Color = component.OutlineColor = NoPowerElectricalColor;
|
||||
@@ -1117,7 +1123,7 @@ namespace Barotrauma.Items.Components
|
||||
int current = (int)-powerTransfer.CurrPowerConsumption, load = (int)powerTransfer.PowerLoad;
|
||||
|
||||
line1 = TextManager.GetWithVariable("statusmonitor.junctionpower.tooltip", "[amount]", current.ToString(), fallBackTag: "statusmonitor.junctioncurrent.tooltip");
|
||||
line2 = TextManager.GetWithVariable("statusmonitor.junctionload.tooltip", "[amount]", load.ToString());
|
||||
line2 = TextManager.GetWithVariables("statusmonitor.junctionload.tooltip", new string[] { "[amount]", "[load]" }, new string[] { load.ToString(), load.ToString() });
|
||||
}
|
||||
|
||||
string line3 = TextManager.GetWithVariable("statusmonitor.durability.tooltip", "[amount]", durability.ToString());
|
||||
|
||||
@@ -19,15 +19,6 @@ namespace Barotrauma.Items.Components
|
||||
private readonly List<(Vector2 position, ParticleEmitter emitter)> pumpOutEmitters = new List<(Vector2 position, ParticleEmitter emitter)>();
|
||||
private readonly List<(Vector2 position, ParticleEmitter emitter)> pumpInEmitters = new List<(Vector2 position, ParticleEmitter emitter)>();
|
||||
|
||||
public float CurrentBrokenVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (item.ConditionPercentage > 10.0f || !IsActive) { return 0.0f; }
|
||||
return (1.0f - item.ConditionPercentage / 10.0f) * 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
@@ -193,8 +184,6 @@ namespace Barotrauma.Items.Components
|
||||
private readonly float flickerFrequency = 1;
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
pumpSpeedLockTimer -= deltaTime;
|
||||
isActiveLockTimer -= deltaTime;
|
||||
autoControlIndicator.Selected = IsAutoControlled;
|
||||
PowerButton.Enabled = isActiveLockTimer <= 0.0f;
|
||||
if (HasPower)
|
||||
|
||||
@@ -83,9 +83,7 @@ namespace Barotrauma.Items.Components
|
||||
private const float ConnectedSubUpdateInterval = 1.0f;
|
||||
float connectedSubUpdateTimer;
|
||||
|
||||
//Vector2 = vector from the ping source to the position of the disruption
|
||||
//float = strength of the disruption, between 0-1
|
||||
private readonly List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
|
||||
private readonly List<(Vector2 pos, float strength)> disruptedDirections = new List<(Vector2 pos, float strength)>();
|
||||
|
||||
private readonly Dictionary<object, CachedDistance> markerDistances = new Dictionary<object, CachedDistance>();
|
||||
|
||||
@@ -455,7 +453,20 @@ namespace Barotrauma.Items.Components
|
||||
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos();
|
||||
|
||||
if (steering != null && steering.DockingModeEnabled && steering.ActiveDockingSource != null)
|
||||
{
|
||||
Vector2 worldFocusPos = (steering.ActiveDockingSource.Item.WorldPosition + steering.DockingTarget.Item.WorldPosition) / 2.0f;
|
||||
DisplayOffset = Vector2.Lerp(DisplayOffset, worldFocusPos - transducerCenter, 0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayOffset = Vector2.Lerp(DisplayOffset, Vector2.Zero, 0.1f);
|
||||
}
|
||||
transducerCenter += DisplayOffset;
|
||||
|
||||
float distort = MathHelper.Clamp(1.0f - item.Condition / item.MaxCondition, 0.0f, 1.0f);
|
||||
for (int i = sonarBlips.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -502,8 +513,6 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos() + DisplayOffset;
|
||||
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
nearbyObjectUpdateTimer -= deltaTime;
|
||||
@@ -829,8 +838,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos();
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos();// + DisplayOffset;
|
||||
|
||||
if (sonarBlips.Count > 0)
|
||||
{
|
||||
@@ -840,7 +848,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (SonarBlip sonarBlip in sonarBlips)
|
||||
{
|
||||
DrawBlip(spriteBatch, sonarBlip, transducerCenter, center, sonarBlip.FadeTimer / 2.0f * signalStrength, blipScale);
|
||||
DrawBlip(spriteBatch, sonarBlip, transducerCenter + DisplayOffset, center, sonarBlip.FadeTimer / 2.0f * signalStrength, blipScale);
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
@@ -849,8 +857,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (item.Submarine != null && !DetectSubmarineWalls)
|
||||
{
|
||||
DrawDockingPorts(spriteBatch, transducerCenter, signalStrength);
|
||||
transducerCenter += DisplayOffset;
|
||||
DrawDockingPorts(spriteBatch, transducerCenter, signalStrength);
|
||||
DrawOwnSubmarineBorders(spriteBatch, transducerCenter, signalStrength);
|
||||
}
|
||||
else
|
||||
@@ -1083,10 +1091,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
DrawDockingIndicator(spriteBatch, steering, ref transducerCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayOffset = Vector2.Lerp(DisplayOffset, Vector2.Zero, 0.1f);
|
||||
}
|
||||
|
||||
foreach (DockingPort dockingPort in DockingPort.List)
|
||||
{
|
||||
@@ -1131,9 +1135,6 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 worldFocusPos = (steering.ActiveDockingSource.Item.WorldPosition + steering.DockingTarget.Item.WorldPosition) / 2.0f;
|
||||
worldFocusPos.X = steering.DockingTarget.Item.WorldPosition.X;
|
||||
|
||||
DisplayOffset = Vector2.Lerp(DisplayOffset, worldFocusPos - transducerCenter, 0.1f);
|
||||
transducerCenter += DisplayOffset;
|
||||
|
||||
Vector2 sourcePortDiff = (steering.ActiveDockingSource.Item.WorldPosition - transducerCenter) * scale;
|
||||
Vector2 sourcePortPos = new Vector2(sourcePortDiff.X, -sourcePortDiff.Y);
|
||||
Vector2 targetPortDiff = (steering.DockingTarget.Item.WorldPosition - transducerCenter) * scale;
|
||||
@@ -1234,7 +1235,7 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 disruptionPos = new Vector2(levelObject.Position.X, levelObject.Position.Y);
|
||||
|
||||
float disruptionDist = Vector2.Distance(pingSource, disruptionPos);
|
||||
disruptedDirections.Add(new Pair<Vector2, float>((disruptionPos - pingSource) / disruptionDist, disruptionStrength));
|
||||
disruptedDirections.Add(((disruptionPos - pingSource) / disruptionDist, disruptionStrength));
|
||||
|
||||
CreateBlipsForDisruption(disruptionPos, disruptionStrength);
|
||||
|
||||
@@ -1246,7 +1247,7 @@ namespace Barotrauma.Items.Components
|
||||
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
|
||||
if (distSqr > worldPingRadiusSqr) { continue; }
|
||||
float disruptionDist = (float)Math.Sqrt(distSqr);
|
||||
disruptedDirections.Add(new Pair<Vector2, float>((aiTarget.WorldPosition - pingSource) / disruptionDist, aiTarget.SonarDisruption));
|
||||
disruptedDirections.Add(((aiTarget.WorldPosition - pingSource) / disruptionDist, aiTarget.SonarDisruption));
|
||||
CreateBlipsForDisruption(aiTarget.WorldPosition, disruption);
|
||||
}
|
||||
}
|
||||
@@ -1461,10 +1462,10 @@ namespace Barotrauma.Items.Components
|
||||
float transducerDist = transducerDiff.Length();
|
||||
Vector2 pingDirection = transducerDiff / transducerDist;
|
||||
bool disrupted = false;
|
||||
foreach (Pair<Vector2, float> disruptDir in disruptedDirections)
|
||||
foreach ((Vector2 disruptPos, float disruptStrength) in disruptedDirections)
|
||||
{
|
||||
float dot = Vector2.Dot(pingDirection, disruptDir.First);
|
||||
if (dot > 1.0f - disruptDir.Second)
|
||||
float dot = Vector2.Dot(pingDirection, disruptPos);
|
||||
if (dot > 1.0f - disruptStrength)
|
||||
{
|
||||
disrupted = true;
|
||||
break;
|
||||
|
||||
@@ -403,7 +403,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
item.SendSignal(new Signal("1", sender: Character.Controlled), "toggle_docking");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -434,6 +434,7 @@ namespace Barotrauma.Items.Components
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
tinkeringDuration = msg.ReadSingle();
|
||||
tinkeringStrength = msg.ReadSingle();
|
||||
tinkeringPowersDevices = msg.ReadBoolean();
|
||||
ushort currentFixerID = msg.ReadUInt16();
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
child.Enabled = buttonsEnabled;
|
||||
child.Children.ForEach(c => c.Enabled = buttonsEnabled);
|
||||
}
|
||||
if (Container == null) { return; }
|
||||
bool itemsContained = Container.Inventory.AllItems.Any();
|
||||
if (itemsContained)
|
||||
{
|
||||
@@ -77,7 +78,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
SendSignal((int)userData);
|
||||
SendSignal((int)userData, Character.Controlled);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,6 +99,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void OnItemLoadedProjSpecific()
|
||||
{
|
||||
if (Container == null) { return; }
|
||||
Container.AllowUIOverlap = true;
|
||||
Container.Inventory.RectTransform = containerHolder.RectTransform;
|
||||
}
|
||||
@@ -109,7 +111,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), isServerMessage: true);
|
||||
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), sender: null, isServerMessage: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific()
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
bool elementVisibilityChanged = false;
|
||||
int visibleElementCount = 0;
|
||||
@@ -209,6 +209,7 @@ namespace Barotrauma.Items.Components
|
||||
if (uiElement.Visible != visible)
|
||||
{
|
||||
uiElement.Visible = visible;
|
||||
uiElement.IgnoreLayoutGroups = !uiElement.Visible;
|
||||
elementVisibilityChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -223,6 +224,7 @@ namespace Barotrauma.Items.Components
|
||||
uiElement.RectTransform.RelativeSize = new Vector2(1.0f, elementSize);
|
||||
}
|
||||
GuiFrame.Visible = visibleElementCount > 0;
|
||||
uiElementContainer.Recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
if (!editing || !MapEntity.SelectedList.Contains(item)) return;
|
||||
if (!editing || !MapEntity.SelectedList.Contains(item)) { return; }
|
||||
|
||||
Vector2 pos = item.WorldPosition + detectOffset;
|
||||
Vector2 pos = item.WorldPosition + TransformedDetectOffset;
|
||||
pos.Y = -pos.Y;
|
||||
GUI.DrawRectangle(spriteBatch, pos - new Vector2(rangeX, rangeY), new Vector2(rangeX, rangeY) * 2.0f, Color.Cyan * 0.5f, isFilled: false, thickness: 2);
|
||||
}
|
||||
|
||||
@@ -286,7 +286,6 @@ namespace Barotrauma.Items.Components
|
||||
item.Color, depth, 0.3f);
|
||||
}
|
||||
|
||||
|
||||
public static void UpdateEditing(List<Wire> wires)
|
||||
{
|
||||
var doubleClicked = PlayerInput.DoubleClicked();
|
||||
@@ -509,6 +508,31 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
//only used in the sub editor, hence only in the client project
|
||||
if (!item.IsSelected) { return; }
|
||||
|
||||
Vector2 wireNodeOffset = item.Submarine == null ? Vector2.Zero : item.Submarine.HiddenSubPosition + amount;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
if (i == 0 || i == nodes.Count - 1)
|
||||
{
|
||||
if (connections[0]?.Item != null && !connections[0].Item.IsSelected &&
|
||||
(Submarine.RectContains(connections[0].Item.Rect, nodes[i] + wireNodeOffset) || Submarine.RectContains(connections[0].Item.Rect, nodes[i] + wireNodeOffset - amount)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (connections[1]?.Item != null && !connections[1].Item.IsSelected &&
|
||||
(Submarine.RectContains(connections[1].Item.Rect, nodes[i] + wireNodeOffset) || Submarine.RectContains(connections[1].Item.Rect, nodes[i] + wireNodeOffset - amount)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes[i] += amount;
|
||||
}
|
||||
UpdateSections();
|
||||
}
|
||||
public bool IsMouseOn()
|
||||
{
|
||||
if (GUI.MouseOn == null)
|
||||
|
||||
@@ -301,7 +301,7 @@ namespace Barotrauma.Items.Components
|
||||
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
|
||||
foreach (Affliction affliction in allAfflictions)
|
||||
{
|
||||
if (affliction.Strength < affliction.Prefab.ShowInHealthScannerThreshold || affliction.Strength <= 0.0f) continue;
|
||||
if (affliction.Strength < affliction.Prefab.ShowInHealthScannerThreshold || affliction.Strength <= 0.0f) { continue; }
|
||||
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
|
||||
{
|
||||
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
|
||||
@@ -314,7 +314,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (AfflictionPrefab affliction in combinedAfflictionStrengths.Keys)
|
||||
{
|
||||
texts.Add(TextManager.AddPunctuation(':', affliction.Name, Math.Max(((int)combinedAfflictionStrengths[affliction]), 1).ToString() + " %"));
|
||||
texts.Add(TextManager.AddPunctuation(':', affliction.Name, Math.Max((int)combinedAfflictionStrengths[affliction], 1).ToString() + " %"));
|
||||
textColors.Add(Color.Lerp(GUI.Style.Orange, GUI.Style.Red, combinedAfflictionStrengths[affliction] / affliction.MaxStrength));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Barotrauma
|
||||
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public static bool ShowItems = true, ShowWires = true;
|
||||
|
||||
|
||||
private readonly List<PosInfo> positionBuffer = new List<PosInfo>();
|
||||
|
||||
private readonly List<ItemComponent> activeHUDs = new List<ItemComponent>();
|
||||
@@ -89,8 +89,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (itemInUseWarning == null)
|
||||
{
|
||||
itemInUseWarning = new GUITextBlock(new RectTransform(new Point(10), GUI.Canvas), "",
|
||||
textColor: GUI.Style.Orange, color: Color.Black,
|
||||
itemInUseWarning = new GUITextBlock(new RectTransform(new Point(10), GUI.Canvas), "",
|
||||
textColor: GUI.Style.Orange, color: Color.Black,
|
||||
textAlignment: Alignment.Center, style: "OuterGlow");
|
||||
}
|
||||
return itemInUseWarning;
|
||||
@@ -105,6 +105,9 @@ namespace Barotrauma
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SubEditorScreen.IsLayerVisible(this)) { return false;}
|
||||
|
||||
return parentInventory == null && (body == null || body.Enabled) && ShowItems;
|
||||
}
|
||||
}
|
||||
@@ -154,7 +157,7 @@ namespace Barotrauma
|
||||
if (containedSprite.UseWhenAttached)
|
||||
{
|
||||
activeContainedSprite = containedSprite;
|
||||
activeSprite = containedSprite.Sprite;
|
||||
activeSprite = containedSprite.Sprite;
|
||||
UpdateSpriteStates(0.0f);
|
||||
return;
|
||||
}
|
||||
@@ -196,7 +199,7 @@ namespace Barotrauma
|
||||
{
|
||||
brokenSprite.Sprite.EnsureLazyLoaded();
|
||||
}
|
||||
|
||||
|
||||
foreach (var decorativeSprite in ((ItemPrefab)prefab).DecorativeSprites)
|
||||
{
|
||||
decorativeSprite.Sprite.EnsureLazyLoaded();
|
||||
@@ -255,7 +258,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (!Visible || (!editing && HiddenInGame)) { return; }
|
||||
if (!Visible || (!editing && HiddenInGame) || !SubEditorScreen.IsLayerVisible(this)) { return; }
|
||||
|
||||
if (editing)
|
||||
{
|
||||
@@ -265,7 +268,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (!ShowItems) { return; }
|
||||
}
|
||||
|
||||
|
||||
Color color = IsIncludedInSelection && editing ? GUI.Style.Blue : IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange * Math.Max(GetSpriteColor().A / (float) byte.MaxValue, 0.1f) : GetSpriteColor();
|
||||
|
||||
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||
@@ -273,7 +276,7 @@ namespace Barotrauma
|
||||
bool isWiringMode = editing && SubEditorScreen.TransparentWiringMode && SubEditorScreen.IsWiringMode() && !isWire && parentInventory == null;
|
||||
bool renderTransparent = isWiringMode && GetComponent<ConnectionPanel>() == null;
|
||||
if (renderTransparent) { color *= 0.15f; }
|
||||
|
||||
|
||||
BrokenItemSprite fadeInBrokenSprite = null;
|
||||
float fadeInBrokenSpriteAlpha = 0.0f;
|
||||
float displayCondition = FakeBroken ? 0.0f : ConditionPercentage;
|
||||
@@ -322,7 +325,7 @@ namespace Barotrauma
|
||||
Vector2 size = new Vector2(rect.Width, rect.Height);
|
||||
if (color.A > 0)
|
||||
{
|
||||
activeSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + drawOffset,
|
||||
activeSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + drawOffset,
|
||||
size, color: color,
|
||||
textureScale: Vector2.One * Scale,
|
||||
depth: depth);
|
||||
@@ -336,11 +339,11 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
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,
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
||||
size, color: color,
|
||||
textureScale: Vector2.One * Scale,
|
||||
@@ -380,7 +383,7 @@ namespace Barotrauma
|
||||
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.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
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,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||
}
|
||||
@@ -440,11 +443,11 @@ namespace Barotrauma
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var upgrade in Upgrades)
|
||||
{
|
||||
var upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
|
||||
|
||||
foreach (var decorativeSprite in upgradeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
@@ -456,7 +459,7 @@ namespace Barotrauma
|
||||
rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
activeSprite.effects = oldEffects;
|
||||
@@ -466,7 +469,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//use a backwards for loop because the drawable components may disable drawing,
|
||||
//use a backwards for loop because the drawable components may disable drawing,
|
||||
//causing them to be removed from the list
|
||||
for (int i = drawableComponents.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -501,7 +504,7 @@ namespace Barotrauma
|
||||
Vector2 drawPos = new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2));
|
||||
Vector2 drawSize = new Vector2(MathF.Ceiling(rect.Width + Math.Abs(drawPos.X - (int)drawPos.X)), MathF.Ceiling(rect.Height + Math.Abs(drawPos.Y - (int)drawPos.Y)));
|
||||
drawPos = new Vector2(MathF.Floor(drawPos.X), MathF.Floor(drawPos.Y));
|
||||
GUI.DrawRectangle(spriteBatch, drawPos, drawSize,
|
||||
GUI.DrawRectangle(spriteBatch, drawPos, drawSize,
|
||||
Color.White, false, 0, thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
|
||||
|
||||
foreach (Rectangle t in Prefab.Triggers)
|
||||
@@ -582,19 +585,25 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
|
||||
if (Prefab.DecorativeSpriteGroups.Count > 0)
|
||||
{
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
}
|
||||
|
||||
foreach (var upgrade in Upgrades)
|
||||
{
|
||||
var upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
var upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
foreach (var decorativeSprite in upgradeSprites)
|
||||
{
|
||||
var spriteState = spriteAnimState[decorativeSprite];
|
||||
spriteState.IsActive = true;
|
||||
foreach (var _ in decorativeSprite.IsActiveConditionals.Where(conditional => !ConditionalMatches(conditional)))
|
||||
foreach (var conditional in decorativeSprite.IsActiveConditionals)
|
||||
{
|
||||
spriteState.IsActive = false;
|
||||
break;
|
||||
if (!ConditionalMatches(conditional))
|
||||
{
|
||||
spriteState.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,8 +705,8 @@ namespace Barotrauma
|
||||
foreach (string tag in ip.PreferredContainers.SelectMany(pc => pc.Primary)) { availableTags.Add(tag); }
|
||||
foreach (string tag in ip.PreferredContainers.SelectMany(pc => pc.Secondary)) { availableTags.Add(tag); }
|
||||
}
|
||||
//remove identifiers from the available container tags
|
||||
//(otherwise the list will include many irrelevant options,
|
||||
//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)
|
||||
availableTags.RemoveWhere(t => MapEntityPrefab.List.Any(me => me.Identifier == t));
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1), tagsField.RectTransform, Anchor.TopRight), "...")
|
||||
@@ -749,7 +758,7 @@ namespace Barotrauma
|
||||
{
|
||||
me.FlipY(relativeToSub: false);
|
||||
}
|
||||
if (!SelectedList.Contains(this)) { FlipY(relativeToSub: false); }
|
||||
if (!SelectedList.Contains(this)) { FlipY(relativeToSub: false); }
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -805,9 +814,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (!ic.AllowInGameEditing) { continue; }
|
||||
if (SerializableProperty.GetProperties<InGameEditable>(ic).Count == 0 &&
|
||||
!SerializableProperty.GetProperties<ConditionallyEditable>(ic).Any(p => p.GetAttribute<ConditionallyEditable>().IsEditable(ic)))
|
||||
!SerializableProperty.GetProperties<ConditionallyEditable>(ic).Any(p => p.GetAttribute<ConditionallyEditable>().IsEditable(ic)))
|
||||
{
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -869,7 +878,7 @@ namespace Barotrauma
|
||||
textBox.Text = relatedItem.JoinedIdentifiers;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ic.CreateEditingHUD(componentEditor);
|
||||
componentEditor.Recalculate();
|
||||
@@ -892,7 +901,7 @@ namespace Barotrauma
|
||||
|
||||
return upgradeSprites;
|
||||
}
|
||||
|
||||
|
||||
public override bool AddUpgrade(Upgrade upgrade, bool createNetworkEvent = false)
|
||||
{
|
||||
if (upgrade.Prefab.IsWallUpgrade) { return false; }
|
||||
@@ -949,7 +958,7 @@ namespace Barotrauma
|
||||
//reset positions first
|
||||
List<GUIComponent> elementsToMove = new List<GUIComponent>();
|
||||
|
||||
if (editingHUD != null && editingHUD.UserData == this &&
|
||||
if (editingHUD != null && editingHUD.UserData == this &&
|
||||
((HasInGameEditableProperties && Character.Controlled?.SelectedConstruction == this) || Screen.Selected == GameMain.SubEditorScreen))
|
||||
{
|
||||
elementsToMove.Add(editingHUD);
|
||||
@@ -972,8 +981,8 @@ namespace Barotrauma
|
||||
int disallowedPadding = (int)(50 * GUI.Scale);
|
||||
disallowedAreas.Add(GameMain.GameSession.CrewManager.GetActiveCrewArea());
|
||||
disallowedAreas.Add(new Rectangle(
|
||||
HUDLayoutSettings.ChatBoxArea.X - disallowedPadding, HUDLayoutSettings.ChatBoxArea.Y,
|
||||
HUDLayoutSettings.ChatBoxArea.Width + disallowedPadding, HUDLayoutSettings.ChatBoxArea.Height));
|
||||
HUDLayoutSettings.ChatBoxArea.X - disallowedPadding, HUDLayoutSettings.ChatBoxArea.Y,
|
||||
HUDLayoutSettings.ChatBoxArea.Width + disallowedPadding, HUDLayoutSettings.ChatBoxArea.Height));
|
||||
}
|
||||
|
||||
if (Screen.Selected is SubEditorScreen editor)
|
||||
@@ -985,8 +994,8 @@ namespace Barotrauma
|
||||
|
||||
GUI.PreventElementOverlap(elementsToMove, disallowedAreas,
|
||||
new Rectangle(
|
||||
0, 20,
|
||||
GameMain.GraphicsWidth,
|
||||
0, 20,
|
||||
GameMain.GraphicsWidth,
|
||||
HUDLayoutSettings.InventoryTopY > 0 ? HUDLayoutSettings.InventoryTopY - 40 : GameMain.GraphicsHeight - 80));
|
||||
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
@@ -995,7 +1004,7 @@ namespace Barotrauma
|
||||
|
||||
|
||||
var linkUIToComponent = ic.GetLinkUIToComponent();
|
||||
if (linkUIToComponent == null) { continue; }
|
||||
if (linkUIToComponent == null) { continue; }
|
||||
|
||||
ic.GuiFrame.RectTransform.ScreenSpaceOffset = linkUIToComponent.GuiFrame.RectTransform.ScreenSpaceOffset;
|
||||
}
|
||||
@@ -1110,14 +1119,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
|
||||
{
|
||||
if (HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped))
|
||||
{
|
||||
DrawEditing(spriteBatch, cam);
|
||||
}
|
||||
|
||||
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
{
|
||||
if (ic.CanBeSelected)
|
||||
@@ -1138,9 +1147,9 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, debugInitialHudPositions[i], Color.Orange);
|
||||
GUI.DrawRectangle(spriteBatch, ic.GuiFrame.Rect, Color.LightGreen);
|
||||
GUI.DrawLine(spriteBatch, debugInitialHudPositions[i].Location.ToVector2(), ic.GuiFrame.Rect.Location.ToVector2(), Color.Orange);
|
||||
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,7 +1271,7 @@ namespace Barotrauma
|
||||
|
||||
NetEntityEvent.Type eventType =
|
||||
(NetEntityEvent.Type)msg.ReadRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
@@ -1323,7 +1332,7 @@ namespace Barotrauma
|
||||
|
||||
ItemComponent targetComponent = componentIndex < components.Count ? components[componentIndex] : null;
|
||||
Character targetCharacter = FindEntityByID(targetCharacterID) as Character;
|
||||
Limb targetLimb = targetCharacter != null && targetLimbID < targetCharacter.AnimController.Limbs.Length ?
|
||||
Limb targetLimb = targetCharacter != null && targetLimbID < targetCharacter.AnimController.Limbs.Length ?
|
||||
targetCharacter.AnimController.Limbs[targetLimbID] : null;
|
||||
Entity useTarget = FindEntityByID(useTargetID);
|
||||
|
||||
@@ -1334,7 +1343,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
targetComponent.ApplyStatusEffects(actionType, 1.0f, targetCharacter, targetLimb, useTarget, worldPosition: worldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
@@ -1346,7 +1355,7 @@ namespace Barotrauma
|
||||
if (UpgradePrefab.Find(identifier) is { } upgradePrefab)
|
||||
{
|
||||
Upgrade upgrade = new Upgrade(this, upgradePrefab, level);
|
||||
|
||||
|
||||
byte targetCount = msg.ReadByte();
|
||||
for (int i = 0; i < targetCount; i++)
|
||||
{
|
||||
@@ -1360,7 +1369,7 @@ namespace Barotrauma
|
||||
|
||||
AddUpgrade(upgrade, false);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case NetEntityEvent.Type.Invalid:
|
||||
break;
|
||||
}
|
||||
@@ -1394,7 +1403,7 @@ namespace Barotrauma
|
||||
Character targetCharacter = FindEntityByID(characterID) as Character;
|
||||
|
||||
msg.Write(characterID);
|
||||
msg.Write(targetCharacter == null ? (byte)255 : (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb));
|
||||
msg.Write(targetCharacter == null ? (byte)255 : (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb));
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
WritePropertyChange(msg, extraData, true);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowGaps;
|
||||
return ShowGaps && SubEditorScreen.IsLayerVisible(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!editing || !ShowGaps) { return; }
|
||||
if (!editing || !ShowGaps || !SubEditorScreen.IsLayerVisible(this)) { return; }
|
||||
|
||||
Color clr = (open == 0.0f) ? GUI.Style.Red : Color.Cyan;
|
||||
if (IsHighlighted) clr = Color.Gold;
|
||||
@@ -128,8 +128,14 @@ namespace Barotrauma
|
||||
{
|
||||
//no flow particles between linked hulls (= rooms consisting of multiple hulls)
|
||||
if (hull1.linkedTo.Contains(hull2)) { return; }
|
||||
if (hull1.linkedTo.Any(h => h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2))) { return; }
|
||||
if (hull2.linkedTo.Any(h => h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2))) { return; }
|
||||
foreach (Hull h in hull1.linkedTo)
|
||||
{
|
||||
if (h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
foreach (Hull h in hull2.linkedTo)
|
||||
{
|
||||
if (h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos = Position;
|
||||
@@ -177,7 +183,7 @@ namespace Barotrauma
|
||||
"bubbles",
|
||||
(Submarine == null ? pos : pos + Submarine.Position),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,14 +34,14 @@ namespace Barotrauma
|
||||
private readonly List<RemoteDecal> remoteDecals = new List<RemoteDecal>();
|
||||
|
||||
private readonly HashSet<Decal> pendingDecalUpdates = new HashSet<Decal>();
|
||||
|
||||
|
||||
private double lastAmbientLightEditTime;
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowHulls;
|
||||
return ShowHulls && SubEditorScreen.IsLayerVisible(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,39 +133,41 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
if (!entity.linkedTo.Contains(this)) { entity.linkedTo.Add(this); }
|
||||
if (!linkedTo.Contains(this)) { linkedTo.Add(entity); }
|
||||
if (!linkedTo.Contains(this)) { linkedTo.Add(entity); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
||||
{
|
||||
serverUpdateDelay -= deltaTime;
|
||||
if (serverUpdateDelay <= 0.0f)
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
ApplyRemoteState();
|
||||
}
|
||||
|
||||
if (networkUpdatePending)
|
||||
{
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
serverUpdateDelay -= deltaTime;
|
||||
if (serverUpdateDelay <= 0.0f)
|
||||
{
|
||||
if (!pendingSectionUpdates.Any() && !pendingDecalUpdates.Any())
|
||||
ApplyRemoteState();
|
||||
}
|
||||
if (networkUpdatePending)
|
||||
{
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
if (!pendingSectionUpdates.Any() && !pendingDecalUpdates.Any())
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
}
|
||||
foreach (Decal decal in pendingDecalUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { decal });
|
||||
}
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { pendingSectionUpdate });
|
||||
}
|
||||
pendingSectionUpdates.Clear();
|
||||
networkUpdatePending = false;
|
||||
networkUpdateTimer = 0.0f;
|
||||
}
|
||||
foreach (Decal decal in pendingDecalUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { decal });
|
||||
}
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { pendingSectionUpdate });
|
||||
}
|
||||
pendingSectionUpdates.Clear();
|
||||
networkUpdatePending = false;
|
||||
networkUpdateTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +245,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ShowHulls && !GameMain.DebugDraw) { return; }
|
||||
if ((!ShowHulls || !SubEditorScreen.IsLayerVisible(this)) && !GameMain.DebugDraw) { return; }
|
||||
|
||||
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) { return; }
|
||||
|
||||
@@ -385,45 +387,42 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Vector3[] corners = new Vector3[6];
|
||||
private static readonly Vector2[] uvCoords = new Vector2[4];
|
||||
private static readonly Vector3[] prevCorners = new Vector3[2];
|
||||
private static readonly Vector2[] prevUVs = new Vector2[2];
|
||||
|
||||
private void UpdateVertices(Camera cam, EntityGrid entityGrid, WaterRenderer renderer)
|
||||
{
|
||||
Vector2 submarinePos = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
|
||||
|
||||
//if there's no more space in the buffer, don't render the water in the hull
|
||||
//not an ideal solution, but this seems to only happen in cases where the missing
|
||||
//not an ideal solution, but this seems to only happen in cases where the missing
|
||||
//water is not very noticeable (e.g. zoomed very far out so that multiple subs and ruins are visible)
|
||||
if (renderer.PositionInBuffer > renderer.vertices.Length - 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderer.IndoorsVertices.ContainsKey(entityGrid))
|
||||
{
|
||||
renderer.IndoorsVertices[entityGrid] = new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize];
|
||||
renderer.PositionInIndoorsBuffer[entityGrid] = 0;
|
||||
}
|
||||
|
||||
//calculate where the surface should be based on the water volume
|
||||
float top = rect.Y + submarinePos.Y;
|
||||
float bottom = top - rect.Height;
|
||||
float renderSurface = drawSurface + submarinePos.Y;
|
||||
|
||||
if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) return;
|
||||
if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) { return; }
|
||||
if (rect.X + submarinePos.X > cam.WorldView.Right || rect.Right + submarinePos.X < cam.WorldView.X) { return; }
|
||||
|
||||
Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
if (!update)
|
||||
{
|
||||
// create the four corners of our triangle.
|
||||
|
||||
Vector3[] corners = new Vector3[4];
|
||||
|
||||
corners[0] = new Vector3(rect.X, rect.Y, 0.0f);
|
||||
corners[1] = new Vector3(rect.X + rect.Width, rect.Y, 0.0f);
|
||||
|
||||
corners[2] = new Vector3(corners[1].X, rect.Y - rect.Height, 0.0f);
|
||||
corners[3] = new Vector3(corners[0].X, corners[2].Y, 0.0f);
|
||||
|
||||
Vector2[] uvCoords = new Vector2[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
corners[i] += new Vector3(submarinePos, 0.0f);
|
||||
@@ -443,6 +442,15 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderer.IndoorsVertices.ContainsKey(entityGrid))
|
||||
{
|
||||
renderer.IndoorsVertices[entityGrid] = new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize];
|
||||
}
|
||||
if (!renderer.PositionInIndoorsBuffer.ContainsKey(entityGrid))
|
||||
{
|
||||
renderer.PositionInIndoorsBuffer[entityGrid] = 0;
|
||||
}
|
||||
|
||||
float x = rect.X;
|
||||
if (Submarine != null) { x += Submarine.DrawPosition.X; }
|
||||
|
||||
@@ -454,20 +462,15 @@ namespace Barotrauma
|
||||
|
||||
x += start * WaveWidth;
|
||||
|
||||
Vector3[] prevCorners = new Vector3[2];
|
||||
Vector2[] prevUVs = new Vector2[2];
|
||||
|
||||
int width = WaveWidth;
|
||||
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
Vector3[] corners = new Vector3[6];
|
||||
|
||||
//top left
|
||||
corners[0] = new Vector3(x, top, 0.0f);
|
||||
//watersurface left
|
||||
corners[3] = new Vector3(corners[0].X, renderSurface + waveY[i], 0.0f);
|
||||
|
||||
|
||||
//top right
|
||||
corners[1] = new Vector3(x + width, top, 0.0f);
|
||||
//watersurface right
|
||||
@@ -477,7 +480,7 @@ namespace Barotrauma
|
||||
corners[4] = new Vector3(x, bottom, 0.0f);
|
||||
//bottom right
|
||||
corners[5] = new Vector3(x + width, bottom, 0.0f);
|
||||
|
||||
|
||||
Vector2[] uvCoords = new Vector2[4];
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
@@ -714,7 +717,7 @@ namespace Barotrauma
|
||||
}
|
||||
remoteBackgroundSections.Clear();
|
||||
|
||||
if (remoteDecals.Any())
|
||||
if (remoteDecals.Count > 0)
|
||||
{
|
||||
decals.Clear();
|
||||
foreach (RemoteDecal remoteDecal in remoteDecals)
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Barotrauma
|
||||
public readonly WaterVertexData IndoorsSurfaceBottomColor = new WaterVertexData(0.2f, 0.1f, 0.9f, 1.0f);
|
||||
|
||||
public VertexPositionTexture[] vertices = new VertexPositionTexture[DefaultBufferSize];
|
||||
public Dictionary<EntityGrid, VertexPositionColorTexture[]> IndoorsVertices = new Dictionary<EntityGrid, VertexPositionColorTexture[]>();// VertexPositionColorTexture[DefaultBufferSize * 2];
|
||||
public Dictionary<EntityGrid, VertexPositionColorTexture[]> IndoorsVertices = new Dictionary<EntityGrid, VertexPositionColorTexture[]>();
|
||||
|
||||
public Effect WaterEffect
|
||||
{
|
||||
@@ -81,13 +81,17 @@ namespace Barotrauma
|
||||
|
||||
if (basicEffect == null)
|
||||
{
|
||||
basicEffect = new BasicEffect(GameMain.Instance.GraphicsDevice);
|
||||
basicEffect.VertexColorEnabled = false;
|
||||
|
||||
basicEffect.TextureEnabled = true;
|
||||
basicEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
VertexColorEnabled = false,
|
||||
TextureEnabled = true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private readonly VertexPositionColorTexture[] tempVertices = new VertexPositionColorTexture[6];
|
||||
private readonly Vector3[] tempCorners = new Vector3[4];
|
||||
|
||||
public void RenderWater(SpriteBatch spriteBatch, RenderTarget2D texture, Camera cam)
|
||||
{
|
||||
spriteBatch.GraphicsDevice.BlendState = BlendState.NonPremultiplied;
|
||||
@@ -139,29 +143,26 @@ namespace Barotrauma
|
||||
|
||||
WaterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
VertexPositionColorTexture[] verts = new VertexPositionColorTexture[6];
|
||||
|
||||
Rectangle view = cam != null ? cam.WorldView : spriteBatch.GraphicsDevice.Viewport.Bounds;
|
||||
|
||||
var corners = new Vector3[4];
|
||||
corners[0] = new Vector3(view.X, view.Y, 0.1f);
|
||||
corners[1] = new Vector3(view.Right, view.Y, 0.1f);
|
||||
corners[2] = new Vector3(view.Right, view.Y - view.Height, 0.1f);
|
||||
corners[3] = new Vector3(view.X, view.Y - view.Height, 0.1f);
|
||||
tempCorners[0] = new Vector3(view.X, view.Y, 0.1f);
|
||||
tempCorners[1] = new Vector3(view.Right, view.Y, 0.1f);
|
||||
tempCorners[2] = new Vector3(view.Right, view.Y - view.Height, 0.1f);
|
||||
tempCorners[3] = new Vector3(view.X, view.Y - view.Height, 0.1f);
|
||||
|
||||
WaterVertexData backGroundColor = new WaterVertexData(0.1f, 0.1f, 0.5f, 1.0f);
|
||||
verts[0] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[1] = new VertexPositionColorTexture(corners[1], backGroundColor, Vector2.Zero);
|
||||
verts[2] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[3] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[4] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[5] = new VertexPositionColorTexture(corners[3], backGroundColor, Vector2.Zero);
|
||||
tempVertices[0] = new VertexPositionColorTexture(tempCorners[0], backGroundColor, Vector2.Zero);
|
||||
tempVertices[1] = new VertexPositionColorTexture(tempCorners[1], backGroundColor, Vector2.Zero);
|
||||
tempVertices[2] = new VertexPositionColorTexture(tempCorners[2], backGroundColor, Vector2.Zero);
|
||||
tempVertices[3] = new VertexPositionColorTexture(tempCorners[0], backGroundColor, Vector2.Zero);
|
||||
tempVertices[4] = new VertexPositionColorTexture(tempCorners[2], backGroundColor, Vector2.Zero);
|
||||
tempVertices[5] = new VertexPositionColorTexture(tempCorners[3], backGroundColor, Vector2.Zero);
|
||||
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, 2);
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, tempVertices, 0, 2);
|
||||
|
||||
foreach (KeyValuePair<EntityGrid, VertexPositionColorTexture[]> subVerts in IndoorsVertices)
|
||||
{
|
||||
if (!PositionInIndoorsBuffer.ContainsKey(subVerts.Key) || PositionInIndoorsBuffer[subVerts.Key] == 0) continue;
|
||||
if (!PositionInIndoorsBuffer.ContainsKey(subVerts.Key) || PositionInIndoorsBuffer[subVerts.Key] == 0) { continue; }
|
||||
|
||||
offset = WavePos;
|
||||
if (subVerts.Key.Submarine != null) { offset -= subVerts.Key.Submarine.WorldPosition; }
|
||||
@@ -207,11 +208,23 @@ namespace Barotrauma
|
||||
basicEffect.CurrentTechnique.Passes[0].Apply();
|
||||
}
|
||||
|
||||
private readonly List<EntityGrid> buffersToRemove = new List<EntityGrid>();
|
||||
public void ResetBuffers()
|
||||
{
|
||||
PositionInBuffer = 0;
|
||||
PositionInIndoorsBuffer.Clear();
|
||||
IndoorsVertices.Clear();
|
||||
buffersToRemove.Clear();
|
||||
foreach (var buffer in IndoorsVertices.Keys)
|
||||
{
|
||||
if (buffer.Submarine?.Removed ?? false)
|
||||
{
|
||||
buffersToRemove.Add(buffer);
|
||||
}
|
||||
}
|
||||
foreach (var bufferToRemove in buffersToRemove)
|
||||
{
|
||||
IndoorsVertices.Remove(bufferToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -517,7 +517,7 @@ namespace Barotrauma.Lights
|
||||
private void RefreshConvexHullList(ConvexHullList chList, Vector2 lightPos, Submarine sub)
|
||||
{
|
||||
var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub);
|
||||
if (fullChList == null) return;
|
||||
if (fullChList == null) { return; }
|
||||
|
||||
chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, ch.BoundingBox));
|
||||
|
||||
@@ -530,105 +530,121 @@ namespace Barotrauma.Lights
|
||||
/// </summary>
|
||||
private void CheckHullsInRange()
|
||||
{
|
||||
List<Submarine> subs = new List<Submarine>(Submarine.Loaded);
|
||||
subs.Add(null);
|
||||
|
||||
foreach (Submarine sub in subs)
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
//find the list of convexhulls that belong to the sub
|
||||
var chList = hullsInRange.Find(x => x.Submarine == sub);
|
||||
CheckHullsInRange(sub);
|
||||
}
|
||||
//check convex hulls that aren't in any sub
|
||||
CheckHullsInRange(null);
|
||||
}
|
||||
|
||||
//not found -> create one
|
||||
if (chList == null)
|
||||
private void CheckHullsInRange(Submarine sub)
|
||||
{
|
||||
//find the list of convexhulls that belong to the sub
|
||||
ConvexHullList chList = null;
|
||||
foreach (var ch in hullsInRange)
|
||||
{
|
||||
if (ch.Submarine == sub)
|
||||
{
|
||||
chList = new ConvexHullList(sub);
|
||||
hullsInRange.Add(chList);
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
|
||||
if (chList.List.Any(ch => ch.LastVertexChangeTime > lastRecalculationTime && !chList.IsHidden.Contains(ch)))
|
||||
{
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
|
||||
Vector2 lightPos = position;
|
||||
if (ParentSub == null)
|
||||
{
|
||||
//light and the convexhulls are both outside
|
||||
if (sub == null)
|
||||
{
|
||||
if (NeedsHullCheck)
|
||||
{
|
||||
RefreshConvexHullList(chList, lightPos, null);
|
||||
}
|
||||
}
|
||||
//light is outside, convexhulls inside a sub
|
||||
else
|
||||
{
|
||||
lightPos -= sub.Position;
|
||||
|
||||
Rectangle subBorders = sub.Borders;
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//only draw if the light overlaps with the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//light is inside, convexhull outside
|
||||
if (sub == null) continue;
|
||||
|
||||
//light and convexhull are both inside the same sub
|
||||
if (sub == ParentSub)
|
||||
{
|
||||
if (NeedsHullCheck)
|
||||
{
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
//light and convexhull are inside different subs
|
||||
else
|
||||
{
|
||||
if (sub.DockedTo.Contains(ParentSub) && !NeedsHullCheck) continue;
|
||||
|
||||
lightPos -= (sub.Position - ParentSub.Position);
|
||||
|
||||
Rectangle subBorders = sub.Borders;
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//don't draw any shadows if the light doesn't overlap with the borders of the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
//recalculate vertices if the subs have moved > 5 px relative to each other
|
||||
Vector2 diff = ParentSub.WorldPosition - sub.WorldPosition;
|
||||
if (!diffToSub.TryGetValue(sub, out Vector2 prevDiff))
|
||||
{
|
||||
diffToSub.Add(sub, diff);
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
else if (Vector2.DistanceSquared(diff, prevDiff) > 5.0f * 5.0f)
|
||||
{
|
||||
diffToSub[sub] = diff;
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
chList = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//not found -> create one
|
||||
if (chList == null)
|
||||
{
|
||||
chList = new ConvexHullList(sub);
|
||||
hullsInRange.Add(chList);
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
|
||||
foreach (var ch in chList.List)
|
||||
{
|
||||
if (ch.LastVertexChangeTime > lastRecalculationTime && !chList.IsHidden.Contains(ch))
|
||||
{
|
||||
NeedsRecalculation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 lightPos = position;
|
||||
if (ParentSub == null)
|
||||
{
|
||||
//light and the convexhulls are both outside
|
||||
if (sub == null)
|
||||
{
|
||||
if (NeedsHullCheck)
|
||||
{
|
||||
RefreshConvexHullList(chList, lightPos, null);
|
||||
}
|
||||
}
|
||||
//light is outside, convexhulls inside a sub
|
||||
else
|
||||
{
|
||||
lightPos -= sub.Position;
|
||||
|
||||
Rectangle subBorders = sub.Borders;
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//only draw if the light overlaps with the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) { NeedsRecalculation = true; }
|
||||
chList.List.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//light is inside, convexhull outside
|
||||
if (sub == null) { return; }
|
||||
|
||||
//light and convexhull are both inside the same sub
|
||||
if (sub == ParentSub)
|
||||
{
|
||||
if (NeedsHullCheck)
|
||||
{
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
//light and convexhull are inside different subs
|
||||
else
|
||||
{
|
||||
if (sub.DockedTo.Contains(ParentSub) && !NeedsHullCheck) { return; }
|
||||
|
||||
lightPos -= (sub.Position - ParentSub.Position);
|
||||
|
||||
Rectangle subBorders = sub.Borders;
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//don't draw any shadows if the light doesn't overlap with the borders of the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) { NeedsRecalculation = true; }
|
||||
chList.List.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
//recalculate vertices if the subs have moved > 5 px relative to each other
|
||||
Vector2 diff = ParentSub.WorldPosition - sub.WorldPosition;
|
||||
if (!diffToSub.TryGetValue(sub, out Vector2 prevDiff))
|
||||
{
|
||||
diffToSub.Add(sub, diff);
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
else if (Vector2.DistanceSquared(diff, prevDiff) > 5.0f * 5.0f)
|
||||
{
|
||||
diffToSub[sub] = diff;
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Vector2> FindRaycastHits()
|
||||
|
||||
@@ -75,10 +75,12 @@ namespace Barotrauma
|
||||
if (linkedTo.Contains(entity))
|
||||
{
|
||||
linkedTo.Remove(entity);
|
||||
entity.linkedTo.Remove(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedTo.Add(entity);
|
||||
if (!entity.linkedTo.Contains(this)) { entity.linkedTo.Add(this); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ namespace Barotrauma
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SubEditorScreen.IsLayerVisible(this)) { return false; }
|
||||
|
||||
return HasBody ? ShowWalls : ShowStructures;
|
||||
}
|
||||
}
|
||||
@@ -244,8 +247,10 @@ namespace Barotrauma
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (prefab.sprite == null) { return; }
|
||||
|
||||
if (editing)
|
||||
{
|
||||
if (!SubEditorScreen.IsLayerVisible(this)) { return; }
|
||||
if (!HasBody && !ShowStructures) { return; }
|
||||
if (HasBody && !ShowWalls) { return; }
|
||||
}
|
||||
@@ -273,6 +278,7 @@ namespace Barotrauma
|
||||
if (prefab.sprite == null) { return; }
|
||||
if (editing)
|
||||
{
|
||||
if (!SubEditorScreen.IsLayerVisible(this)) { return; }
|
||||
if (!HasBody && !ShowStructures) { return; }
|
||||
if (HasBody && !ShowWalls) { return; }
|
||||
}
|
||||
@@ -285,13 +291,11 @@ namespace Barotrauma
|
||||
//color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||
color = spriteColor;
|
||||
|
||||
|
||||
|
||||
Vector2 rectSize = rect.Size.ToVector2();
|
||||
if (BodyWidth > 0.0f) { rectSize.X = BodyWidth; }
|
||||
if (BodyHeight > 0.0f) { rectSize.Y = BodyHeight; }
|
||||
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset;
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset * Scale;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(bodyPos.X, -bodyPos.Y), rectSize.X, rectSize.Y, BodyRotation, Color.White,
|
||||
thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
|
||||
@@ -465,7 +469,8 @@ namespace Barotrauma
|
||||
|
||||
public void UpdateSpriteStates(float deltaTime)
|
||||
{
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
if (Prefab.DecorativeSpriteGroups.Count == 0) { return; }
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
|
||||
{
|
||||
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
|
||||
|
||||
@@ -25,14 +25,11 @@ namespace Barotrauma
|
||||
public readonly bool Stream;
|
||||
public readonly bool IgnoreMuffling;
|
||||
|
||||
|
||||
public string Filename
|
||||
{
|
||||
get { return Sound?.Filename; }
|
||||
}
|
||||
public readonly string Filename;
|
||||
|
||||
public RoundSound(XElement element, Sound sound)
|
||||
{
|
||||
Filename = sound?.Filename;
|
||||
Sound = sound;
|
||||
Stream = sound.Stream;
|
||||
Range = element.GetAttributeFloat("range", 1000.0f);
|
||||
|
||||
@@ -146,6 +146,7 @@ namespace Barotrauma
|
||||
|
||||
private bool IsHidden()
|
||||
{
|
||||
if (!SubEditorScreen.IsLayerVisible(this)) { return false; }
|
||||
if (spawnType == SpawnType.Path)
|
||||
{
|
||||
return (!GameMain.DebugDraw && !ShowWayPoints);
|
||||
@@ -294,7 +295,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), TextManager.Get("Spawnpoint"), font: GUI.LargeFont);
|
||||
|
||||
|
||||
var spawnTypeContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
@@ -318,7 +319,10 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
var descText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardDescription"), font: GUI.SmallFont);
|
||||
TextManager.Get("IDCardDescription"), font: GUI.SmallFont)
|
||||
{
|
||||
ToolTip = TextManager.Get("IDCardDescriptionTooltip")
|
||||
};
|
||||
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), descText.RectTransform, Anchor.CenterRight), IdCardDesc)
|
||||
{
|
||||
MaxTextLength = 150,
|
||||
@@ -342,7 +346,10 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
var idCardTagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardTags"), font: GUI.SmallFont);
|
||||
TextManager.Get("IDCardTags"), font: GUI.SmallFont)
|
||||
{
|
||||
ToolTip = TextManager.Get("IDCardTagsTooltip")
|
||||
};
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), idCardTagsText.RectTransform, Anchor.CenterRight), string.Join(", ", idCardTags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
@@ -414,6 +421,6 @@ namespace Barotrauma
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Barotrauma.Networking
|
||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, targetRoom,
|
||||
givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter,
|
||||
orderOption: orderOption,
|
||||
priority: orderMessageInfo.Priority);
|
||||
isNewOrder: orderMessageInfo.IsNewOrder);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
|
||||
@@ -948,6 +948,9 @@ namespace Barotrauma.Networking
|
||||
case ServerPacketHeader.CREW:
|
||||
campaign?.ClientReadCrew(inc);
|
||||
break;
|
||||
case ServerPacketHeader.MEDICAL:
|
||||
campaign?.MedicalClinic?.ClientRead(inc);
|
||||
break;
|
||||
case ServerPacketHeader.READY_CHECK:
|
||||
ReadyCheck.ClientRead(inc);
|
||||
break;
|
||||
@@ -1116,9 +1119,9 @@ namespace Barotrauma.Networking
|
||||
disconnectReason != DisconnectReason.InvalidVersion)
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.HandleDisconnectMessage",
|
||||
GameAnalyticsManager.ErrorSeverity.Debug,
|
||||
"Client received a disconnect message. Reason: " + disconnectReason.ToString());
|
||||
"GameClient.HandleDisconnectMessage",
|
||||
GameAnalyticsManager.ErrorSeverity.Debug,
|
||||
"Client received a disconnect message. Reason: " + disconnectReason.ToString());
|
||||
}
|
||||
|
||||
if (disconnectReason == DisconnectReason.ServerFull)
|
||||
@@ -1271,7 +1274,15 @@ namespace Barotrauma.Networking
|
||||
private void ReadAchievement(IReadMessage inc)
|
||||
{
|
||||
string achievementIdentifier = inc.ReadString();
|
||||
SteamAchievementManager.UnlockAchievement(achievementIdentifier);
|
||||
int amount = inc.ReadInt32();
|
||||
if (amount == 0)
|
||||
{
|
||||
SteamAchievementManager.UnlockAchievement(achievementIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamAchievementManager.IncrementStat(achievementIdentifier, amount);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadTraitorMessage(IReadMessage inc)
|
||||
@@ -1471,7 +1482,7 @@ namespace Barotrauma.Networking
|
||||
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
||||
serverSettings.AllowLinkingWifiToChat = inc.ReadBoolean();
|
||||
GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
bool usingShuttle = GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
GameMain.LightManager.LosMode = (LosMode)inc.ReadByte();
|
||||
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
GameMain.LightManager.LightingEnabled = true;
|
||||
@@ -1483,6 +1494,8 @@ namespace Barotrauma.Networking
|
||||
Task loadTask = null;
|
||||
var roundSummary = (GUIMessageBox.MessageBoxes.Find(c => c?.UserData is RoundSummary)?.UserData) as RoundSummary;
|
||||
|
||||
bool isOutpost = false;
|
||||
|
||||
if (gameMode != GameModePreset.MultiPlayerCampaign)
|
||||
{
|
||||
string levelSeed = inc.ReadString();
|
||||
@@ -1621,6 +1634,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
GameMain.GameSession.StartRound(levelData, mirrorLevel);
|
||||
}
|
||||
isOutpost = levelData.Type == LevelData.LevelType.Outpost;
|
||||
}
|
||||
|
||||
if (GameMain.Client?.ServerSettings?.Voting != null)
|
||||
@@ -1740,8 +1754,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (respawnAllowed)
|
||||
{
|
||||
bool isOutpost = GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && Level.Loaded?.Type == LevelData.LevelType.Outpost;
|
||||
respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle && !isOutpost ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||
respawnManager = new RespawnManager(this, usingShuttle && !isOutpost ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||
}
|
||||
|
||||
gameStarted = true;
|
||||
@@ -1872,7 +1885,7 @@ namespace Barotrauma.Networking
|
||||
if (int.TryParse(ownedIndexes[i], out int index))
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "owned"))
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.Add(sub);
|
||||
}
|
||||
@@ -1888,7 +1901,7 @@ namespace Barotrauma.Networking
|
||||
if (int.TryParse(ownedIndexes[i], out index))
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "owned"))
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
|
||||
{
|
||||
GameMain.NetLobbyScreen.ServerOwnedSubmarines.Add(sub);
|
||||
}
|
||||
@@ -2090,13 +2103,6 @@ namespace Barotrauma.Networking
|
||||
string selectShuttleName = inc.ReadString();
|
||||
string selectShuttleHash = inc.ReadString();
|
||||
|
||||
UInt16 campaignSubmarineIndexCount = inc.ReadUInt16();
|
||||
List<int> campaignSubIndices = new List<int>();
|
||||
for (int i = 0; i< campaignSubmarineIndexCount; i++)
|
||||
{
|
||||
campaignSubIndices.Add(inc.ReadUInt16());
|
||||
}
|
||||
|
||||
bool allowSubVoting = inc.ReadBoolean();
|
||||
bool allowModeVoting = inc.ReadBoolean();
|
||||
|
||||
@@ -2157,16 +2163,11 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.Client.IsServerOwner) RequestSelectMode(modeIndex);
|
||||
}
|
||||
|
||||
if (campaignSubIndices != null)
|
||||
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = new List<SubmarineInfo>();
|
||||
foreach (UInt16 campaignSubIndex in campaignSubIndices)
|
||||
foreach (SubmarineInfo sub in ServerSubmarines.Where(s => !ServerSettings.HiddenSubs.Contains(s.Name)))
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[campaignSubIndex];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "campaign"))
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(sub);
|
||||
}
|
||||
GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Campaign);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2599,7 +2600,6 @@ namespace Barotrauma.Networking
|
||||
NetLobbyScreen.FailedSubInfo failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.Hash);
|
||||
if (failedCampaignSub != default)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(newSub);
|
||||
GameMain.NetLobbyScreen.FailedCampaignSubs.Remove(failedCampaignSub);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Barotrauma.Networking
|
||||
if (!isActive) { return; }
|
||||
if (steamId != hostSteamId) { return; }
|
||||
Close($"SteamP2P connection failed: {error}");
|
||||
OnDisconnectMessageReceived?.Invoke($"SteamP2P connection failed: {error}");
|
||||
OnDisconnectMessageReceived?.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P connection failed: {error}");
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength)
|
||||
@@ -167,14 +167,14 @@ namespace Barotrauma.Networking
|
||||
if (state == null)
|
||||
{
|
||||
Close("SteamP2P connection could not be established");
|
||||
OnDisconnectMessageReceived?.Invoke("SteamP2P connection could not be established");
|
||||
OnDisconnectMessageReceived?.Invoke(DisconnectReason.SteamP2PError.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state?.P2PSessionError != Steamworks.P2PSessionError.None)
|
||||
{
|
||||
Close($"SteamP2P error code: {state?.P2PSessionError}");
|
||||
OnDisconnectMessageReceived?.Invoke($"SteamP2P error code: {state?.P2PSessionError}");
|
||||
OnDisconnectMessageReceived?.Invoke($"{DisconnectReason.SteamP2PError}/SteamP2P error code: {state?.P2PSessionError}");
|
||||
}
|
||||
}
|
||||
connectionStatusTimer = 1.0f;
|
||||
@@ -210,7 +210,7 @@ namespace Barotrauma.Networking
|
||||
if (timeout < 0.0)
|
||||
{
|
||||
Close("Timed out");
|
||||
OnDisconnectMessageReceived?.Invoke("");
|
||||
OnDisconnectMessageReceived?.Invoke(DisconnectReason.SteamP2PTimeOut.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -349,13 +349,19 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write((byte)PacketHeader.IsDisconnectMessage);
|
||||
outMsg.Write(msg ?? "Disconnected");
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
sentBytes += outMsg.LengthBytes;
|
||||
try
|
||||
{
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
sentBytes += outMsg.LengthBytes;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to send a disconnect message to the server using SteamP2P.", e);
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
|
||||
Steamworks.SteamNetworking.CloseP2PSessionWithUser(hostSteamId);
|
||||
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
|
||||
@@ -81,16 +81,15 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool ContentPackagesMatch()
|
||||
{
|
||||
var myContentPackages = ContentPackage.AllPackages;
|
||||
//make sure we have all the packages the server requires
|
||||
if (ContentPackageHashes.Count != ContentPackageWorkshopIds.Count) { return false; }
|
||||
for (int i = 0; i < ContentPackageWorkshopIds.Count; i++)
|
||||
{
|
||||
string hash = ContentPackageHashes[i];
|
||||
UInt64 id = ContentPackageWorkshopIds[i];
|
||||
if (!myContentPackages.Any(myPackage => myPackage.MD5hash.Hash == hash))
|
||||
if (!GameMain.ServerListScreen.ContentPackagesByHash.ContainsKey(hash))
|
||||
{
|
||||
if (myContentPackages.Any(p => p.SteamWorkshopId == id)) { return false; }
|
||||
if (GameMain.ServerListScreen.ContentPackagesByWorkshopId.ContainsKey(id)) { return false; }
|
||||
if (id == 0) { return false; }
|
||||
}
|
||||
}
|
||||
@@ -98,12 +97,6 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ContentPackagesMatch(IEnumerable<string> myContentPackageHashes)
|
||||
{
|
||||
HashSet<string> contentPackageHashes = new HashSet<string>(ContentPackageHashes);
|
||||
return contentPackageHashes.SetEquals(myContentPackageHashes);
|
||||
}
|
||||
|
||||
public void CreatePreviewWindow(GUIFrame frame)
|
||||
{
|
||||
if (frame == null) { return; }
|
||||
@@ -428,7 +421,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
var rules = ((Task<Dictionary<string, string>>)t).Result;
|
||||
t.TryGetResult(out Dictionary<string, string> rules);
|
||||
SteamManager.AssignServerRulesToServerInfo(rules, this);
|
||||
|
||||
onServerRulesReceived(this);
|
||||
|
||||
@@ -94,10 +94,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
{
|
||||
int count = incMsg.ReadUInt16();
|
||||
for (int i = 0; i < count; i++)
|
||||
while (true)
|
||||
{
|
||||
UInt32 key = incMsg.ReadUInt32();
|
||||
if (key == 0) { break; }
|
||||
if (netProperties.ContainsKey(key))
|
||||
{
|
||||
bool changedLocally = netProperties[key].ChangedLocally;
|
||||
@@ -153,8 +153,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ReadExtraCargo(incMsg);
|
||||
}
|
||||
|
||||
ReadHiddenSubs(incMsg);
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.HiddenSubs))
|
||||
{
|
||||
ReadHiddenSubs(incMsg);
|
||||
}
|
||||
GameMain.NetLobbyScreen.UpdateSubVisibility();
|
||||
|
||||
bool isAdmin = incMsg.ReadBoolean();
|
||||
|
||||
@@ -143,8 +143,7 @@ namespace Barotrauma.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
currentLobby = ((Task<Steamworks.Data.Lobby?>)lobby).Result;
|
||||
|
||||
lobby.TryGetResult(out currentLobby);
|
||||
if (currentLobby == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to create Steam lobby: returned lobby was null");
|
||||
@@ -250,7 +249,7 @@ namespace Barotrauma.Steam
|
||||
TaskPool.Add("JoinLobbyAsync", Steamworks.SteamMatchmaking.JoinLobbyAsync(lobbyID),
|
||||
(lobby) =>
|
||||
{
|
||||
currentLobby = ((Task<Steamworks.Data.Lobby?>)lobby).Result;
|
||||
lobby.TryGetResult(out currentLobby);
|
||||
lobbyState = LobbyState.Joined;
|
||||
lobbyID = (currentLobby?.Id).Value;
|
||||
if (joinServer)
|
||||
@@ -293,10 +292,11 @@ namespace Barotrauma.Steam
|
||||
taskDone();
|
||||
return;
|
||||
}
|
||||
var lobbies = ((Task<List<Steamworks.Data.Lobby>>)t).Result;
|
||||
if (lobbies != null)
|
||||
t.TryGetResult(out List<Steamworks.Data.Lobby> lobbies);
|
||||
IEnumerable<CoroutineStatus> lobbyAddCoroutine()
|
||||
{
|
||||
foreach (var lobby in lobbies)
|
||||
int i = 0;
|
||||
foreach (var lobby in lobbies ?? Enumerable.Empty<Steamworks.Data.Lobby>())
|
||||
{
|
||||
if (string.IsNullOrEmpty(lobby.GetData("name"))) { continue; }
|
||||
|
||||
@@ -312,9 +312,13 @@ namespace Barotrauma.Steam
|
||||
AssignLobbyDataToServerInfo(lobby, serverInfo);
|
||||
|
||||
addToServerList(serverInfo);
|
||||
i++;
|
||||
if (i >= 16) { yield return CoroutineStatus.Running; i = 0; }
|
||||
}
|
||||
taskDone();
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
taskDone();
|
||||
CoroutineManager.StartCoroutine(lobbyAddCoroutine());
|
||||
});
|
||||
|
||||
Steamworks.ServerList.Internet serverQuery = new Steamworks.ServerList.Internet();
|
||||
@@ -344,13 +348,10 @@ namespace Barotrauma.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
var rules = ((Task<Dictionary<string, string>>)t).Result;
|
||||
t.TryGetResult(out Dictionary<string, string> rules);
|
||||
AssignServerRulesToServerInfo(rules, serverInfo);
|
||||
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
addToServerList(serverInfo);
|
||||
});
|
||||
addToServerList(serverInfo);
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -618,7 +619,10 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) { query = query.WithTags(requireTags); }
|
||||
|
||||
TaskPool.Add("GetSubscribedWorkshopItems", GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(((Task<List<Steamworks.Ugc.Item>>)task).Result); });
|
||||
TaskPool.Add("GetSubscribedWorkshopItems", GetWorkshopItemsAsync(query), (task) =>
|
||||
{
|
||||
task.TryGetResult(out List<Steamworks.Ugc.Item> result); onItemsFound?.Invoke(result);
|
||||
});
|
||||
}
|
||||
|
||||
public static void GetPopularWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, int amount, List<string> requireTags = null)
|
||||
@@ -632,7 +636,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
TaskPool.Add("GetPopularWorkshopItems", GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) =>
|
||||
{
|
||||
var entries = ((Task<List<Steamworks.Ugc.Item>>)task).Result;
|
||||
task.TryGetResult(out List<Steamworks.Ugc.Item> entries);
|
||||
|
||||
//count the number of each unique tag
|
||||
foreach (var item in entries)
|
||||
@@ -677,7 +681,10 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
TaskPool.Add("GetPublishedWorkshopItems", GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(((Task<List<Steamworks.Ugc.Item>>)task).Result); });
|
||||
TaskPool.Add("GetPublishedWorkshopItems", GetWorkshopItemsAsync(query), (task) =>
|
||||
{
|
||||
task.TryGetResult(out List<Steamworks.Ugc.Item> result); onItemsFound?.Invoke(result);
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly HashSet<ulong> pendingWorkshopSubscriptions = new HashSet<ulong>();
|
||||
@@ -724,7 +731,7 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = ((Task<Steamworks.Ugc.Item?>)t).Result;
|
||||
t.TryGetResult(out Steamworks.Ugc.Item? item);
|
||||
if (item != null)
|
||||
{
|
||||
if (item?.IsInstalled ?? false)
|
||||
@@ -1077,7 +1084,7 @@ namespace Barotrauma.Steam
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
|
||||
return;
|
||||
}
|
||||
string errorMsg = ((Task<string>)task).Result;
|
||||
task.TryGetResult(out string errorMsg);
|
||||
if (!string.IsNullOrWhiteSpace(errorMsg))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to copy \"{item.Title}\": {errorMsg}");
|
||||
|
||||
@@ -246,6 +246,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (string saveFile in saveFiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(saveFile)) { continue; }
|
||||
|
||||
string fileName = saveFile;
|
||||
string subName = "";
|
||||
string saveTime = "";
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace Barotrauma
|
||||
|
||||
public UpgradeStore UpgradeStore { get; set; }
|
||||
|
||||
public MedicalClinicUI MedicalClinic { get; set; }
|
||||
|
||||
public CampaignUI(CampaignMode campaign, GUIComponent container)
|
||||
{
|
||||
Campaign = campaign;
|
||||
@@ -270,6 +272,9 @@ namespace Barotrauma
|
||||
// Submarine buying tab
|
||||
tabs[(int)CampaignMode.InteractionType.PurchaseSub] = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform, Anchor.TopLeft), color: Color.Black * 0.9f);
|
||||
|
||||
tabs[(int)CampaignMode.InteractionType.MedicalClinic] = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
|
||||
MedicalClinic = new MedicalClinicUI(Campaign.MedicalClinic, GetTabContainer(CampaignMode.InteractionType.MedicalClinic));
|
||||
|
||||
// mission info -------------------------------------------------------------------------
|
||||
|
||||
locationInfoPanel = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.75f), GetTabContainer(CampaignMode.InteractionType.Map).RectTransform, Anchor.CenterRight)
|
||||
@@ -355,6 +360,10 @@ namespace Barotrauma
|
||||
case CampaignMode.InteractionType.Store:
|
||||
Store?.Update(deltaTime);
|
||||
break;
|
||||
|
||||
case CampaignMode.InteractionType.MedicalClinic:
|
||||
MedicalClinic?.Update(deltaTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,16 +247,6 @@ namespace Barotrauma
|
||||
return msgBox;
|
||||
}
|
||||
|
||||
private void NotifyPrompt(string header, string body)
|
||||
{
|
||||
GUIMessageBox msgBox = new GUIMessageBox(header, body, new[] { TextManager.Get("Ok") }, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private bool SaveProjectToFile(GUIButton button, object o)
|
||||
{
|
||||
string directory = Path.GetFullPath("EventProjects");
|
||||
@@ -315,7 +305,7 @@ namespace Barotrauma
|
||||
CreateNodes(prefab.ConfigElement, ref hadNodes);
|
||||
if (!hadNodes)
|
||||
{
|
||||
NotifyPrompt(TextManager.Get("EventEditor.RandomGenerationHeader"), TextManager.Get("EventEditor.RandomGenerationBody"));
|
||||
GUI.NotifyPrompt(TextManager.Get("EventEditor.RandomGenerationHeader"), TextManager.Get("EventEditor.RandomGenerationBody"));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -221,7 +221,6 @@ namespace Barotrauma
|
||||
public SubmarineInfo SelectedShuttle => ShuttleList.SelectedData as SubmarineInfo;
|
||||
|
||||
public MultiPlayerCampaignSetupUI CampaignSetupUI;
|
||||
public List<SubmarineInfo> CampaignSubmarines = new List<SubmarineInfo>();
|
||||
|
||||
// Passed onto the gamesession when created
|
||||
public List<SubmarineInfo> ServerOwnedSubmarines = new List<SubmarineInfo>();
|
||||
@@ -611,6 +610,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null) { return true; }
|
||||
GameMain.Client.RequestStartRound();
|
||||
CoroutineManager.StartCoroutine(WaitForStartRound(StartButton), "WaitForStartRound");
|
||||
return true;
|
||||
@@ -628,7 +628,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnSelected = (tickBox) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, autoRestart: tickBox.Selected);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, autoRestart: tickBox.Selected);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -655,6 +655,7 @@ namespace Barotrauma
|
||||
};
|
||||
ServerName.OnDeselected += (textBox, key) =>
|
||||
{
|
||||
if (GameMain.Client == null) { return; }
|
||||
if (!textBox.Readonly)
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Name);
|
||||
@@ -669,6 +670,7 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("addtofavorites"),
|
||||
OnSelected = (tickbox) =>
|
||||
{
|
||||
if (GameMain.Client == null) { return true; }
|
||||
ServerInfo info = GameMain.Client.ServerSettings.GetServerListInfo();
|
||||
if (tickbox.Selected)
|
||||
{
|
||||
@@ -766,6 +768,7 @@ namespace Barotrauma
|
||||
};
|
||||
ServerMessage.OnDeselected += (textBox, key) =>
|
||||
{
|
||||
if (GameMain.Client == null) { return; }
|
||||
if (!textBox.Readonly)
|
||||
{
|
||||
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Message);
|
||||
@@ -849,7 +852,7 @@ namespace Barotrauma
|
||||
Selected = true,
|
||||
OnSelected = (GUITickBox box) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, useRespawnShuttle: box.Selected);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, useRespawnShuttle: box.Selected);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -868,7 +871,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnSelected = (component, obj) =>
|
||||
{
|
||||
GameMain.Client.RequestSelectSub(component.Parent.GetChildIndex(component), isShuttle: true);
|
||||
GameMain.Client?.RequestSelectSub(component.Parent.GetChildIndex(component), isShuttle: true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -970,7 +973,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (_, __) =>
|
||||
{
|
||||
GameMain.Client.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
|
||||
GameMain.Client?.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1026,7 +1029,7 @@ namespace Barotrauma
|
||||
{
|
||||
int missionTypeOr = tickbox.Selected ? (int)tickbox.UserData : (int)MissionType.None;
|
||||
int missionTypeAnd = (int)MissionType.All & (!tickbox.Selected ? (~(int)tickbox.UserData) : (int)MissionType.All);
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, (int)missionTypeOr, (int)missionTypeAnd);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, (int)missionTypeOr, (int)missionTypeAnd);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1059,7 +1062,7 @@ namespace Barotrauma
|
||||
SeedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedLabel.RectTransform, Anchor.CenterRight));
|
||||
SeedBox.OnDeselected += (textBox, key) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.LevelSeed);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.LevelSeed);
|
||||
};
|
||||
clientDisabledElements.Add(SeedBox);
|
||||
LevelSeed = ToolBox.RandomSeed(8);
|
||||
@@ -1080,7 +1083,7 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("leveldifficultyexplanation"),
|
||||
OnReleased = (scrollbar, value) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, levelDifficulty: scrollbar.BarScrollValue);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, levelDifficulty: scrollbar.BarScrollValue);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1112,8 +1115,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, traitorSetting: -1);
|
||||
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, traitorSetting: -1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1124,8 +1126,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, traitorSetting: 1);
|
||||
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, traitorSetting: 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1143,7 +1144,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botCount: -1);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botCount: -1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1153,7 +1154,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botCount: 1);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botCount: 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1169,7 +1170,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botSpawnMode: -1);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botSpawnMode: -1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1179,7 +1180,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botSpawnMode: 1);
|
||||
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, botSpawnMode: 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -3576,7 +3577,13 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckIfCampaignSubMatches(SubmarineInfo serverSubmarine, string deliveryData)
|
||||
public enum SubmarineDeliveryData
|
||||
{
|
||||
Owned,
|
||||
Campaign
|
||||
}
|
||||
|
||||
public bool CheckIfCampaignSubMatches(SubmarineInfo serverSubmarine, SubmarineDeliveryData deliveryData)
|
||||
{
|
||||
if (GameMain.Client == null) return false;
|
||||
|
||||
@@ -3630,11 +3637,11 @@ namespace Barotrauma
|
||||
{
|
||||
FailedSubInfo fileInfo = (FailedSubInfo)userdata;
|
||||
|
||||
if (deliveryData == "owned") //owned!!!!
|
||||
if (deliveryData == SubmarineDeliveryData.Owned)
|
||||
{
|
||||
FailedOwnedSubs.Add(fileInfo);
|
||||
}
|
||||
else if (deliveryData == "campaign")
|
||||
else if (deliveryData == SubmarineDeliveryData.Campaign)
|
||||
{
|
||||
FailedCampaignSubs.Add(fileInfo);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
@@ -21,6 +22,11 @@ namespace Barotrauma
|
||||
//how often the client is allowed to refresh servers
|
||||
private readonly TimeSpan AllowedRefreshInterval = new TimeSpan(0, 0, 3);
|
||||
|
||||
public ImmutableDictionary<UInt64, ContentPackage> ContentPackagesByWorkshopId { get; private set; }
|
||||
= ImmutableDictionary<UInt64, ContentPackage>.Empty;
|
||||
public ImmutableDictionary<string, ContentPackage> ContentPackagesByHash { get; private set; }
|
||||
= ImmutableDictionary<string, ContentPackage>.Empty;
|
||||
|
||||
private GUIFrame menu;
|
||||
|
||||
private GUIListBox serverList;
|
||||
@@ -1011,6 +1017,17 @@ namespace Barotrauma
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
|
||||
ContentPackagesByWorkshopId = ContentPackage.AllPackages
|
||||
.Select(p => new KeyValuePair<UInt64, ContentPackage>(p.SteamWorkshopId, p))
|
||||
.Where(p => p.Key != 0)
|
||||
.GroupBy(x => x.Key).Select(g => g.First())
|
||||
.ToImmutableDictionary();
|
||||
ContentPackagesByHash = ContentPackage.AllPackages
|
||||
.Select(p => new KeyValuePair<string, ContentPackage>(p.MD5hash.Hash, p))
|
||||
.GroupBy(x => x.Key).Select(g => g.First())
|
||||
.ToImmutableDictionary();
|
||||
|
||||
SelectedTab = ServerListTab.All;
|
||||
LoadServerFilters(GameMain.Config.ServerFilterElement);
|
||||
if (GameSettings.ShowOffensiveServerPrompt)
|
||||
@@ -1039,6 +1056,8 @@ namespace Barotrauma
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
ContentPackagesByWorkshopId = ImmutableDictionary<UInt64, ContentPackage>.Empty;
|
||||
ContentPackagesByHash = ImmutableDictionary<string, ContentPackage>.Empty;
|
||||
base.Deselect();
|
||||
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
@@ -1491,7 +1510,7 @@ namespace Barotrauma
|
||||
}
|
||||
TaskPool.Add($"Get{avatarSize}AvatarAsync", avatarFunc(friend.Id), (task) =>
|
||||
{
|
||||
Steamworks.Data.Image? img = ((Task<Steamworks.Data.Image?>)task).Result;
|
||||
if (!task.TryGetResult(out Steamworks.Data.Image? img)) { return; }
|
||||
if (!img.HasValue) { return; }
|
||||
|
||||
var avatarImage = img.Value;
|
||||
@@ -2203,7 +2222,7 @@ namespace Barotrauma
|
||||
TaskPool.PrintTaskExceptions(t, $"Failed to retrieve Workshop item info (ID {entry.Id})");
|
||||
return;
|
||||
}
|
||||
Steamworks.Ugc.Item? item = ((Task<Steamworks.Ugc.Item?>)t).Result;
|
||||
t.TryGetResult(out Steamworks.Ugc.Item? item);
|
||||
|
||||
if (!item.HasValue)
|
||||
{
|
||||
@@ -2313,7 +2332,7 @@ namespace Barotrauma
|
||||
{
|
||||
var info = obj.Item1;
|
||||
var text = obj.Item2;
|
||||
info.Ping = ((Task<int>)rtt).Result; info.PingChecked = true;
|
||||
rtt.TryGetResult(out info.Ping); info.PingChecked = true;
|
||||
text.TextColor = GetPingTextColor(info.Ping);
|
||||
text.Text = info.Ping > -1 ? info.Ping.ToString() : "?";
|
||||
lock (activePings)
|
||||
|
||||
@@ -854,7 +854,7 @@ namespace Barotrauma
|
||||
(var it, var lb) = tuple;
|
||||
if (lb.Content.FindChild(item)?.GetChildByUserData("previewimage") is GUIImage previewImage)
|
||||
{
|
||||
previewImage.Sprite = ((Task<Sprite>)task).Result;
|
||||
if (task.TryGetResult(out Sprite sprite)) { previewImage.Sprite = sprite; }
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -99,6 +99,10 @@ namespace Barotrauma
|
||||
private GUIFrame previouslyUsedPanel;
|
||||
private GUIListBox previouslyUsedList;
|
||||
|
||||
private GUIButton visibilityButton;
|
||||
private GUIFrame layerPanel;
|
||||
private GUIListBox layerList;
|
||||
|
||||
private GUIFrame undoBufferPanel;
|
||||
private GUIFrame undoBufferDisclaimer;
|
||||
private GUIListBox undoBufferList;
|
||||
@@ -234,6 +238,8 @@ namespace Barotrauma
|
||||
|
||||
public bool WiringMode => mode == Mode.Wiring;
|
||||
|
||||
public static readonly Dictionary<string, bool> Layers = new Dictionary<string, bool>();
|
||||
|
||||
public SubEditorScreen()
|
||||
{
|
||||
cam = new Camera
|
||||
@@ -320,19 +326,34 @@ namespace Barotrauma
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
|
||||
|
||||
var visibilityButton = new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "SetupVisibilityButton")
|
||||
visibilityButton = new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "SetupVisibilityButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("SubEditorVisibilityButton") + '\n' + TextManager.Get("SubEditorVisibilityToolTip"),
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
previouslyUsedPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
layerPanel.Visible = false;
|
||||
showEntitiesPanel.Visible = !showEntitiesPanel.Visible;
|
||||
showEntitiesPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "EditorLayerButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("editor.layer.button") + '\n' + TextManager.Get("editor.layer.tooltip"),
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
previouslyUsedPanel.Visible = false;
|
||||
showEntitiesPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
layerPanel.Visible = !layerPanel.Visible;
|
||||
layerPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var previouslyUsedButton = new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "RecentlyUsedButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("PreviouslyUsedLabel"),
|
||||
@@ -340,6 +361,7 @@ namespace Barotrauma
|
||||
{
|
||||
showEntitiesPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
layerPanel.Visible = false;
|
||||
previouslyUsedPanel.Visible = !previouslyUsedPanel.Visible;
|
||||
previouslyUsedPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
@@ -353,6 +375,7 @@ namespace Barotrauma
|
||||
{
|
||||
showEntitiesPanel.Visible = false;
|
||||
previouslyUsedPanel.Visible = false;
|
||||
layerPanel.Visible = false;
|
||||
undoBufferPanel.Visible = !undoBufferPanel.Visible;
|
||||
undoBufferPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
@@ -484,14 +507,81 @@ namespace Barotrauma
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
layerPanel = new GUIFrame(new RectTransform(new Vector2(0.175f, 0.4f), GUI.Canvas))
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
|
||||
GUILayoutGroup layerGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f), layerPanel.RectTransform, anchor: Anchor.Center));
|
||||
|
||||
layerList = new GUIListBox(new RectTransform(new Vector2(1f, 0.8f), layerGroup.RectTransform))
|
||||
{
|
||||
ScrollBarVisible = true,
|
||||
AutoHideScrollBar = false,
|
||||
OnSelected = (component, o) =>
|
||||
{
|
||||
if (!(o is string layer)) { return false; }
|
||||
|
||||
MapEntity.SelectedList.Clear();
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList.Where(me => !me.Removed && me.Layer == layer))
|
||||
{
|
||||
if (entity.IsSelected) { continue; }
|
||||
|
||||
MapEntity.SelectedList.Add(entity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
GUILayoutGroup layerButtonGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), layerGroup.RectTransform));
|
||||
|
||||
GUILayoutGroup layerButtonTopGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), layerButtonGroup.RectTransform), isHorizontal: true);
|
||||
|
||||
GUIButton layerAddButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), layerButtonTopGroup.RectTransform), text: TextManager.Get("editor.layer.newlayer"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
CreateNewLayer(null, MapEntity.SelectedList.ToList());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
GUIButton layerDeleteButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), layerButtonTopGroup.RectTransform), text: TextManager.Get("editor.layer.deletelayer"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
if (layerList.SelectedData is string layer)
|
||||
{
|
||||
RenameLayer(layer, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
GUIButton layerRenameButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), layerButtonGroup.RectTransform), text: TextManager.Get("editor.layer.renamelayer"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
if (layerList.SelectedData is string layer)
|
||||
{
|
||||
GUI.PromptTextInput(TextManager.Get("editor.layer.renamelayer"), layer, newName =>
|
||||
{
|
||||
RenameLayer(layer, newName);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Vector2 subPanelSize = new Vector2(0.925f, 0.9f);
|
||||
|
||||
undoBufferPanel = new GUIFrame(new RectTransform(new Vector2(0.15f, 0.2f), GUI.Canvas) { MinSize = new Point(200, 200) })
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
|
||||
Vector2 undoSize = new Vector2(0.925f, 0.9f);
|
||||
|
||||
undoBufferList = new GUIListBox(new RectTransform(undoSize, undoBufferPanel.RectTransform, Anchor.Center))
|
||||
undoBufferList = new GUIListBox(new RectTransform(subPanelSize, undoBufferPanel.RectTransform, Anchor.Center))
|
||||
{
|
||||
ScrollBarVisible = true,
|
||||
OnSelected = (_, userData) =>
|
||||
@@ -522,7 +612,7 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
undoBufferDisclaimer = new GUIFrame(new RectTransform(undoSize, undoBufferPanel.RectTransform, Anchor.Center), style: null)
|
||||
undoBufferDisclaimer = new GUIFrame(new RectTransform(subPanelSize, undoBufferPanel.RectTransform, Anchor.Center), style: null)
|
||||
{
|
||||
Color = Color.Black,
|
||||
Visible = false
|
||||
@@ -1354,7 +1444,7 @@ namespace Barotrauma
|
||||
|
||||
TimeSpan timeInEditor = DateTime.Now - editorSelectedTime;
|
||||
#if USE_STEAM
|
||||
Steam.SteamManager.IncrementStat("hoursineditor", (float)timeInEditor.TotalHours);
|
||||
SteamAchievementManager.IncrementStat("hoursineditor", (float)timeInEditor.TotalHours);
|
||||
#endif
|
||||
|
||||
GUI.ForceMouseOn(null);
|
||||
@@ -1400,6 +1490,7 @@ namespace Barotrauma
|
||||
});
|
||||
|
||||
ClearFilter();
|
||||
ClearLayers();
|
||||
}
|
||||
|
||||
private void CreateDummyCharacter()
|
||||
@@ -1752,11 +1843,11 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError($"Saving the preview image of the submarine \"{Submarine.MainSub.Info.Name}\" failed.", e);
|
||||
savePreviewImage = false;
|
||||
}
|
||||
Submarine.MainSub.SaveAs(savePath, savePreviewImage ? imgStream : null);
|
||||
Submarine.MainSub.TrySaveAs(savePath, savePreviewImage ? imgStream : null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Submarine.MainSub.SaveAs(savePath);
|
||||
Submarine.MainSub.TrySaveAs(savePath);
|
||||
}
|
||||
Barotrauma.IO.Validation.SkipValidationInDebugBuilds = false;
|
||||
|
||||
@@ -2890,6 +2981,8 @@ namespace Barotrauma
|
||||
};
|
||||
adjustLightsPrompt.Buttons[1].OnClicked += adjustLightsPrompt.Close;
|
||||
}
|
||||
|
||||
ReconstructLayers();
|
||||
}
|
||||
|
||||
private void TryDeleteSub(SubmarineInfo sub)
|
||||
@@ -3075,6 +3168,8 @@ namespace Barotrauma
|
||||
if (container == null || container.DrawInventory) { target = item; }
|
||||
}
|
||||
|
||||
bool hasTargets = targets.Count > 0;
|
||||
|
||||
// Holding shift brings up special context menu options
|
||||
if (PlayerInput.IsShiftDown())
|
||||
{
|
||||
@@ -3083,7 +3178,7 @@ namespace Barotrauma
|
||||
new ContextMenuOption("SubEditor.ToggleTransparency", isEnabled: true, onSelected: () => TransparentWiringMode = !TransparentWiringMode),
|
||||
new ContextMenuOption("SubEditor.ToggleGrid", isEnabled: true, onSelected: () => ShouldDrawGrid = !ShouldDrawGrid),
|
||||
new ContextMenuOption("SubEditor.PasteAssembly", isEnabled: true, () => PasteAssembly()),
|
||||
new ContextMenuOption("Editor.SelectSame", isEnabled: targets.Count > 0, onSelected: delegate
|
||||
new ContextMenuOption("Editor.SelectSame", isEnabled: hasTargets, onSelected: delegate
|
||||
{
|
||||
bool doorGapSelected = targets.Any(t => t is Gap gap && gap.ConnectedDoor != null);
|
||||
foreach (MapEntity match in MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab?.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e)))
|
||||
@@ -3115,12 +3210,44 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
List<ContextMenuOption> availableLayerOptions = new List<ContextMenuOption>
|
||||
{
|
||||
new ContextMenuOption("editor.layer.nolayer", true, onSelected: () => { MoveToLayer(null, targets); })
|
||||
};
|
||||
|
||||
availableLayerOptions.AddRange(Layers.Select(layer => new ContextMenuOption(layer.Key, true, onSelected: () => { MoveToLayer(layer.Key, targets); })));
|
||||
|
||||
ContextMenuOption[] layerOptions =
|
||||
{
|
||||
new ContextMenuOption("editor.layer.movetolayer", isEnabled: hasTargets, availableLayerOptions.ToArray()),
|
||||
new ContextMenuOption("editor.layer.createlayer", isEnabled: hasTargets, onSelected: () => { CreateNewLayer(null, targets); }),
|
||||
new ContextMenuOption("editor.layer.selectall", isEnabled: hasTargets, onSelected: () =>
|
||||
{
|
||||
foreach (MapEntity match in MapEntity.mapEntityList.Where(e => targets.Any(t => !string.IsNullOrWhiteSpace(t.Layer) && t.Layer == e.Layer && !MapEntity.SelectedList.Contains(e))))
|
||||
{
|
||||
if (MapEntity.SelectedList.Contains(match)) { continue; }
|
||||
MapEntity.SelectedList.Add(match);
|
||||
}
|
||||
}),
|
||||
new ContextMenuOption("editor.layer.openlayermenu", isEnabled: true, onSelected: () =>
|
||||
{
|
||||
if (visibilityButton is null) { return; }
|
||||
previouslyUsedPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
showEntitiesPanel.Visible = false;
|
||||
layerPanel.Visible = !layerPanel.Visible;
|
||||
layerPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(visibilityButton.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
})
|
||||
};
|
||||
|
||||
GUIContextMenu.CreateContextMenu(
|
||||
new ContextMenuOption("label.openlabel", isEnabled: target != null, onSelected: () => OpenItem(target)),
|
||||
new ContextMenuOption("editor.cut", isEnabled: targets.Count > 0, onSelected: () => MapEntity.Cut(targets)),
|
||||
new ContextMenuOption("editor.copytoclipboard", isEnabled: targets.Count > 0, onSelected: () => MapEntity.Copy(targets)),
|
||||
new ContextMenuOption("editor.paste", isEnabled: MapEntity.CopiedList.Any(), onSelected: () => MapEntity.Paste(cam.ScreenToWorld(PlayerInput.MousePosition))),
|
||||
new ContextMenuOption("delete", isEnabled: targets.Count > 0, onSelected: delegate
|
||||
new ContextMenuOption("label.openlabel", isEnabled: target != null, onSelected: () => OpenItem(target)),
|
||||
new ContextMenuOption("editor.layer", isEnabled: hasTargets, layerOptions),
|
||||
new ContextMenuOption("editor.cut", isEnabled: hasTargets, onSelected: () => MapEntity.Cut(targets)),
|
||||
new ContextMenuOption("editor.copytoclipboard", isEnabled: hasTargets, onSelected: () => MapEntity.Copy(targets)),
|
||||
new ContextMenuOption("editor.paste", isEnabled: MapEntity.CopiedList.Any(), onSelected: () => MapEntity.Paste(cam.ScreenToWorld(PlayerInput.MousePosition))),
|
||||
new ContextMenuOption("delete", isEnabled: hasTargets, onSelected: delegate
|
||||
{
|
||||
StoreCommand(new AddOrDeleteCommand(targets, true));
|
||||
foreach (var me in targets)
|
||||
@@ -3131,6 +3258,76 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveToLayer(string layer, List<MapEntity> content)
|
||||
{
|
||||
layer ??= string.Empty;
|
||||
|
||||
foreach (MapEntity entity in content)
|
||||
{
|
||||
entity.Layer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateNewLayer(string name, List<MapEntity> content)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = TextManager.Get("editor.layer.newlayer");
|
||||
}
|
||||
|
||||
string incrementedName = name;
|
||||
|
||||
for (int i = 1; Layers.ContainsKey(incrementedName); i++)
|
||||
{
|
||||
incrementedName = $"{name} ({i})";
|
||||
}
|
||||
|
||||
name = incrementedName;
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
MoveToLayer(name, content);
|
||||
}
|
||||
|
||||
Layers.Add(name, true);
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
|
||||
private void RenameLayer(string original, string newName)
|
||||
{
|
||||
Layers.Remove(original);
|
||||
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList.Where(entity => entity.Layer == original))
|
||||
{
|
||||
entity.Layer = newName ?? string.Empty;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
Layers.TryAdd(newName, true);
|
||||
}
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
|
||||
private void ReconstructLayers()
|
||||
{
|
||||
ClearLayers();
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(entity.Layer))
|
||||
{
|
||||
Layers.TryAdd(entity.Layer, true);
|
||||
}
|
||||
}
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
|
||||
private void ClearLayers()
|
||||
{
|
||||
Layers.Clear();
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
|
||||
private void PasteAssembly(string text = null, Vector2? pos = null)
|
||||
{
|
||||
pos ??= cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
@@ -4044,6 +4241,7 @@ namespace Barotrauma
|
||||
previouslyUsedPanel.AddToGUIUpdateList();
|
||||
undoBufferPanel.AddToGUIUpdateList();
|
||||
entityCountPanel.AddToGUIUpdateList();
|
||||
layerPanel.AddToGUIUpdateList();
|
||||
TopPanel.AddToGUIUpdateList();
|
||||
|
||||
if (WiringMode)
|
||||
@@ -4147,9 +4345,55 @@ namespace Barotrauma
|
||||
GameMain.SubEditorScreen.UpdateUndoHistoryPanel();
|
||||
}
|
||||
|
||||
private void UpdateLayerPanel()
|
||||
{
|
||||
if (layerPanel is null || layerList is null) { return; }
|
||||
|
||||
layerList.Content.ClearChildren();
|
||||
|
||||
layerList.Deselect();
|
||||
|
||||
foreach (var (layer, isVisible) in Layers)
|
||||
{
|
||||
GUIFrame parent = new GUIFrame(new RectTransform(new Vector2(1f, 0.1f), layerList.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = layer
|
||||
};
|
||||
|
||||
GUILayoutGroup layerGroup = new GUILayoutGroup(new RectTransform(Vector2.One, parent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUITickBox layerVisibleButton = new GUITickBox(new RectTransform(Vector2.One, layerGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), string.Empty)
|
||||
{
|
||||
Selected = isVisible,
|
||||
OnSelected = box =>
|
||||
{
|
||||
if (!Layers.TryGetValue(layer, out bool _))
|
||||
{
|
||||
UpdateLayerPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
Layers[layer] = box.Selected;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
layerGroup.Recalculate();
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - layerVisibleButton.RectTransform.RelativeSize.X, 1f), layerGroup.RectTransform), layer, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
layerGroup.Recalculate();
|
||||
}
|
||||
|
||||
layerList.RecalculateChildren();
|
||||
}
|
||||
|
||||
public void UpdateUndoHistoryPanel()
|
||||
{
|
||||
if (undoBufferPanel == null) { return; }
|
||||
if (undoBufferPanel is null) { return; }
|
||||
|
||||
undoBufferDisclaimer.Visible = mode == Mode.Wiring;
|
||||
|
||||
@@ -4203,7 +4447,7 @@ namespace Barotrauma
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
SkipInventorySlotUpdate = false;
|
||||
ImageManager.Update((float) deltaTime);
|
||||
ImageManager.Update((float)deltaTime);
|
||||
|
||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y)
|
||||
{
|
||||
@@ -4720,6 +4964,11 @@ namespace Barotrauma
|
||||
|
||||
if (!saveAssemblyFrame.Rect.Contains(PlayerInput.MousePosition) && dummyCharacter?.SelectedConstruction == null && !WiringMode && GUI.MouseOn == null)
|
||||
{
|
||||
if (layerList is { Visible: true } && GUI.KeyboardDispatcher.Subscriber == layerList)
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
}
|
||||
|
||||
MapEntity.UpdateSelecting(cam);
|
||||
}
|
||||
|
||||
@@ -4998,7 +5247,7 @@ namespace Barotrauma
|
||||
|
||||
var prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle;
|
||||
|
||||
Rectangle subDimensions = Submarine.MainSub.CalculateDimensions(false);
|
||||
Rectangle subDimensions = Submarine.MainSub.CalculateDimensions(onlyHulls: false);
|
||||
Vector2 viewPos = subDimensions.Center.ToVector2();
|
||||
float scale = Math.Min(width / (float)subDimensions.Width, height / (float)subDimensions.Height);
|
||||
|
||||
@@ -5087,5 +5336,19 @@ namespace Barotrauma
|
||||
public static bool IsSubEditor() => Screen.Selected is SubEditorScreen && !Submarine.Unloading;
|
||||
public static bool IsWiringMode() => Screen.Selected == GameMain.SubEditorScreen && GameMain.SubEditorScreen.WiringMode && !Submarine.Unloading;
|
||||
|
||||
public static bool IsLayerVisible(MapEntity entity)
|
||||
{
|
||||
if (!IsSubEditor()) { return true; }
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entity.Layer)) { return true; }
|
||||
|
||||
if (!Layers.TryGetValue(entity.Layer, out bool isVisible))
|
||||
{
|
||||
Layers.TryAdd(entity.Layer, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Barotrauma
|
||||
private Submarine? submarine;
|
||||
private Character? dummyCharacter;
|
||||
public static Effect BlueprintEffect;
|
||||
private GUIFrame container;
|
||||
|
||||
private TabMenu tabMenu;
|
||||
|
||||
@@ -42,21 +43,25 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
|
||||
container = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "InnerGlow", color: Color.Black);
|
||||
var tab = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
|
||||
MedicalClinicUI clinic = new MedicalClinicUI(new MedicalClinic(null!), tab);
|
||||
clinic.RequestLatestPending();
|
||||
if (dummyCharacter is { Removed: false })
|
||||
{
|
||||
dummyCharacter?.Remove();
|
||||
}
|
||||
|
||||
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
|
||||
dummyCharacter.Info.Job = new Job(JobPrefab.Prefabs.Where(jp => TalentTree.JobTalentTrees.ContainsKey(jp.Identifier)).GetRandom());
|
||||
dummyCharacter.Info.Name = "Galldren";
|
||||
dummyCharacter.Inventory.CreateSlots();
|
||||
// dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
|
||||
// dummyCharacter.Info.Job = new Job(JobPrefab.Prefabs.Where(jp => TalentTree.JobTalentTrees.ContainsKey(jp.Identifier)).GetRandom());
|
||||
// dummyCharacter.Info.Name = "Galldren";
|
||||
// dummyCharacter.Inventory.CreateSlots();
|
||||
|
||||
Character.Controlled = dummyCharacter;
|
||||
GameMain.World.ProcessChanges();
|
||||
@@ -67,9 +72,9 @@ namespace Barotrauma
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
Frame.AddToGUIUpdateList();
|
||||
CharacterHUD.AddToGUIUpdateList(dummyCharacter);
|
||||
dummyCharacter?.SelectedConstruction?.AddToGUIUpdateList();
|
||||
tabMenu.AddToGUIUpdateList();
|
||||
container.AddToGUIUpdateList();
|
||||
// CharacterHUD.AddToGUIUpdateList(dummyCharacter);
|
||||
// dummyCharacter?.SelectedConstruction?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
@@ -92,12 +97,12 @@ namespace Barotrauma
|
||||
graphics.Clear(BackgroundColor);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, transformMatrix: Cam.Transform);
|
||||
miniMapItem?.Draw(spriteBatch, false);
|
||||
if (dummyCharacter is { } dummy)
|
||||
{
|
||||
dummyCharacter.DrawFront(spriteBatch, Cam);
|
||||
dummyCharacter.Draw(spriteBatch, Cam);
|
||||
}
|
||||
// miniMapItem?.Draw(spriteBatch, false);
|
||||
// if (dummyCharacter is { } dummy)
|
||||
// {
|
||||
// dummyCharacter.DrawFront(spriteBatch, Cam);
|
||||
// dummyCharacter.Draw(spriteBatch, Cam);
|
||||
// }
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
|
||||
|
||||
@@ -567,8 +567,6 @@ namespace Barotrauma
|
||||
{
|
||||
if (SetPropertyValue(property, entity, numInput.FloatValue))
|
||||
{
|
||||
// This causes stack overflow. What's the purpose of it?
|
||||
//numInput.FloatValue = (float)property.GetValue(entity);
|
||||
TrySendNetworkUpdate(entity, property);
|
||||
}
|
||||
};
|
||||
@@ -674,7 +672,16 @@ namespace Barotrauma
|
||||
Text = value,
|
||||
OverflowClip = true
|
||||
};
|
||||
|
||||
|
||||
HashSet<MapEntity> editedEntities = new HashSet<MapEntity>();
|
||||
propertyBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
foreach (var entity in MapEntity.SelectedList)
|
||||
{
|
||||
editedEntities.Add(entity);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnDeselected += (textBox, keys) => OnApply(textBox);
|
||||
propertyBox.OnEnterPressed += (box, text) => OnApply(box);
|
||||
refresh += () =>
|
||||
@@ -684,12 +691,25 @@ namespace Barotrauma
|
||||
|
||||
bool OnApply(GUITextBox textBox)
|
||||
{
|
||||
List<MapEntity> prevSelected = MapEntity.SelectedList.ToList();
|
||||
//reselect the entities that were selected during editing
|
||||
//otherwise multi-editing won't work when we deselect the entities with unapplied changes in the textbox
|
||||
foreach (var entity in editedEntities)
|
||||
{
|
||||
MapEntity.SelectedList.Add(entity);
|
||||
}
|
||||
if (SetPropertyValue(property, entity, textBox.Text))
|
||||
{
|
||||
TrySendNetworkUpdate(entity, property);
|
||||
textBox.Text = (string) property.GetValue(entity);
|
||||
textBox.Flash(GUI.Style.Green, flashDuration: 1f);
|
||||
}
|
||||
//restore the entities that were selected before applying
|
||||
MapEntity.SelectedList.Clear();
|
||||
foreach (var entity in prevSelected)
|
||||
{
|
||||
MapEntity.SelectedList.Add(entity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ namespace Barotrauma
|
||||
{
|
||||
private List<ParticleEmitter> particleEmitters;
|
||||
|
||||
private static HashSet<StatusEffect> ActiveLoopingSounds = new HashSet<StatusEffect>();
|
||||
private readonly static HashSet<StatusEffect> ActiveLoopingSounds = new HashSet<StatusEffect>();
|
||||
private static double LastMuffleCheckTime;
|
||||
private readonly List<RoundSound> sounds = new List<RoundSound>();
|
||||
public IEnumerable<RoundSound> Sounds { get { return sounds; } }
|
||||
private SoundSelectionMode soundSelectionMode;
|
||||
private SoundChannel soundChannel;
|
||||
private Entity soundEmitter;
|
||||
@@ -53,7 +54,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void ApplyProjSpecific(float deltaTime, Entity entity, IEnumerable<ISerializableEntity> targets, Hull hull, Vector2 worldPosition, bool playSound)
|
||||
partial void ApplyProjSpecific(float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Hull hull, Vector2 worldPosition, bool playSound)
|
||||
{
|
||||
if (playSound)
|
||||
{
|
||||
@@ -84,7 +85,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
targetLimb = targets.FirstOrDefault(t => t is Limb) as Limb;
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (targets[i] is Limb limb)
|
||||
{
|
||||
targetLimb = limb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetLimb != null && !targetLimb.Removed)
|
||||
{
|
||||
@@ -147,10 +155,6 @@ namespace Barotrauma
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
if (selectedSound.Sound.Disposed)
|
||||
{
|
||||
Submarine.ReloadRoundSound(selectedSound);
|
||||
}
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, worldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: hull, ignoreMuffling: selectedSound.IgnoreMuffling);
|
||||
ignoreMuffling = selectedSound.IgnoreMuffling;
|
||||
if (soundChannel != null) { soundChannel.Looping = loopSound; }
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Barotrauma
|
||||
{
|
||||
int width = 4096; int height = 4096;
|
||||
|
||||
Rectangle subDimensions = sub.CalculateDimensions(false);
|
||||
Rectangle subDimensions = sub.Borders;
|
||||
Vector2 viewPos = subDimensions.Center.ToVector2();
|
||||
float scale = Math.Min(width / (float)subDimensions.Width, height / (float)subDimensions.Height);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -61,9 +61,9 @@ namespace Barotrauma
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
|
||||
}
|
||||
|
||||
partial void OnTalentGiven(string talentIdentifier)
|
||||
partial void OnTalentGiven(TalentPrefab talentPrefab)
|
||||
{
|
||||
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentIdentifier}'", ServerLog.MessageType.Talent);
|
||||
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentPrefab.DisplayName}'", ServerLog.MessageType.Talent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,15 +288,18 @@ namespace Barotrauma
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
|
||||
if (prefab != null) { talentSelection.Add(prefab.Identifier); }
|
||||
if (prefab == null) { continue; }
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(this, prefab.Identifier, talentSelection))
|
||||
{
|
||||
GiveTalent(prefab.Identifier);
|
||||
talentSelection.Add(prefab.Identifier);
|
||||
}
|
||||
}
|
||||
talentSelection = TalentTree.CheckTalentSelection(this, talentSelection);
|
||||
|
||||
foreach (string talent in talentSelection)
|
||||
if (talentSelection.Count != talentCount)
|
||||
{
|
||||
GiveTalent(talent);
|
||||
DebugConsole.AddWarning($"Failed to unlock talents: the amount of unlocked talents doesn't match (client: {talentCount}, server: {talentSelection.Count})");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace Barotrauma
|
||||
{
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static bool IsSingleplayer => NetworkMember == null;
|
||||
public static bool IsMultiplayer => NetworkMember != null;
|
||||
|
||||
|
||||
private static World world;
|
||||
public static World World
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
||||
foreach (var activeOrder in ActiveOrders)
|
||||
{
|
||||
if (!(activeOrder?.First is Order order) || activeOrder.Second.HasValue) { continue; }
|
||||
OrderChatMessage.WriteOrder(msg, order, null, order.TargetSpatialEntity, null, 0, order.WallSectionIndex);
|
||||
OrderChatMessage.WriteOrder(msg, order, targetCharacter: null, order.TargetSpatialEntity, orderOption: null, orderPriority: 0, order.WallSectionIndex, isNewOrder: true);
|
||||
bool hasOrderGiver = order.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver)
|
||||
|
||||
@@ -348,7 +348,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateCampaignSubs();
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
PendingSubmarineSwitch = null;
|
||||
@@ -399,44 +398,12 @@ namespace Barotrauma
|
||||
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
|
||||
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
|
||||
|
||||
UpdateCampaignSubs();
|
||||
|
||||
//increment save ID so clients know they're lacking the most up-to-date save file
|
||||
LastSaveID++;
|
||||
}
|
||||
|
||||
public static void UpdateCampaignSubs()
|
||||
{
|
||||
bool isSubmarineVisible(SubmarineInfo s)
|
||||
=> !GameMain.Server.ServerSettings.HiddenSubs.Any(h
|
||||
=> s.Name.Equals(h, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
List<SubmarineInfo> availableSubs =
|
||||
SubmarineInfo.SavedSubmarines
|
||||
.Where(s =>
|
||||
s.IsCampaignCompatible
|
||||
&& isSubmarineVisible(s))
|
||||
.ToList();
|
||||
|
||||
if (!availableSubs.Any())
|
||||
{
|
||||
//None of the available subs were marked as campaign-compatible, just include all visible subs
|
||||
availableSubs.AddRange(
|
||||
SubmarineInfo.SavedSubmarines
|
||||
.Where(isSubmarineVisible));
|
||||
}
|
||||
|
||||
if (!availableSubs.Any())
|
||||
{
|
||||
//No subs are visible at all! Just make the selected one available
|
||||
availableSubs.Add(GameMain.NetLobbyScreen.SelectedSub);
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = availableSubs;
|
||||
}
|
||||
|
||||
public bool CanPurchaseSub(SubmarineInfo info)
|
||||
=> info.Price <= Money && GameMain.NetLobbyScreen.CampaignSubmarines.Contains(info);
|
||||
=> info.Price <= Money && GetCampaignSubs().Contains(info);
|
||||
|
||||
public void DiscardClientCharacterData(Client client)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal partial class MedicalClinic
|
||||
{
|
||||
private enum RateLimitResult
|
||||
{
|
||||
OK,
|
||||
LimitReached
|
||||
}
|
||||
|
||||
private struct RateLimitInfo
|
||||
{
|
||||
public int Requests;
|
||||
public const int MaxRequests = 5;
|
||||
public DateTimeOffset Expiry;
|
||||
}
|
||||
|
||||
private readonly Dictionary<Client, RateLimitInfo> rateLimits = new Dictionary<Client, RateLimitInfo>();
|
||||
|
||||
public void ServerRead(IReadMessage inc, Client sender)
|
||||
{
|
||||
NetworkHeader header = (NetworkHeader)inc.ReadByte();
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case NetworkHeader.REQUEST_AFFLICTIONS:
|
||||
ProcessRequestedAfflictions(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.REQUEST_PENDING:
|
||||
ProcessRequestedPending(sender);
|
||||
break;
|
||||
case NetworkHeader.ADD_PENDING:
|
||||
ProcessNewAddition(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.REMOVE_PENDING:
|
||||
ProcessNewRemoval(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.HEAL_PENDING:
|
||||
ProcessHealing(sender);
|
||||
break;
|
||||
case NetworkHeader.CLEAR_PENDING:
|
||||
ProcessClearing(sender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNewAddition(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetCrewMember newCrewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
InsertPendingCrewMember(newCrewMember);
|
||||
ServerSend(newCrewMember, NetworkHeader.ADD_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessNewRemoval(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetRemovedAffliction removed = INetSerializableStruct.Read<NetRemovedAffliction>(inc);
|
||||
RemovePendingAffliction(removed.CrewMember, removed.Affliction);
|
||||
ServerSend(removed, NetworkHeader.REMOVE_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessRequestedPending(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
INetSerializableStruct writeCrewMember = new NetPendingCrew
|
||||
{
|
||||
CrewMembers = PendingHeals.ToArray()
|
||||
};
|
||||
|
||||
ServerSend(writeCrewMember, NetworkHeader.REQUEST_PENDING, DeliveryMethod.Reliable, targetClient: client);
|
||||
}
|
||||
|
||||
private void ProcessHealing(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
HealRequestResult result = HealAllPending();
|
||||
ServerSend(new NetHealRequest { Result = result }, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessClearing(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
if (!PendingHeals.Any()) { return; }
|
||||
|
||||
ClearPendingHeals();
|
||||
ServerSend(null, NetworkHeader.CLEAR_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessRequestedAfflictions(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetCrewMember crewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
|
||||
CharacterInfo? foundInfo = crewMember.FindCharacterInfo(GetCrewCharacters());
|
||||
|
||||
NetAffliction[] pendingAfflictions = Array.Empty<NetAffliction>();
|
||||
int infoId = 0;
|
||||
|
||||
if (foundInfo is { Character: { CharacterHealth: { } health } })
|
||||
{
|
||||
pendingAfflictions = GetAllAfflictions(health);
|
||||
infoId = foundInfo.GetIdentifierUsingOriginalName();
|
||||
}
|
||||
|
||||
INetSerializableStruct writeCrewMember = new NetCrewMember
|
||||
{
|
||||
CharacterInfoID = infoId,
|
||||
Afflictions = pendingAfflictions
|
||||
};
|
||||
|
||||
ServerSend(writeCrewMember, NetworkHeader.REQUEST_AFFLICTIONS, DeliveryMethod.Unreliable, client);
|
||||
}
|
||||
|
||||
private RateLimitResult CheckRateLimit(Client client)
|
||||
{
|
||||
if (rateLimits.TryGetValue(client, out RateLimitInfo rateLimitInfo))
|
||||
{
|
||||
if (rateLimitInfo.Expiry < DateTimeOffset.Now)
|
||||
{
|
||||
rateLimitInfo.Expiry = DateTimeOffset.Now.AddSeconds(5);
|
||||
rateLimitInfo.Requests = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rateLimitInfo.Requests > RateLimitInfo.MaxRequests) { return RateLimitResult.LimitReached; }
|
||||
|
||||
rateLimitInfo.Requests++;
|
||||
}
|
||||
|
||||
rateLimits[client] = rateLimitInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
rateLimits.Add(client, new RateLimitInfo { Requests = 1, Expiry = DateTimeOffset.Now.AddSeconds(5) });
|
||||
}
|
||||
|
||||
return RateLimitResult.OK;
|
||||
}
|
||||
|
||||
private IWriteMessage StartSending()
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.MEDICAL);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void ServerSend(INetSerializableStruct? netStruct, NetworkHeader header, DeliveryMethod deliveryMethod, Client? targetClient = null, Client? reponseClient = null)
|
||||
{
|
||||
if (targetClient is null)
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
SendToClient(c);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SendToClient(targetClient);
|
||||
|
||||
void SendToClient(Client c)
|
||||
{
|
||||
MessageFlag flag = MessageFlag.Announce;
|
||||
if (reponseClient != null && reponseClient == c)
|
||||
{
|
||||
flag = MessageFlag.Response;
|
||||
}
|
||||
|
||||
IWriteMessage msg = StartSending();
|
||||
msg.Write((byte)header);
|
||||
msg.Write((byte)flag);
|
||||
netStruct?.Write(msg);
|
||||
GameMain.Server.ServerPeer.Send(msg, c.Connection, deliveryMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,14 +50,14 @@ namespace Barotrauma.Items.Components
|
||||
newSteeringInput = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
if (!item.CanClientAccess(c)) return;
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
|
||||
user = c.Character;
|
||||
AutoPilot = autoPilot;
|
||||
|
||||
if (dockingButtonClicked)
|
||||
{
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
item.SendSignal(new Signal("1", sender: c.Character), "toggle_docking");
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), true });
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(DeteriorateAlways);
|
||||
msg.Write(tinkeringDuration);
|
||||
msg.Write(tinkeringStrength);
|
||||
msg.Write(tinkeringPowersDevices);
|
||||
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
|
||||
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
int signalIndex = msg.ReadRangedInteger(0, Signals.Length - 1);
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
if (!SendSignal(signalIndex)) { return; }
|
||||
if (!SendSignal(signalIndex, c.Character)) { return; }
|
||||
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} sent a signal \"{Signals[signalIndex]}\" from {item.Name}", ServerLog.MessageType.ItemInteraction);
|
||||
item.CreateServerEvent(this, new object[] { signalIndex });
|
||||
}
|
||||
|
||||
@@ -218,33 +218,6 @@ namespace Barotrauma.Networking
|
||||
if (shuttle != null) { GameMain.NetLobbyScreen.SelectedShuttle = shuttle; }
|
||||
}
|
||||
|
||||
List<SubmarineInfo> campaignSubs = new List<SubmarineInfo>();
|
||||
if (serverSettings.CampaignSubmarines != null && serverSettings.CampaignSubmarines.Length > 0)
|
||||
{
|
||||
string[] submarines = serverSettings.CampaignSubmarines.Split(ServerSettings.SubmarineSeparatorChar);
|
||||
for (int i = 0; i < submarines.Length; i++)
|
||||
{
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == submarines[i]);
|
||||
if (subInfo != null && subInfo.IsCampaignCompatible)
|
||||
{
|
||||
campaignSubs.Add(subInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add vanilla submarines by default
|
||||
for (int i = 0; i < SubmarineInfo.SavedSubmarines.Count(); i++)
|
||||
{
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.ElementAt(i);
|
||||
if (subInfo.IsVanillaSubmarine() && subInfo.IsCampaignCompatible)
|
||||
{
|
||||
campaignSubs.Add(SubmarineInfo.SavedSubmarines.ElementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = campaignSubs;
|
||||
|
||||
started = true;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("GameServer:Start");
|
||||
@@ -835,6 +808,9 @@ namespace Barotrauma.Networking
|
||||
case ClientPacketHeader.CREW:
|
||||
ReadCrewMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.MEDICAL:
|
||||
ReadMedicalMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.READY_CHECK:
|
||||
ReadyCheck.ServerRead(inc, connectedClient);
|
||||
break;
|
||||
@@ -879,16 +855,16 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (entity is Character character)
|
||||
{
|
||||
errorStr = "Missing character " + character.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStrNoName = "Missing character " + character.SpeciesName + "(event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = $"Missing character {character.Name} (event id {eventID}, entity id {entityID}).";
|
||||
errorStrNoName = $"Missing character {character.SpeciesName} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
errorStr = errorStrNoName = "Missing item " + item.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = errorStrNoName = $"Missing item {item.Name}, sub: {item.Submarine?.Info?.Name ?? "none"} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorStr = errorStrNoName = "Missing entity " + entity.ToString() + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = errorStrNoName = $"Missing entity {entity}, sub: {entity.Submarine?.Info?.Name ?? "none"} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1234,6 +1210,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadMedicalMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
mpCampaign.MedicalClinic.ServerRead(inc, sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
||||
@@ -1861,24 +1845,6 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.ToString());
|
||||
|
||||
List<int> campaignSubIndices = new List<int>();
|
||||
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
||||
{
|
||||
IReadOnlyList<SubmarineInfo> subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
{
|
||||
if (GameMain.NetLobbyScreen.CampaignSubmarines.Contains(subList[i]))
|
||||
{
|
||||
campaignSubIndices.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
outmsg.Write((UInt16)campaignSubIndices.Count);
|
||||
foreach (int campaignSubIndex in campaignSubIndices)
|
||||
{
|
||||
outmsg.Write((UInt16)campaignSubIndex);
|
||||
}
|
||||
|
||||
outmsg.Write(serverSettings.Voting.AllowSubVoting);
|
||||
outmsg.Write(serverSettings.Voting.AllowModeVoting);
|
||||
|
||||
@@ -2166,7 +2132,6 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
SendStartMessage(roundStartSeed, GameMain.NetLobbyScreen.LevelSeed, GameMain.GameSession, connectedClients, false);
|
||||
|
||||
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty);
|
||||
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
|
||||
@@ -2186,8 +2151,7 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
MissionMode missionMode = GameMain.GameSession.GameMode as MissionMode;
|
||||
bool missionAllowRespawn = missionMode == null || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
bool missionAllowRespawn = !(GameMain.GameSession.GameMode is MissionMode missionMode) || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
bool isOutpost = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost;
|
||||
|
||||
if (serverSettings.AllowRespawn && missionAllowRespawn)
|
||||
@@ -2263,7 +2227,7 @@ namespace Barotrauma.Networking
|
||||
characterInfos.Add(client.CharacterInfo);
|
||||
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
||||
{
|
||||
client.CharacterInfo.Job = new Job(client.AssignedJob.First, client.AssignedJob.Second);
|
||||
client.CharacterInfo.Job = new Job(client.AssignedJob.First, Rand.RandSync.Unsynced, client.AssignedJob.Second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2475,7 +2439,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.AllowLinkingWifiToChat);
|
||||
msg.Write(serverSettings.UseRespawnShuttle);
|
||||
msg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
msg.Write((byte)serverSettings.LosMode);
|
||||
msg.Write(includesFinalize); msg.WritePadBits();
|
||||
|
||||
@@ -3372,14 +3336,40 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void IncrementStat(Character character, string achievementIdentifier, int amount)
|
||||
{
|
||||
achievementIdentifier = achievementIdentifier.ToLowerInvariant();
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
if (client.Character == character)
|
||||
{
|
||||
IncrementStat(client, achievementIdentifier, amount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GiveAchievement(Client client, string achievementIdentifier)
|
||||
{
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) return;
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) { return; }
|
||||
client.GivenAchievements.Add(achievementIdentifier);
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.ACHIEVEMENT);
|
||||
msg.Write(achievementIdentifier);
|
||||
msg.Write(0);
|
||||
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void IncrementStat(Client client, string achievementIdentifier, int amount)
|
||||
{
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) { return; }
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.ACHIEVEMENT);
|
||||
msg.Write(achievementIdentifier);
|
||||
msg.Write(amount);
|
||||
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
@@ -3733,7 +3723,7 @@ namespace Barotrauma.Networking
|
||||
if (assignedPlayerCount[jobPrefab] >= jobPrefab.MaxNumber) { continue; }
|
||||
|
||||
var variant = Rand.Range(0, jobPrefab.Variants, Rand.RandSync.Server);
|
||||
unassignedBots[0].Job = new Job(jobPrefab, variant);
|
||||
unassignedBots[0].Job = new Job(jobPrefab, Rand.RandSync.Server, variant);
|
||||
assignedPlayerCount[jobPrefab]++;
|
||||
unassignedBots.Remove(unassignedBots[0]);
|
||||
canAssign = true;
|
||||
@@ -3756,7 +3746,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
var job = remainingJobs.GetRandom();
|
||||
var variant = Rand.Range(0, job.Variants);
|
||||
c.Job = new Job(job, variant);
|
||||
c.Job = new Job(job, Rand.RandSync.Unsynced, variant);
|
||||
assignedPlayerCount[c.Job.Prefab]++;
|
||||
}
|
||||
}
|
||||
@@ -3842,16 +3832,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (GameMain.NetLobbyScreen.SelectedSub != null) { serverSettings.SelectedSubmarine = GameMain.NetLobbyScreen.SelectedSub.Name; }
|
||||
if (GameMain.NetLobbyScreen.SelectedShuttle != null) { serverSettings.SelectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle.Name; }
|
||||
if (GameMain.NetLobbyScreen.CampaignSubmarines != null)
|
||||
{
|
||||
string submarinesString = string.Empty;
|
||||
for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
|
||||
{
|
||||
submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar;
|
||||
}
|
||||
submarinesString.Trim(ServerSettings.SubmarineSeparatorChar);
|
||||
serverSettings.CampaignSubmarines = submarinesString;
|
||||
}
|
||||
|
||||
serverSettings.SaveSettings();
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (campaign?.GetClientCharacterData(c) == null || c.CharacterInfo.Job == null)
|
||||
{
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.First, c.AssignedJob.Second);
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.First, Rand.RandSync.Unsynced, c.AssignedJob.Second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,21 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerSettings
|
||||
{
|
||||
partial class NetPropertyData
|
||||
{
|
||||
private object lastSyncedValue;
|
||||
public UInt16 LastUpdateID { get; private set; }
|
||||
|
||||
public void SyncValue()
|
||||
{
|
||||
if (!PropEquals(lastSyncedValue, Value))
|
||||
{
|
||||
LastUpdateID = (UInt16)(GameMain.NetLobbyScreen.LastUpdateID);
|
||||
lastSyncedValue = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
|
||||
public static readonly char SubmarineSeparatorChar = '|';
|
||||
|
||||
@@ -35,20 +50,25 @@ namespace Barotrauma.Networking
|
||||
LoadClientPermissions();
|
||||
}
|
||||
|
||||
private void WriteNetProperties(IWriteMessage outMsg)
|
||||
private void WriteNetProperties(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
outMsg.Write((UInt16)netProperties.Keys.Count);
|
||||
foreach (UInt32 key in netProperties.Keys)
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
var property = netProperties[key];
|
||||
property.SyncValue();
|
||||
if (property.LastUpdateID > c.LastRecvLobbyUpdate)
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
}
|
||||
}
|
||||
outMsg.Write((UInt32)0);
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
c.LastSentServerSettingsUpdate = LastPropertyUpdateId;
|
||||
WriteNetProperties(outMsg);
|
||||
WriteNetProperties(outMsg, c);
|
||||
WriteMonsterEnabled(outMsg);
|
||||
BanList.ServerAdminWrite(outMsg, c);
|
||||
Whitelist.ServerAdminWrite(outMsg, c);
|
||||
@@ -79,8 +99,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
WriteExtraCargo(outMsg);
|
||||
}
|
||||
|
||||
WriteHiddenSubs(outMsg);
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.HiddenSubs))
|
||||
{
|
||||
WriteHiddenSubs(outMsg);
|
||||
}
|
||||
|
||||
if (c.HasPermission(Networking.ClientPermissions.ManageSettings)
|
||||
&& !NetIdUtils.IdMoreRecentOrMatches(c.LastRecvServerSettingsUpdate, LastPropertyUpdateId))
|
||||
@@ -164,6 +187,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ReadHiddenSubs(incMsg);
|
||||
changed |= true;
|
||||
UpdateFlag(NetFlags.HiddenSubs);
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.Misc))
|
||||
|
||||
@@ -32,26 +32,6 @@ namespace Barotrauma
|
||||
set { selectedShuttle = value; lastUpdateID++; }
|
||||
}
|
||||
|
||||
[Obsolete("TODO: this list shouldn't exist, the client should just use the visible subs list instead")]
|
||||
public List<SubmarineInfo> CampaignSubmarines
|
||||
{
|
||||
get
|
||||
{
|
||||
return campaignSubmarines;
|
||||
}
|
||||
set
|
||||
{
|
||||
campaignSubmarines = value;
|
||||
lastUpdateID++;
|
||||
if (GameMain.NetworkMember?.ServerSettings != null)
|
||||
{
|
||||
GameMain.NetworkMember.ServerSettings.ServerDetailsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SubmarineInfo> campaignSubmarines;
|
||||
|
||||
public GameModePreset[] GameModes { get; }
|
||||
|
||||
private int selectedModeIndex;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.15.23.0</Version>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
<Submarine file="Submarines/Venture.sub" />
|
||||
<Submarine file="Submarines/Azimuth.sub" />
|
||||
<Submarine file="Submarines/R-29.sub" />
|
||||
<Submarine file="Submarines/Barsuk.sub" />
|
||||
<Text file="Content/Texts/English/EnglishVanilla.xml" />
|
||||
<Text file="Content/Texts/German/GermanVanilla.xml" />
|
||||
<Text file="Content/Texts/French/FrenchVanilla.xml" />
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
http://www.barotraumagame.com
|
||||
|
||||
© 2018-2020 FakeFish Ltd. All rights reserved.
|
||||
© 2019-2020 Daedalic Entertainment GmbH. The Daedalic logo is a trademark of Daedalic Entertainment GmbH, Germany. All rights reserved.
|
||||
© 2018-2022 FakeFish Ltd. All rights reserved.
|
||||
© 2019-2022 Daedalic Entertainment GmbH. The Daedalic logo is a trademark of Daedalic Entertainment GmbH, Germany. All rights reserved.
|
||||
Privacy policy: http://privacypolicy.daedalic.com
|
||||
|
||||
See the wiki for more detailed info and instructions:
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Barotrauma
|
||||
|
||||
private CoroutineHandle disableTailCoroutine;
|
||||
|
||||
private readonly IEnumerable<Body> myBodies;
|
||||
private readonly List<Body> myBodies;
|
||||
|
||||
public LatchOntoAI LatchOntoAI { get; private set; }
|
||||
public SwarmBehavior SwarmBehavior { get; private set; }
|
||||
@@ -306,7 +306,8 @@ namespace Barotrauma
|
||||
|
||||
requiredHoleCount = (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderWidth) / Structure.WallSectionSize);
|
||||
|
||||
myBodies = Character.AnimController.Limbs.Select(l => l.body.FarseerBody);
|
||||
myBodies = Character.AnimController.Limbs.Select(l => l.body.FarseerBody).ToList();
|
||||
myBodies.Add(Character.AnimController.Collider.FarseerBody);
|
||||
}
|
||||
|
||||
private CharacterParams.AIParams _aiParams;
|
||||
@@ -1837,7 +1838,7 @@ namespace Barotrauma
|
||||
if (!attack.IsValidTarget(target)) { return false; }
|
||||
if (target is ISerializableEntity se && target is Character)
|
||||
{
|
||||
if (attack.Conditionals.Any(c => !c.Matches(se))) { return false; }
|
||||
if (attack.Conditionals.Any(c => !c.TargetSelf && !c.Matches(se))) { return false; }
|
||||
}
|
||||
if (attack.Conditionals.Any(c => c.TargetSelf && !c.Matches(Character))) { return false; }
|
||||
if (attack.Ranged)
|
||||
@@ -2182,10 +2183,22 @@ namespace Barotrauma
|
||||
float margin = MathHelper.PiOver4 * distanceFactor;
|
||||
if (angle < margin)
|
||||
{
|
||||
var collisionCategories = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel;
|
||||
var pickedBody = Submarine.PickBody(weapon.SimPosition, target.SimPosition, myBodies, collisionCategories, allowInsideFixture: true);
|
||||
var collisionCategories = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel;
|
||||
var pickedBody = Submarine.PickBody(weapon.SimPosition, Character.GetRelativeSimPosition(target), myBodies, collisionCategories, allowInsideFixture: true);
|
||||
if (pickedBody != null)
|
||||
{
|
||||
if (target is MapEntity)
|
||||
{
|
||||
if (pickedBody.UserData is Submarine sub && sub == target.Submarine)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (target == pickedBody.UserData)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Character t = null;
|
||||
if (pickedBody.UserData is Character c)
|
||||
{
|
||||
|
||||
@@ -832,6 +832,8 @@ namespace Barotrauma
|
||||
if (container == null) { return 0; }
|
||||
if (!container.HasAccess(character)) { return 0; }
|
||||
if (!container.Inventory.CanBePut(containableItem)) { return 0; }
|
||||
var rootContainer = container.Item.GetRootContainer();
|
||||
if (rootContainer?.GetComponent<Fabricator>() != null || rootContainer?.GetComponent<Fabricator>() != null) { return 0; }
|
||||
if (container.ShouldBeContained(containableItem, out bool isRestrictionsDefined))
|
||||
{
|
||||
if (isRestrictionsDefined)
|
||||
@@ -1088,6 +1090,7 @@ namespace Barotrauma
|
||||
|
||||
private void RespondToAttack(Character attacker, AttackResult attackResult)
|
||||
{
|
||||
float minorDamageThreshold = 10;
|
||||
float healAmount = 0.0f;
|
||||
if (attacker != null)
|
||||
{
|
||||
@@ -1135,6 +1138,7 @@ namespace Barotrauma
|
||||
// Don't react to attackers that are outside of the sub (e.g. AoE attacks)
|
||||
return;
|
||||
}
|
||||
bool isAttackerInfected = false;
|
||||
bool isAttackerFightingEnemy = false;
|
||||
if (IsFriendly(attacker))
|
||||
{
|
||||
@@ -1155,10 +1159,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
isAttackerInfected = attacker.CharacterHealth.GetAfflictionStrength("alieninfection") > 0;
|
||||
// Inform other NPCs
|
||||
if (cumulativeDamage > 1 || totalDamage >= 10)
|
||||
if (isAttackerInfected || cumulativeDamage > 1 || totalDamage >= minorDamageThreshold)
|
||||
{
|
||||
InformOtherNPCs(cumulativeDamage);
|
||||
if (GameMain.IsMultiplayer || !attacker.IsPlayer || Character.TeamID != attacker.TeamID)
|
||||
{
|
||||
InformOtherNPCs(cumulativeDamage);
|
||||
}
|
||||
}
|
||||
if (Character.IsBot)
|
||||
{
|
||||
@@ -1167,7 +1175,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (Character.IsSecurity)
|
||||
{
|
||||
if (attacker.TeamID != Character.TeamID && cumulativeDamage > 1 || cumulativeDamage > 10)
|
||||
if (attacker.TeamID != Character.TeamID && cumulativeDamage > 1 || cumulativeDamage > minorDamageThreshold)
|
||||
{
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityarrest"), null, 0.50f, "attackedbyfriendlysecurityarrest", minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
@@ -1181,26 +1189,8 @@ namespace Barotrauma
|
||||
Character.Speak(TextManager.Get("DialogAttackedByFriendly"), null, 0.50f, "attackedbyfriendly", minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
}
|
||||
if (cumulativeDamage > 1 && attacker.TeamID != Character.TeamID)
|
||||
{
|
||||
// If the attacker is using a low damage and high frequency weapon like a repair tool, we shouldn't use any delay.
|
||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage), attacker, delay: realDamage > 1 ? GetReactionTime() : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't react to minor (accidental) dmg done by characters that are in the same team
|
||||
if (cumulativeDamage < 10)
|
||||
{
|
||||
if (!Character.IsSecurity && cumulativeDamage > 1)
|
||||
{
|
||||
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, attacker);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage, dmgThreshold: 50), attacker, GetReactionTime() * 2);
|
||||
}
|
||||
}
|
||||
// If the attacker is using a low damage and high frequency weapon like a repair tool, we shouldn't use any delay.
|
||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage), attacker, delay: realDamage > 1 ? GetReactionTime() : 0);
|
||||
}
|
||||
if (!isAttackerFightingEnemy)
|
||||
{
|
||||
@@ -1242,13 +1232,13 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var combatMode = DetermineCombatMode(otherCharacter, cumulativeDamage, isWitnessing, dmgThreshold: attacker.TeamID == Character.TeamID ? 50 : 10);
|
||||
var combatMode = DetermineCombatMode(otherCharacter, cumulativeDamage, isWitnessing);
|
||||
float delay = isWitnessing ? GetReactionTime() : Rand.Range(2.0f, 5.0f, Rand.RandSync.Unsynced);
|
||||
otherHumanAI.AddCombatObjective(combatMode, attacker, delay);
|
||||
}
|
||||
}
|
||||
|
||||
AIObjectiveCombat.CombatMode DetermineCombatMode(Character c, float cumulativeDamage, bool isWitnessing = false, float dmgThreshold = 10, bool allowOffensive = true)
|
||||
AIObjectiveCombat.CombatMode DetermineCombatMode(Character c, float cumulativeDamage, bool isWitnessing = false)
|
||||
{
|
||||
if (!IsFriendly(attacker))
|
||||
{
|
||||
@@ -1268,6 +1258,17 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
float dmgThreshold = attacker.TeamID == Character.TeamID ? 50 : minorDamageThreshold;
|
||||
if (isAttackerInfected)
|
||||
{
|
||||
cumulativeDamage = 100;
|
||||
}
|
||||
if (GameMain.IsSingleplayer && attacker.IsPlayer && Character.TeamID == attacker.TeamID)
|
||||
{
|
||||
// Bots in the player team never act aggressively in single player when attacked by the player
|
||||
dmgThreshold = minorDamageThreshold;
|
||||
return cumulativeDamage > dmgThreshold ? AIObjectiveCombat.CombatMode.Retreat : AIObjectiveCombat.CombatMode.None;
|
||||
}
|
||||
if (Character.Submarine == null || !Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||
{
|
||||
// Outside or attacked from an unconnected submarine -> don't react.
|
||||
@@ -1279,17 +1280,17 @@ namespace Barotrauma
|
||||
isAttackerFightingEnemy = true;
|
||||
return AIObjectiveCombat.CombatMode.None;
|
||||
}
|
||||
else if (isWitnessing && Character.CombatAction != null && !c.IsSecurity)
|
||||
if (isWitnessing && Character.CombatAction != null && !c.IsSecurity)
|
||||
{
|
||||
return Character.CombatAction.WitnessReaction;
|
||||
}
|
||||
else if (attacker.IsPlayer && FindInstigator() is Character instigator)
|
||||
if (attacker.IsPlayer && FindInstigator() is Character instigator)
|
||||
{
|
||||
// The guards don't react when the player there's an instigator around
|
||||
// The guards don't react to player's aggressions when there's an instigator around
|
||||
isAttackerFightingEnemy = true;
|
||||
return c.IsSecurity ? AIObjectiveCombat.CombatMode.None : (instigator.CombatAction != null ? instigator.CombatAction.WitnessReaction : AIObjectiveCombat.CombatMode.Retreat);
|
||||
}
|
||||
else if (attacker.TeamID == CharacterTeamType.FriendlyNPC && !(attacker.AIController.IsMentallyUnstable || attacker.AIController.IsMentallyUnstable))
|
||||
if (attacker.TeamID == CharacterTeamType.FriendlyNPC && !(attacker.AIController.IsMentallyUnstable || attacker.AIController.IsMentallyUnstable))
|
||||
{
|
||||
if (c.IsSecurity)
|
||||
{
|
||||
@@ -1307,15 +1308,11 @@ namespace Barotrauma
|
||||
// Already targeting the attacker -> treat as a more serious threat.
|
||||
cumulativeDamage *= 2;
|
||||
}
|
||||
if (attackResult.Afflictions != null && attackResult.Afflictions.Any(a => a is AfflictionHusk))
|
||||
{
|
||||
cumulativeDamage = 100;
|
||||
}
|
||||
if (cumulativeDamage > dmgThreshold)
|
||||
{
|
||||
if (c.IsSecurity)
|
||||
{
|
||||
return c.IsSecurity && allowOffensive ? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Arrest;
|
||||
return c.IsSecurity ? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Arrest;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1838,7 +1835,7 @@ namespace Barotrauma
|
||||
bool ignoreFire = objectiveManager.CurrentOrder is AIObjectiveExtinguishFires extinguishOrder && extinguishOrder.Priority > 0 || objectiveManager.HasActiveObjective<AIObjectiveExtinguishFire>();
|
||||
bool ignoreWater = HasDivingSuit(character);
|
||||
bool ignoreOxygen = ignoreWater || HasDivingMask(character);
|
||||
bool ignoreEnemies = ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || ObjectiveManager.Objectives.Any(o => o is AIObjectiveFightIntruders);
|
||||
bool ignoreEnemies = ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || ObjectiveManager.GetActiveObjectives<AIObjectiveFightIntruders>().Any();
|
||||
float safety = CalculateHullSafety(hull, visibleHulls, character, ignoreWater, ignoreOxygen, ignoreFire, ignoreEnemies);
|
||||
if (isCurrentHull)
|
||||
{
|
||||
|
||||
@@ -51,19 +51,13 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the current or the next node is in ladders.
|
||||
/// </summary>
|
||||
public bool InLadders =>
|
||||
currentPath != null && currentPath.CurrentNode != null &&
|
||||
(currentPath.CurrentNode.Ladders != null && currentPath.CurrentNode.Ladders.Item.IsInteractable(character) ||
|
||||
(currentPath.NextNode != null && currentPath.NextNode.Ladders != null && currentPath.NextNode.Ladders.Item.IsInteractable(character)));
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any node in the path is in stairs
|
||||
/// </summary>
|
||||
public bool InStairs => currentPath != null && currentPath.Nodes.Any(n => n.Stairs != null);
|
||||
|
||||
public bool IsCurrentNodeLadder => currentPath?.CurrentNode?.Ladders != null && currentPath.CurrentNode.Ladders.Item.IsInteractable(character);
|
||||
|
||||
public bool IsNextNodeLadder => GetNextLadder() != null;
|
||||
|
||||
public bool IsNextLadderSameAsCurrent
|
||||
@@ -99,14 +93,24 @@ namespace Barotrauma
|
||||
base.Update(speed);
|
||||
float step = 1.0f / 60.0f;
|
||||
checkDoorsTimer -= step;
|
||||
buttonPressTimer -= step;
|
||||
if (lastDoor.door == null || !lastDoor.shouldBeOpen || lastDoor.door.IsOpen)
|
||||
{
|
||||
buttonPressTimer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonPressTimer -= step;
|
||||
}
|
||||
findPathTimer -= step;
|
||||
}
|
||||
|
||||
public void SetPath(SteeringPath path)
|
||||
{
|
||||
currentPath = path;
|
||||
if (path.Nodes.Any()) currentTarget = path.Nodes[path.Nodes.Count - 1].SimPosition;
|
||||
if (path.Nodes.Any())
|
||||
{
|
||||
currentTarget = path.Nodes[path.Nodes.Count - 1].SimPosition;
|
||||
}
|
||||
findPathTimer = Math.Min(findPathTimer, 1.0f);
|
||||
IsPathDirty = false;
|
||||
}
|
||||
@@ -124,15 +128,9 @@ namespace Barotrauma
|
||||
|
||||
public void SteeringSeek(Vector2 target, float weight, float minGapWidth = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisiblity = true)
|
||||
{
|
||||
if (buttonPressTimer > 0 && lastDoor.door != null && lastDoor.state && !lastDoor.door.IsOpen)
|
||||
{
|
||||
// We have pressed the button and are waiting for the door to open -> Hold still until we can press the button again.
|
||||
Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
steering += CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity);
|
||||
}
|
||||
// Have to use a variable here or resetting doesn't work.
|
||||
Vector2 addition = CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity);
|
||||
steering += addition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -328,7 +326,13 @@ namespace Barotrauma
|
||||
{
|
||||
CheckDoorsInPath();
|
||||
doorsChecked = true;
|
||||
}
|
||||
}
|
||||
if (buttonPressTimer > 0 && lastDoor.door != null && lastDoor.shouldBeOpen && !lastDoor.door.IsOpen)
|
||||
{
|
||||
// We have pressed the button and are waiting for the door to open -> Hold still until we can press the button again.
|
||||
Reset();
|
||||
return Vector2.Zero;
|
||||
}
|
||||
Vector2 pos = host.WorldPosition;
|
||||
bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;
|
||||
// Only humanoids can climb ladders
|
||||
@@ -378,7 +382,7 @@ namespace Barotrauma
|
||||
//at the same height as the waypoint
|
||||
if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f)
|
||||
{
|
||||
float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY;
|
||||
float heightFromFloor = character.AnimController.GetHeightFromFloor();
|
||||
if (heightFromFloor <= 0.0f)
|
||||
{
|
||||
diff.Y = Math.Max(diff.Y, 100);
|
||||
@@ -516,7 +520,7 @@ namespace Barotrauma
|
||||
return ConvertUnits.ToDisplayUnits(Math.Max(colliderSize.X, colliderSize.Y));
|
||||
}
|
||||
|
||||
private (Door door, bool state) lastDoor;
|
||||
private (Door door, bool shouldBeOpen) lastDoor;
|
||||
private float GetDoorCheckTime()
|
||||
{
|
||||
if (steering.LengthSquared() > 0)
|
||||
@@ -539,7 +543,6 @@ namespace Barotrauma
|
||||
WayPoint nextWaypoint = null;
|
||||
Door door = null;
|
||||
bool shouldBeOpen = false;
|
||||
|
||||
if (currentPath.Nodes.Count == 1)
|
||||
{
|
||||
door = currentPath.Nodes.First().ConnectedDoor;
|
||||
@@ -645,7 +648,7 @@ namespace Barotrauma
|
||||
});
|
||||
if (canAccess)
|
||||
{
|
||||
bool pressButton = buttonPressTimer <= 0 || lastDoor.door != door || lastDoor.state != shouldBeOpen;
|
||||
bool pressButton = buttonPressTimer <= 0 || lastDoor.door != door || lastDoor.shouldBeOpen != shouldBeOpen;
|
||||
if (door.HasIntegratedButtons)
|
||||
{
|
||||
if (pressButton && character.CanSeeTarget(door.Item))
|
||||
@@ -653,7 +656,7 @@ namespace Barotrauma
|
||||
if (door.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
lastDoor = (door, shouldBeOpen);
|
||||
buttonPressTimer = buttonPressCooldown;
|
||||
buttonPressTimer = shouldBeOpen ? buttonPressCooldown : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -671,7 +674,7 @@ namespace Barotrauma
|
||||
if (closestButton.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
lastDoor = (door, shouldBeOpen);
|
||||
buttonPressTimer = buttonPressCooldown;
|
||||
buttonPressTimer = shouldBeOpen ? buttonPressCooldown : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -697,7 +700,6 @@ namespace Barotrauma
|
||||
// The button is on the wrong side of the door or a wall
|
||||
currentPath.Unreachable = true;
|
||||
}
|
||||
lastDoor = (null, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Barotrauma
|
||||
public virtual bool IgnoreUnsafeHulls => false;
|
||||
public virtual bool AbandonWhenCannotCompleteSubjectives => true;
|
||||
public virtual bool AllowSubObjectiveSorting => false;
|
||||
public virtual bool ForceOrderPriority => true;
|
||||
public virtual bool PrioritizeIfSubObjectivesActive => false;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -85,11 +85,12 @@ namespace Barotrauma
|
||||
bool equip = item.GetComponent<Holdable>() != null ||
|
||||
item.AllowedSlots.Any(s => s != InvSlotType.Any) &&
|
||||
item.AllowedSlots.None(s =>
|
||||
s == InvSlotType.Card ||
|
||||
s == InvSlotType.Head ||
|
||||
s == InvSlotType.Headset ||
|
||||
s == InvSlotType.InnerClothes ||
|
||||
s == InvSlotType.OuterClothes);
|
||||
s == InvSlotType.Card ||
|
||||
s == InvSlotType.Head ||
|
||||
s == InvSlotType.Headset ||
|
||||
s == InvSlotType.InnerClothes ||
|
||||
s == InvSlotType.OuterClothes ||
|
||||
s == InvSlotType.HealthInterface);
|
||||
|
||||
TryAddSubObjective(ref decontainObjective, () => new AIObjectiveDecontainItem(character, item, objectiveManager, targetContainer: suitableContainer.GetComponent<ItemContainer>())
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
public override string Identifier { get; set; } = "cleanup items";
|
||||
public override bool KeepDivingGearOn => true;
|
||||
public override bool AllowAutomaticItemUnequipping => false;
|
||||
public override bool ForceOrderPriority => false;
|
||||
protected override bool ForceOrderPriority => false;
|
||||
|
||||
public readonly List<Item> prioritizedItems = new List<Item>();
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Barotrauma
|
||||
private float AimSpeed => HumanAIController.AimSpeed;
|
||||
private float AimAccuracy => HumanAIController.AimAccuracy;
|
||||
|
||||
private bool EnemyIsClose() => Enemy != null && character.CurrentHull != null && character.CurrentHull == Enemy.CurrentHull || Vector2.DistanceSquared(character.Position, Enemy.Position) < 500;
|
||||
private bool EnemyIsClose() => Enemy != null && Enemy.CurrentHull != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull) && Math.Abs(character.WorldPosition.X - Enemy.WorldPosition.X) < 300;
|
||||
|
||||
public AIObjectiveCombat(Character character, Character enemy, CombatMode mode, AIObjectiveManager objectiveManager, float priorityModifier = 1, float coolDown = 10.0f)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
@@ -366,7 +366,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
bool isAllowedToSeekWeapons = !EnemyIsClose() && character.TeamID != CharacterTeamType.FriendlyNPC && IsOffensiveOrArrest;
|
||||
bool isAllowedToSeekWeapons = character.CurrentHull != null && !EnemyIsClose() && character.TeamID != CharacterTeamType.FriendlyNPC && IsOffensiveOrArrest;
|
||||
if (!isAllowedToSeekWeapons)
|
||||
{
|
||||
if (WeaponComponent == null)
|
||||
@@ -1190,19 +1190,5 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private float CalculateEnemyStrength()
|
||||
//{
|
||||
// float enemyStrength = 0;
|
||||
// AttackContext currentContext = character.GetAttackContext();
|
||||
// foreach (Limb limb in Enemy.AnimController.Limbs)
|
||||
// {
|
||||
// if (limb.attack == null) continue;
|
||||
// if (!limb.attack.IsValidContext(currentContext)) { continue; }
|
||||
// if (!limb.attack.IsValidTarget(AttackTarget.Character)) { continue; }
|
||||
// enemyStrength += limb.attack.GetTotalDamage(false);
|
||||
// }
|
||||
// return enemyStrength;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,8 @@ namespace Barotrauma
|
||||
{
|
||||
TargetName = container.Item.Name,
|
||||
AbortCondition = obj =>
|
||||
container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI(character) ||
|
||||
container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI(character) ||
|
||||
(container.Item.GetRootContainer()?.OwnInventory?.Locked ?? false) ||
|
||||
ItemToContain == null || ItemToContain.Removed ||
|
||||
!ItemToContain.IsOwnedBy(character) || container.Item.GetRootInventoryOwner() is Character c && c != character,
|
||||
SpeakIfFails = !objectiveManager.IsCurrentOrder<AIObjectiveCleanupItems>()
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Barotrauma
|
||||
public Func<Item, bool> RemoveExistingPredicate { get; set; }
|
||||
public int? RemoveExistingMax { get; set; }
|
||||
public string AbandonGetItemDialogueIdentifier { get; set; }
|
||||
public Func<bool> AbandonGetItemDialogueCondition { get; set; }
|
||||
|
||||
public AIObjectiveDecontainItem(Character character, Item targetItem, AIObjectiveManager objectiveManager, ItemContainer sourceContainer = null, ItemContainer targetContainer = null, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
@@ -106,6 +107,7 @@ namespace Barotrauma
|
||||
TryAddSubObjective(ref getItemObjective,
|
||||
constructor: () => new AIObjectiveGetItem(character, targetItem, objectiveManager, Equip)
|
||||
{
|
||||
CannotFindDialogueCondition = AbandonGetItemDialogueCondition,
|
||||
CannotFindDialogueIdentifierOverride = AbandonGetItemDialogueIdentifier,
|
||||
SpeakIfFails = AbandonGetItemDialogueIdentifier != null,
|
||||
TakeWholeStack = this.TakeWholeStack
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Barotrauma
|
||||
if (totalEnemies == 0) { return 0; }
|
||||
if (character.IsSecurity) { return 100; }
|
||||
if (objectiveManager.IsOrder(this)) { return 100; }
|
||||
// If there's any security officers onboard, leave fighting for them.
|
||||
return HumanAIController.IsTrueForAnyCrewMember(c => c.Character.IsSecurity && !c.Character.IsIncapacitated && c.Character.Submarine == character.Submarine) ? 0 : 100;
|
||||
}
|
||||
|
||||
@@ -64,6 +65,7 @@ namespace Barotrauma
|
||||
if (target.CurrentHull == null) { return false; }
|
||||
if (HumanAIController.IsFriendly(character, target)) { return false; }
|
||||
if (!character.Submarine.IsConnectedTo(target.Submarine)) { return false; }
|
||||
if (character.Submarine.TeamID != target.Submarine.TeamID) { return false; }
|
||||
if (target.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI)) { return false; }
|
||||
if (target.IsArrested) { return false; }
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user