Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git
This commit is contained in:
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (Character.IsUnconscious || !Character.Enabled || !Enabled) { return; }
|
||||
|
||||
Vector2 pos = Character.WorldPosition;
|
||||
Vector2 pos = Character.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (State == AIState.Idle && PreviousState == AIState.Attack)
|
||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (SelectedAiTarget?.Entity != null)
|
||||
{
|
||||
Vector2 targetPos = SelectedAiTarget.WorldPosition;
|
||||
Vector2 targetPos = SelectedAiTarget.Entity.DrawPosition;
|
||||
if (State == AIState.Attack)
|
||||
{
|
||||
targetPos = attackWorldPos;
|
||||
@@ -72,7 +72,7 @@ namespace Barotrauma
|
||||
}
|
||||
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
|
||||
|
||||
if (LatchOntoAI != null)
|
||||
if (LatchOntoAI != null && (State == AIState.Idle || LatchOntoAI.IsAttachedToSub))
|
||||
{
|
||||
foreach (Joint attachJoint in LatchOntoAI.AttachJoints)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
namespace Barotrauma
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract partial class AIObjective
|
||||
{
|
||||
public static Color ObjectiveIconColor => Color.LightGray;
|
||||
|
||||
public static Sprite GetSprite(string identifier, string option, Entity targetEntity)
|
||||
{
|
||||
if (string.IsNullOrEmpty(identifier))
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Barotrauma
|
||||
|
||||
public bool PlaySound;
|
||||
|
||||
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null)
|
||||
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null, float lifeTime = 3.0f)
|
||||
{
|
||||
RawText = Text = rawText;
|
||||
if (value.HasValue)
|
||||
@@ -166,7 +166,7 @@ namespace Barotrauma
|
||||
Size = GUI.Font.MeasureString(Text);
|
||||
Color = color;
|
||||
Identifier = identifier;
|
||||
Lifetime = 3.0f;
|
||||
Lifetime = lifeTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,11 +312,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (AnimController.CurrentHull?.Submarine != null)
|
||||
{
|
||||
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
|
||||
}
|
||||
UpdateLocalCursor(cam);
|
||||
|
||||
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
|
||||
if (GUI.PauseMenuOpen)
|
||||
@@ -393,6 +389,15 @@ namespace Barotrauma
|
||||
DisableControls = false;
|
||||
}
|
||||
|
||||
public void UpdateLocalCursor(Camera cam)
|
||||
{
|
||||
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (AnimController.CurrentHull?.Submarine != null)
|
||||
{
|
||||
cursorPosition -= AnimController.CurrentHull.Submarine.DrawPosition;
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateControlled(float deltaTime, Camera cam)
|
||||
{
|
||||
if (controlled != this) return;
|
||||
@@ -997,7 +1002,7 @@ namespace Barotrauma
|
||||
return nameColor;
|
||||
}
|
||||
|
||||
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null)
|
||||
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null, float lifetime = 3.0f)
|
||||
{
|
||||
GUIMessage existingMessage = null;
|
||||
|
||||
@@ -1026,7 +1031,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (existingMessage == null || !value.HasValue)
|
||||
{
|
||||
var newMessage = new GUIMessage(rawText, color, delay, identifier, value);
|
||||
var newMessage = new GUIMessage(rawText, color, delay, identifier, value, lifetime);
|
||||
guiMessages.Insert(0, newMessage);
|
||||
if (playSound)
|
||||
{
|
||||
@@ -1156,9 +1161,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Barotrauma
|
||||
|
||||
return
|
||||
character?.Inventory != null &&
|
||||
character.AllowInput &&
|
||||
!character.Removed && !character.IsKnockedDown &&
|
||||
(controller?.User != character || !controller.HideHUD) &&
|
||||
!IsCampaignInterfaceOpen &&
|
||||
!ConversationAction.FadeScreenToBlack;
|
||||
@@ -406,6 +406,7 @@ namespace Barotrauma
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||
if (iconStyle == null) { continue; }
|
||||
Range<float> visibleRange = new Range<float>(npc.CurrentHull == Character.Controlled.CurrentHull ? 500.0f : 100.0f, float.PositiveInfinity);
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.Examine)
|
||||
{
|
||||
@@ -431,7 +432,7 @@ namespace Barotrauma
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.IconStyle is null || item.Submarine != character.Submarine) { continue; }
|
||||
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f*500f) { continue; }
|
||||
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f * 500f) { continue; }
|
||||
var body = Submarine.CheckVisibility(character.SimPosition, item.SimPosition, ignoreLevel: true);
|
||||
if (body != null && body.UserData as Item != item) { continue; }
|
||||
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Range<float>(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Barotrauma
|
||||
private static Sprite infoAreaPortraitBG;
|
||||
|
||||
public bool LastControlled;
|
||||
public int CrewListIndex { get; set; } = -1;
|
||||
|
||||
#warning TODO: Refactor
|
||||
private Sprite disguisedPortrait;
|
||||
@@ -521,6 +522,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)
|
||||
@@ -830,7 +832,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
new GUIFrame(
|
||||
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.RectTransform, Anchor.Center),
|
||||
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.ContentBackground.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow", color: Color.Black)
|
||||
{
|
||||
UserData = "outerglow",
|
||||
@@ -965,10 +967,15 @@ namespace Barotrauma
|
||||
foreach (Sprite sprite in characterSprites) { sprite.Remove(); }
|
||||
characterSprites.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ClearSprites();
|
||||
if (HeadSelectionList != null)
|
||||
{
|
||||
HeadSelectionList.RectTransform.Parent = null;
|
||||
HeadSelectionList = null;
|
||||
}
|
||||
}
|
||||
|
||||
~AppearanceCustomizationMenu()
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
{
|
||||
partial class AfflictionHusk : Affliction
|
||||
{
|
||||
private InfectionState? prevDisplayedMessage;
|
||||
partial void UpdateMessages()
|
||||
{
|
||||
if (character != Character.Controlled) { return; }
|
||||
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 +31,7 @@
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prevDisplayedMessage = State;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma
|
||||
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
|
||||
if (fireHull != null)
|
||||
{
|
||||
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y), fireHull, isNetworkMessage: true)
|
||||
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y + 1), fireHull, isNetworkMessage: true)
|
||||
{
|
||||
CausedByPsychosis = true,
|
||||
DamagesItems = false,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -954,7 +956,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
if (GUI.DisableHUD || Character.Removed) { return; }
|
||||
if (GameMain.GraphicsWidth != screenResolution.X ||
|
||||
GameMain.GraphicsHeight != screenResolution.Y ||
|
||||
Math.Abs(inventoryScale - Inventory.UIScale) > 0.01f ||
|
||||
@@ -995,14 +997,16 @@ namespace Barotrauma
|
||||
{
|
||||
healthBar.RectTransform.ScreenSpaceOffset = healthBarShadow.RectTransform.ScreenSpaceOffset = Point.Zero;
|
||||
}
|
||||
|
||||
// If manning a turret the portrait doesn't get rendered so we push the health bar to remove the empty gap
|
||||
healthBarHolder.RectTransform.ScreenSpaceOffset = Character.ShouldLockHud() ? new Point(0, HUDLayoutSettings.PortraitArea.Height) : Point.Zero;
|
||||
|
||||
if (healthBarHolder != null)
|
||||
{
|
||||
// If manning a turret the portrait doesn't get rendered so we push the health bar to remove the empty gap
|
||||
healthBarHolder.RectTransform.ScreenSpaceOffset = Character.ShouldLockHud() ? new Point(0, HUDLayoutSettings.PortraitArea.Height) : Point.Zero;
|
||||
}
|
||||
|
||||
DrawStatusHUD(spriteBatch);
|
||||
}
|
||||
|
||||
|
||||
private (Affliction affliction, string text)? highlightedAfflictionIcon;
|
||||
public void DrawStatusHUD(SpriteBatch spriteBatch)
|
||||
{
|
||||
@@ -1122,23 +1126,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 +1158,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (afflictionsDirty())
|
||||
if (afflictionsDirty() || selectedLimb != currentDisplayedLimb)
|
||||
{
|
||||
var currentAfflictions = afflictions.Where(a => ShouldDisplayAfflictionOnLimb(a, selectedLimb)).Select(a => a.Key);
|
||||
CreateAfflictionInfos(currentAfflictions);
|
||||
@@ -2015,6 +2020,27 @@ namespace Barotrauma
|
||||
|
||||
limbIndicatorOverlay?.Remove();
|
||||
limbIndicatorOverlay = null;
|
||||
|
||||
if (healthWindow != null)
|
||||
{
|
||||
healthWindow.RectTransform.Parent = null;
|
||||
healthWindow = null;
|
||||
}
|
||||
if (healthBarHolder != null)
|
||||
{
|
||||
healthBarHolder.RectTransform.Parent = null;
|
||||
healthBarHolder = null;
|
||||
}
|
||||
if (SuicideButton != null)
|
||||
{
|
||||
SuicideButton.RectTransform.Parent = null;
|
||||
SuicideButton = null;
|
||||
}
|
||||
if (afflictionTooltip != null)
|
||||
{
|
||||
afflictionTooltip.RectTransform.Parent = null;
|
||||
afflictionTooltip = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
// TODO: move this into the character editor
|
||||
//var mouthPos = ragdoll.GetMouthPosition();
|
||||
//if (mouthPos != null)
|
||||
//{
|
||||
@@ -173,6 +172,7 @@ namespace Barotrauma
|
||||
|
||||
public float DefaultSpriteDepth { get; private set; }
|
||||
|
||||
public WearableSprite HairWithHatSprite { get; set; }
|
||||
public WearableSprite HuskSprite { get; private set; }
|
||||
public WearableSprite HerpesSprite { get; private set; }
|
||||
|
||||
@@ -236,8 +236,8 @@ namespace Barotrauma
|
||||
|
||||
public string HitSoundTag => Params?.Sound?.Tag;
|
||||
|
||||
private List<WearableSprite> wearableTypeHidingSprites = new List<WearableSprite>();
|
||||
private List<WearableType> wearableTypesToHide = new List<WearableType>();
|
||||
private readonly List<WearableSprite> wearableTypeHidingSprites = new List<WearableSprite>();
|
||||
private readonly HashSet<WearableType> wearableTypesToHide = new HashSet<WearableType>();
|
||||
private bool enableHuskSprite;
|
||||
public bool EnableHuskSprite
|
||||
{
|
||||
@@ -895,7 +895,22 @@ namespace Barotrauma
|
||||
foreach (WearableSprite wearable in OtherWearables)
|
||||
{
|
||||
if (wearable.Type == WearableType.Husk) { continue; }
|
||||
if (wearableTypesToHide.Contains(wearable.Type)) { continue; }
|
||||
if (wearableTypesToHide.Contains(wearable.Type))
|
||||
{
|
||||
if (wearable.Type == WearableType.Hair)
|
||||
{
|
||||
if (HairWithHatSprite != null)
|
||||
{
|
||||
DrawWearable(HairWithHatSprite, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||
depthStep += step;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||
depthStep += step;
|
||||
@@ -1195,6 +1210,9 @@ namespace Barotrauma
|
||||
HuskSprite?.Sprite.Remove();
|
||||
HuskSprite = null;
|
||||
|
||||
HairWithHatSprite?.Sprite.Remove();
|
||||
HairWithHatSprite = null;
|
||||
|
||||
HerpesSprite?.Sprite.Remove();
|
||||
HerpesSprite = null;
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace Barotrauma
|
||||
|
||||
public void ClientExecute(string[] args)
|
||||
{
|
||||
if (!CheatsEnabled && IsCheat)
|
||||
bool allowCheats = GameMain.NetworkMember == null && (GameMain.GameSession?.GameMode is TestGameMode || Screen.Selected is EditorScreen);
|
||||
if (!allowCheats && !CheatsEnabled && IsCheat)
|
||||
{
|
||||
NewMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", Color.Red);
|
||||
#if USE_STEAM
|
||||
@@ -743,7 +744,7 @@ namespace Barotrauma
|
||||
AssignOnExecute("explosion", (string[] args) =>
|
||||
{
|
||||
Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
float range = 500, force = 10, damage = 50, structureDamage = 10, itemDamage = 100, empStrength = 0.0f, ballastFloraStrength = 50f;
|
||||
float range = 500, force = 10, damage = 50, structureDamage = 20, itemDamage = 100, empStrength = 0.0f, ballastFloraStrength = 50f;
|
||||
if (args.Length > 0) float.TryParse(args[0], out range);
|
||||
if (args.Length > 1) float.TryParse(args[1], out force);
|
||||
if (args.Length > 2) float.TryParse(args[2], out damage);
|
||||
@@ -1120,7 +1121,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);
|
||||
}
|
||||
@@ -1894,7 +1895,12 @@ namespace Barotrauma
|
||||
ThrowError($"\"{args[0]}\" is not a valid Level.PositionType. Available options are: {string.Join(", ", enums)}");
|
||||
return;
|
||||
}
|
||||
debugLines = EventSet.GetDebugStatistics(filter: monsterEvent => monsterEvent.SpawnPosType.HasFlag(spawnType));
|
||||
bool fullLog = false;
|
||||
if (args.Length > 1)
|
||||
{
|
||||
bool.TryParse(args[1], out fullLog);
|
||||
}
|
||||
debugLines = EventSet.GetDebugStatistics(filter: monsterEvent => monsterEvent.SpawnPosType.HasFlag(spawnType), fullLog: fullLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2392,8 +2398,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);
|
||||
@@ -2408,7 +2415,7 @@ namespace Barotrauma
|
||||
TextManager.CheckForDuplicates(args[0]);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) =>
|
||||
commands.Add(new Command("writetocsv|xmltocsv", "Writes the default language (English) to a .csv file.", (string[] args) =>
|
||||
{
|
||||
TextManager.WriteToCSV();
|
||||
NPCConversation.WriteToCSV();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -20,6 +21,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DisplayAsCompleted => State > 0 && requireRescue.None();
|
||||
public override bool DisplayAsFailed => State == HostagesKilledState;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class AlienRuinMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => State > 0;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BeaconMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => State > 0;
|
||||
public override bool DisplayAsFailed => false;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CargoMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override string GetMissionRewardText(Submarine sub)
|
||||
{
|
||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub)));
|
||||
|
||||
@@ -20,5 +20,8 @@ namespace Barotrauma
|
||||
return descriptions[GameMain.Client.Character.TeamID == CharacterTeamType.Team1 ? 1 : 2];
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class EscortMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => State == 1;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class GoToMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class MineralMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -19,6 +19,15 @@ namespace Barotrauma
|
||||
|
||||
public virtual IEnumerable<Entity> HudIconTargets => Enumerable.Empty<Entity>();
|
||||
|
||||
/// <summary>
|
||||
/// Is the mission at a state at which the only thing left to do is to reach the end of the level?
|
||||
/// </summary>
|
||||
public abstract bool DisplayAsCompleted { get; }
|
||||
/// <summary>
|
||||
/// Is the mission at a state at which the mission cannot be completed anymore?
|
||||
/// </summary>
|
||||
public abstract bool DisplayAsFailed { get; }
|
||||
|
||||
public Color GetDifficultyColor()
|
||||
{
|
||||
int v = Difficulty ?? MissionPrefab.MinDifficulty;
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class MonsterMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => State > 0;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -6,6 +6,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class NestMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => State > 0 && !requireDelivery;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class PirateMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => State > 1;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class SalvageMission : Mission
|
||||
{
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -23,6 +22,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DisplayAsCompleted => false;
|
||||
public override bool DisplayAsFailed => false;
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
@@ -60,7 +62,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)
|
||||
{
|
||||
@@ -389,6 +389,12 @@ namespace Barotrauma
|
||||
DrawString(spriteBatch, new Vector2(10, 10),
|
||||
"FPS: " + Math.Round(GameMain.PerformanceCounter.AverageFramesPerSecond),
|
||||
Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
if (GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 1.0)
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(10, 25),
|
||||
$"Physics: {GameMain.CurrentUpdateRate}",
|
||||
(GameMain.CurrentUpdateRate < Timing.FixedUpdateRate) ? Color.Red : Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.ShowPerf)
|
||||
@@ -397,7 +403,7 @@ namespace Barotrauma
|
||||
DrawString(spriteBatch, new Vector2(300, y),
|
||||
"Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" +
|
||||
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
|
||||
GUI.Style.Green, Color.Black * 0.8f, font: SmallFont);
|
||||
Style.Green, Color.Black * 0.8f, font: SmallFont);
|
||||
y += 15;
|
||||
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Style.Green);
|
||||
y += 50;
|
||||
@@ -408,7 +414,6 @@ namespace Barotrauma
|
||||
Color.LightBlue, Color.Black * 0.8f, font: SmallFont);
|
||||
y += 15;
|
||||
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Color.LightBlue);
|
||||
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), maxValue: 20, color: Style.Red);
|
||||
y += 50;
|
||||
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
|
||||
{
|
||||
@@ -431,7 +436,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && !Submarine.Unloading && !(Screen.Selected is RoundSummaryScreen))
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(10, 25),
|
||||
"Physics: " + GameMain.World.UpdateTime,
|
||||
@@ -706,11 +711,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 +724,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 +764,8 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
additions.Enqueue(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -786,7 +791,7 @@ namespace Barotrauma
|
||||
component.Children.ForEach(c => RemoveFromUpdateList(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearUpdateList()
|
||||
@@ -900,7 +905,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUIMessageBox.VisibleBox.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -941,7 +946,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 +972,7 @@ namespace Barotrauma
|
||||
return MouseOn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static CursorState UpdateMouseCursorState(GUIComponent c)
|
||||
{
|
||||
lock (mutex)
|
||||
@@ -994,7 +999,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (Wire.DraggingWire != null) { return CursorState.Dragging; }
|
||||
}
|
||||
|
||||
|
||||
if (c == null || c is GUICustomComponent)
|
||||
{
|
||||
switch (Screen.Selected)
|
||||
@@ -1027,7 +1032,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (c != null && c.Visible)
|
||||
{
|
||||
if (c.AlwaysOverrideCursor) { return c.HoverCursor; }
|
||||
@@ -1036,20 +1041,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 +1089,7 @@ namespace Barotrauma
|
||||
{
|
||||
// Health menus
|
||||
if (character.CharacterHealth.MouseOnElement) { return CursorState.Hand; }
|
||||
|
||||
|
||||
if (character.SelectedCharacter != null)
|
||||
{
|
||||
if (character.SelectedCharacter.CharacterHealth.MouseOnElement)
|
||||
@@ -1096,7 +1101,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 +1135,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 +1143,7 @@ namespace Barotrauma
|
||||
component.MouseRect.Contains(PlayerInput.MousePosition) :
|
||||
component.Rect.Contains(PlayerInput.MousePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1153,8 +1158,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 +1168,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 +1213,7 @@ namespace Barotrauma
|
||||
{
|
||||
debugDrawMetadataOffset--;
|
||||
}
|
||||
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Down))
|
||||
{
|
||||
debugDrawMetadataOffset++;
|
||||
@@ -1240,17 +1245,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 +1289,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)
|
||||
@@ -1349,7 +1356,7 @@ namespace Barotrauma
|
||||
|
||||
#region Element drawing
|
||||
|
||||
private static List<float> usedIndicatorAngles = new List<float>();
|
||||
private static readonly List<float> usedIndicatorAngles = new List<float>();
|
||||
|
||||
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
|
||||
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
|
||||
@@ -1628,7 +1635,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 +1654,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 +1663,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 +1676,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 +1777,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 +1887,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 +1898,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 +1998,7 @@ namespace Barotrauma
|
||||
if (i == 0)
|
||||
numberInput.IntValue = value.X;
|
||||
else
|
||||
numberInput.IntValue = value.Y;
|
||||
numberInput.IntValue = value.Y;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
@@ -2028,6 +2035,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 +2068,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 +2253,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 +2373,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);
|
||||
@@ -2397,6 +2440,11 @@ namespace Barotrauma
|
||||
private static bool TogglePauseMenu(GUIButton button, object obj)
|
||||
{
|
||||
pauseMenuOpen = !pauseMenuOpen;
|
||||
if (!pauseMenuOpen && PauseMenu != null)
|
||||
{
|
||||
PauseMenu.RectTransform.Parent = null;
|
||||
PauseMenu = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2448,7 +2496,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)
|
||||
|
||||
@@ -22,13 +22,14 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Instance.ResolutionChanged += RecalculateSize;
|
||||
}
|
||||
_instance.ItemComponentHolder = new GUIFrame(new RectTransform(Vector2.One, _instance, Anchor.Center)).RectTransform;
|
||||
_instance.ChildrenChanged += OnChildrenChanged;
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public RectTransform ItemComponentHolder;
|
||||
//GUICanvas stores the children as weak references, to allow elements that we no longer need to get garbage collected
|
||||
private readonly List<WeakReference<RectTransform>> childrenWeakRef = new List<WeakReference<RectTransform>>();
|
||||
|
||||
private static Vector2 size => new Vector2(GameMain.GraphicsWidth / (float)GUI.UIWidth, 1f);
|
||||
|
||||
@@ -36,16 +37,41 @@ namespace Barotrauma
|
||||
|
||||
private enum ResizeAxis { Both = 0, X = 1, Y = 2 }
|
||||
|
||||
private static void OnChildrenChanged(RectTransform _)
|
||||
{
|
||||
//add weak reference if we don't have one yet
|
||||
foreach (var child in _instance.Children)
|
||||
{
|
||||
if (!_instance.childrenWeakRef.Any(c => c.TryGetTarget(out var existingChild) && existingChild == child))
|
||||
{
|
||||
_instance.childrenWeakRef.Add(new WeakReference<RectTransform>(child));
|
||||
}
|
||||
}
|
||||
//get rid of strong references
|
||||
_instance.children.Clear();
|
||||
//remove dead children
|
||||
for (int i = _instance.childrenWeakRef.Count - 2; i >= 0; i--)
|
||||
{
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out var child) || child.Parent != _instance)
|
||||
{
|
||||
_instance.childrenWeakRef.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn public, if there is a need to call this manually.
|
||||
private static void RecalculateSize()
|
||||
{
|
||||
Vector2 recalculatedSize = size;
|
||||
|
||||
// Scale children that are supposed to encompass the whole screen so that they are properly scaled on ultrawide as well
|
||||
for (int i = 0; i < Instance.Children.Count(); i++)
|
||||
for (int i = 0; i < Instance.childrenWeakRef.Count; i++)
|
||||
{
|
||||
RectTransform target = Instance.GetChild(i);
|
||||
if (target == null || target.RelativeSize.X < 1 && target.RelativeSize.Y < 1) continue;
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out RectTransform target) || target == null) { continue; };
|
||||
|
||||
_instance.children.Add(target);
|
||||
|
||||
if (target.RelativeSize.X < 1 && target.RelativeSize.Y < 1) { continue; }
|
||||
|
||||
ResizeAxis axis;
|
||||
|
||||
@@ -80,6 +106,7 @@ namespace Barotrauma
|
||||
|
||||
Instance.Resize(size, resizeChildren: true);
|
||||
Instance.GetAllChildren().Select(c => c.GUIComponent as GUITextBlock).ForEach(t => t?.SetTextPos());
|
||||
_instance.children.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1007,8 +1019,10 @@ namespace Barotrauma
|
||||
case "gridtext":
|
||||
LoadGridText(element, parent);
|
||||
return null;
|
||||
case "conditional":
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("Loading GUI component \""+element.Name+"\" from XML is not implemented.");
|
||||
throw new NotImplementedException("Loading GUI component \"" + element.Name + "\" from XML is not implemented.");
|
||||
}
|
||||
|
||||
if (component != null)
|
||||
@@ -1079,6 +1093,29 @@ namespace Barotrauma
|
||||
var maxVersion = new Version(attribute.Value);
|
||||
if (GameMain.Version > maxVersion) { return false; }
|
||||
break;
|
||||
case "buildconfiguration":
|
||||
switch (attribute.Value.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "debug":
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
case "unstable":
|
||||
#if UNSTABLE
|
||||
return true;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
case "release":
|
||||
#if !DEBUG && !UNSTABLE
|
||||
return true;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -362,6 +362,14 @@ namespace Barotrauma
|
||||
RectTransform.ScaleChanged += () => dimensionsNeedsRecalculation = true;
|
||||
RectTransform.SizeChanged += () => dimensionsNeedsRecalculation = true;
|
||||
UpdateDimensions();
|
||||
|
||||
rectT.ChildrenChanged += CheckForChildren;
|
||||
}
|
||||
|
||||
private void CheckForChildren(RectTransform rectT)
|
||||
{
|
||||
if (rectT == ScrollBar.RectTransform || rectT == Content.RectTransform || rectT == ContentBackground.RectTransform) { return; }
|
||||
throw new InvalidOperationException($"Children were added to {nameof(GUIListBox)}, Add them to {nameof(GUIListBox)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
public void UpdateDimensions()
|
||||
@@ -431,7 +439,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < Content.CountChildren; i++)
|
||||
{
|
||||
GUIComponent child = Content.GetChild(i);
|
||||
if (!child.Visible) { continue; }
|
||||
if (child == null || !child.Visible) { continue; }
|
||||
if (RectTransform != null)
|
||||
{
|
||||
callback(i, new Point(x, y));
|
||||
@@ -837,7 +845,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();
|
||||
@@ -613,6 +618,7 @@ namespace Barotrauma
|
||||
|
||||
public bool Close(GUIButton button, object obj)
|
||||
{
|
||||
RectTransform.Parent = null;
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -80,6 +80,8 @@ namespace Barotrauma
|
||||
private Vector2 selectionEndPos;
|
||||
private Vector2 selectionRectSize;
|
||||
|
||||
private GUICustomComponent caretAndSelectionRenderer;
|
||||
|
||||
private bool mouseHeldInside;
|
||||
|
||||
private readonly Memento<string> memento = new Memento<string>();
|
||||
@@ -188,8 +190,7 @@ namespace Barotrauma
|
||||
}
|
||||
set
|
||||
{
|
||||
base.ToolTip = value;
|
||||
textBlock.ToolTip = value;
|
||||
base.ToolTip = textBlock.ToolTip = caretAndSelectionRenderer.ToolTip = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +279,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)
|
||||
|
||||
1063
Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs
Normal file
1063
Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -58,7 +58,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<RectTransform> children = new List<RectTransform>();
|
||||
protected readonly List<RectTransform> children = new List<RectTransform>();
|
||||
public IEnumerable<RectTransform> Children => children;
|
||||
|
||||
public int CountChildren => children.Count;
|
||||
@@ -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)
|
||||
|
||||
@@ -43,36 +43,42 @@ namespace Barotrauma
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh, needsSellingFromSubRefresh, needsItemsToSellFromSubRefresh;
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
private bool hadPermissions;
|
||||
|
||||
private Dictionary<ItemPrefab, int> OwnedItems { get; } = new Dictionary<ItemPrefab, int>();
|
||||
|
||||
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
|
||||
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
|
||||
private int PlayerMoney => campaignUI.Campaign.Money;
|
||||
private bool HasPermissions => campaignUI.Campaign.AllowedToManageCampaign();
|
||||
|
||||
private bool IsBuying => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => true,
|
||||
StoreTab.Sell => false,
|
||||
StoreTab.SellFromSub => false,
|
||||
StoreTab.SellSub => false,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
private GUIListBox ActiveShoppingCrateList => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => shoppingCrateBuyList,
|
||||
StoreTab.Sell => shoppingCrateSellList,
|
||||
StoreTab.SellFromSub => shoppingCrateSellFromSubList,
|
||||
StoreTab.SellSub => shoppingCrateSellFromSubList,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
private bool IsTabUnavailable(StoreTab tab) => !tabLists.ContainsKey(tab);
|
||||
|
||||
public enum StoreTab
|
||||
{
|
||||
/// <summary>
|
||||
/// Buy items from the store
|
||||
/// </summary>
|
||||
Buy,
|
||||
/// <summary>
|
||||
/// Sell items from the character inventory
|
||||
/// </summary>
|
||||
Sell,
|
||||
SellFromSub
|
||||
/// <summary>
|
||||
/// Sell items from the sub
|
||||
/// </summary>
|
||||
SellSub
|
||||
}
|
||||
|
||||
private enum SortingMethod
|
||||
@@ -84,11 +90,117 @@ namespace Barotrauma
|
||||
CategoryAsc
|
||||
}
|
||||
|
||||
#region Permissions
|
||||
|
||||
private bool hadPermissions, hadBuyPermissions, hadSellInventoryPermissions, hadSellSubPermissions;
|
||||
|
||||
private bool HasPermissions
|
||||
{
|
||||
get => GetPermissions();
|
||||
set => hadPermissions = value;
|
||||
}
|
||||
private bool HasBuyPermissions
|
||||
{
|
||||
get => HasPermissions || GetPermissions(StoreTab.Buy);
|
||||
set => hadBuyPermissions = value;
|
||||
}
|
||||
private bool HasSellInventoryPermissions
|
||||
{
|
||||
get => HasPermissions || GetPermissions(StoreTab.Sell);
|
||||
set => hadSellInventoryPermissions = value;
|
||||
}
|
||||
private bool HasSellSubPermissions
|
||||
{
|
||||
get => HasPermissions || GetPermissions(StoreTab.SellSub);
|
||||
set => hadSellSubPermissions = value;
|
||||
}
|
||||
|
||||
private bool GetPermissions(StoreTab? tab = null)
|
||||
{
|
||||
if (!tab.HasValue)
|
||||
{
|
||||
return campaignUI.Campaign.AllowedToManageCampaign() || campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.CampaignStore);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tab.Value switch
|
||||
{
|
||||
StoreTab.Buy => campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.BuyItems),
|
||||
StoreTab.Sell => campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.SellInventoryItems),
|
||||
StoreTab.SellSub => campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.SellSubItems),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePermissions(StoreTab? tab = null)
|
||||
{
|
||||
HasPermissions = GetPermissions();
|
||||
if (!tab.HasValue)
|
||||
{
|
||||
HasBuyPermissions = GetPermissions(StoreTab.Buy);
|
||||
HasSellInventoryPermissions = GetPermissions(StoreTab.Sell);
|
||||
HasSellSubPermissions = GetPermissions(StoreTab.SellSub);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tab.Value)
|
||||
{
|
||||
case StoreTab.Buy:
|
||||
HasBuyPermissions = GetPermissions(tab.Value);
|
||||
break;
|
||||
case StoreTab.Sell:
|
||||
HasSellInventoryPermissions = GetPermissions(tab.Value);
|
||||
break;
|
||||
case StoreTab.SellSub:
|
||||
HasSellSubPermissions = GetPermissions(tab.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasTabPermissions(StoreTab tab)
|
||||
{
|
||||
return tab switch
|
||||
{
|
||||
StoreTab.Buy => HasBuyPermissions,
|
||||
StoreTab.Sell => HasSellInventoryPermissions,
|
||||
StoreTab.SellSub => HasSellSubPermissions,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
private bool HasActiveTabPermissions()
|
||||
{
|
||||
return HasTabPermissions(activeTab);
|
||||
}
|
||||
|
||||
private bool HavePermissionsChanged(StoreTab? tab = null)
|
||||
{
|
||||
if (!tab.HasValue)
|
||||
{
|
||||
return hadPermissions != HasPermissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hadTabPermissions = tab.Value switch
|
||||
{
|
||||
StoreTab.Buy => hadBuyPermissions,
|
||||
StoreTab.Sell => hadSellInventoryPermissions,
|
||||
StoreTab.SellSub => hadSellSubPermissions,
|
||||
_ => false
|
||||
};
|
||||
return hadTabPermissions != HasTabPermissions(tab.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Store(CampaignUI campaignUI, GUIComponent parentComponent)
|
||||
{
|
||||
this.campaignUI = campaignUI;
|
||||
this.parentComponent = parentComponent;
|
||||
hadPermissions = HasPermissions;
|
||||
UpdatePermissions();
|
||||
CreateUI();
|
||||
campaignUI.Campaign.Map.OnLocationChanged += UpdateLocation;
|
||||
if (CurrentLocation?.Reputation != null)
|
||||
@@ -109,7 +221,7 @@ namespace Barotrauma
|
||||
|
||||
public void Refresh(bool updateOwned = true)
|
||||
{
|
||||
hadPermissions = HasPermissions;
|
||||
UpdatePermissions();
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshBuying(updateOwned: false);
|
||||
RefreshSelling(updateOwned: false);
|
||||
@@ -122,7 +234,7 @@ namespace Barotrauma
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshShoppingCrateBuyList();
|
||||
RefreshStoreBuyList();
|
||||
var hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasTabPermissions(StoreTab.Buy);
|
||||
storeBuyList.Enabled = hasPermissions;
|
||||
shoppingCrateBuyList.Enabled = hasPermissions;
|
||||
needsBuyingRefresh = false;
|
||||
@@ -133,7 +245,7 @@ namespace Barotrauma
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshShoppingCrateSellList();
|
||||
RefreshStoreSellList();
|
||||
var hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
|
||||
storeSellList.Enabled = hasPermissions;
|
||||
shoppingCrateSellList.Enabled = hasPermissions;
|
||||
needsSellingRefresh = false;
|
||||
@@ -141,13 +253,11 @@ namespace Barotrauma
|
||||
|
||||
private void RefreshSellingFromSub(bool updateOwned = true, bool updateItemsToSellFromSub = true)
|
||||
{
|
||||
if (IsTabUnavailable(StoreTab.SellFromSub)) { return; }
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
if (updateItemsToSellFromSub) RefreshItemsToSellFromSub();
|
||||
RefreshShoppingCrateSellFromSubList();
|
||||
RefreshStoreSellFromSubList();
|
||||
// TODO: Separate permissions from regular campaign permissions
|
||||
var hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasTabPermissions(StoreTab.SellSub);
|
||||
storeSellFromSubList.Enabled = hasPermissions;
|
||||
shoppingCrateSellFromSubList.Enabled = hasPermissions;
|
||||
needsSellingFromSubRefresh = false;
|
||||
@@ -261,7 +371,7 @@ namespace Barotrauma
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation.StoreCurrentBalance + buyTotal,
|
||||
StoreTab.Sell => CurrentLocation.StoreCurrentBalance - sellTotal,
|
||||
StoreTab.SellFromSub => CurrentLocation.StoreCurrentBalance - sellFromSubTotal,
|
||||
StoreTab.SellSub => CurrentLocation.StoreCurrentBalance - sellFromSubTotal,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
|
||||
@@ -325,10 +435,9 @@ namespace Barotrauma
|
||||
tabSortingMethods.Clear();
|
||||
foreach (StoreTab tab in tabs)
|
||||
{
|
||||
if (tab == StoreTab.SellFromSub && GameMain.IsMultiplayer) { continue; }
|
||||
string text = tab switch
|
||||
{
|
||||
StoreTab.SellFromSub => TextManager.Get("submarine"),
|
||||
StoreTab.SellSub => TextManager.Get("submarine"),
|
||||
_ => TextManager.Get("campaignstoretab." + tab)
|
||||
};
|
||||
var tabButton = new GUIButton(new RectTransform(new Vector2(1.0f / (tabs.Length + 1), 1.0f), modeButtonContainer.RectTransform),
|
||||
@@ -456,16 +565,13 @@ namespace Barotrauma
|
||||
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
|
||||
tabLists.Add(StoreTab.Sell, storeSellList);
|
||||
|
||||
if (GameMain.IsSingleplayer)
|
||||
storeSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
storeSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList);
|
||||
tabLists.Add(StoreTab.SellFromSub, storeSellFromSubList);
|
||||
}
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList);
|
||||
tabLists.Add(StoreTab.SellSub, storeSellFromSubList);
|
||||
|
||||
// Shopping Crate ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -526,10 +632,7 @@ namespace Barotrauma
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
}
|
||||
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
|
||||
var relevantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -569,16 +672,16 @@ namespace Barotrauma
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(0.35f, 1.0f), buttonContainer.RectTransform), TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ClickSound = GUISoundType.DecreaseQuantity,
|
||||
Enabled = HasPermissions,
|
||||
Enabled = HasActiveTabPermissions(),
|
||||
ForceUpperCase = true,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (!HasPermissions) { return false; }
|
||||
if (!HasActiveTabPermissions()) { return false; }
|
||||
var itemsToRemove = activeTab switch
|
||||
{
|
||||
StoreTab.Buy => new List<PurchasedItem>(CargoManager.ItemsInBuyCrate),
|
||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
||||
StoreTab.SellFromSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
itemsToRemove.ForEach(i => ClearFromShoppingCrate(i));
|
||||
@@ -637,7 +740,6 @@ namespace Barotrauma
|
||||
|
||||
private void ChangeStoreTab(StoreTab tab)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
activeTab = tab;
|
||||
foreach (GUIButton tabButton in storeTabButtons)
|
||||
{
|
||||
@@ -680,7 +782,7 @@ namespace Barotrauma
|
||||
}
|
||||
shoppingCrateSellList.Visible = true;
|
||||
break;
|
||||
case StoreTab.SellFromSub:
|
||||
case StoreTab.SellSub:
|
||||
storeBuyList.Visible = false;
|
||||
storeSellList.Visible = false;
|
||||
if (storeSellFromSubList != null)
|
||||
@@ -699,7 +801,6 @@ namespace Barotrauma
|
||||
|
||||
private void FilterStoreItems(MapEntityCategory? category, string filter)
|
||||
{
|
||||
if (IsTabUnavailable(activeTab)) { return; }
|
||||
selectedItemCategory = category;
|
||||
var list = tabLists[activeTab];
|
||||
filter = filter?.ToLower();
|
||||
@@ -733,7 +834,7 @@ namespace Barotrauma
|
||||
float prevBuyListScroll = storeBuyList.BarScroll;
|
||||
float prevShoppingCrateScroll = shoppingCrateBuyList.BarScroll;
|
||||
|
||||
bool hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasBuyPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
int dailySpecialCount = CurrentLocation?.DailySpecials.Count() ?? 3;
|
||||
@@ -816,7 +917,7 @@ namespace Barotrauma
|
||||
{
|
||||
float prevSellListScroll = storeSellList.BarScroll;
|
||||
float prevShoppingCrateScroll = shoppingCrateSellList.BarScroll;
|
||||
bool hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
if ((storeRequestedGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
||||
@@ -894,7 +995,7 @@ namespace Barotrauma
|
||||
{
|
||||
float prevSellListScroll = storeSellFromSubList.BarScroll;
|
||||
float prevShoppingCrateScroll = shoppingCrateSellFromSubList.BarScroll;
|
||||
bool hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasSellSubPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
if ((storeRequestedSubGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
||||
@@ -938,12 +1039,12 @@ namespace Barotrauma
|
||||
if (itemFrame == null)
|
||||
{
|
||||
var parentComponent = isRequestedGood ? storeRequestedSubGoodGroup : storeSellFromSubList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), parentComponent, StoreTab.SellFromSub, forceDisable: !hasPermissions);
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), parentComponent, StoreTab.SellSub, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = itemQuantity;
|
||||
SetQuantityLabelText(StoreTab.SellFromSub, itemFrame);
|
||||
SetQuantityLabelText(StoreTab.SellSub, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetPriceGetters(itemFrame, false);
|
||||
}
|
||||
@@ -961,8 +1062,8 @@ namespace Barotrauma
|
||||
removedItemFrames.AddRange(storeRequestedSubGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (activeTab == StoreTab.SellFromSub) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.SellFromSub);
|
||||
if (activeTab == StoreTab.SellSub) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.SellSub);
|
||||
|
||||
storeSellFromSubList.BarScroll = prevSellListScroll;
|
||||
shoppingCrateSellFromSubList.BarScroll = prevShoppingCrateScroll;
|
||||
@@ -1062,17 +1163,14 @@ namespace Barotrauma
|
||||
|
||||
private void RefreshShoppingCrateList(List<PurchasedItem> items, GUIListBox listBox, StoreTab tab)
|
||||
{
|
||||
bool hasPermissions = HasPermissions;
|
||||
bool hasPermissions = HasTabPermissions(tab);
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
int totalPrice = 0;
|
||||
foreach (PurchasedItem item in items)
|
||||
{
|
||||
PriceInfo priceInfo = item.ItemPrefab.GetPriceInfo(CurrentLocation);
|
||||
if (priceInfo == null) { continue; }
|
||||
|
||||
var itemFrame = listBox.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab.Identifier == item.ItemPrefab.Identifier);
|
||||
if (!(item.ItemPrefab.GetPriceInfo(CurrentLocation) is { } priceInfo)) { continue; }
|
||||
GUINumberInput numInput = null;
|
||||
if (itemFrame == null)
|
||||
if (!(listBox.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab.Identifier == item.ItemPrefab.Identifier) is { } itemFrame))
|
||||
{
|
||||
itemFrame = CreateItemFrame(item, listBox, tab, forceDisable: !hasPermissions);
|
||||
numInput = itemFrame.FindChild(c => c is GUINumberInput, recursive: true) as GUINumberInput;
|
||||
@@ -1100,10 +1198,21 @@ namespace Barotrauma
|
||||
}
|
||||
suppressBuySell = false;
|
||||
|
||||
var price = tab == StoreTab.Buy ?
|
||||
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
|
||||
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
totalPrice += item.Quantity * price;
|
||||
try
|
||||
{
|
||||
int price = tab switch
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||
StoreTab.Sell => CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||
StoreTab.SellSub => CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
totalPrice += item.Quantity * price;
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error getting item price: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
}
|
||||
}
|
||||
|
||||
var removedItemFrames = listBox.Content.Children.Except(existingItemFrames).ToList();
|
||||
@@ -1119,7 +1228,7 @@ namespace Barotrauma
|
||||
case StoreTab.Sell:
|
||||
sellTotal = totalPrice;
|
||||
break;
|
||||
case StoreTab.SellFromSub:
|
||||
case StoreTab.SellSub:
|
||||
sellFromSubTotal = totalPrice;
|
||||
break;
|
||||
}
|
||||
@@ -1135,7 +1244,7 @@ namespace Barotrauma
|
||||
|
||||
private void RefreshShoppingCrateSellList() => RefreshShoppingCrateList(CargoManager.ItemsInSellCrate, shoppingCrateSellList, StoreTab.Sell);
|
||||
|
||||
private void RefreshShoppingCrateSellFromSubList() => RefreshShoppingCrateList(CargoManager.ItemsInSellFromSubCrate, shoppingCrateSellFromSubList, StoreTab.SellFromSub);
|
||||
private void RefreshShoppingCrateSellFromSubList() => RefreshShoppingCrateList(CargoManager.ItemsInSellFromSubCrate, shoppingCrateSellFromSubList, StoreTab.SellSub);
|
||||
|
||||
private void SortItems(GUIListBox list, SortingMethod sortingMethod)
|
||||
{
|
||||
@@ -1286,14 +1395,12 @@ namespace Barotrauma
|
||||
|
||||
private void SortItems(StoreTab tab, SortingMethod sortingMethod)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
tabSortingMethods[tab] = sortingMethod;
|
||||
SortItems(tabLists[tab], sortingMethod);
|
||||
}
|
||||
|
||||
private void SortItems(StoreTab tab)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
SortItems(tab, tabSortingMethods[tab]);
|
||||
}
|
||||
|
||||
@@ -1301,12 +1408,6 @@ namespace Barotrauma
|
||||
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, GUIComponent parentComponent, StoreTab containingTab, bool forceDisable = false)
|
||||
{
|
||||
var tooltip = pi.ItemPrefab.Name;
|
||||
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
|
||||
{
|
||||
tooltip += "\n" + pi.ItemPrefab.Description;
|
||||
}
|
||||
|
||||
GUIListBox parentListBox = parentComponent as GUIListBox;
|
||||
int width = 0;
|
||||
RectTransform parent = null;
|
||||
@@ -1320,7 +1421,11 @@ namespace Barotrauma
|
||||
width = parentComponent.Rect.Width;
|
||||
parent = parentComponent.RectTransform;
|
||||
}
|
||||
|
||||
string tooltip = pi.ItemPrefab.Name;
|
||||
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
|
||||
{
|
||||
tooltip += $"\n{pi.ItemPrefab.Description}";
|
||||
}
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, (int)(GUI.yScale * 80)), parent: parent), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = tooltip,
|
||||
@@ -1338,8 +1443,7 @@ namespace Barotrauma
|
||||
var iconRelativeWidth = 0.0f;
|
||||
var priceAndButtonRelativeWidth = 1.0f - nameAndIconRelativeWidth;
|
||||
|
||||
Sprite itemIcon = pi.ItemPrefab.InventoryIcon ?? pi.ItemPrefab.sprite;
|
||||
if (itemIcon != null)
|
||||
if ((pi.ItemPrefab.InventoryIcon ?? pi.ItemPrefab.sprite) is { } itemIcon)
|
||||
{
|
||||
iconRelativeWidth = (0.9f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
GUIImage img = new GUIImage(new RectTransform(new Vector2(iconRelativeWidth, 0.9f), mainGroup.RectTransform), itemIcon, scaleToFit: true)
|
||||
@@ -1425,7 +1529,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (suppressBuySell) { return; }
|
||||
PurchasedItem purchasedItem = numberInput.UserData as PurchasedItem;
|
||||
if (!HasPermissions)
|
||||
if (!HasActiveTabPermissions())
|
||||
{
|
||||
numberInput.IntValue = purchasedItem.Quantity;
|
||||
return;
|
||||
@@ -1528,11 +1632,16 @@ namespace Barotrauma
|
||||
OwnedItems.Clear();
|
||||
|
||||
// Add items on the sub(s)
|
||||
Submarine.MainSub?.GetItems(true)
|
||||
.Where(i => i.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached) &&
|
||||
i.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null)) &&
|
||||
ItemAndAllContainersInteractable(i))
|
||||
.ForEach(i => AddToOwnedItems(i.Prefab));
|
||||
if (Submarine.MainSub?.GetItems(true) is List<Item> subItems)
|
||||
{
|
||||
foreach (var subItem in subItems)
|
||||
{
|
||||
if (!subItem.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { continue; }
|
||||
if (!subItem.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { continue; }
|
||||
if (!ItemAndAllContainersInteractable(subItem)) { continue; }
|
||||
AddToOwnedItems(subItem.Prefab);
|
||||
}
|
||||
}
|
||||
|
||||
// Add items in character inventories
|
||||
foreach (var item in Item.ItemList)
|
||||
@@ -1574,8 +1683,9 @@ namespace Barotrauma
|
||||
|
||||
private void SetItemFrameStatus(GUIComponent itemFrame, bool enabled)
|
||||
{
|
||||
if (itemFrame == null || !(itemFrame.UserData is PurchasedItem pi)) { return; }
|
||||
|
||||
if (!(itemFrame?.UserData is PurchasedItem pi)) { return; }
|
||||
bool refreshFrameStatus = !pi.IsStoreComponentEnabled.HasValue || pi.IsStoreComponentEnabled.Value != enabled;
|
||||
if (!refreshFrameStatus) { return; }
|
||||
if (itemFrame.FindChild("icon", recursive: true) is GUIImage icon)
|
||||
{
|
||||
if (pi.ItemPrefab?.InventoryIcon != null)
|
||||
@@ -1587,14 +1697,11 @@ namespace Barotrauma
|
||||
icon.Color = pi.ItemPrefab.SpriteColor * (enabled ? 1.0f : 0.5f);
|
||||
}
|
||||
};
|
||||
|
||||
var color = Color.White * (enabled ? 1.0f : 0.5f);
|
||||
|
||||
if (itemFrame.FindChild("name", recursive: true) is GUITextBlock name)
|
||||
{
|
||||
name.TextColor = color;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("quantitylabel", recursive: true) is GUITextBlock qty)
|
||||
{
|
||||
qty.TextColor = color;
|
||||
@@ -1603,25 +1710,21 @@ namespace Barotrauma
|
||||
{
|
||||
numberInput.Enabled = enabled;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock ownedBlock)
|
||||
{
|
||||
ownedBlock.TextColor = color;
|
||||
}
|
||||
|
||||
var isDiscounted = false;
|
||||
bool isDiscounted = false;
|
||||
if (itemFrame.FindChild("undiscountedprice", recursive: true) is GUITextBlock undiscountedPriceBlock)
|
||||
{
|
||||
undiscountedPriceBlock.TextColor = color;
|
||||
undiscountedPriceBlock.Strikethrough.Color = color;
|
||||
isDiscounted = true;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock priceBlock)
|
||||
{
|
||||
priceBlock.TextColor = isDiscounted ? storeSpecialColor * (enabled ? 1.0f : 0.5f) : color;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("addbutton", recursive: true) is GUIButton addButton)
|
||||
{
|
||||
addButton.Enabled = enabled;
|
||||
@@ -1630,6 +1733,8 @@ namespace Barotrauma
|
||||
{
|
||||
removeButton.Enabled = enabled;
|
||||
}
|
||||
pi.IsStoreComponentEnabled = enabled;
|
||||
itemFrame.UserData = pi;
|
||||
}
|
||||
|
||||
private void SetQuantityLabelText(StoreTab mode, GUIComponent itemFrame)
|
||||
@@ -1664,14 +1769,22 @@ namespace Barotrauma
|
||||
|
||||
private int GetMaxAvailable(ItemPrefab itemPrefab, StoreTab mode)
|
||||
{
|
||||
var list = mode switch
|
||||
List<PurchasedItem> list = null;
|
||||
try
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation.StoreStock,
|
||||
StoreTab.Sell => itemsToSell,
|
||||
StoreTab.SellFromSub => itemsToSellFromSub,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
if (list.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem item)
|
||||
list = mode switch
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation?.StoreStock,
|
||||
StoreTab.Sell => itemsToSell,
|
||||
StoreTab.SellSub => itemsToSellFromSub,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error getting item availability: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
}
|
||||
if (list != null && list.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem item)
|
||||
{
|
||||
if (mode == StoreTab.Buy)
|
||||
{
|
||||
@@ -1691,8 +1804,8 @@ namespace Barotrauma
|
||||
|
||||
private bool ModifyBuyQuantity(PurchasedItem item, int quantity)
|
||||
{
|
||||
if (item == null || item.ItemPrefab == null) { return false; }
|
||||
if (!HasPermissions) { return false; }
|
||||
if (item?.ItemPrefab == null) { return false; }
|
||||
if (!HasBuyPermissions) { return false; }
|
||||
if (quantity > 0)
|
||||
{
|
||||
var itemInCrate = CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
||||
@@ -1703,13 +1816,13 @@ namespace Barotrauma
|
||||
}
|
||||
CargoManager.ModifyItemQuantityInBuyCrate(item.ItemPrefab, quantity);
|
||||
GameMain.Client?.SendCampaignState();
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ModifySellQuantity(PurchasedItem item, int quantity)
|
||||
{
|
||||
if (item == null || item.ItemPrefab == null) { return false; }
|
||||
if (!HasPermissions) { return false; }
|
||||
if (item?.ItemPrefab == null) { return false; }
|
||||
if (!HasSellInventoryPermissions) { return false; }
|
||||
if (quantity > 0)
|
||||
{
|
||||
// Make sure there's enough available to sell
|
||||
@@ -1718,45 +1831,68 @@ namespace Barotrauma
|
||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.Sell)) { return false; }
|
||||
}
|
||||
CargoManager.ModifyItemQuantityInSellCrate(item.ItemPrefab, quantity);
|
||||
//GameMain.Client?.SendCampaignState();
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ModifySellFromSubQuantity(PurchasedItem item, int quantity)
|
||||
{
|
||||
if (item == null || item.ItemPrefab == null) { return false; }
|
||||
if (!HasPermissions) { return false; }
|
||||
if (item?.ItemPrefab == null) { return false; }
|
||||
if (!HasSellSubPermissions) { return false; }
|
||||
if (quantity > 0)
|
||||
{
|
||||
// Make sure there's enough available to sell
|
||||
var itemToSell = CargoManager.ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
||||
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.SellFromSub)) { return false; }
|
||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.SellSub)) { return false; }
|
||||
}
|
||||
CargoManager.ModifyItemQuantityInSellFromSubCrate(item.ItemPrefab, quantity);
|
||||
// TODO: GameMain.Client?.SendCampaignState();
|
||||
return false;
|
||||
GameMain.Client?.SendCampaignState();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool AddToShoppingCrate(PurchasedItem item, int quantity = 1) => activeTab switch
|
||||
private bool AddToShoppingCrate(PurchasedItem item, int quantity = 1)
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, quantity),
|
||||
StoreTab.SellFromSub => ModifySellFromSubQuantity(item, quantity),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
if (item == null) { return false; }
|
||||
try
|
||||
{
|
||||
return activeTab switch
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, quantity),
|
||||
StoreTab.SellSub => ModifySellFromSubQuantity(item, quantity),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error adding an item to the shopping crate: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ClearFromShoppingCrate(PurchasedItem item) => activeTab switch
|
||||
private bool ClearFromShoppingCrate(PurchasedItem item)
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, -item.Quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, -item.Quantity),
|
||||
StoreTab.SellFromSub => ModifySellFromSubQuantity(item, -item.Quantity),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
if (item == null) { return false; }
|
||||
try
|
||||
{
|
||||
return activeTab switch
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, -item.Quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, -item.Quantity),
|
||||
StoreTab.SellSub => ModifySellFromSubQuantity(item, -item.Quantity),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error clearing the shopping crate: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool BuyItems()
|
||||
{
|
||||
if (!HasPermissions) { return false; }
|
||||
if (!HasBuyPermissions) { return false; }
|
||||
|
||||
var itemsToPurchase = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
||||
var itemsToRemove = new List<PurchasedItem>();
|
||||
@@ -1788,15 +1924,24 @@ namespace Barotrauma
|
||||
|
||||
private bool SellItems()
|
||||
{
|
||||
if (!HasPermissions) { return false; }
|
||||
var itemsToSell = activeTab switch
|
||||
if (!HasActiveTabPermissions()) { return false; }
|
||||
List<PurchasedItem> itemsToSell;
|
||||
try
|
||||
{
|
||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
||||
StoreTab.SellFromSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
itemsToSell = activeTab switch
|
||||
{
|
||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
||||
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error confirming the store transaction: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
return false;
|
||||
}
|
||||
var itemsToRemove = new List<PurchasedItem>();
|
||||
var totalValue = 0;
|
||||
int totalValue = 0;
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
{
|
||||
if (item?.ItemPrefab?.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
|
||||
@@ -1811,11 +1956,7 @@ namespace Barotrauma
|
||||
itemsToRemove.ForEach(i => itemsToSell.Remove(i));
|
||||
if (itemsToSell.None() || totalValue > CurrentLocation.StoreCurrentBalance) { return false; }
|
||||
CargoManager.SellItems(itemsToSell, activeTab);
|
||||
if (activeTab == StoreTab.Sell)
|
||||
{
|
||||
// TODO: Implement selling sub items in multiplayer
|
||||
GameMain.Client?.SendCampaignState();
|
||||
}
|
||||
GameMain.Client?.SendCampaignState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1831,7 +1972,7 @@ namespace Barotrauma
|
||||
int total = activeTab switch
|
||||
{
|
||||
StoreTab.Sell => sellTotal,
|
||||
StoreTab.SellFromSub => sellFromSubTotal,
|
||||
StoreTab.SellSub => sellFromSubTotal,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
shoppingCrateTotal.Text = GetCurrencyFormatted(total);
|
||||
@@ -1863,21 +2004,29 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConfirmButtonStatus() => confirmButton.Enabled =
|
||||
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any() &&
|
||||
activeTab switch
|
||||
{
|
||||
StoreTab.Buy => buyTotal <= PlayerMoney,
|
||||
StoreTab.Sell => CurrentLocation != null && sellTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
StoreTab.SellFromSub => CurrentLocation != null && sellFromSubTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
private void SetConfirmButtonStatus()
|
||||
{
|
||||
confirmButton.Enabled =
|
||||
HasActiveTabPermissions() &&
|
||||
ActiveShoppingCrateList.Content.RectTransform.Children.Any() &&
|
||||
activeTab switch
|
||||
{
|
||||
StoreTab.Buy => buyTotal <= PlayerMoney,
|
||||
StoreTab.Sell => CurrentLocation != null && sellTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
StoreTab.SellSub => CurrentLocation != null && sellFromSubTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
private void SetClearAllButtonStatus() => clearAllButton.Enabled =
|
||||
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any();
|
||||
private void SetClearAllButtonStatus()
|
||||
{
|
||||
clearAllButton.Enabled =
|
||||
HasActiveTabPermissions() &&
|
||||
ActiveShoppingCrateList.Content.RectTransform.Children.Any();
|
||||
}
|
||||
|
||||
private float ownedItemsUpdateTimer = 0.0f, sellableItemsFromSubUpdateTimer = 0.0f;
|
||||
private readonly float timerUpdateInterval = 1.5f;
|
||||
private const float timerUpdateInterval = 1.5f;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
@@ -1914,10 +2063,10 @@ namespace Barotrauma
|
||||
|
||||
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
|
||||
if (needsItemsToSellFromSubRefresh) { RefreshItemsToSellFromSub(); }
|
||||
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsBuyingRefresh) { RefreshBuying(); }
|
||||
if (needsSellingRefresh) { RefreshSelling(); }
|
||||
if (needsSellingFromSubRefresh) { RefreshSellingFromSub(updateItemsToSellFromSub: sellableItemsFromSubUpdateTimer > 0.0f); }
|
||||
if (needsRefresh || HavePermissionsChanged()) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsBuyingRefresh || HavePermissionsChanged(StoreTab.Buy)) { RefreshBuying(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsSellingRefresh || HavePermissionsChanged(StoreTab.Sell)) { RefreshSelling(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsSellingFromSubRefresh || HavePermissionsChanged(StoreTab.SellSub)) { RefreshSellingFromSub(updateItemsToSellFromSub: sellableItemsFromSubUpdateTimer > 0.0f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
public enum InfoFrameTab { Crew, Mission, Reputation, Traitor, Submarine, Talents };
|
||||
public static InfoFrameTab selectedTab;
|
||||
public static InfoFrameTab SelectedTab { get; private set; }
|
||||
private GUIFrame infoFrame, contentFrame;
|
||||
|
||||
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
||||
@@ -129,9 +129,8 @@ namespace Barotrauma
|
||||
public TabMenu()
|
||||
{
|
||||
if (!initialized) { Initialize(); }
|
||||
|
||||
CreateInfoFrame(selectedTab);
|
||||
SelectInfoFrameTab(null, selectedTab);
|
||||
CreateInfoFrame(SelectedTab);
|
||||
SelectInfoFrameTab(SelectedTab);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
@@ -147,8 +146,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTab != InfoFrameTab.Crew) return;
|
||||
if (linkedGUIList == null) return;
|
||||
if (SelectedTab != InfoFrameTab.Crew) { return; }
|
||||
if (linkedGUIList == null) { return; }
|
||||
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
@@ -226,7 +225,7 @@ namespace Barotrauma
|
||||
{
|
||||
UserData = tab,
|
||||
ToolTip = TextManager.Get(textTag),
|
||||
OnClicked = SelectInfoFrameTab
|
||||
OnClicked = (btn, userData) => { SelectInfoFrameTab((InfoFrameTab)userData); return true; }
|
||||
};
|
||||
tabButtons.Add(newButton);
|
||||
return newButton;
|
||||
@@ -277,16 +276,16 @@ namespace Barotrauma
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null;
|
||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||
{
|
||||
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
||||
SelectInfoFrameTab(InfoFrameTab.Crew);
|
||||
}
|
||||
};
|
||||
|
||||
talentPointNotification = GameSession.CreateTalentIconNotification(talentsButton);
|
||||
}
|
||||
|
||||
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
||||
public void SelectInfoFrameTab(InfoFrameTab selectedTab)
|
||||
{
|
||||
selectedTab = (InfoFrameTab)userData;
|
||||
SelectedTab = selectedTab;
|
||||
|
||||
CreateInfoFrame(selectedTab);
|
||||
tabButtons.ForEach(tb => tb.Selected = (InfoFrameTab)tb.UserData == selectedTab);
|
||||
@@ -300,7 +299,7 @@ namespace Barotrauma
|
||||
CreateMissionInfo(infoFrameHolder);
|
||||
break;
|
||||
case InfoFrameTab.Reputation:
|
||||
if (GameMain.GameSession.RoundSummary != null && GameMain.GameSession.GameMode is CampaignMode campaignMode)
|
||||
if (GameMain.GameSession?.RoundSummary != null && GameMain.GameSession?.GameMode is CampaignMode campaignMode)
|
||||
{
|
||||
infoFrameHolder.ClearChildren();
|
||||
GUIFrame reputationFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrameHolder.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
@@ -308,9 +307,9 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case InfoFrameTab.Traitor:
|
||||
TraitorMissionPrefab traitorMission = GameMain.Client.TraitorMission;
|
||||
Character traitor = GameMain.Client.Character;
|
||||
if (traitor == null || traitorMission == null) return false;
|
||||
TraitorMissionPrefab traitorMission = GameMain.Client?.TraitorMission;
|
||||
Character traitor = GameMain.Client?.Character;
|
||||
if (traitor == null || traitorMission == null) { return; }
|
||||
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
|
||||
break;
|
||||
case InfoFrameTab.Submarine:
|
||||
@@ -320,8 +319,6 @@ namespace Barotrauma
|
||||
CreateTalentInfo(infoFrameHolder);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private const float jobColumnWidthPercentage = 0.138f;
|
||||
@@ -755,7 +752,7 @@ namespace Barotrauma
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
if (GameMain.NetworkMember == null)
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GUIComponent preview = character.Info.CreateInfoFrame(background, false, null);
|
||||
}
|
||||
@@ -859,7 +856,7 @@ namespace Barotrauma
|
||||
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
|
||||
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
|
||||
|
||||
if (GameSession.IsTabMenuOpen && selectedTab == InfoFrameTab.Crew)
|
||||
if (GameSession.IsTabMenuOpen && SelectedTab == InfoFrameTab.Crew)
|
||||
{
|
||||
TabMenu instance = GameSession.TabMenuInstance;
|
||||
instance.AddLineToLog(msg, message.ChangeType);
|
||||
@@ -1023,13 +1020,15 @@ namespace Barotrauma
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);*/
|
||||
|
||||
new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
var icon = new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
{
|
||||
Color = mission.Prefab.IconColor,
|
||||
HoverColor = mission.Prefab.IconColor,
|
||||
SelectedColor = mission.Prefab.IconColor,
|
||||
CanBeFocused = false
|
||||
};
|
||||
UpdateMissionStateIcon(mission, icon);
|
||||
mission.OnMissionStateChanged += (mission) => UpdateMissionStateIcon(mission, icon);
|
||||
}
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionNameRichTextData, missionNameString, font: GUI.LargeFont);
|
||||
GUILayoutGroup difficultyIndicatorGroup = null;
|
||||
@@ -1066,6 +1065,33 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMissionStateIcon(Mission mission, GUIImage missionIcon)
|
||||
{
|
||||
if (mission == null || missionIcon == null) { return; }
|
||||
string style = string.Empty;
|
||||
if (mission.DisplayAsFailed)
|
||||
{
|
||||
style = "MissionFailedIcon";
|
||||
}
|
||||
else if (mission.DisplayAsCompleted)
|
||||
{
|
||||
style = "MissionCompletedIcon";
|
||||
}
|
||||
GUIImage stateIcon = missionIcon.GetChild<GUIImage>();
|
||||
if (string.IsNullOrEmpty(style))
|
||||
{
|
||||
if (stateIcon != null)
|
||||
{
|
||||
stateIcon.Visible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stateIcon ??= new GUIImage(new RectTransform(Vector2.One, missionIcon.RectTransform), style, scaleToFit: true);
|
||||
stateIcon.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTraitorInfo(GUIFrame infoFrame, TraitorMissionPrefab traitorMission, Character traitor)
|
||||
{
|
||||
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
@@ -1443,7 +1469,7 @@ namespace Barotrauma
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
|
||||
UpdateTalentButtons();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
@@ -1508,7 +1534,7 @@ namespace Barotrauma
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
|
||||
UpdateTalentButtons();
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
||||
@@ -1543,30 +1569,14 @@ 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()
|
||||
private void UpdateTalentInfo()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter?.Info == null) { return; }
|
||||
|
||||
bool unlockedAllTalents = HasUnlockedAllTalents(controlledCharacter);
|
||||
if (SelectedTab != InfoFrameTab.Talents) { return; }
|
||||
|
||||
bool unlockedAllTalents = controlledCharacter.HasUnlockedAllTalents();
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
@@ -1646,7 +1656,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentButtons();
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private bool ApplyTalentSelection(GUIButton guiButton, object userData)
|
||||
@@ -1660,63 +1670,14 @@ namespace Barotrauma
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentButtons();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnExperienceChanged(Character character)
|
||||
{
|
||||
if (character != Character.Controlled) { return; }
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private readonly StatTypes[] basicStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MaximumHealthMultiplier,
|
||||
StatTypes.MovementSpeed,
|
||||
StatTypes.SwimmingSpeed,
|
||||
StatTypes.RepairSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] combatStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MeleeAttackMultiplier,
|
||||
StatTypes.MeleeAttackSpeed,
|
||||
StatTypes.RangedAttackSpeed,
|
||||
StatTypes.TurretAttackSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] miscStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.ReputationGainMultiplier,
|
||||
StatTypes.MissionMoneyGainMultiplier,
|
||||
StatTypes.ExperienceGainMultiplier,
|
||||
StatTypes.MissionExperienceGainMultiplier,
|
||||
};
|
||||
|
||||
private void CreateCharacterSheet(GUILayoutGroup characterInfoColumn)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
CreateRow(basicStats);
|
||||
CreateRow(combatStats);
|
||||
CreateRow(miscStats);
|
||||
|
||||
void CreateRow(StatTypes[] statTypes)
|
||||
{
|
||||
GUILayoutGroup characterInfoRow = new GUILayoutGroup(new RectTransform(new Vector2(0.33f, 1.0f), characterInfoColumn.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopCenter);
|
||||
foreach (StatTypes statType in statTypes)
|
||||
{
|
||||
ShowStat(statType, characterInfoRow);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowStat(StatTypes statType, GUILayoutGroup characterInfoRow)
|
||||
{
|
||||
GUIFrame textInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), characterInfoRow.RectTransform, Anchor.TopCenter), style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), statType.ToString(), font: GUI.SmallFont, textAlignment: Alignment.TopLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), (int)(100f * (1 + controlledCharacter.GetStatValue(statType))) + "%", font: GUI.Font, textAlignment: Alignment.TopRight);
|
||||
}
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
internal class UpgradeStore
|
||||
{
|
||||
public readonly struct CategoryData
|
||||
@@ -168,6 +167,7 @@ namespace Barotrauma
|
||||
//TODO: move this somewhere else
|
||||
public static void UpdateCategoryList(GUIListBox categoryList, CampaignMode campaign, Submarine? drawnSubmarine, IEnumerable<UpgradeCategory> applicableCategories)
|
||||
{
|
||||
var subItems = GetSubItems();
|
||||
foreach (GUIComponent component in categoryList.Content.Children)
|
||||
{
|
||||
if (!(component.UserData is CategoryData data)) { continue; }
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma
|
||||
var customizeButton = component.FindChild("customizebutton", true);
|
||||
if (customizeButton != null)
|
||||
{
|
||||
customizeButton.Visible = HasSwappableItems(data.Category);
|
||||
customizeButton.Visible = HasSwappableItems(data.Category, subItems);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,6 +434,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= hullRepairCost)
|
||||
{
|
||||
Campaign.Money -= hullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
Campaign.PurchasedHullRepairs = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
@@ -468,6 +469,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
||||
{
|
||||
Campaign.Money -= itemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
Campaign.PurchasedItemRepairs = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
@@ -513,6 +515,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
||||
{
|
||||
Campaign.Money -= shuttleRetrieveCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
Campaign.PurchasedLostShuttles = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
@@ -717,16 +720,19 @@ namespace Barotrauma
|
||||
|
||||
private bool customizeTabOpen;
|
||||
|
||||
private static bool HasSwappableItems(UpgradeCategory category)
|
||||
private static bool HasSwappableItems(UpgradeCategory category, List<Item>? subItems = null)
|
||||
{
|
||||
if (Submarine.MainSub == null) { return false; }
|
||||
return Submarine.MainSub.GetItems(true).Any(i =>
|
||||
subItems ??= GetSubItems();
|
||||
return subItems.Any(i =>
|
||||
i.Prefab.SwappableItem != null &&
|
||||
!i.HiddenInGame && i.AllowSwapping &&
|
||||
(i.Prefab.SwappableItem.CanBeBought || ItemPrefab.Prefabs.Any(ip => ip.SwappableItem?.ReplacementOnUninstall == i.Prefab.Identifier)) &&
|
||||
Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && category.ItemTags.Any(t => i.HasTag(t)));
|
||||
}
|
||||
|
||||
private static List<Item> GetSubItems() => Submarine.MainSub?.GetItems(true) ?? new List<Item>();
|
||||
|
||||
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
||||
{
|
||||
if (selectedUpgradeCategoryLayout == null) { return; }
|
||||
@@ -1688,7 +1694,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());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static partial class GameAnalyticsManager
|
||||
static partial class GameAnalyticsManager
|
||||
{
|
||||
static partial void CreateConsentPrompt()
|
||||
{
|
||||
|
||||
@@ -32,6 +32,13 @@ namespace Barotrauma
|
||||
|
||||
public static PerformanceCounter PerformanceCounter;
|
||||
|
||||
private static Stopwatch performanceCounterTimer;
|
||||
private static int updateCount = 0;
|
||||
public static int CurrentUpdateRate
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static string[] ConsoleArguments;
|
||||
@@ -124,6 +131,12 @@ namespace Barotrauma
|
||||
|
||||
private bool exiting;
|
||||
|
||||
public static bool IsFirstLaunch
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static GameMain Instance
|
||||
{
|
||||
get;
|
||||
@@ -353,6 +366,8 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Item));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
performanceCounterTimer = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -441,8 +456,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;
|
||||
});
|
||||
|
||||
@@ -583,6 +598,18 @@ namespace Barotrauma
|
||||
{
|
||||
Steamworks.SteamFriends.OnGameRichPresenceJoinRequested += OnInvitedToGame;
|
||||
Steamworks.SteamFriends.OnGameLobbyJoinRequested += OnLobbyJoinRequested;
|
||||
|
||||
if (SteamManager.TryGetUnlockedAchievements(out List<Steamworks.Data.Achievement> achievements))
|
||||
{
|
||||
//check the achievements too, so we don't consider people who've played the game before this "gamelaunchcount" stat was added as being 1st-time-players
|
||||
//(people who have played previous versions, but not unlocked any achievements, will be incorrectly considered 1st-time-players, but that should be a small enough group to not skew the statistics)
|
||||
if (!achievements.Any() && SteamManager.GetStatInt("gamelaunchcount") <= 0)
|
||||
{
|
||||
IsFirstLaunch = true;
|
||||
GameAnalyticsManager.AddDesignEvent("FirstLaunch");
|
||||
}
|
||||
}
|
||||
SteamManager.IncrementStat("gamelaunchcount", 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -700,11 +727,10 @@ namespace Barotrauma
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds;
|
||||
int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step);
|
||||
if (Timing.Accumulator > Timing.Step * 6.0)
|
||||
if (Timing.Accumulator > Timing.AccumulatorMax)
|
||||
{
|
||||
//if the game's running too slowly then we have no choice
|
||||
//but to skip a bunch of steps
|
||||
//prevent spiral of death:
|
||||
//if the game's running too slowly then we have no choice but to skip a bunch of steps
|
||||
//otherwise it snowballs and becomes unplayable
|
||||
Timing.Accumulator = Timing.Step;
|
||||
}
|
||||
@@ -740,7 +766,6 @@ namespace Barotrauma
|
||||
|
||||
PlayerInput.Update(Timing.Step);
|
||||
|
||||
|
||||
if (loadingScreenOpen)
|
||||
{
|
||||
//reset accumulator if loading
|
||||
@@ -760,7 +785,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)
|
||||
{
|
||||
@@ -979,13 +1007,21 @@ namespace Barotrauma
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
|
||||
updateCount++;
|
||||
|
||||
sw.Stop();
|
||||
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
|
||||
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||
PerformanceCounter.UpdateIterationsGraph.Update(updateIterations);
|
||||
}
|
||||
|
||||
if (!Paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
|
||||
if (!Paused) { Timing.Alpha = Timing.Accumulator / Timing.Step; }
|
||||
|
||||
if (performanceCounterTimer.ElapsedMilliseconds > 1000)
|
||||
{
|
||||
CurrentUpdateRate = (int)Math.Round(updateCount / (double)(performanceCounterTimer.ElapsedMilliseconds / 1000.0));
|
||||
performanceCounterTimer.Restart();
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetFrameTime()
|
||||
@@ -1090,8 +1126,15 @@ namespace Barotrauma
|
||||
{
|
||||
double roundDuration = Timing.TotalTime - GameSession.RoundStartTime;
|
||||
GameAnalyticsManager.AddProgressionEvent(GameAnalyticsManager.ProgressionStatus.Fail,
|
||||
GameSession.GameMode?.Name ?? "none",
|
||||
GameSession.GameMode?.Preset.Identifier ?? "none",
|
||||
roundDuration);
|
||||
string eventId = "QuitRound:" + (GameSession.GameMode?.Preset.Identifier ?? "none") + ":";
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:CurrentIntensity", GameSession.EventManager.CurrentIntensity);
|
||||
foreach (var activeEvent in GameSession.EventManager.ActiveEvents)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:ActiveEvents:" + activeEvent.ToString());
|
||||
}
|
||||
GameSession.LogEndRoundStats(eventId);
|
||||
if (Tutorial.Initialized)
|
||||
{
|
||||
((TutorialMode)GameSession.GameMode).Tutorial?.Stop();
|
||||
@@ -1183,11 +1226,7 @@ namespace Barotrauma
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), linkHolder.RectTransform), TextManager.Get("bugreportgithubform"), style: "MainMenuGUIButton", textAlignment: Alignment.Left)
|
||||
{
|
||||
#if UNSTABLE
|
||||
UserData = "https://barotraumagame.com/unstable-3rf3w5t4ter/",
|
||||
#else
|
||||
UserData = "https://github.com/Regalis11/Barotrauma/issues/new?template=bug_report.md",
|
||||
#endif
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
ShowOpenUrlInWebBrowserPrompt(userdata as string);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -7,37 +8,6 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CargoManager
|
||||
{
|
||||
private class SoldEntity
|
||||
{
|
||||
public enum SellStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity sold in SP. Or, entity sold by client and confirmed by server in MP.
|
||||
/// </summary>
|
||||
Confirmed,
|
||||
/// <summary>
|
||||
/// Entity sold by client in MP. Client has received at least one update from server after selling, but this entity wasn't yet confirmed.
|
||||
/// </summary>
|
||||
Unconfirmed,
|
||||
/// <summary>
|
||||
/// Entity sold by client in MP. Client hasn't yet received an update from server after selling.
|
||||
/// </summary>
|
||||
Local
|
||||
}
|
||||
|
||||
public Item Item { get; }
|
||||
public SellStatus Status { get; set; }
|
||||
|
||||
private SoldEntity(Item item, SellStatus status)
|
||||
{
|
||||
Item = item;
|
||||
Status = status;
|
||||
}
|
||||
|
||||
public static SoldEntity CreateInSinglePlayer(Item item) => new SoldEntity(item, SellStatus.Confirmed);
|
||||
public static SoldEntity CreateInMultiPlayer(Item item) => new SoldEntity(item, SellStatus.Local);
|
||||
}
|
||||
|
||||
private List<SoldEntity> SoldEntities { get; } = new List<SoldEntity>();
|
||||
|
||||
// The bag slot is intentionally left out since we want to be able to sell items from there
|
||||
@@ -67,31 +37,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Item> GetSellableItemsFromSub()
|
||||
{
|
||||
if (Submarine.MainSub == null) { return new List<Item>(); }
|
||||
var confirmedSoldEntities = GetConfirmedSoldEntities();
|
||||
return Submarine.MainSub.GetItems(true).FindAll(item =>
|
||||
{
|
||||
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
|
||||
if (item.GetRootInventoryOwner() is Character) { return false; }
|
||||
if (!item.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { return false; }
|
||||
if (!ItemAndAllContainersInteractable(item)) { return false; }
|
||||
return true;
|
||||
}).Distinct();
|
||||
|
||||
static bool ItemAndAllContainersInteractable(Item item)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!item.IsPlayerTeamInteractable) { return false; }
|
||||
item = item.Container;
|
||||
} while (item != null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<SoldEntity> GetConfirmedSoldEntities()
|
||||
{
|
||||
// Only consider items which have been:
|
||||
@@ -100,24 +45,6 @@ namespace Barotrauma
|
||||
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
}
|
||||
|
||||
private bool IsItemSellable(Item item, IEnumerable<SoldEntity> confirmedSoldEntities)
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInCurrentOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
if (item.OwnInventory?.Container is ItemContainer itemContainer)
|
||||
{
|
||||
var containedItems = item.ContainedItems;
|
||||
if (containedItems.None()) { return true; }
|
||||
// Allow selling the item if contained items are unsellable and set to be removed on deconstruct
|
||||
if (itemContainer.RemoveContainedItemsOnDeconstruct && containedItems.All(it => !it.Prefab.CanBeSold)) { return true; }
|
||||
// Otherwise there must be no contained items or the contained items must be confirmed as sold
|
||||
if (!containedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInBuyCrate.Clear();
|
||||
@@ -125,15 +52,21 @@ namespace Barotrauma
|
||||
OnItemsInBuyCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetItemsInSubSellCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInSellFromSubCrate.Clear();
|
||||
ItemsInSellFromSubCrate.AddRange(items);
|
||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetSoldItems(List<SoldItem> items)
|
||||
{
|
||||
SoldItems.Clear();
|
||||
SoldItems.AddRange(items);
|
||||
|
||||
foreach (SoldEntity se in SoldEntities)
|
||||
foreach (var se in SoldEntities)
|
||||
{
|
||||
if (se.Status == SoldEntity.SellStatus.Confirmed) { continue; }
|
||||
if (SoldItems.Any(si => si.ID == se.Item.ID && si.ItemPrefab == se.Item.Prefab && (GameMain.Client == null || GameMain.Client.ID == si.SellerID)))
|
||||
if (SoldItems.Any(si => Match(si, se, true)))
|
||||
{
|
||||
se.Status = SoldEntity.SellStatus.Confirmed;
|
||||
}
|
||||
@@ -142,13 +75,28 @@ namespace Barotrauma
|
||||
se.Status = SoldEntity.SellStatus.Unconfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var si in SoldItems)
|
||||
{
|
||||
if (si.Origin != SoldItem.SellOrigin.Submarine) { continue; }
|
||||
if (!(SoldEntities.FirstOrDefault(se => se.Item == null && Match(si, se, false)) is SoldEntity soldEntityMatch)) { continue; }
|
||||
if (!(Entity.FindEntityByID(si.ID) is Item item)) { continue; }
|
||||
soldEntityMatch.SetItem(item);
|
||||
soldEntityMatch.Status = SoldEntity.SellStatus.Confirmed;
|
||||
}
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
|
||||
static bool Match(SoldItem soldItem, SoldEntity soldEntity, bool matchId)
|
||||
{
|
||||
if (soldItem.ItemPrefab != soldEntity.ItemPrefab) { return false; }
|
||||
if (matchId && (soldEntity.Item == null || soldItem.ID != soldEntity.Item.ID)) { return false; }
|
||||
if (soldItem.Origin == SoldItem.SellOrigin.Character && GameMain.Client != null && soldItem.SellerID != GameMain.Client.ID) { return false; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifyItemQuantityInSellCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
||||
{
|
||||
PurchasedItem itemToSell = ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
var itemToSell = ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
if (itemToSell != null)
|
||||
{
|
||||
itemToSell.Quantity += changeInQuantity;
|
||||
@@ -186,72 +134,69 @@ namespace Barotrauma
|
||||
|
||||
public void SellItems(List<PurchasedItem> itemsToSell, Store.StoreTab sellingMode)
|
||||
{
|
||||
var sellableItems = sellingMode switch
|
||||
IEnumerable<Item> sellableItems;
|
||||
try
|
||||
{
|
||||
Store.StoreTab.Sell => GetSellableItems(Character.Controlled),
|
||||
Store.StoreTab.SellFromSub => GetSellableItemsFromSub(),
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
sellableItems = sellingMode switch
|
||||
{
|
||||
Store.StoreTab.Sell => GetSellableItems(Character.Controlled),
|
||||
Store.StoreTab.SellSub => GetSellableItemsFromSub(),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
DebugConsole.ShowError($"Error selling items: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
||||
return;
|
||||
}
|
||||
bool canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
||||
var sellerId = GameMain.Client?.ID ?? 0;
|
||||
|
||||
byte sellerId = GameMain.Client?.ID ?? 0;
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
Dictionary<ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
||||
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
{
|
||||
var itemValue = item.Quantity * sellValues[item.ItemPrefab];
|
||||
|
||||
int itemValue = item.Quantity * sellValues[item.ItemPrefab];
|
||||
// check if the store can afford the item
|
||||
if (Location.StoreCurrentBalance < itemValue) { continue; }
|
||||
|
||||
// TODO: Write logic for prioritizing certain items over others (e.g. lone Battery Cell should be preferred over one inside a Stun Baton)
|
||||
var matchingItems = sellableItems.Where(i => i.Prefab == item.ItemPrefab);
|
||||
if (matchingItems.Count() <= item.Quantity)
|
||||
int count = Math.Min(item.Quantity, matchingItems.Count());
|
||||
SoldItem.SellOrigin origin = sellingMode == Store.StoreTab.Sell ? SoldItem.SellOrigin.Character : SoldItem.SellOrigin.Submarine;
|
||||
if (origin == SoldItem.SellOrigin.Character || GameMain.IsSingleplayer)
|
||||
{
|
||||
foreach (Item i in matchingItems)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
SoldItems.Add(new SoldItem(i.Prefab, i.ID, canAddToRemoveQueue, sellerId));
|
||||
SoldEntities.Add(campaign.IsSinglePlayer ? SoldEntity.CreateInSinglePlayer(i) : SoldEntity.CreateInMultiPlayer(i));
|
||||
if (canAddToRemoveQueue) { Entity.Spawner.AddToRemoveQueue(i); }
|
||||
var matchingItem = matchingItems.ElementAt(i);
|
||||
SoldItems.Add(new SoldItem(matchingItem.Prefab, matchingItem.ID, canAddToRemoveQueue, sellerId, origin));
|
||||
SoldEntities.Add(new SoldEntity(matchingItem, campaign.IsSinglePlayer ? SoldEntity.SellStatus.Confirmed : SoldEntity.SellStatus.Local));
|
||||
if (canAddToRemoveQueue) { Entity.Spawner.AddToRemoveQueue(matchingItem); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < item.Quantity; i++)
|
||||
// When selling from the sub in multiplayer, the server will determine the items that are sold
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var matchingItem = matchingItems.ElementAt(i);
|
||||
SoldItems.Add(new SoldItem(matchingItem.Prefab, matchingItem.ID, canAddToRemoveQueue, sellerId));
|
||||
SoldEntities.Add(campaign.IsSinglePlayer ? SoldEntity.CreateInSinglePlayer(matchingItem) : SoldEntity.CreateInMultiPlayer(matchingItem));
|
||||
if (canAddToRemoveQueue) { Entity.Spawner.AddToRemoveQueue(matchingItem); }
|
||||
SoldItems.Add(new SoldItem(item.ItemPrefab, Entity.NullEntityID, canAddToRemoveQueue, sellerId, origin));
|
||||
SoldEntities.Add(new SoldEntity(item.ItemPrefab, SoldEntity.SellStatus.Local));
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange money
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier);
|
||||
|
||||
// Remove from the sell crate
|
||||
// TODO: Simplify duplicate logic?
|
||||
if (sellingMode == Store.StoreTab.Sell && ItemsInSellCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } inventoryItem)
|
||||
if ((sellingMode == Store.StoreTab.Sell ? ItemsInSellCrate : ItemsInSellFromSubCrate)?.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } itemToSell)
|
||||
{
|
||||
inventoryItem.Quantity -= item.Quantity;
|
||||
if (inventoryItem.Quantity < 1)
|
||||
itemToSell.Quantity -= item.Quantity;
|
||||
if (itemToSell.Quantity < 1)
|
||||
{
|
||||
ItemsInSellCrate.Remove(inventoryItem);
|
||||
}
|
||||
}
|
||||
else if(sellingMode == Store.StoreTab.SellFromSub && ItemsInSellFromSubCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } subItem)
|
||||
{
|
||||
subItem.Quantity -= item.Quantity;
|
||||
if (subItem.Quantity < 1)
|
||||
{
|
||||
ItemsInSellFromSubCrate.Remove(subItem);
|
||||
(sellingMode == Store.StoreTab.Sell ? ItemsInSellCrate : ItemsInSellFromSubCrate)?.Remove(itemToSell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), null, Color.Transparent)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -145,12 +145,14 @@ namespace Barotrauma
|
||||
string msgCommand = ChatMessage.GetChatMessageCommand(text, out string msg);
|
||||
// add to local history
|
||||
ChatBox.ChatManager.Store(text);
|
||||
WifiComponent headset = null;
|
||||
ChatMessageType messageType =
|
||||
((msgCommand == "r" || msgCommand == "radio") && ChatMessage.CanUseRadio(Character.Controlled, out headset)) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
AddSinglePlayerChatMessage(
|
||||
Character.Controlled.Info.Name,
|
||||
msg,
|
||||
((msgCommand == "r" || msgCommand == "radio") && ChatMessage.CanUseRadio(Character.Controlled)) ? ChatMessageType.Radio : ChatMessageType.Default,
|
||||
msg, messageType,
|
||||
Character.Controlled);
|
||||
if (ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent headset))
|
||||
if (messageType == ChatMessageType.Radio && headset != null)
|
||||
{
|
||||
Signal s = new Signal(msg, sender: Character.Controlled, source: headset.Item);
|
||||
headset.TransmitSignal(s, sentFromChat: true);
|
||||
@@ -302,7 +304,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
/// <param name="character">The character to remove</param>
|
||||
/// <param name="removeInfo">If the character info is also removed, the character will not be visible in the round summary.</param>
|
||||
public void RemoveCharacter(Character character, bool removeInfo = false)
|
||||
public void RemoveCharacter(Character character, bool removeInfo = false, bool resetCrewListIndex = true)
|
||||
{
|
||||
if (character == null)
|
||||
{
|
||||
@@ -311,14 +313,15 @@ namespace Barotrauma
|
||||
}
|
||||
characters.Remove(character);
|
||||
if (removeInfo) { characterInfos.Remove(character.Info); }
|
||||
if (resetCrewListIndex) { ResetCrewListIndex(character); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add character to the list without actually adding it to the crew
|
||||
/// </summary>
|
||||
public void AddCharacterToCrewList(Character character)
|
||||
public GUIComponent AddCharacterToCrewList(Character character)
|
||||
{
|
||||
if (character == null) { return; }
|
||||
if (character == null) { return null; }
|
||||
|
||||
var background = new GUIFrame(
|
||||
new RectTransform(crewListEntrySize, parent: crewList.Content.RectTransform, anchor: Anchor.TopRight),
|
||||
@@ -510,6 +513,8 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
private void SetCharacterComponentTooltip(GUIComponent characterComponent)
|
||||
@@ -549,13 +554,13 @@ namespace Barotrauma
|
||||
if (characterInfos.Contains(revivedCharacter.Info)) { AddCharacter(revivedCharacter); }
|
||||
}
|
||||
|
||||
public void KillCharacter(Character killedCharacter)
|
||||
public void KillCharacter(Character killedCharacter, bool resetCrewListIndex = true)
|
||||
{
|
||||
if (crewList.Content.GetChildByUserData(killedCharacter) is GUIComponent characterComponent)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(KillCharacterAnim(characterComponent));
|
||||
}
|
||||
RemoveCharacter(killedCharacter);
|
||||
RemoveCharacter(killedCharacter, resetCrewListIndex: resetCrewListIndex);
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> KillCharacterAnim(GUIComponent component)
|
||||
@@ -601,9 +606,53 @@ namespace Barotrauma
|
||||
{
|
||||
if (crewList != this.crewList) { return; }
|
||||
if (!(draggedElementData is Character)) { return; }
|
||||
if (crewList.HasDraggedElementIndexChanged) { return; }
|
||||
if (!IsSinglePlayer) { return; }
|
||||
CharacterClicked(crewList.DraggedElement, draggedElementData);
|
||||
if (crewList.HasDraggedElementIndexChanged)
|
||||
{
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterClicked(crewList.DraggedElement, draggedElementData);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetCrewListIndex(Character c)
|
||||
{
|
||||
if (c?.Info == null) { return; }
|
||||
c.Info.CrewListIndex = -1;
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
|
||||
private void UpdateCrewListIndices()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
for (int i = 0; i < crewList.Content.CountChildren; i++)
|
||||
{
|
||||
var characterComponent = crewList.Content.GetChild(i);
|
||||
if (!(characterComponent?.UserData is Character c)) { continue; }
|
||||
if (c.Info == null) { continue; }
|
||||
c.Info.CrewListIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
private void SortCrewList()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
crewList.Content.RectTransform.SortChildren((x, y) =>
|
||||
{
|
||||
var infoX = (x.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
var infoY = (y.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
if (infoX.HasValue)
|
||||
{
|
||||
return infoY.HasValue ? infoX.Value.CompareTo(infoY.Value) : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return infoY.HasValue ? 1 : 0;
|
||||
}
|
||||
});
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -718,7 +767,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,11 +817,11 @@ 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
|
||||
{
|
||||
OrderChatMessage msg = new OrderChatMessage(order, "", priority, order.IsReport ? hull : order.TargetEntity, null, orderGiver);
|
||||
OrderChatMessage msg = new OrderChatMessage(order, "", priority, order.IsReport ? hull : order.TargetEntity, null, orderGiver, isNewOrder: isNewOrder);
|
||||
GameMain.Client?.SendChatMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -784,12 +833,12 @@ 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)
|
||||
{
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item, character, orderGiver);
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item, character, orderGiver, isNewOrder: isNewOrder);
|
||||
GameMain.Client?.SendChatMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -1071,13 +1120,19 @@ 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)
|
||||
{
|
||||
if (orderPrefab == null) { return ""; }
|
||||
if (!string.IsNullOrEmpty(option))
|
||||
if (orderPrefab.DisplayGiverInTooltip && orderPrefab.OrderGiver != null)
|
||||
{
|
||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||
new string[2] { "[ordername]", "[orderoption]" },
|
||||
new string[2] { orderPrefab.Name, orderPrefab.OrderGiver.DisplayName });
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(option))
|
||||
{
|
||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||
new string[2] { "[ordername]", "[orderoption]" },
|
||||
@@ -1210,6 +1265,10 @@ namespace Barotrauma
|
||||
DisableCommandUI();
|
||||
Character.Controlled = character;
|
||||
HintManager.OnChangeCharacter();
|
||||
if (GameSession.TabMenuInstance != null && TabMenu.SelectedTab == TabMenu.InfoFrameTab.Talents)
|
||||
{
|
||||
GameSession.TabMenuInstance.SelectInfoFrameTab(TabMenu.SelectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
private int TryAdjustIndex(int amount)
|
||||
@@ -1566,10 +1625,28 @@ namespace Barotrauma
|
||||
{
|
||||
crewList.Select(character, force: true);
|
||||
}
|
||||
// Icon colors might change based on the target so we check if they need to be updated
|
||||
if (GetCurrentOrderIconList(characterComponent) is GUIListBox currentOrderIconList)
|
||||
{
|
||||
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||
{
|
||||
if (!(orderIcon.UserData is OrderInfo orderInfo)) { continue; }
|
||||
if (!(orderInfo.Order is Order order)) { continue; }
|
||||
if (order.ColoredWhenControllingGiver && order.OrderGiver != Character.Controlled)
|
||||
{
|
||||
orderIcon.Color = AIObjective.ObjectiveIconColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
orderIcon.Color = order.Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only update the order highlights and objective icons here in singleplayer
|
||||
// The server will let the clients know when they need to update in multiplayer
|
||||
if (GameMain.IsSingleplayer && character.IsBot && character.AIController is HumanAIController controller &&
|
||||
controller.ObjectiveManager is AIObjectiveManager objectiveManager)
|
||||
{
|
||||
// In multiplayer, these are set through character networking (the server lets the clients now when these are updated)
|
||||
if (objectiveManager.CurrentObjective is AIObjective currentObjective)
|
||||
{
|
||||
if (objectiveManager.IsOrder(currentObjective))
|
||||
@@ -1638,8 +1715,8 @@ namespace Barotrauma
|
||||
bool foundMatch = false;
|
||||
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||
{
|
||||
var glowComponent = orderIcon.GetChildByUserData("glow");
|
||||
if (glowComponent == null) { continue; }
|
||||
if (!(orderIcon.GetChildByUserData("glow") is GUIComponent glowComponent)) { continue; }
|
||||
glowComponent.Color = orderIcon.Color;
|
||||
if (foundMatch)
|
||||
{
|
||||
glowComponent.Visible = false;
|
||||
@@ -1684,11 +1761,11 @@ namespace Barotrauma
|
||||
objectiveIconFrame.ClearChildren();
|
||||
if (sprite != null)
|
||||
{
|
||||
var objectiveIcon = CreateNodeIcon(Vector2.One, objectiveIconFrame.RectTransform, sprite, Color.LightGray, tooltip: tooltip);
|
||||
var objectiveIcon = CreateNodeIcon(Vector2.One, objectiveIconFrame.RectTransform, sprite, AIObjective.ObjectiveIconColor, tooltip: tooltip);
|
||||
new GUIFrame(new RectTransform(new Vector2(1.5f), objectiveIcon.RectTransform, anchor: Anchor.Center), style: "OuterGlowCircular")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = Color.LightGray
|
||||
Color = AIObjective.ObjectiveIconColor
|
||||
};
|
||||
objectiveIconFrame.Visible = true;
|
||||
}
|
||||
@@ -1909,7 +1986,7 @@ namespace Barotrauma
|
||||
ScaleCommandUI();
|
||||
|
||||
commandFrame = new GUIFrame(
|
||||
new RectTransform(Vector2.One, GUICanvas.Instance, anchor: Anchor.Center),
|
||||
new RectTransform(Vector2.One, GUI.Canvas, anchor: Anchor.Center),
|
||||
style: null,
|
||||
color: Color.Transparent);
|
||||
background = new GUIImage(
|
||||
@@ -2458,6 +2535,7 @@ namespace Barotrauma
|
||||
{
|
||||
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, dismissedOrderPrefab, -1));
|
||||
}
|
||||
shortcutNodes.RemoveAll(n => n.UserData is Order o && !IsOrderAvailable(o));
|
||||
if (shortcutNodes.Count < 1) { return; }
|
||||
shortcutCenterNode = new GUIFrame(new RectTransform(shortcutCenterNodeSize, parent: commandFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||
{
|
||||
@@ -2498,7 +2576,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateOrderNodes(OrderCategory orderCategory)
|
||||
{
|
||||
var orders = Order.PrefabList.FindAll(o => o.Category == orderCategory && !o.IsReport);
|
||||
var orders = Order.PrefabList.FindAll(o => o.Category == orderCategory && !o.IsReport && IsOrderAvailable(o));
|
||||
Order order;
|
||||
bool disableNode;
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance,
|
||||
@@ -2582,15 +2660,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);
|
||||
@@ -2653,6 +2728,7 @@ namespace Barotrauma
|
||||
contextualOrders.Add(new OrderInfo(Order.GetPrefab(orderIdentifier), null));
|
||||
}
|
||||
}
|
||||
contextualOrders.RemoveAll(o => !IsOrderAvailable(o.Order));
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance, contextualOrders.Count, MathHelper.ToRadians(90f + 180f / contextualOrders.Count));
|
||||
bool disableNode = !CanCharacterBeHeard();
|
||||
for (int i = 0; i < contextualOrders.Count; i++)
|
||||
@@ -3411,6 +3487,20 @@ namespace Barotrauma
|
||||
return character?.Info?.GetManualOrderPriority(order) ?? CharacterInfo.HighestManualOrderPriority;
|
||||
}
|
||||
|
||||
private bool IsOrderAvailable(Order order)
|
||||
{
|
||||
if (order == null) { return false; }
|
||||
switch (order.Identifier.ToLowerInvariant())
|
||||
{
|
||||
case "assaultenemy":
|
||||
Character character = characterContext ?? Character.Controlled;
|
||||
if (character?.Submarine == null) { return false; }
|
||||
return character.Submarine.GetConnectedSubs().Any(s => s.TeamID != character.TeamID);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#region Crew Member Assignment Logic
|
||||
private bool CanOpenManualAssignment(GUIComponent node)
|
||||
{
|
||||
@@ -3487,7 +3577,7 @@ namespace Barotrauma
|
||||
bool hasLeaks = Character.Controlled.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f);
|
||||
ToggleReportButton("reportbreach", hasLeaks);
|
||||
|
||||
bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled));
|
||||
bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled, false));
|
||||
ToggleReportButton("reportintruders", hasIntruders);
|
||||
|
||||
foreach (GUIComponent reportButton in ReportButtonFrame.Children)
|
||||
@@ -3523,16 +3613,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();
|
||||
@@ -3543,12 +3623,14 @@ namespace Barotrauma
|
||||
public void Save(XElement parentElement)
|
||||
{
|
||||
XElement element = new XElement("crew");
|
||||
foreach (CharacterInfo ci in characterInfos)
|
||||
for (int i = 0; i < characterInfos.Count; i++)
|
||||
{
|
||||
var ci = characterInfos[i];
|
||||
var infoElement = ci.Save(element);
|
||||
if (ci.InventoryData != null) { infoElement.Add(ci.InventoryData); }
|
||||
if (ci.HealthData != null) { infoElement.Add(ci.HealthData); }
|
||||
if (ci.OrderData != null) { infoElement.Add(ci.OrderData); }
|
||||
infoElement.Add(new XAttribute("crewlistindex", ci.CrewListIndex));
|
||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||
}
|
||||
SaveActiveOrders(element);
|
||||
|
||||
@@ -97,17 +97,16 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// There is a server-side implementation of the method in <see cref="MultiPlayerCampaign"/>
|
||||
/// </summary>
|
||||
public bool AllowedToManageCampaign()
|
||||
public bool AllowedToManageCampaign(ClientPermissions permissions = ClientPermissions.ManageCampaign)
|
||||
{
|
||||
//allow ending the round if the client has permissions, is the owner, the only client in the server,
|
||||
//allow managing the round if the client has permissions, is the owner, the only client in the server,
|
||||
//or if no-one has management permissions
|
||||
if (GameMain.Client == null) { return true; }
|
||||
return
|
||||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
GameMain.Client.HasPermission(permissions) ||
|
||||
GameMain.Client.ConnectedClients.Count == 1 ||
|
||||
GameMain.Client.IsServerOwner ||
|
||||
GameMain.Client.ConnectedClients.None(c =>
|
||||
c.InGame && (c.IsOwner || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
GameMain.Client.ConnectedClients.None(c => c.InGame && (c.IsOwner || c.HasPermission(permissions)));
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
@@ -242,6 +241,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 +294,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 +326,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);
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUICanvas.Instance),
|
||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUI.Canvas),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterRight)
|
||||
{
|
||||
CanBeFocused = false
|
||||
@@ -108,7 +108,7 @@ namespace Barotrauma
|
||||
buttonCenter = buttonHeight / 2,
|
||||
screenMiddle = GameMain.GraphicsWidth / 2;
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle - buttonWidth / 2, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle - buttonWidth / 2, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, buttonWidth, buttonHeight), GUI.Canvas),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
{
|
||||
Pulse = true,
|
||||
@@ -145,7 +145,7 @@ namespace Barotrauma
|
||||
int readyButtonHeight = buttonHeight;
|
||||
int readyButtonWidth = (int) (GUI.Scale * 50);
|
||||
|
||||
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (buttonWidth / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, readyButtonWidth, readyButtonHeight), GUICanvas.Instance),
|
||||
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (buttonWidth / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, readyButtonWidth, readyButtonHeight), GUI.Canvas),
|
||||
style: "RepairBuyButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("ReadyCheck.Tooltip"),
|
||||
@@ -545,14 +545,21 @@ namespace Barotrauma
|
||||
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.ItemsInSellFromSubCrate.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.ItemsInSellFromSubCrate)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.SoldItems.Count);
|
||||
@@ -562,6 +569,7 @@ namespace Barotrauma
|
||||
msg.Write((UInt16)si.ID);
|
||||
msg.Write(si.Removed);
|
||||
msg.Write(si.SellerID);
|
||||
msg.Write((byte)si.Origin);
|
||||
}
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PurchasedUpgrades.Count);
|
||||
@@ -640,6 +648,15 @@ namespace Barotrauma
|
||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 subSellCrateItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> subSellCrateItems = new List<PurchasedItem>();
|
||||
for (int i = 0; i < subSellCrateItemCount; i++)
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
|
||||
for (int i = 0; i < purchasedItemCount; i++)
|
||||
@@ -657,7 +674,8 @@ namespace Barotrauma
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool removed = msg.ReadBoolean();
|
||||
byte sellerId = msg.ReadByte();
|
||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
|
||||
byte origin = msg.ReadByte();
|
||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId, (SoldItem.SellOrigin)origin));
|
||||
}
|
||||
|
||||
ushort pendingUpgradeCount = msg.ReadUInt16();
|
||||
@@ -678,13 +696,9 @@ namespace Barotrauma
|
||||
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||
{
|
||||
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||
Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item;
|
||||
|
||||
string itemToInstallIdentifier = msg.ReadString();
|
||||
ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||
|
||||
if (itemToRemove == null) { continue; }
|
||||
|
||||
if (!(Entity.FindEntityByID(itemToRemoveID) is Item itemToRemove)) { continue; }
|
||||
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
}
|
||||
|
||||
@@ -728,12 +742,11 @@ namespace Barotrauma
|
||||
campaign.Map.SelectMission(selectedMissionIndices);
|
||||
campaign.Map.AllowDebugTeleport = allowDebugTeleport;
|
||||
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
|
||||
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
|
||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||
campaign.CargoManager.SetSoldItems(soldItems);
|
||||
if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; }
|
||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||
|
||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,9 @@ namespace Barotrauma
|
||||
case "pets":
|
||||
petsElement = subElement;
|
||||
break;
|
||||
case "stats":
|
||||
LoadStats(subElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ namespace Barotrauma
|
||||
int buttonHeight = (int)(GUI.Scale * 40);
|
||||
int buttonWidth = GUI.IntScale(450);
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUI.Canvas),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
{
|
||||
Pulse = true,
|
||||
@@ -412,6 +415,10 @@ namespace Barotrauma
|
||||
break;
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
Map.MoveToNextLocation();
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
case TransitionType.ProgressToNextEmptyLocation:
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -728,6 +735,7 @@ namespace Barotrauma
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||
modeElement.Add(Settings.Save());
|
||||
modeElement.Add(SaveStats());
|
||||
|
||||
//save and remove all items that are in someone's inventory so they don't get included in the sub file as well
|
||||
foreach (Character c in Character.CharacterList)
|
||||
|
||||
@@ -220,12 +220,12 @@ namespace Barotrauma.Tutorials
|
||||
SetHighlight(captain_navConsole.Item, true);
|
||||
SetHighlight(captain_sonar.Item, true);
|
||||
SetHighlight(captain_statusMonitor, true);
|
||||
captain_navConsole.UseAutoDocking = false;
|
||||
do
|
||||
{
|
||||
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
|
||||
yield return new WaitForSeconds(1.0f, false);
|
||||
} while (Submarine.MainSub.DockedTo.Any());
|
||||
captain_navConsole.UseAutoDocking = false;
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(5); // Navigate to destination
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0;
|
||||
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0 && !Character.Controlled.HasUnlockedAllTalents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Barotrauma
|
||||
static class HintManager
|
||||
{
|
||||
private const string HintManagerFile = "hintmanager.xml";
|
||||
|
||||
public static bool Enabled => GameMain.Config != null && !GameMain.Config.DisableInGameHints;
|
||||
private static HashSet<string> HintIdentifiers { get; set; }
|
||||
private static Dictionary<string, HashSet<string>> HintTags { get; } = new Dictionary<string, HashSet<string>>();
|
||||
private static Dictionary<string, (string identifier, string option)> HintOrders { get; } = new Dictionary<string, (string orderIdentifier, string orderOption)>();
|
||||
@@ -666,6 +668,8 @@ namespace Barotrauma
|
||||
ActiveHintMessageBox.InnerFrame.Flash(color: iconColor ?? Color.Orange, flashDuration: 0.75f);
|
||||
onDisplay?.Invoke();
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent($"HintManager:{GameMain.GameSession?.GameMode?.Preset?.Identifier ?? "none"}:HintDisplayed:{hintIdentifier}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
if (campaign?.CampaignUI?.MedicalClinic is { } ui)
|
||||
{
|
||||
ui.ClosePopup();
|
||||
}
|
||||
|
||||
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,15 @@ namespace Barotrauma
|
||||
statisticsTickBox.OnSelected = prevHandler;
|
||||
statisticsTickBox.Enabled = GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
|
||||
});
|
||||
#endif
|
||||
|
||||
foreach (var child in leftPanel.Children)
|
||||
{
|
||||
if (child is GUITextBlock textBlock)
|
||||
{
|
||||
textBlock.RectTransform.MinSize = new Point(textBlock.RectTransform.MinSize.X, (int)Math.Max(textBlock.RectTransform.MinSize.Y, textBlock.TextSize.Y));
|
||||
}
|
||||
}
|
||||
|
||||
// right panel --------------------------------------
|
||||
|
||||
@@ -597,6 +607,10 @@ namespace Barotrauma
|
||||
OnClicked = (bt, userdata) => { SelectTab((Tab)userdata); return true; }
|
||||
};
|
||||
tabButtons[(int)tab].Text = ToolBox.LimitString(buttonText, tabButtons[(int)tab].Font, (int)(0.75f * tabWidth * tabButtonHolder.Rect.Width));
|
||||
if (tabButtons[(int)tab].Text != buttonText)
|
||||
{
|
||||
tabButtons[(int)tab].ToolTip = buttonText;
|
||||
}
|
||||
}
|
||||
|
||||
/// Graphics tab --------------------------------------------------------------
|
||||
|
||||
@@ -153,12 +153,6 @@ namespace Barotrauma
|
||||
return container.Inventory;
|
||||
}
|
||||
|
||||
protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
|
||||
{
|
||||
base.PutItem(item, i, user, removeItem, createNetworkEvent);
|
||||
CreateSlots();
|
||||
}
|
||||
|
||||
public override void CreateSlots()
|
||||
{
|
||||
visualSlots ??= new VisualSlot[capacity];
|
||||
@@ -504,6 +498,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)
|
||||
@@ -789,7 +790,7 @@ namespace Barotrauma
|
||||
if (quickUseAction != QuickUseAction.Drop)
|
||||
{
|
||||
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
|
||||
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", item?.Name);
|
||||
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.HeldItems.FirstOrDefault()?.Name ?? item?.Name);
|
||||
if (PlayerInput.PrimaryMouseButtonDown()) { slot.EquipButtonState = GUIComponent.ComponentState.Pressed; }
|
||||
if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
@@ -963,7 +964,9 @@ namespace Barotrauma
|
||||
{
|
||||
return QuickUseAction.TakeFromCharacter;
|
||||
}
|
||||
else if (character.HeldItems.Any(i => i.OwnInventory != null && i.OwnInventory.CanBePut(item)) && allowInventorySwap)
|
||||
else if (character.HeldItems.Any(i =>
|
||||
i.OwnInventory != null &&
|
||||
(i.OwnInventory.CanBePut(item) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
||||
{
|
||||
return QuickUseAction.PutToEquippedItem;
|
||||
}
|
||||
@@ -1128,8 +1131,9 @@ namespace Barotrauma
|
||||
case QuickUseAction.PutToEquippedItem:
|
||||
foreach (Item heldItem in character.HeldItems)
|
||||
{
|
||||
if (heldItem.OwnInventory != null &&
|
||||
heldItem.OwnInventory.TryPutItem(item, Character.Controlled))
|
||||
if (heldItem.OwnInventory == null) { continue; }
|
||||
if (heldItem.OwnInventory.TryPutItem(item, Character.Controlled) ||
|
||||
(heldItem.OwnInventory.Capacity == 1 && heldItem.OwnInventory.TryPutItem(item, 0, allowSwapping: true, allowCombine: false, user: Character.Controlled)))
|
||||
{
|
||||
success = true;
|
||||
for (int j = 0; j < capacity; j++)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -256,6 +256,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
targetHull.IncreaseSectionColorOrStrength(targetSections[i], color, sizeAdjustedSprayStrength * deltaTime, true, false);
|
||||
}
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
GameMain.GameSession.TimeSpentCleaning += deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,6 +267,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
targetHull.CleanSection(targetSections[i], -sizeAdjustedSprayStrength * deltaTime, true);
|
||||
}
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
GameMain.GameSession.TimeSpentPainting += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 particleStartPos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public GUIFrame GuiFrame { get; protected set; }
|
||||
public GUIFrame GuiFrame { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool AllowUIOverlap
|
||||
@@ -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
|
||||
{
|
||||
@@ -554,7 +554,7 @@ namespace Barotrauma.Items.Components
|
||||
color = GuiFrameSource.GetAttributeColor("color", Color.White);
|
||||
}
|
||||
string style = GuiFrameSource.Attribute("style") == null ? null : GuiFrameSource.GetAttributeString("style", "");
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas.ItemComponentHolder, Anchor.Center), style, color);
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas, Anchor.Center), style, color);
|
||||
DefaultLayout = GUILayoutSettings.Load(GuiFrameSource);
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
|
||||
@@ -76,6 +76,9 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false, description: "If true, the contained state indicator calculates how full the item is based on the total amount of items that can be stacked inside it, as opposed to how many of the inventory slots are occupied.")]
|
||||
public bool ShowTotalStackCapacityInContainedStateIndicator { get; set; }
|
||||
|
||||
[Serialize(false, false, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
|
||||
public bool KeepOpenWhenEquipped { get; set; }
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelArea.RectTransform), TextManager.Get("uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelArea.RectTransform), TextManager.Get("deconstructor.input", fallBackTag: "uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
inputLabel.RectTransform.Resize(new Point((int) inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, inputLabelArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.03f
|
||||
};
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("fabricator.input", fallBackTag: "uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
inputLabel.RectTransform.Resize(new Point((int) inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, separatorArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 origin = weaponSprite.Origin;
|
||||
float scale = parentWidth / Math.Max(weaponSprite.size.X, weaponSprite.size.Y);
|
||||
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? GUI.Style.Red : GUI.Style.Green;
|
||||
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? Color.DimGray : GUI.Style.Green;
|
||||
weaponSprite.Draw(batch, center, color, origin, rotation, scale, it.SpriteEffects);
|
||||
}
|
||||
});
|
||||
@@ -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());
|
||||
@@ -1329,7 +1335,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
RectangleF entityRect = ScaleRectToUI(structure, parent, border);
|
||||
Vector2 spriteScale = new Vector2(entityRect.Size.X / sprite.size.X, entityRect.Size.Y / sprite.size.Y);
|
||||
sprite.Draw(spriteBatch, new Vector2(entityRect.Location.X + inflate, entityRect.Location.Y + inflate), structure.SpriteColor, Vector2.Zero, 0f, spriteScale, structure.SpriteEffects);
|
||||
sprite.Draw(spriteBatch, new Vector2(entityRect.Location.X + inflate, entityRect.Location.Y + inflate), structure.SpriteColor, Vector2.Zero, 0f, spriteScale, sprite.effects ^ structure.SpriteEffects);
|
||||
}
|
||||
|
||||
private static RectangleF ScaleRectToUI(MapEntity entity, RectangleF parentRect, RectangleF worldBorders)
|
||||
@@ -1414,10 +1420,11 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 drawPos = new Vector2(frame.Rect.Right - sizeX, frame.Rect.Y - sizeY / 2f);
|
||||
|
||||
UISprite icon = GUI.Style.IconOverflowIndicator;
|
||||
|
||||
const int iconPadding = 4;
|
||||
icon.Draw(spriteBatch, new Rectangle((int) drawPos.X - iconPadding, (int) drawPos.Y - iconPadding, (int) maxWidth + iconPadding * 2, (int) maxWidth + iconPadding * 2), Color.White, SpriteEffects.None);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
const int iconPadding = 4;
|
||||
icon.Draw(spriteBatch, new Rectangle((int) drawPos.X - iconPadding, (int) drawPos.Y - iconPadding, (int) maxWidth + iconPadding * 2, (int) maxWidth + iconPadding * 2), Color.White, SpriteEffects.None);
|
||||
}
|
||||
GUI.DrawString(spriteBatch, drawPos, text, GUI.Style.TextColor, font: GUI.SubHeadingFont);
|
||||
}
|
||||
break;
|
||||
@@ -1712,5 +1719,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
return new MiniMapHullData(scaledPolygon, worldRect, parentRect.Size, snappedRectangles, hullRefs.ToImmutableArray());
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
if (searchAutoComplete != null)
|
||||
{
|
||||
searchAutoComplete.RectTransform.Parent = null;
|
||||
searchAutoComplete = null;
|
||||
}
|
||||
if (hullInfoFrame != null)
|
||||
{
|
||||
hullInfoFrame.RectTransform.Parent = null;
|
||||
hullInfoFrame = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (selectionUI == null)
|
||||
{
|
||||
selectionUI = new SubmarineSelection(true, null, GUICanvas.Instance.ItemComponentHolder);
|
||||
selectionUI = new SubmarineSelection(true, null, GUI.Canvas);
|
||||
}
|
||||
|
||||
GuiFrame = selectionUI.GuiFrame;
|
||||
@@ -35,5 +35,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
selectionUI?.Update();
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
if (selectionUI != null)
|
||||
{
|
||||
selectionUI.GuiFrame.RectTransform.Parent = null;
|
||||
selectionUI = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
@@ -350,6 +348,27 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 GetTransducerPos()
|
||||
{
|
||||
if (!UseTransducers || connectedTransducers.Count == 0)
|
||||
{
|
||||
//use the position of the sub if the item is static (no body) and inside a sub
|
||||
return item.Submarine != null && item.body == null ? item.Submarine.WorldPosition : item.WorldPosition;
|
||||
}
|
||||
|
||||
Vector2 transducerPosSum = Vector2.Zero;
|
||||
foreach (ConnectedTransducer transducer in connectedTransducers)
|
||||
{
|
||||
if (transducer.Transducer.Item.Submarine != null && !CenterOnTransducers)
|
||||
{
|
||||
return transducer.Transducer.Item.Submarine.WorldPosition;
|
||||
}
|
||||
transducerPosSum += transducer.Transducer.Item.WorldPosition;
|
||||
}
|
||||
return transducerPosSum / connectedTransducers.Count;
|
||||
}
|
||||
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
@@ -455,7 +474,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 +534,6 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos() + DisplayOffset;
|
||||
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
nearbyObjectUpdateTimer -= deltaTime;
|
||||
@@ -829,8 +859,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos();
|
||||
|
||||
Vector2 transducerCenter = GetTransducerPos();// + DisplayOffset;
|
||||
|
||||
if (sonarBlips.Count > 0)
|
||||
{
|
||||
@@ -840,7 +869,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 +878,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,14 +1112,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
DrawDockingIndicator(spriteBatch, steering, ref transducerCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayOffset = Vector2.Lerp(DisplayOffset, Vector2.Zero, 0.1f);
|
||||
}
|
||||
|
||||
foreach (DockingPort dockingPort in DockingPort.List)
|
||||
{
|
||||
if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||
if (dockingPort.Item.HiddenInGame) { continue; }
|
||||
if (dockingPort.Item.Submarine == null) { continue; }
|
||||
if (dockingPort.Item.Submarine.Info.IsWreck) { continue; }
|
||||
// docking ports should be shown even if defined as not, if the submarine is the same as the sonar's
|
||||
@@ -1131,9 +1157,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 +1257,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 +1269,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 +1484,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;
|
||||
@@ -1670,13 +1693,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (iconIdentifier == null || !targetIcons.ContainsKey(iconIdentifier))
|
||||
if (iconIdentifier == null || !targetIcons.TryGetValue(iconIdentifier, out var iconInfo) || iconInfo.Item1 == null)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X - 3, (int)markerPos.Y - 3, 6, 6), markerColor, thickness: 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var iconInfo = targetIcons[iconIdentifier];
|
||||
iconInfo.Item1.Draw(spriteBatch, markerPos, iconInfo.Item2);
|
||||
}
|
||||
|
||||
@@ -1689,7 +1711,10 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 textSize = GUI.SmallFont.MeasureString(wrappedLabel);
|
||||
|
||||
//flip the text to left side when the marker is on the left side or goes outside the right edge of the interface
|
||||
if ((dir.X < 0.0f || labelPos.X + textSize.X + 10 > GuiFrame.Rect.X) && labelPos.X - textSize.X > 0) labelPos.X -= textSize.X + 10;
|
||||
if (GuiFrame != null && (dir.X < 0.0f || labelPos.X + textSize.X + 10 > GuiFrame.Rect.X) && labelPos.X - textSize.X > 0)
|
||||
{
|
||||
labelPos.X -= textSize.X + 10;
|
||||
}
|
||||
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(labelPos.X + 10, labelPos.Y),
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -682,7 +682,7 @@ namespace Barotrauma.Items.Components
|
||||
enterOutpostPrompt?.Close();
|
||||
}
|
||||
}
|
||||
else if (DockingSources.Any(d => d.Docked))
|
||||
else if (connectedPorts.Any(d => d.Docked))
|
||||
{
|
||||
dockingButton.Text = undockText;
|
||||
dockingContainer.Visible = true;
|
||||
@@ -819,7 +819,7 @@ namespace Barotrauma.Items.Components
|
||||
Connection dockingConnection = item.Connections?.FirstOrDefault(c => c.Name == "toggle_docking");
|
||||
if (dockingConnection != null)
|
||||
{
|
||||
connectedPorts = item.GetConnectedComponentsRecursive<DockingPort>(dockingConnection);
|
||||
connectedPorts = item.GetConnectedComponentsRecursive<DockingPort>(dockingConnection, ignoreInactiveRelays: true);
|
||||
}
|
||||
checkConnectedPortsTimer = CheckConnectedPortsInterval;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,12 @@ namespace Barotrauma.Items.Components
|
||||
private GUIProgressBar chargeIndicator;
|
||||
private GUIScrollBar rechargeSpeedSlider;
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float RechargeWarningIndicatorLow { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float RechargeWarningIndicatorHigh { get; set; }
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
//use the extents of the item as the draw size
|
||||
@@ -28,19 +34,38 @@ namespace Barotrauma.Items.Components
|
||||
var upperArea = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), paddedFrame.RectTransform, Anchor.TopCenter), style: null);
|
||||
var lowerArea = new GUIFrame(new RectTransform(new Vector2(1, 0.6f), paddedFrame.RectTransform, Anchor.BottomCenter), style: null);
|
||||
|
||||
|
||||
string rechargeStr = TextManager.Get("PowerContainerRechargeRate");
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), upperArea.RectTransform, Anchor.TopCenter),
|
||||
"RechargeRate", textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
|
||||
var rechargeRateContainer = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), upperArea.RectTransform), style: null);
|
||||
var rechargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), rechargeRateContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get("rechargerate"), textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
string kW = TextManager.Get("kilowatt");
|
||||
var rechargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), rechargeRateContainer.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () =>
|
||||
{
|
||||
return rechargeStr.Replace("[rate]", ((int)((rechargeSpeed / maxRechargeSpeed) * 100.0f)).ToString());
|
||||
}
|
||||
TextGetter = () => $"{(int)MathF.Round(currPowerConsumption)} {kW} ({(int)MathF.Round(RechargeRatio * 100)} %)"
|
||||
};
|
||||
if (rechargeText.TextSize.X > rechargeText.Rect.Width) { rechargeText.Font = GUI.SmallFont; }
|
||||
|
||||
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 0.4f), upperArea.RectTransform, Anchor.BottomCenter),
|
||||
barSize: 0.15f, style: "DeviceSlider")
|
||||
var rechargeSliderContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.4f), upperArea.RectTransform, Anchor.BottomCenter));
|
||||
|
||||
if (RechargeWarningIndicatorLow > 0.0f || RechargeWarningIndicatorHigh > 0.0f)
|
||||
{
|
||||
var rechargeSliderFill = new GUICustomComponent(new RectTransform(new Vector2(0.95f, 0.9f), rechargeSliderContainer.RectTransform, Anchor.Center), (SpriteBatch sb, GUICustomComponent c) =>
|
||||
{
|
||||
if (RechargeWarningIndicatorLow > 0.0f)
|
||||
{
|
||||
float warningLow = c.Rect.Width * RechargeWarningIndicatorLow;
|
||||
GUI.DrawRectangle(sb, new Vector2(c.Rect.X + warningLow, c.Rect.Y), new Vector2(c.Rect.Width - warningLow, c.Rect.Height), GUI.Style.Orange, isFilled: true);
|
||||
}
|
||||
if (RechargeWarningIndicatorHigh > 0.0f)
|
||||
{
|
||||
float warningHigh = c.Rect.Width * RechargeWarningIndicatorHigh;
|
||||
GUI.DrawRectangle(sb, new Vector2(c.Rect.X + warningHigh, c.Rect.Y), new Vector2(c.Rect.Width - warningHigh, c.Rect.Height), GUI.Style.Red, isFilled: true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(Vector2.One, rechargeSliderContainer.RectTransform, Anchor.Center),
|
||||
barSize: 0.15f, style: "DeviceSliderSeeThrough")
|
||||
{
|
||||
Step = 0.1f,
|
||||
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
@@ -61,17 +86,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
// lower area --------------------------
|
||||
|
||||
var textArea = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), lowerArea.RectTransform), style: null);
|
||||
var chargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), textArea.RectTransform, Anchor.CenterLeft),
|
||||
var chargeTextContainer = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), lowerArea.RectTransform), style: null);
|
||||
var chargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), chargeTextContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get("charge"), textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
ToolTip = TextManager.Get("PowerTransferTipPower")
|
||||
};
|
||||
string kWmin = TextManager.Get("kilowattminute");
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), textArea.RectTransform, Anchor.CenterRight),
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), chargeTextContainer.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () => $"{(int)Math.Round(charge)}/{(int)capacity} {kWmin} ({(int)Math.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
TextGetter = () => $"{(int)MathF.Round(charge)}/{(int)capacity} {kWmin} ({(int)MathF.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
};
|
||||
if (chargeText.TextSize.X > chargeText.Rect.Width) { chargeText.Font = GUI.SmallFont; }
|
||||
|
||||
|
||||
@@ -381,17 +381,17 @@ namespace Barotrauma.Items.Components
|
||||
if (deteriorationTimer > 0.0f)
|
||||
{
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(item.WorldPosition.X, -item.WorldPosition.Y), "Deterioration delay " + ((int)deteriorationTimer) + (paused ? " [PAUSED]" : ""),
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), "Deterioration delay " + ((int)deteriorationTimer) + (paused ? " [PAUSED]" : ""),
|
||||
paused ? Color.Cyan : Color.Lime, Color.Black * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(item.WorldPosition.X, -item.WorldPosition.Y), "Deteriorating at " + (int)(DeteriorationSpeed * 60.0f) + " units/min" + (paused ? " [PAUSED]" : ""),
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), "Deteriorating at " + (int)(DeteriorationSpeed * 60.0f) + " units/min" + (paused ? " [PAUSED]" : ""),
|
||||
paused ? Color.Cyan : GUI.Style.Red, Color.Black * 0.5f);
|
||||
}
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(item.WorldPosition.X, -item.WorldPosition.Y + 20), "Condition: " + (int)item.Condition + "/" + (int)item.MaxCondition,
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y + 20), "Condition: " + (int)item.Condition + "/" + (int)item.MaxCondition,
|
||||
GUI.Style.Orange);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -199,6 +199,26 @@ namespace Barotrauma.Items.Components
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
snapped = msg.ReadBoolean();
|
||||
|
||||
if (!snapped)
|
||||
{
|
||||
UInt16 targetId = msg.ReadUInt16();
|
||||
UInt16 sourceId = msg.ReadUInt16();
|
||||
byte limbIndex = msg.ReadByte();
|
||||
|
||||
Item target = Entity.FindEntityByID(targetId) as Item;
|
||||
if (target == null) { return; }
|
||||
var source = Entity.FindEntityByID(sourceId);
|
||||
if (source is Character sourceCharacter && limbIndex >= 0 && limbIndex < sourceCharacter.AnimController.Limbs.Length)
|
||||
{
|
||||
Limb sourceLimb = sourceCharacter.AnimController.Limbs[limbIndex];
|
||||
Attach(sourceLimb, target);
|
||||
}
|
||||
else if (source is ISpatialEntity spatialEntity)
|
||||
{
|
||||
Attach(spatialEntity, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
|
||||
{
|
||||
if (DraggingConnected?.Item.Removed ?? false)
|
||||
if (DraggingConnected?.Item?.Removed ?? true)
|
||||
{
|
||||
DraggingConnected = null;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -19,5 +20,10 @@ namespace Barotrauma.Items.Components
|
||||
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitX * range, pos - Vector2.UnitX * range, Color.Cyan * 0.5f, 2);
|
||||
ShapeExtensions.DrawCircle(spriteBatch, pos, range, 32, Color.Cyan * 0.5f, 3);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Channel = msg.ReadRangedInteger(MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,13 @@ namespace Barotrauma.Items.Components
|
||||
wireSprite = overrideSprite ?? defaultWireSprite;
|
||||
}
|
||||
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
Draw(spriteBatch, editing, Vector2.Zero, itemDepth);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, Vector2 offset, float itemDepth = -1)
|
||||
{
|
||||
if (sections.Count == 0 && !IsActive || Hidden)
|
||||
{
|
||||
@@ -156,6 +162,8 @@ namespace Barotrauma.Items.Components
|
||||
drawOffset = sub.DrawPosition + sub.HiddenSubPosition;
|
||||
}
|
||||
|
||||
drawOffset += offset;
|
||||
|
||||
float baseDepth = UseSpriteDepth ? item.SpriteDepth : wireSprite.Depth;
|
||||
float depth = item.IsSelected ? 0.0f : SubEditorScreen.IsWiringMode() ? 0.02f : baseDepth + (item.ID % 100) * 0.000001f;// item.GetDrawDepth(wireSprite.Depth, wireSprite);
|
||||
|
||||
@@ -286,7 +294,6 @@ namespace Barotrauma.Items.Components
|
||||
item.Color, depth, 0.3f);
|
||||
}
|
||||
|
||||
|
||||
public static void UpdateEditing(List<Wire> wires)
|
||||
{
|
||||
var doubleClicked = PlayerInput.DoubleClicked();
|
||||
@@ -509,6 +516,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,14 +580,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void GetAvailablePower(out float availableCharge, out float availableCapacity)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
availableCharge = 0.0f;
|
||||
availableCapacity = 0.0f;
|
||||
foreach (PowerContainer battery in batteries)
|
||||
if (item.Connections == null) { return; }
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
availableCharge += battery.Charge;
|
||||
availableCapacity += battery.Capacity;
|
||||
var recipients = c.Recipients;
|
||||
foreach (Connection recipient in recipients)
|
||||
{
|
||||
if (!recipient.IsPower || !recipient.IsOutput) { continue; }
|
||||
var battery = recipient.Item?.GetComponent<PowerContainer>();
|
||||
if (battery == null) { continue; }
|
||||
availableCharge += battery.Charge;
|
||||
availableCapacity += battery.Capacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,7 +653,9 @@ namespace Barotrauma.Items.Components
|
||||
bool readyToFire = reload <= 0.0f && charged && availableAmmo.Any(p => p != null);
|
||||
if (ShowChargeIndicator && PowerConsumption > 0.0f)
|
||||
{
|
||||
powerIndicator.Color = charged ? GUI.Style.Green : GUI.Style.Red;
|
||||
powerIndicator.Color = charged ?
|
||||
(HasPowerToShoot() ? GUI.Style.Green : GUI.Style.Orange) :
|
||||
GUI.Style.Red;
|
||||
if (flashLowPower)
|
||||
{
|
||||
powerIndicator.BarSize = 1;
|
||||
|
||||
@@ -10,7 +10,13 @@ namespace Barotrauma.Items.Components
|
||||
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
|
||||
if (roundedValue == 0) { return; }
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}";
|
||||
|
||||
string afflictionName =
|
||||
AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ??
|
||||
TextManager.Get($"afflictiontype.{afflictionIdentifier}", returnNull: true) ??
|
||||
afflictionIdentifier;
|
||||
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {afflictionName}";
|
||||
}
|
||||
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
@@ -33,9 +39,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
||||
}
|
||||
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes)
|
||||
foreach (string afflictionType in damageModifier.ParsedAfflictionTypes)
|
||||
{
|
||||
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
||||
GetDamageModifierText(ref description, damageModifier, afflictionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1584,6 +1584,10 @@ namespace Barotrauma
|
||||
{
|
||||
containedState = item.Condition / item.MaxCondition;
|
||||
}
|
||||
else if (itemContainer.ShowTotalStackCapacityInContainedStateIndicator)
|
||||
{
|
||||
containedState = itemContainer.Inventory.AllItems.Count() / (float)(itemContainer.GetMaxStackSize(0) * itemContainer.Capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var containedItem = itemContainer.Inventory.slots[Math.Max(itemContainer.ContainedStateIndicatorSlot, 0)].FirstOrDefault();
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1172,7 +1181,7 @@ namespace Barotrauma
|
||||
}
|
||||
texts.Add(new ColoredText(nameText, GUI.Style.TextColor, false, false));
|
||||
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||
if (CampaignMode.BlocksInteraction(CampaignInteractionType))
|
||||
{
|
||||
texts.Add(new ColoredText(TextManager.GetWithVariable($"CampaignInteraction.{CampaignInteractionType}", "[key]", GameMain.Config.KeyBindText(InputType.Use)), Color.Cyan, false, false));
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1541,6 +1550,7 @@ namespace Barotrauma
|
||||
|
||||
Vector2 pos = Vector2.Zero;
|
||||
Submarine sub = null;
|
||||
float rotation = 0.0f;
|
||||
int itemContainerIndex = -1;
|
||||
int inventorySlotIndex = -1;
|
||||
|
||||
@@ -1552,7 +1562,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
pos = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
|
||||
rotation = msg.ReadRangedSingle(0, MathHelper.TwoPi, 8);
|
||||
ushort subID = msg.ReadUInt16();
|
||||
if (subID > 0)
|
||||
{
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveClaim(itemId);
|
||||
RemoveClaim(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -14,7 +13,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowGaps;
|
||||
return ShowGaps && SubEditorScreen.IsLayerVisible(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +24,14 @@ namespace Barotrauma
|
||||
|
||||
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
|
||||
{
|
||||
float depth = (ID % 255) * 0.000001f;
|
||||
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
{
|
||||
Vector2 center = new Vector2(WorldRect.X + rect.Width / 2.0f, -(WorldRect.Y - rect.Height / 2.0f));
|
||||
GUI.DrawLine(sb, center, center + new Vector2(flowForce.X, -flowForce.Y) / 10.0f, GUI.Style.Red);
|
||||
GUI.DrawLine(sb, center + Vector2.One * 5.0f, center + new Vector2(lerpedFlowForce.X, -lerpedFlowForce.Y) / 10.0f + Vector2.One * 5.0f, GUI.Style.Orange);
|
||||
if (FlowTargetHull != null)
|
||||
{
|
||||
DrawArrow(FlowTargetHull, IsHorizontal ? rect.Height: rect.Width, Math.Abs(lerpedFlowForce.Length()), Color.Red * 0.3f);
|
||||
}
|
||||
|
||||
if (outsideCollisionBlocker.Enabled && Submarine != null)
|
||||
{
|
||||
@@ -42,12 +44,10 @@ 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;
|
||||
|
||||
float depth = (ID % 255) * 0.000001f;
|
||||
if (IsHighlighted) { clr = Color.Gold; }
|
||||
|
||||
GUI.DrawRectangle(
|
||||
sb, new Rectangle(WorldRect.X, -WorldRect.Y, rect.Width, rect.Height),
|
||||
@@ -81,33 +81,38 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < linkedTo.Count; i++)
|
||||
{
|
||||
Vector2 dir = IsHorizontal ?
|
||||
new Vector2(Math.Sign(linkedTo[i].Rect.Center.X - rect.Center.X), 0.0f)
|
||||
: new Vector2(0.0f, Math.Sign((rect.Y - rect.Height / 2.0f) - (linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f)));
|
||||
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
float arrowWidth = 32.0f;
|
||||
float arrowSize = 15.0f;
|
||||
|
||||
bool invalidDir = false;
|
||||
if (dir == Vector2.Zero)
|
||||
if (linkedTo[i] is Hull hull)
|
||||
{
|
||||
invalidDir = true;
|
||||
dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY;
|
||||
DrawArrow(hull, 32.0f, 15f, clr);
|
||||
}
|
||||
|
||||
GUI.Arrow.Draw(sb,
|
||||
arrowPos, invalidDir ? Color.Red : clr * 0.8f,
|
||||
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
|
||||
IsHorizontal ?
|
||||
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) :
|
||||
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y),
|
||||
SpriteEffects.None, depth);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawArrow(Hull targetHull, float arrowWidth, float arrowLength, Color clr)
|
||||
{
|
||||
Vector2 dir = IsHorizontal ?
|
||||
new Vector2(Math.Sign(targetHull.Rect.Center.X - rect.Center.X), 0.0f)
|
||||
: new Vector2(0.0f, Math.Sign((rect.Y - rect.Height / 2.0f) - (targetHull.Rect.Y - targetHull.Rect.Height / 2.0f)));
|
||||
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
bool invalidDir = false;
|
||||
if (dir == Vector2.Zero)
|
||||
{
|
||||
invalidDir = true;
|
||||
dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY;
|
||||
}
|
||||
|
||||
GUI.Arrow.Draw(sb,
|
||||
arrowPos, invalidDir ? Color.Red : clr * 0.8f,
|
||||
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
|
||||
IsHorizontal ?
|
||||
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowLength / GUI.Arrow.size.Y) :
|
||||
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowLength / GUI.Arrow.size.Y),
|
||||
SpriteEffects.None, depth);
|
||||
}
|
||||
|
||||
if (IsSelected)
|
||||
{
|
||||
GUI.DrawRectangle(sb,
|
||||
@@ -128,8 +133,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 (var linkedEntity in hull1.linkedTo)
|
||||
{
|
||||
if (linkedEntity is Hull h && h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
foreach (var linkedEntity in hull2.linkedTo)
|
||||
{
|
||||
if (linkedEntity is Hull h && h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos = Position;
|
||||
@@ -177,7 +188,7 @@ namespace Barotrauma
|
||||
"bubbles",
|
||||
(Submarine == null ? pos : pos + Submarine.Position),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
@@ -202,9 +213,9 @@ namespace Barotrauma
|
||||
"watersplash",
|
||||
(Submarine == null ? pos : pos + Submarine.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
if (particle != null)
|
||||
{
|
||||
if (particle.CurrentHull == null) { GameMain.ParticleManager.RemoveParticle(particle); }
|
||||
particle.Size *= Math.Min(Math.Abs(flowForce.X / 500.0f), 5.0f);
|
||||
}
|
||||
}
|
||||
@@ -232,13 +243,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) return;
|
||||
if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) { return; }
|
||||
|
||||
float particlesPerSec = open * rect.Width * 0.3f * particleAmountMultiplier;
|
||||
float particlesPerSec = Math.Max(open * rect.Width * 0.3f * particleAmountMultiplier, 20.0f);
|
||||
float emitInterval = 1.0f / particlesPerSec;
|
||||
while (particleTimer > emitInterval)
|
||||
{
|
||||
pos.X = Rand.Range(rect.X, rect.X + rect.Width);
|
||||
pos.X = Rand.Range(rect.X, rect.X + rect.Width + 1);
|
||||
Vector2 velocity = new Vector2(
|
||||
lerpedFlowForce.X * Rand.Range(0.5f, 0.7f),
|
||||
MathHelper.Clamp(lerpedFlowForce.Y, -500.0f, 1000.0f) * Rand.Range(0.5f, 0.7f));
|
||||
@@ -246,17 +257,21 @@ namespace Barotrauma
|
||||
if (flowTargetHull.WaterVolume < flowTargetHull.Volume * 0.95f)
|
||||
{
|
||||
var splash = GameMain.ParticleManager.CreateParticle(
|
||||
"watersplash",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
velocity, 0, FlowTargetHull);
|
||||
if (splash != null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f);
|
||||
"watersplash",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
velocity, 0, FlowTargetHull);
|
||||
if (splash != null)
|
||||
{
|
||||
if (splash.CurrentHull == null) { GameMain.ParticleManager.RemoveParticle(splash); }
|
||||
splash.Size *= MathHelper.Clamp(rect.Width / 50.0f, 1.5f, 4.0f);
|
||||
}
|
||||
}
|
||||
if (Math.Abs(flowForce.Y) > 190.0f && Rand.Range(0.0f, 1.0f) < 0.3f && flowTargetHull.WaterVolume > flowTargetHull.Volume * 0.1f)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
"bubbles",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
flowForce / 2.0f, 0, FlowTargetHull);
|
||||
"bubbles",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
flowForce / 2.0f, 0, FlowTargetHull);
|
||||
}
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
|
||||
@@ -34,14 +34,27 @@ namespace Barotrauma
|
||||
private readonly List<RemoteDecal> remoteDecals = new List<RemoteDecal>();
|
||||
|
||||
private readonly HashSet<Decal> pendingDecalUpdates = new HashSet<Decal>();
|
||||
|
||||
|
||||
private double lastAmbientLightEditTime;
|
||||
|
||||
private float drawSurface;
|
||||
|
||||
public float DrawSurface
|
||||
{
|
||||
get { return drawSurface; }
|
||||
set
|
||||
{
|
||||
if (Math.Abs(drawSurface - value) < 0.00001f) { return; }
|
||||
drawSurface = MathHelper.Clamp(value, rect.Y - rect.Height, rect.Y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowHulls;
|
||||
return ShowHulls && SubEditorScreen.IsLayerVisible(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,91 +146,101 @@ 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)
|
||||
partial void UpdateProjSpecific(float deltaTime, Camera _)
|
||||
{
|
||||
serverUpdateDelay -= deltaTime;
|
||||
if (serverUpdateDelay <= 0.0f)
|
||||
{
|
||||
ApplyRemoteState();
|
||||
}
|
||||
float waterDepth = WaterVolume / rect.Width;
|
||||
//interpolate the position of the rendered surface towards the "target surface"
|
||||
drawSurface = Math.Max(MathHelper.Lerp(
|
||||
drawSurface,
|
||||
rect.Y - rect.Height + waterDepth,
|
||||
deltaTime * 10.0f), rect.Y - rect.Height);
|
||||
|
||||
if (networkUpdatePending)
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
serverUpdateDelay -= deltaTime;
|
||||
if (serverUpdateDelay <= 0.0f)
|
||||
{
|
||||
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;
|
||||
ApplyRemoteState();
|
||||
}
|
||||
}
|
||||
|
||||
if (!IdFreed)
|
||||
{
|
||||
if (EditWater)
|
||||
if (networkUpdatePending)
|
||||
{
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (Submarine.RectContains(WorldRect, position))
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonHeld())
|
||||
if (!pendingSectionUpdates.Any() && !pendingDecalUpdates.Any())
|
||||
{
|
||||
WaterVolume += 1500.0f;
|
||||
networkUpdatePending = true;
|
||||
serverUpdateDelay = 0.5f;
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
}
|
||||
else if (PlayerInput.SecondaryMouseButtonHeld())
|
||||
foreach (Decal decal in pendingDecalUpdates)
|
||||
{
|
||||
WaterVolume -= 1500.0f;
|
||||
networkUpdatePending = true;
|
||||
serverUpdateDelay = 0.5f;
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { decal });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (EditFire)
|
||||
{
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (Submarine.RectContains(WorldRect, position))
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
new FireSource(position, this, isNetworkMessage: true);
|
||||
networkUpdatePending = true;
|
||||
serverUpdateDelay = 0.5f;
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { pendingSectionUpdate });
|
||||
}
|
||||
pendingSectionUpdates.Clear();
|
||||
networkUpdatePending = false;
|
||||
networkUpdateTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waterVolume < 1.0f) { return; }
|
||||
/*if (waterVolume < 1.0f) { return; }
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i]));
|
||||
if (maxDelta > 1.0f && maxDelta > Rand.Range(1.0f, 10.0f))
|
||||
if (maxDelta > 0.1f && maxDelta > Rand.Range(0.1f, 10.0f))
|
||||
{
|
||||
var particlePos = new Vector2(rect.X + WaveWidth * i, surface + waveY[i]);
|
||||
if (Submarine != null) particlePos += Submarine.Position;
|
||||
if (Submarine != null) { particlePos += Submarine.Position; }
|
||||
|
||||
GameMain.ParticleManager.CreateParticle("mist",
|
||||
particlePos,
|
||||
new Vector2(0.0f, -50.0f), 0.0f, this);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public static void UpdateCheats(float deltaTime, Camera cam)
|
||||
{
|
||||
bool primaryMouseButtonHeld = PlayerInput.PrimaryMouseButtonHeld();
|
||||
bool secondaryMouseButtonHeld = PlayerInput.SecondaryMouseButtonHeld();
|
||||
if (!primaryMouseButtonHeld && !secondaryMouseButtonHeld) { return; }
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
Hull hull = FindHull(position);
|
||||
|
||||
if (hull == null || hull.IdFreed) { return; }
|
||||
if (EditWater)
|
||||
{
|
||||
if (primaryMouseButtonHeld)
|
||||
{
|
||||
hull.WaterVolume += 100000.0f * deltaTime;
|
||||
hull.networkUpdatePending = true;
|
||||
hull.serverUpdateDelay = 0.5f;
|
||||
}
|
||||
else if (secondaryMouseButtonHeld)
|
||||
{
|
||||
hull.WaterVolume -= 100000.0f * deltaTime;
|
||||
hull.networkUpdatePending = true;
|
||||
hull.serverUpdateDelay = 0.5f;
|
||||
}
|
||||
|
||||
}
|
||||
else if (EditFire)
|
||||
{
|
||||
if (primaryMouseButtonHeld)
|
||||
{
|
||||
new FireSource(position, hull, isNetworkMessage: true);
|
||||
hull.networkUpdatePending = true;
|
||||
hull.serverUpdateDelay = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +266,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 +408,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 +463,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 +483,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 +501,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 +738,7 @@ namespace Barotrauma
|
||||
}
|
||||
remoteBackgroundSections.Clear();
|
||||
|
||||
if (remoteDecals.Any())
|
||||
if (remoteDecals.Count > 0)
|
||||
{
|
||||
decals.Clear();
|
||||
foreach (RemoteDecal remoteDecal in remoteDecals)
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Barotrauma
|
||||
var prefab = ToolBox.SelectWeightedRandom(availablePrefabs, availablePrefabs.Select(p => p.GetCommonness(level.GenerationParams)).ToList(), Rand.RandSync.ClientOnly);
|
||||
if (prefab == null) { break; }
|
||||
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax, Rand.RandSync.ClientOnly);
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax + 1, Rand.RandSync.ClientOnly);
|
||||
List<BackgroundCreature> swarmMembers = new List<BackgroundCreature>();
|
||||
for (int n = 0; n < amount; n++)
|
||||
{
|
||||
|
||||
@@ -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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,18 +130,31 @@ namespace Barotrauma
|
||||
int tilesY = (int)Math.Ceiling(Height / tileSize.Y);
|
||||
mapTiles = new Sprite[tilesX, tilesY];
|
||||
tileDiscovered = new bool[tilesX, tilesY];
|
||||
HashSet<Biome> missingBiomes = new HashSet<Biome>();
|
||||
for (int x = 0; x < tilesX; x++)
|
||||
{
|
||||
for (int y = 0; y < tilesY; y++)
|
||||
{
|
||||
var biome = GetBiome(x * tileSize.X);
|
||||
var tileList = generationParams.MapTiles.ContainsKey(biome.Identifier) ?
|
||||
generationParams.MapTiles[biome.Identifier] :
|
||||
generationParams.MapTiles.Values.First();
|
||||
List<Sprite> tileList = null;
|
||||
if (generationParams.MapTiles.ContainsKey(biome.Identifier))
|
||||
{
|
||||
tileList = generationParams.MapTiles[biome.Identifier];
|
||||
}
|
||||
else
|
||||
{
|
||||
tileList = generationParams.MapTiles.Values.First();
|
||||
missingBiomes.Add(biome);
|
||||
}
|
||||
mapTiles[x, y] = tileList[x % tileList.Count];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var missingBiome in missingBiomes)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find campaign map sprites for the biome \"{missingBiome.Identifier}\". Using the sprites of the first biome instead...");
|
||||
}
|
||||
|
||||
RemoveFogOfWar(StartLocation);
|
||||
|
||||
GenerateLocationConnectionVisuals();
|
||||
@@ -194,7 +207,11 @@ namespace Barotrauma
|
||||
private void RemoveFogOfWar(Location location, bool removeFromAdjacentLocations = true)
|
||||
{
|
||||
if (location == null) { return; }
|
||||
Vector2 mapTileSize = mapTiles[0, 0].size * generationParams.MapTileScale;
|
||||
|
||||
var mapTile = generationParams.MapTiles.Values.FirstOrDefault()?.FirstOrDefault();
|
||||
if (mapTile == null) { return; }
|
||||
|
||||
Vector2 mapTileSize = mapTile.size * generationParams.MapTileScale;
|
||||
int startX = (int)Math.Max(Math.Floor(location.MapPosition.X / mapTileSize.X - 0.25f), 0);
|
||||
int startY = (int)Math.Max(Math.Floor(location.MapPosition.Y / mapTileSize.Y - 0.25f), 0);
|
||||
int endX = (int)Math.Min(Math.Floor(location.MapPosition.X / mapTileSize.X + 0.25f), mapTiles.GetLength(0));
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Lights;
|
||||
|
||||
@@ -36,9 +37,6 @@ namespace Barotrauma
|
||||
|
||||
private static List<MapEntity> highlightedList = new List<MapEntity>();
|
||||
|
||||
// Test feature. Not yet saved.
|
||||
public static Dictionary<MapEntity, HashSet<MapEntity>> SelectionGroups { get; private set; } = new Dictionary<MapEntity, HashSet<MapEntity>>();
|
||||
|
||||
private static float highlightTimer;
|
||||
|
||||
private static GUIListBox highlightedListBox;
|
||||
@@ -197,7 +195,7 @@ namespace Barotrauma
|
||||
{
|
||||
Paste(cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.G))
|
||||
/*else if (PlayerInput.KeyHit(Keys.G))
|
||||
{
|
||||
if (SelectedList.Any())
|
||||
{
|
||||
@@ -217,7 +215,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,14 +358,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (highLightedEntity != null)
|
||||
{
|
||||
if (SelectionGroups.TryGetValue(highLightedEntity, out HashSet<MapEntity> group))
|
||||
if (SubEditorScreen.IsLayerLinked(highLightedEntity)/*SelectionGroups.TryGetValue(highLightedEntity, out HashSet<MapEntity> group)*/)
|
||||
{
|
||||
foreach (MapEntity entity in group.Where(e => !newSelection.Contains(e)))
|
||||
ImmutableHashSet<MapEntity> entitiesInSameLayer = SubEditorScreen.GetEntitiesInSameLayer(highLightedEntity);
|
||||
foreach (MapEntity entity in entitiesInSameLayer.Where(e => !newSelection.Contains(e)))
|
||||
{
|
||||
newSelection.Add(entity);
|
||||
}
|
||||
|
||||
foreach (MapEntity entity in group)
|
||||
foreach (MapEntity entity in entitiesInSameLayer)
|
||||
{
|
||||
entity.IsIncludedInSelection = true;
|
||||
}
|
||||
@@ -769,34 +768,40 @@ namespace Barotrauma
|
||||
switch (e)
|
||||
{
|
||||
case Item item:
|
||||
{
|
||||
if (item.FlippedX && item.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
|
||||
if (item.flippedY && item.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
|
||||
break;
|
||||
}
|
||||
{
|
||||
if (item.FlippedX && item.Prefab.CanSpriteFlipX) { spriteEffects ^= SpriteEffects.FlipHorizontally; }
|
||||
if (item.flippedY && item.Prefab.CanSpriteFlipY) { spriteEffects ^= SpriteEffects.FlipVertically; }
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire != null && wire.Item.body != null && !wire.Item.body.Enabled)
|
||||
{
|
||||
wire.Draw(spriteBatch, editing: false, new Vector2(moveAmount.X, -moveAmount.Y));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Structure structure:
|
||||
{
|
||||
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
|
||||
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
|
||||
break;
|
||||
}
|
||||
{
|
||||
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) { spriteEffects ^= SpriteEffects.FlipHorizontally; }
|
||||
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) { spriteEffects ^= SpriteEffects.FlipVertically; }
|
||||
break;
|
||||
}
|
||||
case WayPoint wayPoint:
|
||||
{
|
||||
Vector2 drawPos = e.WorldPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
drawPos += moveAmount;
|
||||
wayPoint.Draw(spriteBatch, drawPos);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
Vector2 drawPos = e.WorldPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
drawPos += moveAmount;
|
||||
wayPoint.Draw(spriteBatch, drawPos);
|
||||
continue;
|
||||
}
|
||||
case LinkedSubmarine linkedSub:
|
||||
{
|
||||
var ma = moveAmount;
|
||||
ma.Y = -ma.Y;
|
||||
Vector2 lPos = linkedSub.Position;
|
||||
lPos += ma;
|
||||
linkedSub.Draw(spriteBatch, lPos, alpha: 0.5f);
|
||||
break;
|
||||
}
|
||||
{
|
||||
var ma = moveAmount;
|
||||
ma.Y = -ma.Y;
|
||||
Vector2 lPos = linkedSub.Position;
|
||||
lPos += ma;
|
||||
linkedSub.Draw(spriteBatch, lPos, alpha: 0.5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
e.prefab?.DrawPlacing(spriteBatch,
|
||||
new Rectangle(e.WorldRect.Location + new Point((int)moveAmount.X, (int)-moveAmount.Y), e.WorldRect.Size), e.Scale, spriteEffects);
|
||||
@@ -1197,14 +1202,24 @@ namespace Barotrauma
|
||||
|
||||
Rectangle selectionRect = Submarine.AbsRect(pos, size);
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
{
|
||||
if (!e.SelectableInEditor) continue;
|
||||
if (!entity.SelectableInEditor) { continue; }
|
||||
|
||||
if (Submarine.RectsOverlap(selectionRect, e.rect))
|
||||
if (Submarine.RectsOverlap(selectionRect, entity.rect))
|
||||
{
|
||||
foundEntities.Add(e);
|
||||
e.IsIncludedInSelection = true;
|
||||
foundEntities.Add(entity);
|
||||
entity.IsIncludedInSelection = true;
|
||||
|
||||
if (SubEditorScreen.IsLayerLinked(entity))
|
||||
{
|
||||
ImmutableHashSet<MapEntity> entitiesInSameLayer = SubEditorScreen.GetEntitiesInSameLayer(entity);
|
||||
foreach (MapEntity layerEntity in entitiesInSameLayer.Where(e => !foundEntities.Contains(e)))
|
||||
{
|
||||
foundEntities.Add(layerEntity);
|
||||
layerEntity.IsIncludedInSelection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -55,9 +55,9 @@ namespace Barotrauma
|
||||
if (closestSub != null && subsToMove.Contains(closestSub))
|
||||
{
|
||||
GameMain.GameScreen.Cam.Position += moveAmount;
|
||||
if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += moveAmount;
|
||||
if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) { GameMain.GameScreen.Cam.TargetPos += moveAmount; }
|
||||
|
||||
if (Character.Controlled != null) Character.Controlled.CursorPosition += moveAmount;
|
||||
if (Character.Controlled != null) { Character.Controlled.CursorPosition += moveAmount; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -91,7 +91,7 @@ namespace Barotrauma
|
||||
public void CreateSpecsWindow(GUIListBox parent, ScalableFont font, bool includeTitle = true, bool includeClass = true, bool includeDescription = false)
|
||||
{
|
||||
float leftPanelWidth = 0.6f;
|
||||
float rightPanelWidth = 0.4f;
|
||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||
string className = !HasTag(SubmarineTag.Shuttle) ? TextManager.Get($"submarineclass.{SubmarineClass}") : TextManager.Get("shuttle");
|
||||
|
||||
int classHeight = (int)GUI.SubHeadingFont.MeasureString(className).Y;
|
||||
@@ -110,6 +110,17 @@ namespace Barotrauma
|
||||
submarineClassText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, classHeight), parent.Content.RectTransform), className, textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont) { CanBeFocused = false };
|
||||
submarineClassText.RectTransform.MinSize = new Point(0, (int)submarineClassText.TextSize.Y);
|
||||
}
|
||||
|
||||
if (Price > 0)
|
||||
{
|
||||
var priceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("subeditor.price"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), priceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", Price)), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
}
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
if (realWorldDimensions != Vector2.Zero)
|
||||
{
|
||||
|
||||
@@ -316,11 +316,11 @@ namespace Barotrauma
|
||||
var srcRect = prefab.sprite.SourceRect;
|
||||
|
||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||
if (flippedX)
|
||||
if (flippedX && ((prefab as ItemPrefab)?.CanSpriteFlipX ?? true))
|
||||
{
|
||||
spriteEffects |= SpriteEffects.FlipHorizontally;
|
||||
}
|
||||
if (flippedY)
|
||||
if (flippedY && ((prefab as ItemPrefab)?.CanSpriteFlipY ?? true))
|
||||
{
|
||||
spriteEffects |= SpriteEffects.FlipVertically;
|
||||
}
|
||||
@@ -651,7 +651,11 @@ namespace Barotrauma
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
previewFrame = null;
|
||||
if (previewFrame != null)
|
||||
{
|
||||
previewFrame.RectTransform.Parent = null;
|
||||
previewFrame = null;
|
||||
}
|
||||
spriteRecorder?.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(ConnectedGap.WorldPosition.X, -ConnectedGap.WorldPosition.Y),
|
||||
new Vector2(ConnectedGap.DrawPosition.X, -ConnectedGap.DrawPosition.Y),
|
||||
GUI.Style.Green * 0.5f, width: 1);
|
||||
}
|
||||
if (Ladders != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(Ladders.Item.WorldPosition.X, -Ladders.Item.WorldPosition.Y),
|
||||
new Vector2(Ladders.Item.DrawPosition.X, -Ladders.Item.DrawPosition.Y),
|
||||
GUI.Style.Green * 0.5f, width: 1);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ namespace Barotrauma.Networking
|
||||
senderName = senderCharacter.Name;
|
||||
}
|
||||
}
|
||||
|
||||
Color? textColor = null;
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
textColor = msg.ReadColorR8G8B8A8();
|
||||
}
|
||||
|
||||
msg.ReadPadBits();
|
||||
|
||||
switch (type)
|
||||
@@ -78,7 +85,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)
|
||||
{
|
||||
@@ -135,14 +142,18 @@ namespace Barotrauma.Networking
|
||||
//only show the message box if the text differs from the text in the currently visible box
|
||||
if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
|
||||
{
|
||||
new GUIMessageBox("", txt);
|
||||
GUIMessageBox messageBox = new GUIMessageBox("", txt);
|
||||
if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.ServerMessageBoxInGame:
|
||||
new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
|
||||
{
|
||||
GUIMessageBox messageBox = new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
|
||||
if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.Console:
|
||||
DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
|
||||
DebugConsole.NewMessage(txt, textColor == null ? MessageColor[(int)ChatMessageType.Console] : textColor.Value);
|
||||
break;
|
||||
case ChatMessageType.ServerLog:
|
||||
if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType))
|
||||
@@ -152,7 +163,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
|
||||
break;
|
||||
default:
|
||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType);
|
||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType, textColor: textColor);
|
||||
break;
|
||||
}
|
||||
LastID = id;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -15,7 +16,11 @@ namespace Barotrauma
|
||||
var entity = FindEntityByID(entityId);
|
||||
if (entity != null)
|
||||
{
|
||||
DebugConsole.Log("Received entity removal message for \"" + entity.ToString() + "\".");
|
||||
DebugConsole.Log($"Received entity removal message for \"{entity}\".");
|
||||
if (entity is Item item && item.Container?.GetComponent<Deconstructor>() != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ItemDeconstructed:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none") + ":" + item.prefab.Identifier);
|
||||
}
|
||||
entity.Remove();
|
||||
}
|
||||
else
|
||||
@@ -28,7 +33,11 @@ namespace Barotrauma
|
||||
switch (message.ReadByte())
|
||||
{
|
||||
case (byte)SpawnableType.Item:
|
||||
Item.ReadSpawnData(message, true);
|
||||
var newItem = Item.ReadSpawnData(message, true);
|
||||
if (newItem is Item item && item.Container?.GetComponent<Fabricator>() != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none") + ":" + item.prefab.Identifier);
|
||||
}
|
||||
break;
|
||||
case (byte)SpawnableType.Character:
|
||||
Character.ReadSpawnData(message);
|
||||
|
||||
@@ -859,7 +859,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAMEFINALIZE:
|
||||
DebugConsole.Log("Received STARTGAMEFINALIZE packet.");
|
||||
DebugConsole.NewMessage("Received STARTGAMEFINALIZE packet. Round init status: " + roundInitStatus);
|
||||
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
|
||||
{
|
||||
//waiting for a save file
|
||||
@@ -950,6 +950,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;
|
||||
@@ -1121,9 +1124,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)
|
||||
@@ -1276,7 +1279,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)
|
||||
@@ -1476,7 +1487,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;
|
||||
@@ -1488,6 +1499,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();
|
||||
@@ -1626,6 +1639,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
GameMain.GameSession.StartRound(levelData, mirrorLevel);
|
||||
}
|
||||
isOutpost = levelData.Type == LevelData.LevelType.Outpost;
|
||||
}
|
||||
|
||||
if (GameMain.Client?.ServerSettings?.Voting != null)
|
||||
@@ -1745,8 +1759,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;
|
||||
@@ -1877,7 +1890,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);
|
||||
}
|
||||
@@ -1893,7 +1906,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);
|
||||
}
|
||||
@@ -2095,13 +2108,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();
|
||||
|
||||
@@ -2162,16 +2168,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2604,7 +2605,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);
|
||||
}
|
||||
|
||||
@@ -2881,19 +2881,16 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void SendCampaignState()
|
||||
{
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||
if (campaign == null)
|
||||
if (!(GameMain.GameSession.GameMode is MultiPlayerCampaign campaign))
|
||||
{
|
||||
DebugConsole.ThrowError("Failed send campaign state to the server (no campaign active).\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||
msg.Write((UInt16)ClientPermissions.ManageCampaign);
|
||||
campaign.ClientWrite(msg);
|
||||
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
@@ -3571,6 +3568,11 @@ namespace Barotrauma.Networking
|
||||
case ClientNetError.MISSING_ENTITY:
|
||||
outMsg.Write(eventID);
|
||||
outMsg.Write(entityID);
|
||||
outMsg.Write((byte)Submarine.Loaded.Count);
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
outMsg.Write(sub.Info.Name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
clientPeer.Send(outMsg, DeliveryMethod.Reliable);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user