v0.19.0.0 (unstable)

This commit is contained in:
Regalis11
2022-07-20 18:47:07 +03:00
parent 2e2663a175
commit 6b55adcdd9
170 changed files with 2769 additions and 1634 deletions
@@ -159,7 +159,7 @@ namespace Barotrauma
GameMain.LightManager.LosEnabled = true;
}
#endif
timer += CoroutineManager.UnscaledDeltaTime;
timer += CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
@@ -73,6 +73,11 @@ namespace Barotrauma
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
if (State == AIState.Attack && selectedTargetingParams != null && selectedTargetingParams.AttackPattern == AttackPattern.Circle)
{
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 100.0f, CirclePhase.ToString(), stateColor, Color.Black);
}
if (LatchOntoAI != null && (State == AIState.Idle || LatchOntoAI.IsAttachedToSub))
{
foreach (Joint attachJoint in LatchOntoAI.AttachJoints)
@@ -1,15 +1,14 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Particles;
using Barotrauma.SpriteDeformations;
using Barotrauma.Extensions;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
using System.Collections.Generic;
using Barotrauma.Particles;
using System.Linq;
namespace Barotrauma
{
@@ -55,21 +54,34 @@ namespace Barotrauma
if (character.MemState[0].SelectedItem == null || character.MemState[0].SelectedItem.Removed)
{
character.SelectedConstruction = null;
character.SelectedItem = null;
}
else
else if (character.SelectedItem != character.MemState[0].SelectedItem)
{
if (character.SelectedConstruction != character.MemState[0].SelectedItem)
foreach (var ic in character.MemState[0].SelectedItem.Components)
{
foreach (var ic in character.MemState[0].SelectedItem.Components)
if (ic.CanBeSelected)
{
if (ic.CanBeSelected)
{
ic.Select(character);
}
ic.Select(character);
}
}
character.SelectedConstruction = character.MemState[0].SelectedItem;
character.SelectedItem = character.MemState[0].SelectedItem;
}
if (character.MemState[0].SelectedSecondaryItem == null || character.MemState[0].SelectedSecondaryItem.Removed)
{
character.SelectedSecondaryItem = null;
}
else if (character.SelectedSecondaryItem != character.MemState[0].SelectedSecondaryItem)
{
foreach (var ic in character.MemState[0].SelectedSecondaryItem.Components)
{
if (ic.CanBeSelected)
{
ic.Select(character);
}
}
character.SelectedSecondaryItem = character.MemState[0].SelectedSecondaryItem;
}
if (character.MemState[0].Animation == AnimController.Animation.CPR)
@@ -201,15 +213,24 @@ namespace Barotrauma
{
if (serverPos.SelectedItem == null || serverPos.SelectedItem.Removed)
{
character.SelectedConstruction = null;
character.SelectedItem = null;
}
else if (serverPos.SelectedItem != null)
else if (character.SelectedItem != serverPos.SelectedItem)
{
if (character.SelectedConstruction != serverPos.SelectedItem)
{
serverPos.SelectedItem.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true);
}
character.SelectedConstruction = serverPos.SelectedItem;
serverPos.SelectedItem.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true);
character.SelectedItem = serverPos.SelectedItem;
}
}
if (localPos.SelectedSecondaryItem != serverPos.SelectedSecondaryItem)
{
if (serverPos.SelectedSecondaryItem == null || serverPos.SelectedSecondaryItem.Removed)
{
character.SelectedSecondaryItem = null;
}
else if (character.SelectedSecondaryItem != serverPos.SelectedSecondaryItem)
{
serverPos.SelectedSecondaryItem.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true);
character.SelectedSecondaryItem = serverPos.SelectedSecondaryItem;
}
}
@@ -496,12 +517,11 @@ namespace Barotrauma
float maxDepth = 0.0f;
float minDepth = 1.0f;
float depthOffset = 0.0f;
var ladder = character.SelectedConstruction?.GetComponent<Ladder>();
if (ladder != null)
if (character.SelectedSecondaryItem?.GetComponent<Ladder>() is Ladder ladder)
{
CalculateLimbDepths();
if (character.WorldPosition.X < character.SelectedConstruction.WorldPosition.X)
if (character.WorldPosition.X < character.SelectedSecondaryItem.WorldPosition.X)
{
//at the left side of the ladder, needs to be drawn in front of the rungs
if (maxDepth > ladder.BackgroundSpriteDepth)
@@ -522,16 +542,21 @@ namespace Barotrauma
else
{
CalculateLimbDepths();
var controller = character.SelectedConstruction?.GetComponent<Controller>();
if (controller != null && controller.ControlCharacterPose && controller.User == character && controller.UserInCorrectPosition)
AdjustDepthOffset(character.SelectedItem);
AdjustDepthOffset(character.SelectedSecondaryItem);
void AdjustDepthOffset(Item item)
{
if (controller.Item.SpriteDepth <= maxDepth || controller.DrawUserBehind)
if (item?.GetComponent<Controller>() is { ControlCharacterPose: true, UserInCorrectPosition: true } controller && controller.User == character)
{
depthOffset = Math.Max(controller.Item.GetDrawDepth() + 0.0001f - minDepth, -minDepth);
}
else
{
depthOffset = Math.Max(controller.Item.GetDrawDepth() - 0.0001f - maxDepth, 0.0f);
if (controller.Item.SpriteDepth <= maxDepth || controller.DrawUserBehind)
{
depthOffset = Math.Max(controller.Item.GetDrawDepth() + 0.0001f - minDepth, -minDepth);
}
else
{
depthOffset = Math.Max(controller.Item.GetDrawDepth() - 0.0001f - maxDepth, 0.0f);
}
}
}
}
@@ -9,7 +9,6 @@ using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
@@ -323,8 +322,8 @@ namespace Barotrauma
{
cam.OffsetAmount = targetOffsetAmount = item.Prefab.OffsetOnSelected * item.OffsetOnSelectedMultiplier;
}
else if (SelectedConstruction != null && ViewTarget == null &&
SelectedConstruction.Components.Any(ic => ic?.GuiFrame != null && ic.ShouldDrawHUD(this)))
else if (SelectedItem != null && ViewTarget == null &&
SelectedItem.Components.Any(ic => ic?.GuiFrame != null && ic.ShouldDrawHUD(this)))
{
cam.OffsetAmount = targetOffsetAmount = 0.0f;
cursorPosition =
@@ -368,21 +367,20 @@ namespace Barotrauma
if (!GUI.InputBlockingMenuOpen)
{
if (SelectedConstruction != null &&
(SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)) ||
if (SelectedItem != null &&
(SelectedItem.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)) ||
((ViewTarget as Item)?.Prefab.FocusOnSelected ?? false) && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)))
{
if (GameMain.Client != null)
{
//emulate a Select input to get the character to deselect the item server-side
//keys[(int)InputType.Select].Hit = true;
keys[(int)InputType.Deselect].Hit = true;
//emulate a Deselect input to get the character to deselect the item server-side
EmulateInput(InputType.Deselect);
}
//reset focus to prevent us from accidentally interacting with another entity
focusedItem = null;
FocusedCharacter = null;
findFocusedTimer = 0.2f;
SelectedConstruction = null;
SelectedItem = null;
}
}
@@ -425,6 +423,11 @@ namespace Barotrauma
}
}
}
public void EmulateInput(InputType input)
{
keys[(int)input].Hit = true;
}
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
{
@@ -518,7 +521,7 @@ namespace Barotrauma
//reduce the amount of aim assist if an item has been selected
//= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item
//otherwise it would be too easy to accidentally switch the selected item when rewiring items
float aimAssistAmount = SelectedConstruction == null ? 100.0f * aimAssistModifier : 1.0f;
float aimAssistAmount = SelectedItem == null ? 100.0f * aimAssistModifier : 1.0f;
Vector2 displayPosition = ConvertUnits.ToDisplayUnits(simPosition);
@@ -623,12 +626,12 @@ namespace Barotrauma
{
if (this != controlled) { return false; }
if (GameMain.GameSession?.Campaign != null && GameMain.GameSession.Campaign.ShowCampaignUI) { return true; }
var controller = SelectedConstruction?.GetComponent<Controller>();
var controller = SelectedItem?.GetComponent<Controller>();
//lock if using a controller, except if we're also using a connection panel in the same item
return
SelectedConstruction != null &&
SelectedItem != null &&
controller?.User == this && controller.HideHUD &&
SelectedConstruction?.GetComponent<ConnectionPanel>()?.User != this;
SelectedItem?.GetComponent<ConnectionPanel>()?.User != this;
}
@@ -900,7 +903,14 @@ namespace Barotrauma
if (info != null)
{
LocalizedString name = Info.DisplayName;
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
if (controlled == null && name != Info.Name)
{
name += " " + TextManager.Get("Disguised");
}
else if (Info.Title != null)
{
name += '\n' + Info.Title;
}
Vector2 nameSize = GUIStyle.Font.MeasureString(name);
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
@@ -108,7 +108,7 @@ namespace Barotrauma
private static bool ShouldDrawInventory(Character character)
{
var controller = character.SelectedConstruction?.GetComponent<Controller>();
var controller = character.SelectedItem?.GetComponent<Controller>();
return
character?.Inventory != null &&
@@ -417,13 +417,17 @@ namespace Barotrauma
visibleRange = new Range<float>(-100f, 500f);
}
float dist = Vector2.Distance(character.WorldPosition, npc.WorldPosition);
float distFactor = 1.0f - MathUtils.InverseLerp(1000.0f, 3000.0f, dist);
float alpha = MathHelper.Lerp(0.3f, 1.0f, distFactor);
GUI.DrawIndicator(
spriteBatch,
npc.WorldPosition,
cam,
visibleRange,
iconStyle.GetDefaultSprite(),
iconStyle.Color);
iconStyle.Color * alpha,
label: npc.Info?.Title);
}
foreach (Item item in Item.ItemList)
@@ -436,10 +440,10 @@ namespace Barotrauma
}
}
if (character.SelectedConstruction != null &&
(character.CanInteractWith(character.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen))
if (character.SelectedItem != null &&
(character.CanInteractWith(character.SelectedItem) || Screen.Selected == GameMain.SubEditorScreen))
{
character.SelectedConstruction.DrawHUD(spriteBatch, cam, character);
character.SelectedItem.DrawHUD(spriteBatch, cam, character);
}
if (character.Inventory != null)
{
@@ -561,9 +565,15 @@ namespace Barotrauma
Color nameColor = character.FocusedCharacter.GetNameColor();
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUIStyle.SubHeadingFont, ForceUpperCase.No);
textPos.X += 10.0f * GUI.Scale;
textPos.Y += GUIStyle.SubHeadingFont.MeasureString(focusName).Y;
if (character.FocusedCharacter.Info?.Title != null && !character.FocusedCharacter.Info.Title.IsNullOrEmpty())
{
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.Info.Title, nameColor, Color.Black * 0.7f, 2, GUIStyle.SubHeadingFont, ForceUpperCase.No);
textPos.Y += GUIStyle.SubHeadingFont.MeasureString(character.FocusedCharacter.Info.Title.Value).Y;
}
textPos.X += 10.0f * GUI.Scale;
if (!character.FocusedCharacter.IsIncapacitated && character.FocusedCharacter.IsPet)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("PlayHint", InputType.Use),
@@ -102,7 +102,7 @@ namespace Barotrauma
if (PersonalityTrait != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + PersonalityTrait.Name.Replace(" ".ToIdentifier(), "".ToIdentifier()))),
TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), PersonalityTrait.DisplayName),
font: font)
{
Padding = Vector4.Zero
@@ -523,22 +523,20 @@ namespace Barotrauma
Color facialHairColor = inc.ReadColorR8G8B8();
string ragdollFile = inc.ReadString();
string jobIdentifier = inc.ReadString();
uint jobIdentifier = inc.ReadUInt32();
int variant = inc.ReadByte();
JobPrefab jobPrefab = null;
Dictionary<Identifier, float> skillLevels = new Dictionary<Identifier, float>();
if (!string.IsNullOrEmpty(jobIdentifier))
{
jobPrefab = JobPrefab.Get(jobIdentifier);
byte skillCount = inc.ReadByte();
for (int i = 0; i < skillCount; i++)
if (jobIdentifier > 0)
{
jobPrefab = JobPrefab.Prefabs.Find(jp => jp.UintIdentifier == jobIdentifier);
foreach (SkillPrefab skillPrefab in jobPrefab.Skills.OrderBy(s => s.Identifier))
{
Identifier skillIdentifier = inc.ReadIdentifier();
float skillLevel = inc.ReadSingle();
skillLevels.Add(skillIdentifier, skillLevel);
}
}
skillLevels.Add(skillPrefab.Identifier, skillLevel);
}
}
// TODO: animations
CharacterInfo ch = new CharacterInfo(speciesName, newName, originalName, jobPrefab, ragdollFile, variant)
@@ -777,7 +775,21 @@ namespace Barotrauma
createColorSelector($"Customization.{nameof(info.Head.SkinColor)}".ToIdentifier(), info.SkinColors, () => info.Head.SkinColor,
(color) => info.Head.SkinColor = color);
#if DEBUG
new GUIButton(new RectTransform(Vector2.One * 0.12f,
parentComponent.RectTransform,
anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
{ RelativeOffset = new Vector2(0.01f, 0.005f) }, style: "SaveButton", color: Color.Magenta)
{
ToolTip = "DEBUG ONLY: copy the character info XML to clipboard",
OnClicked = (button, o) =>
{
XElement element = info.Save(null);
Clipboard.SetText(element.ToString());
return false;
}
};
#endif
RandomizeButton = new GUIButton(new RectTransform(Vector2.One * 0.12f,
parentComponent.RectTransform,
anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
@@ -1,5 +1,4 @@
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
@@ -44,7 +43,8 @@ namespace Barotrauma
LastNetworkUpdateID,
AnimController.TargetDir,
SelectedCharacter,
SelectedConstruction,
SelectedItem,
SelectedSecondaryItem,
AnimController.Anim);
memLocalState.Add(posInfo);
@@ -219,15 +219,17 @@ namespace Barotrauma
bool entitySelected = msg.ReadBoolean();
Character selectedCharacter = null;
Item selectedItem = null;
Item selectedItem = null, selectedSecondaryItem = null;
AnimController.Animation animation = AnimController.Animation.None;
if (entitySelected)
{
ushort characterID = msg.ReadUInt16();
ushort itemID = msg.ReadUInt16();
ushort secondaryItemID = msg.ReadUInt16();
selectedCharacter = FindEntityByID(characterID) as Character;
selectedItem = FindEntityByID(itemID) as Item;
selectedSecondaryItem = FindEntityByID(secondaryItemID) as Item;
if (characterID != NullEntityID)
{
bool doingCpr = msg.ReadBoolean();
@@ -274,7 +276,7 @@ namespace Barotrauma
pos, rotation,
networkUpdateID,
facingRight ? Direction.Right : Direction.Left,
selectedCharacter, selectedItem, animation);
selectedCharacter, selectedItem, selectedSecondaryItem, animation);
while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
index++;
@@ -286,7 +288,7 @@ namespace Barotrauma
pos, rotation,
linearVelocity, angularVelocity,
sendingTime, facingRight ? Direction.Right : Direction.Left,
selectedCharacter, selectedItem, animation);
selectedCharacter, selectedItem, selectedSecondaryItem, animation);
while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
index++;
@@ -375,9 +377,15 @@ namespace Barotrauma
if (attackLimbIndex == 255 || Removed) { break; }
if (attackLimbIndex >= AnimController.Limbs.Length)
{
string errorMsg = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:AttackLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
//it's possible to get these errors when mid-round syncing, as the client may not
//yet know about afflictions that have given the character extra limbs (e.g. spineling genes)
//ignoring the error should be safe though, not executing the attack should not cause any further issues
if (!GameMain.Client.MidRoundSyncing)
{
string errorMsg = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:AttackLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
break;
}
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
@@ -673,16 +681,17 @@ namespace Barotrauma
AfflictionPrefab causeOfDeathAffliction = null;
if (causeOfDeathType == CauseOfDeathType.Affliction)
{
string afflictionName = msg.ReadString();
if (!AfflictionPrefab.Prefabs.ContainsKey(afflictionName))
uint afflictionId = msg.ReadUInt32();
AfflictionPrefab afflictionPrefab = AfflictionPrefab.Prefabs.Find(p => p.UintIdentifier == afflictionId);
if (afflictionPrefab == null)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction not found ({afflictionName})";
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction not found (id {afflictionId})";
causeOfDeathType = CauseOfDeathType.Unknown;
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionNotFound", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
else
{
causeOfDeathAffliction = AfflictionPrefab.Prefabs[afflictionName];
causeOfDeathAffliction = afflictionPrefab;
}
}
bool containsAfflictionData = msg.ReadBoolean();
@@ -162,11 +162,7 @@ namespace Barotrauma
openHealthWindow.characterName.Text = value.Character.Info.DisplayName;
value.Character.Info.CheckDisguiseStatus(false);
}
if (Character.Controlled.SelectedConstruction != null && Character.Controlled.SelectedConstruction.GetComponent<Ladder>() == null)
{
Character.Controlled.SelectedConstruction = null;
}
Character.Controlled.SelectedItem = null;
}
HintManager.OnShowHealthInterface();
@@ -724,7 +720,7 @@ namespace Barotrauma
//emulate a Health input to get the character to deselect the item server-side
if (GameMain.Client != null)
{
Character.Controlled.Keys[(int)InputType.Health].Hit = true;
Character.Controlled.EmulateInput(InputType.Health);
}
OpenHealthWindow = null;
}
@@ -2014,7 +2010,7 @@ namespace Barotrauma
FaceTint = DefaultFaceTint;
BodyTint = Color.TransparentBlack;
if (!(Character?.Params?.Health.ApplyAfflictionColors ?? false)) { return; }
if (!Character.Params.Health.ApplyAfflictionColors) { return; }
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
@@ -2031,15 +2027,21 @@ namespace Barotrauma
foreach (Limb limb in Character.AnimController.Limbs)
{
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }
limb.BurnOverlayStrength = 0.0f;
limb.DamageOverlayStrength = 0.0f;
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
if (kvp.Value != limbHealths[limb.HealthIndex]) { continue; }
var affliction = kvp.Key;
limb.BurnOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.BurnOverlayAlpha;
limb.DamageOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.DamageOverlayAlpha;
float burnStrength = affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.BurnOverlayAlpha;
if (kvp.Value == limbHealths[limb.HealthIndex])
{
limb.BurnOverlayStrength += burnStrength;
limb.DamageOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.DamageOverlayAlpha;
}
else
{
limb.BurnOverlayStrength += burnStrength / 2;
}
}
}
}
@@ -481,7 +481,7 @@ namespace Barotrauma
{
ContentPath texturePath =
character.Params.VariantFile?.Root?.GetAttributeContentPath("texture", character.Prefab.ContentPackage)
?? ContentPath.FromRaw(character.Prefab.ContentPackage, spriteParams.GetTexturePath());
?? ContentPath.FromRaw(spriteParams.Element.ContentPackage ?? character.Prefab.ContentPackage, spriteParams.GetTexturePath());
path = GetSpritePath(texturePath);
}
else
@@ -1,21 +1,18 @@
using Barotrauma.Items.Components;
using Barotrauma.ClientSource.Settings;
using Barotrauma.Extensions;
using Barotrauma.IO;
using Barotrauma.Items.Components;
using Barotrauma.MapCreatures.Behavior;
using Barotrauma.Networking;
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using Barotrauma.IO;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
using FarseerPhysics;
using Barotrauma.Extensions;
using Barotrauma.Steam;
using System.Threading.Tasks;
using Barotrauma.ClientSource.Settings;
using Barotrauma.MapCreatures.Behavior;
using static Barotrauma.FabricationRecipe;
namespace Barotrauma
@@ -1299,7 +1296,7 @@ namespace Barotrauma
int? fabricationCost = null;
int? deconstructProductCost = null;
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab && f.RequiredItems.Any());
if (fabricationRecipe != null)
{
foreach (var ingredient in fabricationRecipe.RequiredItems)
@@ -1334,6 +1331,21 @@ namespace Barotrauma
if (fabricationRecipe != null)
{
var ingredient = fabricationRecipe.RequiredItems.Find(r => r.ItemPrefabs.Contains(targetItem));
if (ingredient == null)
{
foreach (var requiredItem in fabricationRecipe.RequiredItems)
{
foreach (var itemPrefab2 in requiredItem.ItemPrefabs)
{
foreach (var recipe in itemPrefab2.FabricationRecipes.Values)
{
ingredient ??= recipe.RequiredItems.Find(r => r.ItemPrefabs.Contains(targetItem));
}
}
}
}
if (ingredient == null)
{
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Red);
@@ -2077,7 +2089,17 @@ namespace Barotrauma
var prefab = MapEntityPrefab.Find(null, args[0]);
if (prefab != null)
{
DebugConsole.NewMessage(prefab.Name + " " + prefab.Identifier + " " + prefab.GetType().ToString());
NewMessage(prefab.Name + " " + prefab.Identifier + " " + prefab.GetType().ToString());
}
}));
commands.Add(new Command("copycharacterinfotoclipboard", "", (string[] args) =>
{
if (Character.Controlled?.Info != null)
{
XElement element = Character.Controlled?.Info.Save(null);
Clipboard.SetText(element.ToString());
DebugConsole.NewMessage($"Copied the characterinfo of {Character.Controlled.Name} to clipboard.");
}
}));
@@ -2507,7 +2529,7 @@ namespace Barotrauma
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
{
if (args.Length != 1) return;
if (args.Length != 1) { return; }
TextManager.CheckForDuplicates(args[0].ToIdentifier().ToLanguageIdentifier());
}));
@@ -2517,9 +2539,20 @@ namespace Barotrauma
NPCConversation.WriteToCSV();
}));
commands.Add(new Command("csvtoxml", "csvtoxml [language] -> Converts .csv localization files in Content/NPCConversations & Content/Texts to .xml for use in-game.", (string[] args) =>
commands.Add(new Command("csvtoxml", "csvtoxml -> Converts .csv localization files Content/Texts/Texts.csv and Content/Texts/NPCConversations.csv to .xml for use in-game.", (string[] args) =>
{
LocalizationCSVtoXML.Convert();
ShowQuestionPrompt("Do you want to save the text files to the project folder (../../../BarotraumaShared/Content/Texts/)? If not, they are saved in the current working directory. Y/N",
(option1) =>
{
ShowQuestionPrompt("Do you want to convert the NPC conversations as well? Y/N",
(option2) =>
{
LocalizationCSVtoXML.ConvertMasterLocalizationKit(
option1.ToLowerInvariant() == "y" ? "../../../BarotraumaShared/Content/Texts/" : "Content/Texts",
option1.ToLowerInvariant() == "y" ? "../../../BarotraumaShared/Content/NPCConversations/" : "Content/NPCConversations",
convertConversations: option2.ToLowerInvariant() == "y");
});
});
}));
commands.Add(new Command("printproperties", "Goes through the currently collected property list for missing localizations and writes them to a file.", (string[] args) =>
@@ -32,12 +32,12 @@ namespace Barotrauma
private static bool shouldFadeToBlack;
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> _)
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> _, float duration)
{
return
lastActiveAction != null &&
lastActiveAction.ParentEvent != ParentEvent &&
Timing.TotalTime < lastActiveAction.lastActiveTime + BlockOtherConversationsDuration;
Timing.TotalTime < lastActiveAction.lastActiveTime + duration;
}
partial void ShowDialog(Character speaker, Character targetCharacter)
@@ -528,7 +528,7 @@ namespace Barotrauma
if (characterInfo.PersonalityTrait is NPCPersonalityTrait trait)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("PersonalityTrait"));
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get("personalitytrait." + trait.Name.Replace(" ".ToIdentifier(), Identifier.Empty)));
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), trait.DisplayName);
}
infoLabelGroup.Recalculate();
infoValueGroup.Recalculate();
@@ -958,7 +958,7 @@ namespace Barotrauma
// Wire cursors
if (Character.Controlled != null)
{
if (Character.Controlled.SelectedConstruction?.GetComponent<ConnectionPanel>() != null)
if (Character.Controlled.SelectedItem?.GetComponent<ConnectionPanel>() != null)
{
if (Connection.DraggingConnected != null)
{
@@ -1344,7 +1344,7 @@ namespace Barotrauma
/// <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>
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Range<float> visibleRange, Sprite sprite, in Color color,
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null, LocalizedString label = null)
{
Vector2 diff = worldPosition - cam.WorldViewCenter;
float dist = diff.Length();
@@ -1394,10 +1394,6 @@ namespace Barotrauma
angle = MathHelper.Lerp(originalAngle, angle, MathHelper.Clamp(((screenDist + 10f) - iconDiff.Length()) / 10f, 0f, 1f));
/*Vector2 unclampedDiff = new Vector2(
(float)Math.Cos(angle) * screenDist,
(float)-Math.Sin(angle) * screenDist);*/
iconDiff = new Vector2(
(float)Math.Cos(angle) * Math.Min(GameMain.GraphicsWidth * 0.4f, screenDist),
(float)-Math.Sin(angle) * Math.Min(GameMain.GraphicsHeight * 0.4f, screenDist));
@@ -1405,7 +1401,20 @@ namespace Barotrauma
Vector2 iconPos = cam.WorldToScreen(cam.WorldViewCenter) + iconDiff;
sprite.Draw(spriteBatch, iconPos, color * alpha, rotate: 0.0f, scale: symbolScale);
if (/*unclampedDiff.Length()*/ screenDist - 10 > iconDiff.Length())
if (label != null)
{
float cursorDist = Vector2.Distance(PlayerInput.MousePosition, iconPos);
if (cursorDist < sprite.size.X * symbolScale)
{
Vector2 textSize = GUIStyle.Font.MeasureString(label);
Vector2 textPos = iconPos + new Vector2(sprite.size.X * symbolScale * 0.7f * Math.Sign(-iconDiff.X), -textSize.Y / 2);
if (iconDiff.X > 0) { textPos.X -= textSize.X; }
DrawString(spriteBatch, textPos + Vector2.One, label, Color.Black);
DrawString(spriteBatch, textPos, label, color);
}
}
if (screenDist - 10 > iconDiff.Length())
{
Vector2 normalizedDiff = Vector2.Normalize(targetScreenPos - iconPos);
Vector2 arrowOffset = normalizedDiff * sprite.size.X * symbolScale * 0.7f;
@@ -1465,9 +1474,9 @@ namespace Barotrauma
depth);
}
public static void DrawString(SpriteBatch sb, Vector2 pos, LocalizedString text, Color color, Color? backgroundColor = null, int backgroundPadding = 0, GUIFont font = null)
public static void DrawString(SpriteBatch sb, Vector2 pos, LocalizedString text, Color color, Color? backgroundColor = null, int backgroundPadding = 0, GUIFont font = null, ForceUpperCase forceUpperCase = ForceUpperCase.Inherit)
{
DrawString(sb, pos, text.Value, color, backgroundColor, backgroundPadding, font);
DrawString(sb, pos, text.Value, color, backgroundColor, backgroundPadding, font, forceUpperCase);
}
public static void DrawString(SpriteBatch sb, Vector2 pos, string text, Color color, Color? backgroundColor = null, int backgroundPadding = 0, GUIFont font = null, ForceUpperCase forceUpperCase = ForceUpperCase.Inherit)
@@ -62,7 +62,7 @@ namespace Barotrauma
GUIFont headerFont = GUIStyle.SubHeadingFont;
GUIFont font = GUIStyle.SmallFont; // font the context menu options use
Vector4 padding = new Vector4(4), headerPadding = new Vector4(8);
int horizontalPadding = (int) (padding.X + padding.Z), verticalPadding = (int) (padding.Y + padding.W);
int horizontalPadding = (int)(padding.X + padding.Z), verticalPadding = (int)(padding.Y + padding.W);
bool hasHeader = !header.IsNullOrWhiteSpace();
//----------------------------------------------------------------------------------
@@ -131,9 +131,15 @@ namespace Barotrauma
optionElement.ToolTip = option.Tooltip;
}
if (!option.IsEnabled)
//option doesn't do anything, make it a label
if (option.OnSelected == null)
{
optionElement.TextColor *= 0.5f;
optionElement.TextAlignment = Alignment.BottomLeft;
optionElement.TextColor = optionElement.DisabledTextColor = GUIStyle.Green;
}
else if (!option.IsEnabled)
{
optionElement.TextColor *= 0.5f;
}
}
@@ -146,7 +152,10 @@ namespace Barotrauma
// Resize all children to the size of their text
foreach (GUITextBlock block in children.Where(c => c is GUITextBlock).Cast<GUITextBlock>())
{
block.RectTransform.NonScaledSize = new Point((int) (block.TextSize.X + (block.Padding.X + block.Padding.Z)), (int) (18 * GUI.Scale));
bool isLabel = block.UserData is ContextMenuOption option && option.OnSelected == null;
block.RectTransform.NonScaledSize = new Point(
(int)(block.TextSize.X + (block.Padding.X + block.Padding.Z)),
(int)Math.Max(block.TextSize.Y * 1.2f, 18 * GUI.Scale));
}
int largestWidth = children.Max(c => c.Rect.Width + horizontalPadding);
@@ -155,7 +164,7 @@ namespace Barotrauma
if (HeaderLabel != null)
{
RectTransform headerTransform = HeaderLabel.RectTransform;
headerTransform.MinSize = new Point((int) (HeaderLabel.TextSize.X + (headerPadding.X + headerPadding.Z)), headerTransform.NonScaledSize.Y);
headerTransform.MinSize = new Point((int)(HeaderLabel.TextSize.X + (headerPadding.X + headerPadding.Z)), headerTransform.NonScaledSize.Y);
if (largestWidth < headerTransform.MinSize.X)
{
largestWidth = headerTransform.MinSize.X;
@@ -171,7 +180,7 @@ namespace Barotrauma
// the cropped size of the option list
Point newSize = new Point(largestWidth, children.Sum(c => c.Rect.Height) + verticalPadding);
// resize the menu itself taking into account the option menus relative Y size
RectTransform.NonScaledSize = new Point(newSize.X, (int) (newSize.Y / optionList.RectTransform.RelativeSize.Y));
RectTransform.NonScaledSize = new Point(newSize.X, (int)(newSize.Y / optionList.RectTransform.RelativeSize.Y));
optionList.RectTransform.NonScaledSize = newSize;
// move the context menu if it would go outside of screen
@@ -227,8 +236,8 @@ namespace Barotrauma
private Vector2 InflateSize(ref Point size, LocalizedString label, ScalableFont font)
{
Vector2 textSize = font.MeasureString(label);
size.X = Math.Max((int) Math.Ceiling(textSize.X), size.X);
size.Y += (int) Math.Ceiling(textSize.Y);
size.X = Math.Max((int)Math.Ceiling(textSize.X), size.X);
size.Y += (int)Math.Ceiling(textSize.Y);
return textSize;
}
@@ -0,0 +1,75 @@
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma
{
public class GUIDragHandle : GUIComponent
{
private readonly RectTransform elementToMove;
private Vector2 dragStart;
private bool dragStarted;
public Rectangle DragArea;
public GUIDragHandle(RectTransform rectT, RectTransform elementToMove, string style = "GUIDragIndicator")
: base(style, rectT)
{
this.elementToMove = elementToMove;
DragArea = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
}
protected override void Update(float deltaTime)
{
if (!Visible) return;
base.Update(deltaTime);
Enabled = true;
if (dragStarted)
{
Point moveAmount = (PlayerInput.MousePosition - dragStart).ToPoint() - elementToMove.ScreenSpaceOffset;
Rectangle rect = elementToMove.Rect;
rect.Location += moveAmount;
moveAmount.X += Math.Max(DragArea.X - rect.X, 0);
moveAmount.X -= Math.Max(rect.Right - DragArea.Right, 0);
moveAmount.Y += Math.Max(DragArea.Y - rect.Y, 0);
moveAmount.Y -= Math.Max(rect.Bottom - DragArea.Bottom, 0);
if (moveAmount != Point.Zero)
{
elementToMove.ScreenSpaceOffset += moveAmount;
}
if (!PlayerInput.PrimaryMouseButtonHeld())
{
dragStarted = false;
}
}
else if (Rect.Contains(PlayerInput.MousePosition) && CanBeFocused && Enabled && GUI.IsMouseOn(this))
{
State = Selected ? ComponentState.HoverSelected : ComponentState.Hover;
if (PlayerInput.PrimaryMouseButtonDown())
{
dragStart = PlayerInput.MousePosition - elementToMove.ScreenSpaceOffset.ToVector2();
dragStarted = true;
}
}
else
{
if (!ExternalHighlight)
{
State = Selected ? ComponentState.Selected : ComponentState.None;
}
else
{
State = ComponentState.Hover;
}
}
foreach (GUIComponent child in Children)
{
child.State = State;
}
}
}
}
@@ -49,7 +49,7 @@ namespace Barotrauma
//scaling the bar linearly with the resolution tends to make them too large on large resolutions
float desiredSize = 25.0f;
float scaledSize = desiredSize * GUI.Scale;
return (int)((desiredSize + scaledSize) / 2.0f);
return (int)Math.Min((desiredSize + scaledSize) / 2.0f, Rect.Height / 3);
}
}
@@ -73,6 +73,8 @@ namespace Barotrauma
public bool HideChildrenOutsideFrame = true;
public bool ResizeContentToMakeSpaceForScrollBar = true;
private bool useGridLayout;
private GUIComponent scrollToElement;
@@ -419,7 +421,7 @@ namespace Barotrauma
{
dimensionsNeedsRecalculation = false;
ContentBackground.RectTransform.Resize(Rect.Size);
bool reduceScrollbarSize = KeepSpaceForScrollBar ? ScrollBarEnabled : ScrollBarVisible;
bool reduceScrollbarSize = ResizeContentToMakeSpaceForScrollBar && (KeepSpaceForScrollBar ? ScrollBarEnabled : ScrollBarVisible);
Point contentSize = reduceScrollbarSize ? CalculateFrameSize(ScrollBar.IsHorizontal, ScrollBarSize) : Rect.Size;
Content.RectTransform.Resize(new Point((int)(contentSize.X - Padding.X - Padding.Z), (int)(contentSize.Y - Padding.Y - Padding.W)));
if (!IsScrollBarOnDefaultSide) { Content.RectTransform.SetPosition(Anchor.BottomRight); }
@@ -471,6 +471,7 @@ namespace Barotrauma
public void SetBackgroundIcon(Sprite icon)
{
if (icon == null) { return; }
if (icon == BackgroundIcon.Sprite) { return; }
GUIImage newIcon = new GUIImage(new RectTransform(icon.size.ToPoint(), RectTransform), icon)
{
IgnoreLayoutGroups = true,
@@ -593,7 +594,7 @@ namespace Barotrauma
{
newBackgroundIcon.SetAsFirstChild();
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int)(newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
newBackgroundIcon.Color = Color.Lerp(Color.Transparent, Color.White, iconState);
if (newBackgroundIcon.Color.A == 255)
{
BackgroundIcon = newBackgroundIcon;
@@ -81,6 +81,11 @@ namespace Barotrauma
get; private set;
}
public static Rectangle ItemHUDArea
{
get; private set;
}
public static int Padding
{
get; private set;
@@ -168,6 +173,8 @@ namespace Barotrauma
// Height is based on text content
VotingArea = new Rectangle(votingAreaX, votingAreaY, votingAreaWidth, 0);
ItemHUDArea = new Rectangle(0, ButtonAreaTop.Bottom, GameMain.GraphicsWidth, GameMain.GraphicsHeight - ButtonAreaTop.Bottom - InventoryAreaLower.Height);
}
public static void Draw(SpriteBatch spriteBatch)
@@ -181,6 +188,7 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, InventoryAreaLower, Color.Yellow * 0.5f);
GUI.DrawRectangle(spriteBatch, HealthWindowAreaLeft, Color.Red * 0.5f);
GUI.DrawRectangle(spriteBatch, BottomRightInfoArea, Color.Green * 0.5f);
GUI.DrawRectangle(spriteBatch, ItemHUDArea, Color.Magenta * 0.3f);
}
}
@@ -403,7 +403,7 @@ namespace Barotrauma
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
break;
case InfoFrameTab.Talents:
CreateTalentInfo(infoFrameHolder);
CreateCharacterInfo(infoFrameHolder);
break;
}
}
@@ -1803,161 +1803,121 @@ namespace Barotrauma
{ TalentTree.TalentTreeStageState.Highlighted, new Color(50,47,33,255) },
}.ToImmutableDictionary();
private void CreateTalentInfo(GUIFrame infoFrame)
private void CreateCharacterInfo(GUIFrame infoFrame)
{
infoFrame.ClearChildren();
talentButtons.Clear();
talentCornerIcons.Clear();
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
int padding = GUI.IntScale(15);
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
GUIFrame frame = new GUIFrame(new RectTransform(new Point(background.Rect.Width - padding, background.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
GUIFrame paddedTalentFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), talentFrameContent.RectTransform, Anchor.Center), style: null);
GUIFrame talentFrameMain = new GUIFrame(new RectTransform(Vector2.One, paddedTalentFrame.RectTransform), style: null);
GUIFrame content = new GUIFrame(new RectTransform(new Vector2(0.98f), frame.RectTransform, Anchor.Center), style: null);
GUIFrame characterSettingsFrame = null;
GUILayoutGroup characterLayout = null;
if (!(GameMain.NetworkMember is null))
{
characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrameContent.RectTransform), style: null) { Visible = false };
characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, frame.RectTransform), style: null) { Visible = false };
characterLayout = new GUILayoutGroup(new RectTransform(Vector2.One, characterSettingsFrame.RectTransform));
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
GUIFrame playerFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), containerFrame.RectTransform, Anchor.Center), style: null);
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
}
/*Character controlledCharacter = Character.Controlled;
if (controlledCharacter == null) { return; }
if (controlledCharacter.Info is null)
{
DebugConsole.ThrowError("No character info found for talent UI");
return;
}*/
Character controlledCharacter = Character.Controlled;
CharacterInfo info = controlledCharacter?.Info ?? GameMain.Client?.CharacterInfo;
if (info == null) { return; }
Job job = info.Job;
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), content.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
{
AbsoluteSpacing = GUI.IntScale(5)
AbsoluteSpacing = GUI.IntScale(10),
Stretch = true
};
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
GUILayoutGroup topLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), contentLayout.RectTransform, Anchor.Center), isHorizontal: true);
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), topLayout.RectTransform), onDraw: (batch, component) =>
{
float posY = component.Rect.Center.Y - component.Rect.Width / 2;
info.DrawPortrait(batch, new Vector2(component.Rect.X, posY), Vector2.Zero, component.Rect.Width, false, false);
});
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), talentInfoLayoutGroup.RectTransform)) { RelativeSpacing = 0.05f };
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), topLayout.RectTransform))
{
AbsoluteSpacing = GUI.IntScale(5),
CanBeFocused = true
};
Vector2 nameSize = GUIStyle.SubHeadingFont.MeasureString(info.Name);
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
nameBlock.RectTransform.NonScaledSize = nameSize.Pad(nameBlock.Padding).ToPoint();
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
if (!info.OmitJobInMenus)
{
nameBlock.TextColor = job.Prefab.UIColor;
Vector2 jobSize = GUIStyle.SmallFont.MeasureString(job.Name);
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
}
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + info.PersonalityTrait.Name.Replace(" ", "")));
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), info.PersonalityTrait.DisplayName);
Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString);
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
GUIFrame talentsOutsideTreeFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
if (!(GameMain.NetworkMember is null))
IEnumerable<TalentPrefab> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
if (talentsOutsideTree.Count() > 0)
{
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), talentsOutsideTreeFrame.RectTransform, Anchor.TopLeft),
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), nameLayout.RectTransform), style: null);
GUILayoutGroup extraTalentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), nameLayout.RectTransform), childAnchor: Anchor.TopCenter);
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), extraTalentLayout.RectTransform, anchor: Anchor.Center), TextManager.Get("talentmenu.extratalents"), font: GUIStyle.SubHeadingFont);
talentPointText.RectTransform.MaxSize = new Point(int.MaxValue, (int)talentPointText.TextSize.Y);
var extraTalentList = new GUIListBox(new RectTransform(new Vector2(0.9f, 0.8f), extraTalentLayout.RectTransform, anchor: Anchor.Center), isHorizontal: true)
{
IgnoreLayoutGroups = true
AutoHideScrollBar = false,
ResizeContentToMakeSpaceForScrollBar = false
};
newCharacterBox.TextBlock.AutoScaleHorizontal = true;
extraTalentList.ScrollBar.RectTransform.SetPosition(Anchor.BottomCenter, Pivot.TopCenter);
extraTalentList.RectTransform.MinSize = new Point(0, GUI.IntScale(65));
extraTalentLayout.Recalculate();
extraTalentList.ForceLayoutRecalculation();
newCharacterBox.OnClicked = (button, o) =>
foreach (var extraTalent in talentsOutsideTree)
{
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
var img = new GUIImage(new RectTransform(new Point(extraTalentList.Content.Rect.Height), extraTalentList.Content.RectTransform), sprite: extraTalent.Icon, scaleToFit: true)
{
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
{
newCharacterBox.Text = TextManager.Get("settings");
if (pendingChangesFrame != null)
{
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
}
OpenMenu();
});
return true;
}
OpenMenu();
return true;
void OpenMenu()
{
characterSettingsFrame!.Visible = true;
talentFrameMain.Visible = false;
}
};
if (!(characterLayout is null))
{
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomRight);
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
{
OnClicked = (button, o) =>
{
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
characterSettingsFrame!.Visible = false;
talentFrameMain.Visible = true;
return true;
}
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{extraTalent.DisplayName}‖color:end‖" + "\n\n" + extraTalent.Description),
Color = GUIStyle.Green
};
img.RectTransform.SizeChanged += () =>
{
img.RectTransform.MaxSize = new Point(img.Rect.Height);
};
}
}
IEnumerable<TalentPrefab> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), topLayout.RectTransform), childAnchor: Anchor.TopRight)
{
AbsoluteSpacing = GUI.IntScale(5),
Stretch = true
};
if (talentsOutsideTree.Count() > 0)
{
//TODO: replace with something more generic
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), talentsOutsideTreeFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
{
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", talentsOutsideTree.Select(e => e.DisplayName))}"
};
}
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true };
LocalizedString skillString = TextManager.Get("skills");
Vector2 skillSize = GUIStyle.SubHeadingFont.MeasureString(skillString);
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(Vector2.One, skillLayout.RectTransform), skillString, font: GUIStyle.SubHeadingFont);
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillLayout.RectTransform), TextManager.Get("skills"), font: GUIStyle.SubHeadingFont);
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
CreateTalentSkillList(controlledCharacter, info, skillListBox);
CreateSkillList(controlledCharacter, info, skillListBox);
if (controlledCharacter != null)
{
if (!TalentTree.JobTalentTrees.TryGet(info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
new GUIFrame(new RectTransform(new Vector2(1f, 1f), contentLayout.RectTransform), style: "HorizontalLine");
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.6f), contentLayout.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
selectedTalents = info.GetUnlockedTalentsInTree().ToList();
@@ -2008,10 +1968,9 @@ namespace Barotrauma
};
GUIFrame croppedTalentFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), style: null);
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, croppedTalentFrame.RectTransform, anchor: Anchor.Center), style: null)
{
ToolTip = RichString.Rich(talent.DisplayName + "\n\n" + talent.Description),
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{talent.DisplayName}‖color:end‖" + "\n\n" + talent.Description),
UserData = talent.Identifier,
PressedColor = pressedColor,
Enabled = controlledCharacter != null,
@@ -2078,9 +2037,13 @@ namespace Barotrauma
}
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), contentLayout.RectTransform, Anchor.TopCenter), isHorizontal: true)
{
RelativeSpacing = 0.01f,
Stretch = true
};
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), bottomLayout.RectTransform));
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
@@ -2097,30 +2060,84 @@ namespace Barotrauma
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
{
OnClicked = ResetTalentSelection
};
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
{
OnClicked = ApplyTalentSelection,
};
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
}
if (!(GameMain.NetworkMember is null))
{
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
{
IgnoreLayoutGroups = false
};
newCharacterBox.TextBlock.AutoScaleHorizontal = true;
newCharacterBox.OnClicked = (button, o) =>
{
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
{
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
{
newCharacterBox.Text = TextManager.Get("settings");
if (pendingChangesFrame != null)
{
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
}
OpenMenu();
});
return true;
}
OpenMenu();
return true;
void OpenMenu()
{
characterSettingsFrame!.Visible = true;
content.Visible = false;
}
};
if (!(characterLayout is null))
{
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
{
OnClicked = (button, o) =>
{
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
characterSettingsFrame!.Visible = false;
content.Visible = true;
return true;
}
};
}
}
UpdateTalentInfo();
}
private void CreateTalentSkillList(Character character, CharacterInfo info, GUIListBox parent)
private void CreateSkillList(Character character, CharacterInfo info, GUIListBox parent)
{
parent.Content.ClearChildren();
List<GUITextBlock> skillNames = new List<GUITextBlock>();
foreach (Skill skill in info.Job.GetSkills())
{
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value)));
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.0f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = true };
var skillName = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value));
skillNames.Add(skillName);
skillName.RectTransform.MinSize = new Point(0, skillName.Rect.Height);
skillContainer.RectTransform.MinSize = new Point(0, skillName.Rect.Height);
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.TopRight);
float modifiedSkillLevel = character?.GetSkillLevel(skill.Identifier) ?? skill.Level;
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
@@ -2129,15 +2146,15 @@ namespace Barotrauma
//TODO: if/when we upgrade to C# 9, do neater pattern matching here
string stringColor = true switch
{
true when skillChange > 0 => XMLExtensions.ColorToString(GUIStyle.Green),
true when skillChange < 0 => XMLExtensions.ColorToString(GUIStyle.Red),
_ => XMLExtensions.ColorToString(GUIStyle.TextColorNormal)
true when skillChange > 0 => XMLExtensions.ToStringHex(GUIStyle.Green),
true when skillChange < 0 => XMLExtensions.ToStringHex(GUIStyle.Red),
_ => XMLExtensions.ToStringHex(GUIStyle.TextColorNormal)
};
RichString changeText = RichString.Rich($"(‖color:{stringColor}‖{(skillChange > 0 ? "+" : string.Empty) + skillChange}‖color:end‖)");
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), changeText) { Padding = Vector4.Zero };
}
skillContainer.Recalculate();
//skillContainer.Recalculate();
}
parent.RecalculateChildren();
@@ -2216,7 +2233,7 @@ namespace Barotrauma
talentButton.icon.HoverColor = hoverColor;
}
CreateTalentSkillList(controlledCharacter, controlledCharacter.Info, skillListBox);
CreateSkillList(controlledCharacter, controlledCharacter.Info, skillListBox);
}
private void ApplyTalents(Character controlledCharacter)
@@ -432,13 +432,21 @@ namespace Barotrauma
};
Location location = Campaign.Map.CurrentLocation;
int hullRepairCost = location?.GetAdjustedMechanicalCost(CampaignMode.HullRepairCost) ?? CampaignMode.HullRepairCost;
int itemRepairCost = location?.GetAdjustedMechanicalCost(CampaignMode.ItemRepairCost) ?? CampaignMode.ItemRepairCost;
int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(CampaignMode.ShuttleReplaceCost) ?? CampaignMode.ShuttleReplaceCost;
int hullRepairCost = Campaign.GetHullRepairCost();
int itemRepairCost = Campaign.GetItemRepairCost();
int shuttleRetrieveCost = CampaignMode.ShuttleReplaceCost;
if (location != null)
{
hullRepairCost = location.GetAdjustedMechanicalCost(hullRepairCost);
itemRepairCost = location.GetAdjustedMechanicalCost(itemRepairCost);
shuttleRetrieveCost = location.GetAdjustedMechanicalCost(shuttleRetrieveCost);
}
CreateRepairEntry(currentStoreLayout.Content, TextManager.Get("repairallwalls"), "RepairHullButton", hullRepairCost, (button, o) =>
{
if (Campaign.PurchasedHullRepairs)
//cost is zero = nothing to repair
if (Campaign.PurchasedHullRepairs || hullRepairCost <= 0)
{
button.Enabled = false;
return false;
@@ -471,7 +479,7 @@ namespace Barotrauma
return false;
}
return true;
}, Campaign.PurchasedHullRepairs || !HasPermission, isHovered =>
}, Campaign.PurchasedHullRepairs || !HasPermission || hullRepairCost <= 0, isHovered =>
{
highlightWalls = isHovered;
return true;
@@ -479,7 +487,8 @@ namespace Barotrauma
CreateRepairEntry(currentStoreLayout.Content, TextManager.Get("repairallitems"), "RepairItemsButton", itemRepairCost, (button, o) =>
{
if (PlayerBalance >= itemRepairCost && !Campaign.PurchasedItemRepairs)
//cost is zero = nothing to repair
if (PlayerBalance >= itemRepairCost && !Campaign.PurchasedItemRepairs && itemRepairCost > 0)
{
LocalizedString body = TextManager.GetWithVariable("ItemRepairs.PurchasePromptBody", "[amount]", itemRepairCost.ToString());
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
@@ -505,9 +514,8 @@ namespace Barotrauma
button.Enabled = false;
return false;
}
return true;
}, Campaign.PurchasedItemRepairs || !HasPermission, isHovered =>
}, Campaign.PurchasedItemRepairs || !HasPermission || itemRepairCost <= 0, isHovered =>
{
foreach (var (item, itemFrame) in itemPreviews)
{
@@ -814,7 +814,7 @@ namespace Barotrauma
else if ((Character.Controlled == null || !itemHudActive())
&& CharacterHealth.OpenHealthWindow == null
&& !CrewManager.IsCommandInterfaceOpen
&& !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null))
&& !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedItem != null))
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
@@ -822,9 +822,9 @@ namespace Barotrauma
static bool itemHudActive()
{
if (Character.Controlled?.SelectedConstruction == null) { return false; }
if (Character.Controlled?.SelectedItem == null) { return false; }
return
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
Character.Controlled.SelectedItem.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
((Character.Controlled.ViewTarget as Item)?.Prefab?.FocusOnSelected ?? false);
}
}
@@ -919,7 +919,7 @@ namespace Barotrauma
#endif
}
CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step);
CoroutineManager.Update(Paused, (float)Timing.Step);
SteamManager.Update((float)Timing.Step);
@@ -1098,7 +1098,7 @@ namespace Barotrauma
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:CurrentIntensity", GameSession.EventManager.CurrentIntensity);
foreach (var activeEvent in GameSession.EventManager.ActiveEvents)
{
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:ActiveEvents:" + activeEvent.ToString());
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:ActiveEvents:" + activeEvent.Prefab.Identifier);
}
GameSession.LogEndRoundStats(eventId);
if (GameSession.GameMode is TutorialMode tutorialMode)
@@ -2412,7 +2412,7 @@ namespace Barotrauma
float reactorOutput = -reactor.CurrPowerConsumption;
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
// --> Create shortcut node for "Operate Reactor" order's "Power Up" option
if (ShouldDelegateOrder("operatereactor") && reactorOutput < float.Epsilon && characters.None(c => c.SelectedConstruction == reactor.Item))
if (ShouldDelegateOrder("operatereactor") && reactorOutput < float.Epsilon && characters.None(c => c.SelectedItem == reactor.Item))
{
var orderPrefab = OrderPrefab.Prefabs["operatereactor"];
var order = new Order(orderPrefab, orderPrefab.Options[0], reactor.Item, reactor);
@@ -2426,7 +2426,7 @@ namespace Barotrauma
// If player is not a captain AND nobody is using the nav terminal AND the nav terminal is powered up
// --> Create shortcut node for Steer order
if (CanFitMoreNodes() && ShouldDelegateOrder("steer") && IsNonDuplicateOrderPrefab(OrderPrefab.Prefabs["steer"]) &&
subItems.Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
subItems.Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedItem == nav) &&
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
{
var order = new Order(OrderPrefab.Prefabs["steer"], steering.Item, steering);
@@ -3,8 +3,8 @@ namespace Barotrauma
{
partial class GameMode
{
public virtual void Draw(SpriteBatch spriteBatch)
{
}
public virtual void HUDScaleChanged() { }
public virtual void Draw(SpriteBatch spriteBatch) { }
}
}
@@ -115,12 +115,16 @@ namespace Barotrauma
partial void InitProjSpecific()
{
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUI.Canvas),
isHorizontal: true, childAnchor: Anchor.CenterRight)
{
CanBeFocused = false
};
CreateButtons();
}
public override void HUDScaleChanged()
{
CreateButtons();
}
private void CreateButtons()
{
int buttonHeight = (int) (GUI.Scale * 40),
buttonWidth = GUI.IntScale(450),
buttonCenter = buttonHeight / 2,
@@ -166,8 +170,6 @@ namespace Barotrauma
},
UserData = "ReadyCheckButton"
};
buttonContainer.Recalculate();
}
private void InitCampaignUI()
@@ -311,7 +313,7 @@ namespace Barotrauma
if (prevControlled != null)
{
prevControlled.SelectedConstruction = null;
prevControlled.SelectedItem = prevControlled.SelectedSecondaryItem = null;
if (prevControlled.AIController != null)
{
prevControlled.AIController.Enabled = true;
@@ -362,7 +364,7 @@ namespace Barotrauma
float t = 0.0f;
while (t < fadeOutDuration || endTransition.Running)
{
t += CoroutineManager.UnscaledDeltaTime;
t += CoroutineManager.DeltaTime;
overlayColor = Color.Lerp(Color.Transparent, Color.White, t / fadeOutDuration);
yield return CoroutineStatus.Running;
}
@@ -469,7 +471,6 @@ namespace Barotrauma
{
base.End(transitionType);
ForceMapUI = ShowCampaignUI = false;
UpgradeManager.CanUpgrade = true;
// remove all event dialogue boxes
GUIMessageBox.MessageBoxes.ForEachMod(mb =>
@@ -169,10 +169,20 @@ namespace Barotrauma
public static SinglePlayerCampaign Load(XElement element) => new SinglePlayerCampaign(element);
private void InitUI()
{
CreateEndRoundButton();
campaignUIContainer = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "InnerGlow", color: Color.Black);
CampaignUI = new CampaignUI(this, campaignUIContainer)
{
StartRound = () => { TryEndRound(); }
};
}
private void CreateEndRoundButton()
{
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), GUI.Canvas),
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
{
@@ -190,12 +200,11 @@ namespace Barotrauma
return true;
}
};
}
campaignUIContainer = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "InnerGlow", color: Color.Black);
CampaignUI = new CampaignUI(this, campaignUIContainer)
{
StartRound = () => { TryEndRound(); }
};
public override void HUDScaleChanged()
{
CreateEndRoundButton();
}
#endregion
@@ -292,7 +301,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
overlayTextColor = Color.Lerp(Color.Transparent, Color.White, (timer - 1.0f) / fadeInDuration);
timer = Math.Min(timer + CoroutineManager.UnscaledDeltaTime, textDuration);
timer = Math.Min(timer + CoroutineManager.DeltaTime, textDuration);
yield return CoroutineStatus.Running;
}
var outpost = GameMain.GameSession.Level.StartOutpost;
@@ -320,7 +329,7 @@ namespace Barotrauma
while (timer < fadeInDuration)
{
overlayColor = Color.Lerp(Color.LightGray, Color.Transparent, timer / fadeInDuration);
timer += CoroutineManager.UnscaledDeltaTime;
timer += CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
overlayColor = Color.Transparent;
@@ -353,7 +362,7 @@ namespace Barotrauma
if (prevControlled != null)
{
prevControlled.SelectedConstruction = null;
prevControlled.SelectedItem = prevControlled.SelectedSecondaryItem = null;
if (prevControlled.AIController != null)
{
prevControlled.AIController.Enabled = true;
@@ -424,7 +433,7 @@ namespace Barotrauma
float t = 0.0f;
while (t < fadeOutDuration || endTransition.Running)
{
t += CoroutineManager.UnscaledDeltaTime;
t += CoroutineManager.DeltaTime;
overlayColor = Color.Lerp(Color.Transparent, Color.White, t / fadeOutDuration);
yield return CoroutineStatus.Running;
}
@@ -436,6 +445,7 @@ namespace Barotrauma
if (success)
{
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
GameMain.GameSession.EventManager.RegisterEventHistory();
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
}
else
@@ -124,7 +124,7 @@ namespace Barotrauma.Tutorials
captain_medicSpawnPos = Item.ItemList.Find(i => i.HasTag("captain_medicspawnpos")).WorldPosition;
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("medicaldoctor"))
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("medicaldoctor".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -148,21 +148,21 @@ namespace Barotrauma.Tutorials
SetDoorAccess(tutorial_lockedDoor_1, null, false);
SetDoorAccess(tutorial_lockedDoor_2, null, false);
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("mechanic"))
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("mechanic".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "mechanic");
captain_mechanic.GiveJobItems();
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer"))
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "securityofficer");
captain_security.GiveJobItems();
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -339,8 +339,8 @@ namespace Barotrauma.Tutorials
private bool IsSelectedItem(Item item)
{
return
captain?.SelectedConstruction == item ||
(captain?.SelectedConstruction?.linkedTo?.Contains(item) ?? false);
captain?.SelectedItem == item ||
(captain?.SelectedItem?.linkedTo?.Contains(item) ?? false);
}
}
}
@@ -119,7 +119,7 @@ namespace Barotrauma.Tutorials
var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"))
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -130,7 +130,7 @@ namespace Barotrauma.Tutorials
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 15.0f) }, stun: 0, playSound: false);
patient1.AIController.Enabled = false;
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"))
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -139,7 +139,7 @@ namespace Barotrauma.Tutorials
patient2.CanSpeak = false;
patient2.AIController.Enabled = false;
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -148,13 +148,13 @@ namespace Barotrauma.Tutorials
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient1);
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer"));
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer".ToIdentifier()));
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
subPatient2.TeamID = CharacterTeamType.Team1;
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient2);
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer".ToIdentifier()))
{
TeamID = CharacterTeamType.Team1
};
@@ -262,7 +262,7 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(doctor_suppliesCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_suppliesCabinet.Item)
if (doctor.SelectedItem == doctor_suppliesCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.Capacity; i++)
{
@@ -373,7 +373,7 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(doctor_medBayCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_medBayCabinet.Item)
if (doctor.SelectedItem == doctor_medBayCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.Capacity; i++)
{
@@ -400,7 +400,7 @@ namespace Barotrauma.Tutorials
wait -= 0.1f;
engineer_reactor.AutoTemp = true;
} while (wait > 0.0f);
engineer.SelectedConstruction = null;
engineer.SelectedItem = null;
engineer_reactor.CanBeSelected = false;
RemoveCompletedObjective(2);
GameAnalyticsManager.AddDesignEvent("Tutorial:EngineerTutorial:Objective2");
@@ -513,7 +513,7 @@ namespace Barotrauma.Tutorials
private bool IsSelectedItem(Item item)
{
return engineer?.SelectedConstruction == item;
return engineer?.SelectedItem == item;
}
private IEnumerable<CoroutineStatus> ReactorOperatedProperly()
@@ -568,7 +568,7 @@ namespace Barotrauma.Tutorials
private void HandleJunctionBoxWiringHighlights()
{
Item selected = engineer.SelectedConstruction;
Item selected = engineer.SelectedItem;
if (!engineer.HasEquippedItem("screwdriver".ToIdentifier()))
{
@@ -440,7 +440,7 @@ namespace Barotrauma.Tutorials
bool gotSodium = false;
do
{
if (mechanic.SelectedConstruction == mechanic_craftingCabinet.Item)
if (mechanic.SelectedItem == mechanic_craftingCabinet.Item)
{
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
{
@@ -702,7 +702,7 @@ namespace Barotrauma.Tutorials
private bool IsSelectedItem(Item item)
{
return mechanic?.SelectedConstruction == item;
return mechanic?.SelectedItem == item;
}
private bool WallHasDamagedSections(Structure wall)
@@ -510,7 +510,7 @@ namespace Barotrauma.Tutorials
private bool IsSelectedItem(Item item)
{
return officer?.SelectedConstruction == item;
return officer?.SelectedItem == item;
}
private Character SpawnMonster(string speciesName, Vector2 pos)
@@ -14,6 +14,7 @@ namespace Barotrauma
public static bool IsTabMenuOpen => GameMain.GameSession?.tabMenu != null;
public static TabMenu TabMenuInstance => GameMain.GameSession?.tabMenu;
private float prevHudScale;
private TabMenu tabMenu;
@@ -119,6 +120,7 @@ namespace Barotrauma
return true;
}
};
prevHudScale = GameSettings.CurrentConfig.Graphics.HUDScale;
}
public void AddToGUIUpdateList()
@@ -178,6 +180,12 @@ namespace Barotrauma
}
}
public void HUDScaleChanged()
{
CreateTopLeftButtons();
GameMode?.HUDScaleChanged();
}
partial void UpdateProjSpecific(float deltaTime)
{
if (GUI.DisableHUD) { return; }
@@ -112,19 +112,19 @@ namespace Barotrauma
CheckReminders();
}
public static void OnSetSelectedConstruction(Character character, Item oldConstruction, Item newConstruction)
public static void OnSetSelectedItem(Character character, Item oldItem, Item newItem)
{
if (oldConstruction == newConstruction) { return; }
if (oldItem == newItem) { return; }
if (Character.Controlled != null && Character.Controlled == character && oldConstruction != null && oldConstruction.GetComponent<Ladder>() == null)
if (Character.Controlled != null && Character.Controlled == character && oldItem != null && !oldItem.IsLadder)
{
TimeStoppedInteracting = Timing.TotalTime;
}
if (newConstruction == null) { return; }
if (newConstruction.GetComponent<Ladder>() != null) { return; }
if (newConstruction.GetComponent<ConnectionPanel>() is ConnectionPanel cp && cp.User == character) { return; }
OnStartedInteracting(character, newConstruction);
if (newItem == null) { return; }
if (newItem.IsLadder) { return; }
if (newItem.GetComponent<ConnectionPanel>() is ConnectionPanel cp && cp.User == character) { return; }
OnStartedInteracting(character, newItem);
}
private static void OnStartedInteracting(Character character, Item item)
@@ -177,10 +177,10 @@ namespace Barotrauma
private static void CheckIsInteracting()
{
if (!CanDisplayHints()) { return; }
if (Character.Controlled?.SelectedConstruction == null) { return; }
if (Character.Controlled?.SelectedItem == null) { return; }
if (Character.Controlled.SelectedConstruction.GetComponent<Reactor>() is Reactor reactor && reactor.PowerOn &&
Character.Controlled.SelectedConstruction.OwnInventory?.AllItems is IEnumerable<Item> containedItems &&
if (Character.Controlled.SelectedItem.GetComponent<Reactor>() is Reactor reactor && reactor.PowerOn &&
Character.Controlled.SelectedItem.OwnInventory?.AllItems is IEnumerable<Item> containedItems &&
containedItems.Count(i => i.HasTag("reactorfuel")) > 1)
{
if (DisplayHint("onisinteracting.reactorwithextrarods".ToIdentifier())) { return; }
@@ -272,7 +272,7 @@ namespace Barotrauma
if (!CanDisplayHints()) { return; }
if (sonar == null || sonar.Removed) { return; }
if (spottedCharacter == null || spottedCharacter.Removed || spottedCharacter.IsDead) { return; }
if (Character.Controlled.SelectedConstruction != sonar) { return; }
if (Character.Controlled.SelectedItem != sonar) { return; }
if (HumanAIController.IsFriendly(Character.Controlled, spottedCharacter)) { return; }
DisplayHint("onsonarspottedenemy".ToIdentifier());
}
@@ -305,7 +305,7 @@ namespace Barotrauma
{
if (!CanDisplayHints()) { return; }
if (character != Character.Controlled) { return; }
if (character.SelectedConstruction != null || character.FocusedItem != null) { return; }
if (character.HasSelectedAnyItem || character.FocusedItem != null) { return; }
if (item == null || !item.IsShootable || !item.RequireAimToUse) { return; }
if (TimeStoppedInteracting + 1 > Timing.TotalTime) { return; }
if (GUI.MouseOn != null) { return; }
@@ -317,7 +317,7 @@ namespace Barotrauma
variables: new[] { ("[key]".ToIdentifier(), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim)) },
onUpdate: () =>
{
if (character.SelectedConstruction == null && GUI.MouseOn == null && PlayerInput.KeyDown(InputType.Aim))
if (character.SelectedItem == null && GUI.MouseOn == null && PlayerInput.KeyDown(InputType.Aim))
{
ActiveHintMessageBox.Close();
}
@@ -562,7 +562,7 @@ namespace Barotrauma
break;
}
//if putting an item to a container with a max stack size of 1, only put one item from the stack
if (quickUseAction == QuickUseAction.PutToContainer && (character.SelectedConstruction?.GetComponent<ItemContainer>()?.MaxStackSize ?? 0) <= 1)
if (quickUseAction == QuickUseAction.PutToContainer && (character.SelectedItem?.GetComponent<ItemContainer>()?.MaxStackSize ?? 0) <= 1)
{
break;
}
@@ -595,14 +595,14 @@ namespace Barotrauma
if (rootInventory != null &&
rootInventory.Owner != Character.Controlled &&
rootInventory.Owner != Character.Controlled.SelectedConstruction &&
rootInventory.Owner != Character.Controlled.SelectedItem &&
rootInventory.Owner != Character.Controlled.SelectedCharacter)
{
//allow interacting if the container is linked to the item the character is interacting with
if (!(rootContainer != null &&
rootContainer.DisplaySideBySideWhenLinked &&
Character.Controlled.SelectedConstruction != null &&
rootContainer.linkedTo.Contains(Character.Controlled.SelectedConstruction)))
Character.Controlled.SelectedItem != null &&
rootContainer.linkedTo.Contains(Character.Controlled.SelectedItem)))
{
DraggingItems.Clear();
}
@@ -756,7 +756,7 @@ namespace Barotrauma
}
else
{
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();
if (selectedContainer != null &&
selectedContainer.Inventory != null &&
!selectedContainer.Inventory.Locked)
@@ -775,7 +775,8 @@ namespace Barotrauma
else
{
bool isEquippable = item.AllowedSlots.Any(s => s != InvSlotType.Any);
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();
if (selectedContainer != null &&
selectedContainer.Inventory != null &&
!selectedContainer.Inventory.Locked &&
@@ -930,7 +931,7 @@ namespace Barotrauma
}
break;
case QuickUseAction.PutToContainer:
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();
if (selectedContainer != null && selectedContainer.Inventory != null)
{
//player has selected the inventory of another item -> attempt to move the item there
@@ -965,8 +966,8 @@ namespace Barotrauma
}
break;
case QuickUseAction.PutToEquippedItem:
foreach (Item heldItem in character.HeldItems)
//order by the condition of the contained item to prefer putting into the item with the emptiest ammo/battery/tank
foreach (Item heldItem in character.HeldItems.OrderBy(it => it.ContainedItems.FirstOrDefault()?.Condition ?? 0.0f))
{
if (heldItem.OwnInventory == null) { continue; }
//don't allow swapping if we're moving items into an item with 1 slot holding a stack of items
@@ -23,11 +23,10 @@ namespace Barotrauma.Items.Components
public void ExtractJobPrefab(IReadOnlyDictionary<Identifier, string> tags)
{
if (!tags.TryGetValue("jobid".ToIdentifier(), out string jobId)) { return; }
if (!tags.TryGetValue("jobid".ToIdentifier(), out string jobId)) { return; }
if (!jobId.IsNullOrEmpty())
{
JobPrefab = JobPrefab.Get(jobId);
JobPrefab = JobPrefab.Get(jobId.ToIdentifier());
}
}
@@ -522,13 +522,11 @@ namespace Barotrauma.Items.Components
if (soundSelectionModes == null) soundSelectionModes = new Dictionary<ActionType, SoundSelectionMode>();
if (!soundSelectionModes.ContainsKey(type) || soundSelectionModes[type] == SoundSelectionMode.Random)
{
SoundSelectionMode selectionMode = SoundSelectionMode.Random;
Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out selectionMode);
Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode);
soundSelectionModes[type] = selectionMode;
}
List<ItemSound> soundList = null;
if (!sounds.TryGetValue(itemSound.Type, out soundList))
if (!sounds.TryGetValue(itemSound.Type, out List<ItemSound> soundList))
{
soundList = new List<ItemSound>();
sounds.Add(itemSound.Type, soundList);
@@ -566,6 +564,9 @@ namespace Barotrauma.Items.Components
}
string style = GuiFrameSource.Attribute("style") == null ? null : GuiFrameSource.GetAttributeString("style", "");
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas, Anchor.Center), style, color);
TryCreateDragHandle();
DefaultLayout = GUILayoutSettings.Load(GuiFrameSource);
if (GuiFrame != null)
{
@@ -574,6 +575,22 @@ namespace Barotrauma.Items.Components
GameMain.Instance.ResolutionChanged += OnResolutionChanged;
}
protected void TryCreateDragHandle()
{
if (GuiFrame != null && GuiFrameSource.GetAttributeBool("draggable", true))
{
var handle = new GUIDragHandle(new RectTransform(Vector2.One, GuiFrame.RectTransform, Anchor.Center),
GuiFrame.RectTransform, style: null)
{
DragArea = HUDLayoutSettings.ItemHUDArea
};
int iconHeight = GUIStyle.ItemFrameMargin.Y / 4;
new GUIImage(new RectTransform(new Point(GuiFrame.Rect.Width, iconHeight), handle.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, iconHeight / 2) },
style: "GUIDragIndicatorHorizontal");
}
}
/// <summary>
/// Overload this method and implement. The method is automatically called when the resolution changes.
/// </summary>
@@ -189,7 +189,7 @@ namespace Barotrauma.Items.Components
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
CanBeFocused = true
};
// Expand the frame vertically if it's too small to fit the text
@@ -381,10 +381,15 @@ namespace Barotrauma.Items.Components
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
}
if (item.ParentInventory?.Owner == character && character.SelectedItem == item)
{
character.SelectedItem = null;
}
//if the item is in the character's inventory, no need to update the item's inventory
//because the player can see it by hovering the cursor over the item
guiCustomComponent.Visible = item.ParentInventory?.Owner != character && DrawInventory;
if (!guiCustomComponent.Visible) { return; }
//because the player can see it by hovering the cursor over the item
guiCustomComponent.Visible = DrawInventory && item.ParentInventory?.Owner != character;
if (!guiCustomComponent.Visible) { return; }
Inventory.Update(deltaTime, cam);
}
@@ -1,4 +1,5 @@
using Barotrauma.Extensions;
using System.Collections.Generic;
using System.Collections.Immutable;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -15,6 +16,7 @@ namespace Barotrauma.Items.Components
}
private GUIButton activateButton;
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUIListBox outputDisplayListBox;
private GUIComponent inSufficientPowerWarning;
@@ -44,32 +46,43 @@ namespace Barotrauma.Items.Components
protected override void CreateGUI()
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.90f, 0.80f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.88f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
Stretch = true,
RelativeSpacing = 0.08f
};
new GUITextBlock(new RectTransform(new Vector2(1f, 0.07f), paddedFrame.RectTransform), item.Name, font: GUIStyle.SubHeadingFont)
new GUITextBlock(new RectTransform(new Vector2(1f, 0.07f), paddedFrame.RectTransform) { MinSize = new Point(0, GUI.IntScale(25)) }, item.Name, font: GUIStyle.SubHeadingFont)
{
TextAlignment = Alignment.Center,
AutoScaleHorizontal = true
};
var topFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), paddedFrame.RectTransform), style: null);
var topFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.375f), paddedFrame.RectTransform), style: null);
// === INPUT LABEL === //
var inputLabelArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.15f), topFrame.RectTransform, Anchor.TopCenter), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelArea.RectTransform), TextManager.Get("deconstructor.input", "uilabel.input"), font: GUIStyle.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");
var inputLabelArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.15f), topFrame.RectTransform, Anchor.TopCenter), childAnchor: Anchor.CenterLeft, isHorizontal: true);
var queueLabelLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.43f, 1f), inputLabelArea.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
var queueLabel = new GUITextBlock(new RectTransform(Vector2.One, queueLabelLayout.RectTransform), TextManager.Get("deconstructor.inputqueue"), font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero };
queueLabel.RectTransform.Resize(new Point((int) queueLabel.Font.MeasureString(queueLabel.Text).X, queueLabel.RectTransform.Rect.Height));
new GUIFrame(new RectTransform(Vector2.One, queueLabelLayout.RectTransform), style: "HorizontalLine");
var inputLabelLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.57f, 1f), inputLabelArea.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelLayout.RectTransform), TextManager.Get("deconstructor.input", "uilabel.input"), font: GUIStyle.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, inputLabelLayout.RectTransform), style: "HorizontalLine");
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), topFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
// === INPUT SLOTS === //
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
@@ -92,8 +105,8 @@ namespace Barotrauma.Items.Components
};
// === OUTPUT AREA === //
var bottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), paddedFrame.RectTransform), style: null);
var bottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.375f), paddedFrame.RectTransform), style: null);
// === OUTPUT LABEL === //
var outputLabelArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.15f), bottomFrame.RectTransform, Anchor.TopCenter), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
@@ -104,10 +117,16 @@ namespace Barotrauma.Items.Components
outputLabel.RectTransform.Resize(new Point((int) outputLabel.Font.MeasureString(outputLabel.Text).X, outputLabel.RectTransform.Rect.Height));
new GUIFrame(new RectTransform(Vector2.One, outputLabelArea.RectTransform), style: "HorizontalLine");
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
// === OUTPUT SLOTS === //
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f - InfoAreaWidth, 1f), outputArea.RectTransform, Anchor.CenterLeft), style: null);
// === OUTPUT SLOTS === //
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f - InfoAreaWidth, 1f), outputArea.RectTransform, Anchor.CenterLeft), style: null);
GUILayoutGroup outputDisplayLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), paddedFrame.RectTransform), childAnchor: Anchor.TopCenter);
GUILayoutGroup outDisplayTopGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.2f), outputDisplayLayout.RectTransform), isHorizontal: true);
GUITextBlock outDisplayBlock = new GUITextBlock(new RectTransform(Vector2.One, outDisplayTopGroup.RectTransform), TextManager.Get("deconstructor.output"), font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero };
GUILayoutGroup outDisplayBottomGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.975f, 0.8f), outputDisplayLayout.RectTransform), isHorizontal: true);
outputDisplayListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f), outDisplayBottomGroup.RectTransform), isHorizontal: true, style: null);
if (InfoAreaWidth >= 0.0f)
{
@@ -181,7 +200,7 @@ namespace Barotrauma.Items.Components
{
if (!(linkedTo is Item { DisplaySideBySideWhenLinked: true } linkedItem)) { continue; }
if (!linkedItem.Components.Any()) { continue; }
var itemContainer = linkedItem.GetComponent<ItemContainer>();
if (itemContainer?.GuiFrame == null || itemContainer.AllowUIOverlap) { continue; }
@@ -195,6 +214,170 @@ namespace Barotrauma.Items.Components
return base.Select(character);
}
partial void OnItemSlotsChanged(ItemContainer container)
{
if (container.Inventory is null) { return; }
RefreshOutputDisplay(container.Inventory.AllItems.ToImmutableArray());
}
private void RefreshOutputDisplay(ImmutableArray<Item> items)
{
const string outputItemCountUserData = "OutputItemCount";
const string questionMarkUserData = "UnknownItemOutput";
if (outputDisplayListBox is null || inputContainer.Inventory is null) { return; }
Dictionary<Identifier, int> itemCounts = new Dictionary<Identifier, int>();
Dictionary<Identifier, GUIComponent> children = new Dictionary<Identifier, GUIComponent>();
bool addQuestionMark = false;
foreach (GUIComponent child in outputDisplayListBox.Content.Children)
{
if (child.UserData is Identifier it)
{
children.Add(it, child);
}
}
if (outputDisplayListBox.Content.FindChild(questionMarkUserData) is { } foundChild)
{
outputDisplayListBox.RemoveChild(foundChild);
}
foreach (Item it in items)
{
if (it.Prefab.RandomDeconstructionOutput)
{
addQuestionMark = true;
continue;
}
foreach (DeconstructItem deconstructItem in it.Prefab.DeconstructItems)
{
RegisterItem(deconstructItem.ItemIdentifier);
}
if (it.OwnInventory is { } inventory)
{
foreach (Item inventoryItems in inventory.AllItems)
{
RegisterItem(inventoryItems.Prefab.Identifier);
}
}
void RegisterItem(Identifier identifier)
{
if (itemCounts.ContainsKey(identifier))
{
itemCounts[identifier]++;
return;
}
itemCounts.Add(identifier, 1);
}
}
foreach (var (it, child) in children)
{
if (!itemCounts.ContainsKey(it))
{
outputDisplayListBox.RemoveChild(child);
}
}
foreach (var (it, amount) in itemCounts)
{
if (!children.TryGetValue(it, out GUIComponent child))
{
child = CreateOutputDisplayItem(it, outputDisplayListBox.Content);
}
if (child is null) { continue; }
UpdateOutputDisplayItemCount(child, amount);
}
if (addQuestionMark)
{
CreateQuestionMark(outputDisplayListBox.Content);
}
static void CreateQuestionMark(GUIComponent parent)
{
GUIFrame itemFrame = new GUIFrame(new RectTransform(new Vector2(0.1f, 1f), parent.RectTransform), style: null)
{
UserData = questionMarkUserData,
ToolTip = TextManager.Get("deconstructor.unknownitemsoutput")
};
GUIFrame questionMarkFrame = new GUIFrame(new RectTransform(Vector2.One, itemFrame.RectTransform, scaleBasis: ScaleBasis.Smallest, anchor: Anchor.Center), style: "GUIFrameListBox")
{
CanBeFocused = false,
};
// question mark text
new GUITextBlock(new RectTransform(Vector2.One, questionMarkFrame.RectTransform, anchor: Anchor.Center), text: "?", textAlignment: Alignment.Center, font: GUIStyle.LargeFont)
{
CanBeFocused = false
};
}
static GUIComponent CreateOutputDisplayItem(Identifier identifier, GUIComponent parent)
{
ItemPrefab prefab = ItemPrefab.Find(null, identifier);
if (prefab is null) { return null; }
GUIFrame itemFrame = new GUIFrame(new RectTransform(new Vector2(0.1f, 1f), parent.RectTransform), style: null)
{
UserData = identifier,
ToolTip = GetTooltip(prefab)
};
Sprite icon = prefab.InventoryIcon ?? prefab.Sprite;
Color iconColor = prefab.InventoryIcon is null ? prefab.SpriteColor : prefab.InventoryIconColor;
GUIImage itemIcon = new GUIImage(new RectTransform(Vector2.One, itemFrame.RectTransform, scaleBasis: ScaleBasis.Smallest, anchor: Anchor.Center), sprite: icon, scaleToFit: true)
{
Color = iconColor,
CanBeFocused = false
};
// item count text
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), itemIcon.RectTransform, anchor: Anchor.BottomRight), "", font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
UserData = outputItemCountUserData,
Shadow = true,
CanBeFocused = false,
Padding = Vector4.Zero,
TextColor = Color.White,
};
return itemFrame;
}
static void UpdateOutputDisplayItemCount(GUIComponent component, int count)
{
if (!(component.FindChild(outputItemCountUserData, recursive: true) is GUITextBlock textBlock)) { return; }
textBlock.Text = TextManager.GetWithVariable("campaignstore.quantity", "[amount]", count.ToString());
}
static RichString GetTooltip(ItemPrefab prefab)
{
LocalizedString toolTip = $"‖color:{Color.White.ToStringHex()}‖{prefab.Name}‖color:end‖";
LocalizedString description = prefab.Description;
if (!description.IsNullOrEmpty()) { toolTip += '\n' + description; }
if (prefab.ContentPackage != GameMain.VanillaContent && prefab.ContentPackage != null)
{
toolTip += $"\n‖color:{Color.MediumPurple.ToStringHex()}‖{prefab.ContentPackage.Name}‖color:end‖";
}
return RichString.Rich(toolTip);
}
}
partial void OnItemLoadedProjSpecific()
{
inputContainer.AllowUIOverlap = true;
@@ -208,7 +391,7 @@ namespace Barotrauma.Items.Components
overlayComponent.RectTransform.SetAsLastChild();
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
if (DeconstructItemsSimultaneously)
{
for (int i = 0; i < InputContainer.Inventory.Capacity; i++)
@@ -246,6 +246,7 @@ namespace Barotrauma.Items.Components
protected override void CreateGUI()
{
GuiFrame.ClearChildren();
TryCreateDragHandle();
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.05f, 0.0f);
GuiFrame.CanBeFocused = true;
@@ -25,7 +25,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
if (Character.Controlled?.SelectedConstruction != item)
if (Character.Controlled?.SelectedItem != item)
{
IsActive = false;
return;
@@ -871,13 +871,11 @@ namespace Barotrauma.Items.Components
posToMaintain = item.Submarine.WorldPosition;
}
MaintainPos = true;
if (userdata is Vector2)
if (userdata is Vector2 nudgeAmount)
{
Sonar sonar = item.GetComponent<Sonar>();
Vector2 nudgeAmount = (Vector2)userdata;
if (sonar != null)
if (item.GetComponent<Sonar>() is Sonar sonar)
{
nudgeAmount *= sonar == null ? 500.0f : 500.0f / sonar.Zoom;
nudgeAmount *= 500.0f / sonar.Zoom;
}
PosToMaintain += nudgeAmount;
}
@@ -59,7 +59,7 @@ namespace Barotrauma.Items.Components
public override bool ShouldDrawHUD(Character character)
{
if (item.HiddenInGame) { return false; }
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; }
if (!HasRequiredItems(character, false) || character.SelectedItem != item) { return false; }
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
float defaultMaxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
@@ -110,6 +110,7 @@ namespace Barotrauma.Items.Components
if (GuiFrame != null)
{
GuiFrame.ClearChildren();
TryCreateDragHandle();
CreateGUI();
}
}
@@ -265,7 +266,7 @@ namespace Barotrauma.Items.Components
}
}
if (CurrentFixer != null && CurrentFixer.SelectedConstruction == item)
if (CurrentFixer != null && CurrentFixer.SelectedItem == item)
{
if (repairSoundChannel == null || !repairSoundChannel.IsPlaying)
{
@@ -33,10 +33,16 @@ namespace Barotrauma.Items.Components
originalMaxSize = GuiFrame.RectTransform.MaxSize;
originalRelativeSize = GuiFrame.RectTransform.RelativeSize;
CheckForLabelOverlap();
new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform), DrawConnections, null)
var content = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform), DrawConnections, null)
{
UserData = this
};
content.RectTransform.SetAsFirstChild();
//prevents inputs from going through the GUICustomComponent to the drag handle
var blocker = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center)
{ AbsoluteOffset = GUIStyle.ItemFrameOffset },
style: null);
}
public void TriggerRewiringSound()
@@ -62,7 +68,7 @@ namespace Barotrauma.Items.Components
}
rewireSoundTimer -= deltaTime;
if (user != null && user.SelectedConstruction == item && rewireSoundTimer > 0.0f)
if (user != null && user.SelectedItem == item && rewireSoundTimer > 0.0f)
{
if (rewireSoundChannel == null || !rewireSoundChannel.IsPlaying)
{
@@ -85,12 +91,12 @@ namespace Barotrauma.Items.Components
public override bool ShouldDrawHUD(Character character)
{
return character == Character.Controlled && character == user && character.SelectedConstruction == item;
return character == Character.Controlled && character == user && character.SelectedItem == item;
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; }
if (character != Character.Controlled || character != user || character.SelectedItem != item) { return; }
if (HighlightedWire != null)
{
@@ -311,7 +311,7 @@ namespace Barotrauma.Items.Components
Wire equippedWire = Character.Controlled.HeldItems.FirstOrDefault(it => it.GetComponent<Wire>() != null)?.GetComponent<Wire>();
if (equippedWire != null && GUI.MouseOn == null)
{
if (PlayerInput.PrimaryMouseButtonClicked() && Character.Controlled.SelectedConstruction == null)
if (PlayerInput.PrimaryMouseButtonClicked() && Character.Controlled.SelectedItem == null)
{
equippedWire.Use(1.0f, Character.Controlled);
}
@@ -364,7 +364,7 @@ namespace Barotrauma
get
{
return Character.Controlled != null &&
Character.Controlled.SelectedConstruction == null &&
!Character.Controlled.HasSelectedAnyItem &&
CharacterHealth.OpenHealthWindow == null &&
DraggingItems.Any();
}
@@ -924,9 +924,9 @@ namespace Barotrauma
}
}
if (Character.Controlled.SelectedConstruction != null)
if (Character.Controlled.SelectedItem != null)
{
foreach (var ic in Character.Controlled.SelectedConstruction.ActiveHUDs)
foreach (var ic in Character.Controlled.SelectedItem.ActiveHUDs)
{
var itemContainer = ic as ItemContainer;
if (itemContainer?.Inventory?.visualSlots == null) { continue; }
@@ -1003,9 +1003,9 @@ namespace Barotrauma
}
}
if (character.SelectedConstruction != null)
if (character.SelectedItem != null)
{
foreach (var ic in character.SelectedConstruction.ActiveHUDs)
foreach (var ic in character.SelectedItem.ActiveHUDs)
{
var itemContainer = ic as ItemContainer;
if (itemContainer?.Inventory?.visualSlots == null) { continue; }
@@ -1341,27 +1341,29 @@ namespace Barotrauma
}
else
{
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
rootOwner != Character.Controlled &&
rootOwner != Character.Controlled.SelectedCharacter &&
rootOwner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
static bool OwnerInaccessible(Entity owner) =>
owner != Character.Controlled &&
owner != Character.Controlled.SelectedCharacter &&
owner != Character.Controlled.SelectedItem &&
(Character.Controlled.SelectedItem == null || !Character.Controlled.SelectedItem.linkedTo.Contains(owner));
Entity owner = selectedSlot.ParentInventory?.Owner;
Entity rootOwner = (owner as Item)?.GetRootInventoryOwner();
if (OwnerInaccessible(owner) && (rootOwner == owner || OwnerInaccessible(rootOwner)))
{
return false;
}
var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item;
if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) &&
ownerCharacter == Character.Controlled &&
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface) &&
Screen.Selected != GameMain.SubEditorScreen)
Item parentItem = (owner as Item) ?? selectedSlot?.Item;
if (parentItem?.GetRootInventoryOwner() is Character ownerCharacter)
{
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
return false;
if (ownerCharacter == Character.Controlled &&
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface) &&
Screen.Selected != GameMain.SubEditorScreen)
{
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
return false;
}
}
}
return true;
@@ -1725,7 +1727,8 @@ namespace Barotrauma
if (inventory != null &&
!inventory.Locked &&
Character.Controlled?.Inventory == inventory &&
slot.InventoryKeyIndex != -1)
slot.InventoryKeyIndex != -1 &&
slot.InventoryKeyIndex < GameSettings.CurrentConfig.InventoryKeyMap.Bindings.Length)
{
spriteBatch.Draw(slotHotkeySprite.Texture, rect.ScaleSize(1.15f), slotHotkeySprite.SourceRect, slotColor);
GUI.DrawString(spriteBatch, rect.Location.ToVector2() + new Vector2((int)(4.25f * UIScale), (int)Math.Ceiling(-1.5f * UIScale)), GameSettings.CurrentConfig.InventoryKeyMap.Bindings[slot.InventoryKeyIndex].Name, Color.Black, font: GUIStyle.HotkeyFont);
@@ -982,7 +982,7 @@ namespace Barotrauma
List<GUIComponent> elementsToMove = new List<GUIComponent>();
if (editingHUD != null && editingHUD.UserData == this &&
((HasInGameEditableProperties && Character.Controlled?.SelectedConstruction == this) || Screen.Selected == GameMain.SubEditorScreen))
((HasInGameEditableProperties && Character.Controlled?.SelectedItem == this) || Screen.Selected == GameMain.SubEditorScreen))
{
elementsToMove.Add(editingHUD);
}
@@ -1042,7 +1042,7 @@ namespace Barotrauma
public void UpdateHUD(Camera cam, Character character, float deltaTime)
{
bool editingHUDCreated = false;
if ((HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped)) ||
if ((HasInGameEditableProperties && (character.SelectedItem == this || EditableWhenEquipped)) ||
Screen.Selected == GameMain.SubEditorScreen)
{
GUIComponent prevEditingHUD = editingHUD;
@@ -1126,7 +1126,7 @@ namespace Barotrauma
foreach (Character otherCharacter in Character.CharacterList)
{
if (otherCharacter != character &&
otherCharacter.SelectedConstruction == this)
otherCharacter.SelectedItem == this)
{
ItemInUseWarning.Visible = true;
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
@@ -1145,7 +1145,7 @@ namespace Barotrauma
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
{
if (HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped))
if (HasInGameEditableProperties && (character.SelectedItem == this || EditableWhenEquipped))
{
DrawEditing(spriteBatch, cam);
}
@@ -1215,6 +1215,7 @@ namespace Barotrauma
if (ic.DisplayMsg.IsNullOrEmpty()) { continue; }
if (!ic.CanBePicked && !ic.CanBeSelected) { continue; }
if (ic is Holdable holdable && !holdable.CanBeDeattached()) { continue; }
if (ic is ConnectionPanel connectionPanel && !connectionPanel.CanRewire()) { continue; }
Color color = Color.Gray;
if (ic.HasRequiredItems(character, false))
@@ -1246,15 +1247,15 @@ namespace Barotrauma
}
else
{
if (HasInGameEditableProperties && Character.Controlled != null && (Character.Controlled.SelectedConstruction == this || EditableWhenEquipped))
if (HasInGameEditableProperties && Character.Controlled != null && (Character.Controlled.SelectedItem == this || EditableWhenEquipped))
{
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(); }
}
}
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this && GetComponent<RemoteController>() == null)
if (Character.Controlled != null && Character.Controlled.SelectedItem != this && GetComponent<RemoteController>() == null)
{
if (Character.Controlled.SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem != this &&
if (Character.Controlled.SelectedItem?.GetComponent<RemoteController>()?.TargetItem != this &&
!Character.Controlled.HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == this))
{
return;
@@ -1,5 +1,4 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Linq;
@@ -17,7 +16,7 @@ namespace Barotrauma
{
if (PlayerInput.KeyHit(InputType.Select))
{
Character.Controlled.SelectedConstruction = null;
Character.Controlled.SelectedItem = null;
}
}*/
}
@@ -232,8 +232,7 @@ namespace Barotrauma
{
foreach (MapEntity e in mapEntityList)
{
if (!e.SelectableInEditor) continue;
if (!e.SelectableInEditor) { continue; }
if (e.IsMouseOn(position))
{
int i = 0;
@@ -243,9 +242,7 @@ namespace Barotrauma
{
i++;
}
highlightedEntities.Insert(i, e);
if (i == 0) highLightedEntity = e;
}
}
@@ -741,7 +738,14 @@ namespace Barotrauma
/// </summary>
public static void DrawSelecting(SpriteBatch spriteBatch, Camera cam)
{
if (GUI.MouseOn != null) return;
if (Screen.Selected is SubEditorScreen subEditor)
{
if (subEditor.IsMouseOnEditorGUI()) { return; }
}
else if (GUI.MouseOn != null)
{
return;
}
Vector2 position = PlayerInput.MousePosition;
position = cam.ScreenToWorld(position);
@@ -1093,6 +1097,10 @@ namespace Barotrauma
resizeDirY = y;
resizing = true;
startMovingPos = Vector2.Zero;
foreach (var mapEntity in mapEntityList)
{
if (mapEntity != this) { mapEntity.isHighlighted = false; }
}
}
}
}
@@ -1202,6 +1202,8 @@ namespace Barotrauma.Networking
connected = false;
var prevContentPackages = clientPeer.ServerContentPackages;
//decrement lobby update ID to make sure we update the lobby when we reconnect
GameMain.NetLobbyScreen.LastUpdateID--;
ConnectToServer(serverEndpoint, serverName);
if (clientPeer != null)
{
@@ -3271,8 +3273,8 @@ namespace Barotrauma.Networking
if (gameStarted && Screen.Selected == GameMain.GameScreen)
{
var controller = Character.Controlled?.SelectedConstruction?.GetComponent<Controller>();
bool disableButtons = Character.Controlled != null && (controller != null && controller.HideHUD);
bool disableButtons = Character.Controlled?.SelectedItem?.GetComponent<Controller>() is Controller c1 && c1.HideHUD ||
Character.Controlled?.SelectedSecondaryItem?.GetComponent<Controller>() is Controller c2 && c2.HideHUD;
buttonContainer.Visible = !disableButtons;
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
@@ -227,10 +227,13 @@ namespace Barotrauma.Networking
bool allowEnqueue = overrideSound != null;
if (GameMain.WindowActive && SettingsMenu.Instance is null)
{
bool pttDown = PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null;
bool usingActiveMode = PlayerInput.KeyDown(InputType.Voice);
bool usingLocalMode = PlayerInput.KeyDown(InputType.LocalVoice);
bool usingRadioMode = PlayerInput.KeyDown(InputType.RadioVoice);
bool pttDown = (usingActiveMode || usingLocalMode || usingRadioMode) && GUI.KeyboardDispatcher.Subscriber == null;
if (pttDown || captureTimer <= 0)
{
ForceLocal = GameMain.ActiveChatMode == ChatMode.Local;
ForceLocal = (usingActiveMode && GameMain.ActiveChatMode == ChatMode.Local) || usingLocalMode;
}
if (GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Activity)
{
@@ -121,10 +121,9 @@ namespace Barotrauma.Networking
{
client.VoipSound.SetRange(ChatMessage.SpeakRange * 0.4f, ChatMessage.SpeakRange);
}
if (messageType != ChatMessageType.Radio && Character.Controlled != null && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters)
{
client.VoipSound.UseMuffleFilter = SoundPlayer.ShouldMuffleSound(Character.Controlled, client.Character.WorldPosition, ChatMessage.SpeakRange, client.Character.CurrentHull);
}
client.VoipSound.UseMuffleFilter =
messageType != ChatMessageType.Radio && Character.Controlled != null && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters &&
SoundPlayer.ShouldMuffleSound(Character.Controlled, client.Character.WorldPosition, ChatMessage.SpeakRange, client.Character.CurrentHull);
}
GameMain.NetLobbyScreen?.SetPlayerSpeaking(client);
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Particles
{
@@ -217,6 +216,11 @@ namespace Barotrauma.Particles
}
}
public void ClearParticles()
{
particleCount = 0;
}
public void RemoveByPrefab(ParticlePrefab prefab)
{
if (particles == null) { return; }
@@ -132,11 +132,11 @@ namespace Barotrauma
}
else if (a.MouseButton != MouseButton.None)
{
return a.MouseButton == b.MouseButton;
return !(b is null) && a.MouseButton == b.MouseButton;
}
else
{
return a.Key.Equals(b.Key);
return !(b is null) && a.Key.Equals(b.Key);
}
}
@@ -27,8 +27,6 @@ namespace Barotrauma
private bool hasMaxMissions;
private GUIButton repairHullsButton, replaceShuttlesButton, repairItemsButton;
private SubmarineSelection submarineSelection;
private Location selectedLocation;
@@ -101,170 +99,6 @@ namespace Barotrauma
tabs[(int)CampaignMode.InteractionType.Store] = storeTab;
Store = new Store(this, storeTab);
// repair tab -------------------------------------------------------------------------
tabs[(int)CampaignMode.InteractionType.Repair] = CreateDefaultTabContainer(container, new Vector2(0.7f));
var repairFrame = new GUIFrame(new RectTransform(Vector2.One, GetTabContainer(CampaignMode.InteractionType.Repair).RectTransform, Anchor.TopLeft), color: Color.Black * 0.9f);
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), repairFrame.RectTransform, Anchor.Center), style: "OuterGlow", color: Color.Black * 0.7f)
{
UserData = "outerglow",
CanBeFocused = false
};
var repairContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), repairFrame.RectTransform, Anchor.Center))
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), repairContent.RectTransform), "", font: GUIStyle.LargeFont)
{
TextGetter = GetMoney
};
// repair hulls -----------------------------------------------
var repairHullsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Vector2(0.3f, 1.0f), repairHullsHolder.RectTransform, Anchor.CenterLeft), "RepairHullButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
var repairHullsLabel = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.3f), repairHullsHolder.RectTransform), TextManager.Get("RepairAllWalls"), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont)
{
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairHullsHolder.RectTransform), CampaignMode.HullRepairCost.ToString(), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont);
repairHullsButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), repairHullsHolder.RectTransform) { MinSize = new Point(140, 0) }, TextManager.Get("Repair"))
{
OnClicked = (btn, userdata) =>
{
if (Campaign.PurchasedHullRepairs)
{
Campaign.Wallet.Refund(CampaignMode.HullRepairCost);
Campaign.PurchasedHullRepairs = false;
}
else
{
if (Campaign.TryPurchase(null, CampaignMode.HullRepairCost))
{
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.HullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
Campaign.PurchasedHullRepairs = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = Campaign.PurchasedHullRepairs;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), repairHullsButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
// repair items -------------------------------------------
var repairItemsHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Vector2(0.3f, 1.0f), repairItemsHolder.RectTransform, Anchor.CenterLeft), "RepairItemsButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
var repairItemsLabel = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.3f), repairItemsHolder.RectTransform), TextManager.Get("RepairAllItems"), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont)
{
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), repairItemsHolder.RectTransform), CampaignMode.ItemRepairCost.ToString(), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont);
repairItemsButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), repairItemsHolder.RectTransform) { MinSize = new Point(140, 0) }, TextManager.Get("Repair"))
{
OnClicked = (btn, userdata) =>
{
if (Campaign.PurchasedItemRepairs)
{
Campaign.Wallet.Refund(CampaignMode.ItemRepairCost);
Campaign.PurchasedItemRepairs = false;
}
else
{
if (Campaign.TryPurchase(null, CampaignMode.ItemRepairCost))
{
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.ItemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
Campaign.PurchasedItemRepairs = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = Campaign.PurchasedItemRepairs;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), repairItemsButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
// replace lost shuttles -------------------------------------------
var replaceShuttlesHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), repairContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Vector2(0.3f, 1.0f), replaceShuttlesHolder.RectTransform, Anchor.CenterLeft), "ReplaceShuttlesButton")
{
IgnoreLayoutGroups = true,
CanBeFocused = false
};
var replaceShuttlesLabel = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.3f), replaceShuttlesHolder.RectTransform), TextManager.Get("ReplaceLostShuttles"), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont)
{
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), replaceShuttlesHolder.RectTransform), CampaignMode.ShuttleReplaceCost.ToString(), textAlignment: Alignment.Right, font: GUIStyle.SubHeadingFont);
replaceShuttlesButton = new GUIButton(new RectTransform(new Vector2(0.4f, 0.3f), replaceShuttlesHolder.RectTransform) { MinSize = new Point(140, 0) }, TextManager.Get("ReplaceShuttles"))
{
OnClicked = (btn, userdata) =>
{
if (GameMain.GameSession?.SubmarineInfo != null &&
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
{
new GUIMessageBox("", TextManager.Get("ReplaceShuttleDockingPortOccupied"));
return true;
}
if (Campaign.PurchasedLostShuttles)
{
Campaign.Wallet.Refund(CampaignMode.ShuttleReplaceCost);
Campaign.PurchasedLostShuttles = false;
}
else
{
if (Campaign.TryPurchase(null, CampaignMode.ShuttleReplaceCost))
{
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.ShuttleReplaceCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
Campaign.PurchasedLostShuttles = true;
}
}
GameMain.Client?.SendCampaignState();
btn.GetChild<GUITickBox>().Selected = Campaign.PurchasedLostShuttles;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.65f), replaceShuttlesButton.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(10, 0) }, "")
{
CanBeFocused = false
};
GUITextBlock.AutoScaleAndNormalize(repairHullsLabel, repairItemsLabel, replaceShuttlesLabel);
GUITextBlock.AutoScaleAndNormalize(repairHullsButton.GetChild<GUITickBox>().TextBlock, repairItemsButton.GetChild<GUITickBox>().TextBlock, replaceShuttlesButton.GetChild<GUITickBox>().TextBlock);
// upgrade tab -------------------------------------------------------------------------
tabs[(int)CampaignMode.InteractionType.Upgrade] = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
@@ -701,26 +535,6 @@ namespace Barotrauma
switch (selectedTab)
{
case CampaignMode.InteractionType.Repair:
repairHullsButton.Enabled =
(Campaign.PurchasedHullRepairs || Campaign.Wallet.CanAfford(CampaignMode.HullRepairCost));
repairHullsButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedHullRepairs;
repairItemsButton.Enabled =
(Campaign.PurchasedItemRepairs || Campaign.Wallet.CanAfford(CampaignMode.ItemRepairCost));
repairItemsButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedItemRepairs;
if (GameMain.GameSession?.SubmarineInfo == null || !GameMain.GameSession.SubmarineInfo.SubsLeftBehind)
{
replaceShuttlesButton.Enabled = false;
replaceShuttlesButton.GetChild<GUITickBox>().Selected = false;
}
else
{
replaceShuttlesButton.Enabled =
(Campaign.PurchasedLostShuttles || Campaign.Wallet.CanAfford(CampaignMode.ShuttleReplaceCost));
replaceShuttlesButton.GetChild<GUITickBox>().Selected = Campaign.PurchasedLostShuttles;
}
break;
case CampaignMode.InteractionType.Store:
Store.SelectStore(storeIdentifier);
break;
@@ -2606,8 +2606,8 @@ namespace Barotrauma.CharacterEditor
animationControls = new GUIFrame(new RectTransform(Vector2.One, centerArea.RectTransform), style: null) { CanBeFocused = false };
var layoutGroupAnimation = new GUILayoutGroup(new RectTransform(Vector2.One, animationControls.RectTransform), childAnchor: Anchor.TopLeft) { CanBeFocused = false };
var animationSelectionElement = new GUIFrame(new RectTransform(new Point(elementSize.X * 2 - (int)(5 * GUI.xScale), elementSize.Y), layoutGroupAnimation.RectTransform), style: null);
var animationSelectionText = new GUITextBlock(new RectTransform(new Point(elementSize.X, elementSize.Y), animationSelectionElement.RectTransform), GetCharacterEditorTranslation("SelectedAnimation") + ": ", Color.WhiteSmoke, textAlignment: Alignment.Center);
animSelection = new GUIDropDown(new RectTransform(new Point((int)(100 * GUI.xScale), elementSize.Y), animationSelectionElement.RectTransform, Anchor.TopRight), elementCount: 5);
var animationSelectionText = new GUITextBlock(new RectTransform(new Point(elementSize.X, elementSize.Y), animationSelectionElement.RectTransform), GetCharacterEditorTranslation("SelectedAnimation"), Color.WhiteSmoke, textAlignment: Alignment.CenterRight);
animSelection = new GUIDropDown(new RectTransform(new Point((int)(150 * GUI.xScale), elementSize.Y), animationSelectionElement.RectTransform, Anchor.Center, Pivot.CenterLeft), elementCount: 5);
if (character.AnimController.CanWalk)
{
animSelection.AddItem(AnimationType.Walk.ToString(), AnimationType.Walk);
@@ -1,11 +1,10 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using FarseerPhysics;
using System.Diagnostics;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -79,21 +78,27 @@ namespace Barotrauma
public override void AddToGUIUpdateList()
{
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction))
if (Character.Controlled != null)
{
Character.Controlled.SelectedConstruction.AddToGUIUpdateList();
}
if (Character.Controlled?.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.AllItems)
if (Character.Controlled.SelectedItem is { } selectedItem && Character.Controlled.CanInteractWith(selectedItem))
{
if (Character.Controlled.HasEquippedItem(item))
selectedItem.AddToGUIUpdateList();
}
if (Character.Controlled.SelectedSecondaryItem is { } selectedSecondaryItem && Character.Controlled.CanInteractWith(selectedSecondaryItem))
{
selectedSecondaryItem.AddToGUIUpdateList();
}
if (Character.Controlled.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.AllItems)
{
item.AddToGUIUpdateList();
if (Character.Controlled.HasEquippedItem(item))
{
item.AddToGUIUpdateList();
}
}
}
}
GameMain.GameSession?.AddToGUIUpdateList();
Character.AddAllToGUIUpdateList();
}
@@ -260,11 +265,7 @@ namespace Barotrauma
//Draw the rest of the structures, characters and front structures
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawBack(spriteBatch, false, e => !(e is Structure) || e.SpriteDepth < 0.9f);
foreach (Character c in Character.CharacterList)
{
if (!c.IsVisible || c.AnimController.Limbs.Any(l => l.DeformSprite != null)) { continue; }
c.Draw(spriteBatch, Cam);
}
DrawCharacters(deformed: false, firstPass: true);
spriteBatch.End();
sw.Stop();
@@ -272,11 +273,12 @@ namespace Barotrauma
sw.Restart();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
DrawDeformed(firstPass: true);
DrawDeformed(firstPass: false);
DrawCharacters(deformed: true, firstPass: true);
DrawCharacters(deformed: true, firstPass: false);
DrawCharacters(deformed: false, firstPass: false);
spriteBatch.End();
void DrawDeformed(bool firstPass)
void DrawCharacters(bool deformed, bool firstPass)
{
//backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth)
for (int i = Character.CharacterList.Count - 1; i >= 0; i--)
@@ -284,7 +286,14 @@ namespace Barotrauma
Character c = Character.CharacterList[i];
if (!c.IsVisible) { continue; }
if (c.Params.DrawLast == firstPass) { continue; }
if (c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; }
if (deformed)
{
if (c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; }
}
else
{
if (c.AnimController.Limbs.Any(l => l.DeformSprite != null)) { continue; }
}
c.Draw(spriteBatch, Cam);
}
}
@@ -695,8 +695,13 @@ namespace Barotrauma
gamesession.StartRound(fixedSeed ? "abcd" : ToolBox.RandomSeed(8), difficulty, levelGenerationParams);
GameMain.GameScreen.Select();
// TODO: modding support
string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic", "securityofficer", "medicaldoctor" };
foreach (string job in jobIdentifiers)
Identifier[] jobIdentifiers = new Identifier[] {
"captain".ToIdentifier(),
"engineer".ToIdentifier(),
"mechanic".ToIdentifier(),
"securityofficer".ToIdentifier(),
"medicaldoctor".ToIdentifier() };
foreach (Identifier job in jobIdentifiers)
{
var jobPrefab = JobPrefab.Get(job);
var variant = Rand.Range(0, jobPrefab.Variants);
@@ -55,9 +55,7 @@ namespace Barotrauma
while (timer < duration)
{
GUI.ScreenOverlayColor = Color.Lerp(from, to, Math.Min(timer / duration, 1.0f));
timer += CoroutineManager.UnscaledDeltaTime;
timer += CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
@@ -813,8 +813,13 @@ namespace Barotrauma
var itemCount = new GUITextBlock(new RectTransform(new Vector2(0.33f, 1.0f), itemCountText.RectTransform, Anchor.TopRight, Pivot.TopLeft), "", textAlignment: Alignment.CenterRight);
itemCount.TextGetter = () =>
{
itemCount.TextColor = Item.ItemList.Count > MaxItems ? GUIStyle.Red : Color.Lerp(GUIStyle.Green, GUIStyle.Orange, Item.ItemList.Count / (float)MaxItems);
return Item.ItemList.Count.ToString();
int count = Item.ItemList.Count;
if (dummyCharacter?.Inventory != null)
{
count -= dummyCharacter.Inventory.AllItems.Count();
}
itemCount.TextColor = count > MaxItems ? GUIStyle.Red : Color.Lerp(GUIStyle.Green, GUIStyle.Orange, count / (float)MaxItems);
return count.ToString();
};
var structureCountText = new GUITextBlock(new RectTransform(new Vector2(0.75f, 0.0f), paddedEntityCountPanel.RectTransform), TextManager.Get("Structures"),
@@ -1497,7 +1502,7 @@ namespace Barotrauma
/// <returns></returns>
private static IEnumerable<CoroutineStatus> AutoSaveCoroutine()
{
DateTime target = DateTime.Now.AddMinutes(GameSettings.CurrentConfig.AutoSaveIntervalSeconds);
DateTime target = DateTime.Now.AddSeconds(GameSettings.CurrentConfig.AutoSaveIntervalSeconds);
DateTime tempTarget = DateTime.Now;
bool wasPaused = false;
@@ -1549,7 +1554,9 @@ namespace Barotrauma
MapEntity.DeselectAll();
ClearUndoBuffer();
#if !DEBUG
DebugConsole.DeactivateCheats();
#endif
SetMode(Mode.Default);
@@ -3337,23 +3344,21 @@ namespace Barotrauma
{
if (!(userData is XElement element)) { return; }
#warning TODO: revise
#warning TODO: revise
string filePath = element.GetAttributeStringUnrestricted("file", "");
if (string.IsNullOrWhiteSpace(filePath)) { return; }
var loadedSub = Submarine.Load(new SubmarineInfo(filePath), true);
// set the submarine file path to the "default" value
var unspecifiedFileName = TextManager.Get("UnspecifiedSubFileName");
loadedSub.Info.FilePath = Path.Combine(ContentPackage.LocalModsDir, unspecifiedFileName.Value, $"{unspecifiedFileName}.sub");
loadedSub.Info.Name = unspecifiedFileName.Value;
try
{
loadedSub.Info.Name = loadedSub.Info.SubmarineElement.GetAttributeString("name", loadedSub.Info.Name);
loadedSub.Info.Name = loadedSub.Info.SubmarineElement.GetAttributeString("name", loadedSub.Info.Name);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to find a name for the submarine.", e);
var unspecifiedFileName = TextManager.Get("UnspecifiedSubFileName");
loadedSub.Info.Name = unspecifiedFileName.Value;
}
MainSub = loadedSub;
MainSub.SetPrevTransform(MainSub.Position);
@@ -3726,7 +3731,6 @@ namespace Barotrauma
}
else
{
List<ContextMenuOption> availableLayerOptions = new List<ContextMenuOption>
{
new ContextMenuOption("editor.layer.nolayer", true, onSelected: () => { MoveToLayer(null, targets); })
@@ -3769,7 +3773,8 @@ namespace Barotrauma
{
if (!me.Removed) { me.Remove(); }
}
}));
}),
new ContextMenuOption(TextManager.Get("editortip.shiftforextraoptions") + '\n' + TextManager.Get("editortip.altforruler"), isEnabled: false, onSelected: null));
}
}
@@ -4257,7 +4262,7 @@ namespace Barotrauma
MapEntity.SelectedList.Clear();
MapEntity.FilteredSelectedList.Clear();
MapEntity.SelectEntity(itemContainer);
dummyCharacter.SelectedConstruction = itemContainer;
dummyCharacter.SelectedItem = itemContainer;
FilterEntities(entityFilterBox.Text);
}
@@ -4268,9 +4273,9 @@ namespace Barotrauma
{
if (dummyCharacter == null) { return; }
//nothing to close -> return
if (DraggedItemPrefab == null && dummyCharacter?.SelectedConstruction == null && OpenedItem == null) { return; }
if (DraggedItemPrefab == null && dummyCharacter?.SelectedItem == null && OpenedItem == null) { return; }
DraggedItemPrefab = null;
dummyCharacter.SelectedConstruction = null;
dummyCharacter.SelectedItem = null;
OpenedItem?.Drop(dummyCharacter);
OpenedItem?.SetTransform(oldItemPosition, 0f);
OpenedItem = null;
@@ -4347,9 +4352,9 @@ namespace Barotrauma
}
}
if (dummyCharacter?.SelectedConstruction != null)
if (dummyCharacter?.SelectedItem != null)
{
var inv = dummyCharacter?.SelectedConstruction?.OwnInventory;
var inv = dummyCharacter?.SelectedItem?.OwnInventory;
if (inv != null)
{
switch (obj)
@@ -4779,9 +4784,9 @@ namespace Barotrauma
if (dummyCharacter != null)
{
CharacterHUD.AddToGUIUpdateList(dummyCharacter);
if (dummyCharacter.SelectedConstruction != null)
if (dummyCharacter.SelectedItem != null)
{
dummyCharacter.SelectedConstruction.AddToGUIUpdateList();
dummyCharacter.SelectedItem.AddToGUIUpdateList();
}
else if (WiringMode && MapEntity.SelectedList.FirstOrDefault() is Item item && item.GetComponent<Wire>() != null)
{
@@ -4801,7 +4806,7 @@ namespace Barotrauma
/// <summary>
/// GUI.MouseOn doesn't get updated while holding primary mouse and we need it to
/// </summary>
private bool IsMouseOnEditorGUI()
public bool IsMouseOnEditorGUI()
{
if (GUI.MouseOn == null) { return false; }
@@ -5143,7 +5148,7 @@ namespace Barotrauma
{
if (dummyCharacter != null)
{
if (dummyCharacter.SelectedConstruction == null)
if (dummyCharacter.SelectedItem == null)
{
foreach (var entity in MapEntity.mapEntityList)
{
@@ -5285,7 +5290,7 @@ namespace Barotrauma
me.IsHighlighted = false;
}
if (dummyCharacter.SelectedConstruction == null)
if (dummyCharacter.SelectedItem == null)
{
List<Wire> wires = new List<Wire>();
foreach (Item item in Item.ItemList)
@@ -5308,8 +5313,8 @@ namespace Barotrauma
});
}
if (dummyCharacter.SelectedConstruction == null ||
dummyCharacter.SelectedConstruction.GetComponent<Pickable>() != null)
if (dummyCharacter.SelectedItem == null ||
dummyCharacter.SelectedItem.GetComponent<Pickable>() != null)
{
if (WiringMode && PlayerInput.IsShiftDown())
{
@@ -5341,7 +5346,7 @@ namespace Barotrauma
TeleportDummyCharacter(oldItemPosition);
}
if (WiringMode && dummyCharacter?.SelectedConstruction == null)
if (WiringMode && dummyCharacter?.SelectedItem == null)
{
TeleportDummyCharacter(FarseerPhysics.ConvertUnits.ToSimUnits(dummyCharacter.CursorPosition));
}
@@ -5358,7 +5363,7 @@ namespace Barotrauma
}
// Deposit item from our "infinite stack" into inventory slots
var inv = dummyCharacter?.SelectedConstruction?.OwnInventory;
var inv = dummyCharacter?.SelectedItem?.OwnInventory;
if (inv?.visualSlots != null && !PlayerInput.IsCtrlDown())
{
var dragginMouse = MouseDragStart != Vector2.Zero && Vector2.Distance(PlayerInput.MousePosition, MouseDragStart) >= GUI.Scale * 20;
@@ -5524,7 +5529,7 @@ namespace Barotrauma
}
if (!saveAssemblyFrame.Rect.Contains(PlayerInput.MousePosition) && !snapToGridFrame.Rect.Contains(PlayerInput.MousePosition) &&
dummyCharacter?.SelectedConstruction == null && !WiringMode && GUI.MouseOn == null)
dummyCharacter?.SelectedItem == null && !WiringMode && GUI.MouseOn == null)
{
if (layerList is { Visible: true } && GUI.KeyboardDispatcher.Subscriber == layerList)
{
@@ -5549,7 +5554,7 @@ namespace Barotrauma
if (!WiringMode)
{
bool shouldCloseHud = dummyCharacter?.SelectedConstruction != null && HUD.CloseHUD(dummyCharacter.SelectedConstruction.Rect) && DraggedItemPrefab == null;
bool shouldCloseHud = dummyCharacter?.SelectedItem != null && HUD.CloseHUD(dummyCharacter.SelectedItem.Rect) && DraggedItemPrefab == null;
if (MapEntityPrefab.Selected != null && GUI.MouseOn == null)
{
@@ -5565,7 +5570,7 @@ namespace Barotrauma
}
else
{
if (dummyCharacter?.SelectedConstruction == null)
if (dummyCharacter?.SelectedItem == null)
{
CreateContextMenu();
}
@@ -5622,11 +5627,11 @@ namespace Barotrauma
wire?.Update((float)deltaTime, cam);
}
if (dummyCharacter.SelectedConstruction != null)
if (dummyCharacter.SelectedItem != null)
{
if (MapEntity.SelectedList.Contains(dummyCharacter.SelectedConstruction) || WiringMode)
if (MapEntity.SelectedList.Contains(dummyCharacter.SelectedItem) || WiringMode)
{
dummyCharacter.SelectedConstruction?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
dummyCharacter.SelectedItem?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
}
else
{
@@ -1,5 +1,4 @@
#nullable enable
using System;
using System.Linq;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
@@ -14,18 +13,14 @@ using Microsoft.Xna.Framework.Graphics;
*/
namespace Barotrauma
{
class TestScreen : EditorScreen
internal sealed class TestScreen : EditorScreen
{
public override Camera Cam { get; }
private Item? miniMapItem;
private Submarine? submarine;
public static Character? dummyCharacter;
public static Effect? BlueprintEffect;
private GUIFrame? container;
private TabMenu? tabMenu;
public TestScreen()
{
@@ -43,14 +38,11 @@ namespace Barotrauma
return true;
}
};
}
public override void Select()
{
base.Select();
container = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "InnerGlow", color: Color.Black);
var tab = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
if (dummyCharacter is { Removed: false })
{
dummyCharacter?.Remove();
@@ -61,30 +53,50 @@ namespace Barotrauma
dummyCharacter.Info.Name = "Galldren";
dummyCharacter.Inventory.CreateSlots();
miniMapItem = new Item(ItemPrefab.Find(null, "deconstructor".ToIdentifier()), Vector2.Zero, null, 1337, false);
foreach (ItemComponent component in miniMapItem.Components)
{
component.OnItemLoaded();
}
Character.Controlled = dummyCharacter;
GameMain.World.ProcessChanges();
tabMenu = new TabMenu();
}
public override void AddToGUIUpdateList()
{
Frame.AddToGUIUpdateList();
container?.AddToGUIUpdateList();
tabMenu?.AddToGUIUpdateList();
// CharacterHUD.AddToGUIUpdateList(dummyCharacter);
// dummyCharacter?.SelectedConstruction?.AddToGUIUpdateList();
CharacterHUD.AddToGUIUpdateList(dummyCharacter);
dummyCharacter?.SelectedItem?.AddToGUIUpdateList();
}
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (dummyCharacter is { } dummy)
if (dummyCharacter is { } dummy && miniMapItem is { } item)
{
if (dummy.SelectedItem != item)
{
dummy.SelectedItem = item;
}
dummy.SelectedItem?.UpdateHUD(Cam, dummy, (float)deltaTime);
Vector2 pos = FarseerPhysics.ConvertUnits.ToSimUnits(item.Position);
foreach (Limb limb in dummy.AnimController.Limbs)
{
limb.body.SetTransform(pos, 0.0f);
}
if (dummy.AnimController?.Collider is { } collider)
{
collider.SetTransform(pos, 0);
}
dummy.ControlLocalPlayer((float)deltaTime, Cam, false);
dummy.Control((float)deltaTime, Cam);
}
tabMenu?.Update((float)deltaTime);
}
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
@@ -93,12 +105,13 @@ namespace Barotrauma
graphics.Clear(BackgroundColor);
spriteBatch.Begin(SpriteSortMode.BackToFront, transformMatrix: Cam.Transform);
// miniMapItem?.Draw(spriteBatch, false);
// if (dummyCharacter is { } dummy)
// {
// dummyCharacter.DrawFront(spriteBatch, Cam);
// dummyCharacter.Draw(spriteBatch, Cam);
// }
miniMapItem?.Draw(spriteBatch, false);
if (dummyCharacter is { } dummy)
{
dummyCharacter.DrawFront(spriteBatch, Cam);
dummyCharacter.Draw(spriteBatch, Cam);
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
@@ -1448,7 +1448,9 @@ namespace Barotrauma
var component = otherComponents[componentIndex];
Debug.Assert(component.GetType() == parentObject.GetType());
SafeAdd(component, property);
if (value is string stringValue && Enum.TryParse(property.PropertyType, stringValue, out var enumValue))
if (value is string stringValue &&
property.PropertyType.IsEnum &&
Enum.TryParse(property.PropertyType, stringValue, out var enumValue))
{
property.PropertyInfo.SetValue(component, enumValue);
}
@@ -26,7 +26,9 @@ namespace Barotrauma
Gameplay,
Mods
}
public Tab CurrentTab { get; private set; }
private GameSettings.Config unsavedConfig;
private readonly GUIFrame mainFrame;
@@ -37,7 +39,13 @@ namespace Barotrauma
public readonly WorkshopMenu WorkshopMenu;
private static readonly ImmutableHashSet<InputType> LegacyInputTypes = new List<InputType>() { InputType.Chat, InputType.RadioChat }.ToImmutableHashSet();
private static readonly ImmutableHashSet<InputType> LegacyInputTypes = new List<InputType>()
{
InputType.Chat,
InputType.RadioChat,
InputType.LocalVoice,
InputType.RadioVoice,
}.ToImmutableHashSet();
public static SettingsMenu Create(RectTransform mainParent)
{
@@ -97,6 +105,7 @@ namespace Barotrauma
public void SelectTab(Tab tab)
{
CurrentTab = tab;
SwitchContent(tabContents[tab].Content);
tabber.Children.ForEach(c =>
{
@@ -764,27 +773,35 @@ namespace Barotrauma
private void CreateBottomButtons()
{
GUIButton cancelButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("Cancel"))
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("Cancel"))
{
OnClicked = (btn, obj) =>
{
OnClicked = (btn, obj) =>
{
Close();
return false;
}
};
GUIButton applyButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("applysettingsbutton"))
Close();
return false;
}
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("applysettingsbutton"))
{
OnClicked = (btn, obj) =>
{
OnClicked = (btn, obj) =>
GameSettings.SetCurrentConfig(unsavedConfig);
if (WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu &&
mutableWorkshopMenu.CurrentTab == MutableWorkshopMenu.Tab.InstalledMods)
{
GameSettings.SetCurrentConfig(unsavedConfig);
if (WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu) { mutableWorkshopMenu.Apply(); }
GameSettings.SaveCurrentConfig();
mainFrame.Flash(color: GUIStyle.Green);
return false;
mutableWorkshopMenu.Apply();
}
};
GameSettings.SaveCurrentConfig();
mainFrame.Flash(color: GUIStyle.Green);
return false;
},
OnAddedToGUIUpdateList = (GUIComponent component) =>
{
component.Enabled =
CurrentTab != Tab.Mods ||
(WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu && mutableWorkshopMenu.CurrentTab == MutableWorkshopMenu.Tab.InstalledMods && !mutableWorkshopMenu.ViewingItemDetails);
}
};
}
public void Close()
@@ -368,7 +368,7 @@ namespace Barotrauma.Sounds
string filePath = overrideFilePath ?? element.GetAttributeContentPath("file")?.Value ?? "";
if (!File.Exists(filePath))
{
throw new System.IO.FileNotFoundException("Sound file \"" + filePath + "\" doesn't exist!");
throw new System.IO.FileNotFoundException($"Sound file \"{filePath}\" doesn't exist! Content package \"{(element.ContentPackage?.Name ?? "Unknown")}\".");
}
var newSound = new OggSound(this, filePath, stream, xElement: element);
@@ -253,12 +253,18 @@ namespace Barotrauma
if (flipHorizontal)
{
float diff = targetSize.X % (sourceRect.Width * scale.X);
flippedDrawOffset.X = (int)((sourceRect.Width * scale.X - diff) / scale.X);
flippedDrawOffset.X = (sourceRect.Width * scale.X - diff) / scale.X;
flippedDrawOffset.X =
MathUtils.NearlyEqual(flippedDrawOffset.X, MathF.Round(flippedDrawOffset.X)) ?
MathF.Round(flippedDrawOffset.X) : flippedDrawOffset.X;
}
if (flipVertical)
{
float diff = targetSize.Y % (sourceRect.Height * scale.Y);
flippedDrawOffset.Y = (int)((sourceRect.Height * scale.Y - diff) / scale.Y);
flippedDrawOffset.Y = (sourceRect.Height * scale.Y - diff) / scale.Y;
flippedDrawOffset.Y =
MathUtils.NearlyEqual(flippedDrawOffset.Y, MathF.Round(flippedDrawOffset.Y)) ?
MathF.Round(flippedDrawOffset.Y) : flippedDrawOffset.Y;
}
drawOffset += flippedDrawOffset;
@@ -395,8 +395,8 @@ namespace Barotrauma.Steam
if (rules.ContainsKey("allowspectating")) { serverInfo.AllowSpectating = rules["allowspectating"] == "True"; }
if (rules.ContainsKey("allowrespawn")) { serverInfo.AllowRespawn = rules["allowrespawn"] == "True"; }
if (rules.ContainsKey("voicechatenabled")) { serverInfo.VoipEnabled = rules["voicechatenabled"] == "True"; }
if (rules.ContainsKey("friendlyfireenabled")) { serverInfo.AllowRespawn = rules["friendlyfireenabled"] == "True"; }
if (rules.ContainsKey("karmaenabled")) { serverInfo.VoipEnabled = rules["karmaenabled"] == "True"; }
if (rules.ContainsKey("friendlyfireenabled")) { serverInfo.FriendlyFireEnabled = rules["friendlyfireenabled"] == "True"; }
if (rules.ContainsKey("karmaenabled")) { serverInfo.KarmaEnabled = rules["karmaenabled"] == "True"; }
if (rules.ContainsKey("traitors"))
{
if (Enum.TryParse(rules["traitors"], out YesNoMaybe traitorsEnabled)) { serverInfo.TraitorsEnabled = traitorsEnabled; }
@@ -13,6 +13,8 @@ namespace Barotrauma.Steam
{
private CorePackage EnabledCorePackage => enabledCoreDropdown.SelectedData as CorePackage ?? throw new Exception("Valid core package not selected");
public bool ViewingItemDetails { get; private set; }
private readonly GUIDropDown enabledCoreDropdown;
private readonly GUIListBox enabledRegularModsList;
private readonly GUIListBox disabledRegularModsList;
@@ -167,7 +169,7 @@ namespace Barotrauma.Steam
swapSoundType = null;
}
}
private void CreateInstalledModsTab(
out GUIDropDown enabledCoreDropdown,
out GUIListBox enabledRegularModsList,
@@ -523,6 +525,7 @@ namespace Barotrauma.Steam
public void PopulateInstalledModLists(bool forceRefreshEnabled = false, bool refreshDisabled = true)
{
ViewingItemDetails = false;
bulkUpdateButton.Enabled = false;
bulkUpdateButton.ToolTip = "";
ContentPackageManager.UpdateContentPackageList();
@@ -283,6 +283,7 @@ namespace Barotrauma.Steam
{
CanBeFocused = false
};
unpublishedLayout.Recalculate();
}
if (publishedGuiComponents.Any())
@@ -456,6 +457,7 @@ namespace Barotrauma.Steam
{
CreateSubscribeButton(workshopItem, new RectTransform(Vector2.One, itemLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), spriteScale: 0.4f);
}
itemLayout.Recalculate();
}
onFill?.Invoke(workshopItems);
});
@@ -550,6 +552,7 @@ namespace Barotrauma.Steam
private void PopulateFrameWithItemInfo(Steamworks.Ugc.Item workshopItem, GUIFrame parentFrame)
{
ViewingItemDetails = true;
taskCancelSrc = taskCancelSrc.IsCancellationRequested ? new CancellationTokenSource() : taskCancelSrc;
var contentPackage
@@ -1,12 +1,9 @@
#nullable enable
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ItemOrPackage = Barotrauma.Either<Steamworks.Ugc.Item, Barotrauma.ContentPackage>;
namespace Barotrauma.Steam
{
@@ -28,6 +25,8 @@ namespace Barotrauma.Steam
ShowOnlySubs,
ShowOnlyItemAssemblies
}
public Tab CurrentTab { get; private set; }
private readonly GUILayoutGroup tabber;
private readonly Dictionary<Tab, (GUIButton Button, GUIFrame Content)> tabContents;
@@ -78,6 +77,7 @@ namespace Barotrauma.Steam
public void SelectTab(Tab tab)
{
CurrentTab = tab;
SwitchContent(tabContents[tab].Content);
tabber.Children.ForEach(c =>
{
@@ -1,30 +1,75 @@
#if DEBUG
using Barotrauma.IO;
using System;
using System.Collections.Generic;
using Barotrauma.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Globalization;
using System.Text;
namespace Barotrauma
{
class LocalizationCSVtoXML
{
private static Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"])*\"|[^,]*)", RegexOptions.Compiled); // Handling commas inside data fields surrounded by ""
private static List<int> conversationClosingIndent = new List<int>();
private static char[] separator = new char[1] { '|' };
private static readonly List<int> conversationClosingIndent = new List<int>();
private static readonly char[] separator = new char[1] { '|' };
private const string conversationsPath = "Content/NPCConversations";
private const string infoTextPath = "Content/Texts";
private const string xmlHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
private static string[,] translatedLanguageNames = new string[13, 2] { { "English", "English" }, { "French", "Français" }, { "German", "Deutsch" },
private static readonly string[,] translatedLanguageNames = new string[13, 2] { { "English", "English" }, { "French", "Français" }, { "German", "Deutsch" },
{ "Russian", "Русский" }, { "Brazilian Portuguese", "Português brasileiro" }, { "Simplified Chinese", "中文(简体)" }, { "Traditional Chinese", "中文(繁體)" },
{ "Castilian Spanish", "Castellano" }, { "Latinamerican Spanish", "Español Latinoamericano" }, { "Polish", "Polski" }, { "Turkish", "Türkçe" },
{ "Japanese", "日本語" }, { "Korean", "한국어" } };
public static void Convert()
public static void ConvertMasterLocalizationKit(string outputTextsDirectory, string outputConversationsDirectory, bool convertConversations)
{
string textFilePath = Path.Combine(infoTextPath, "Texts.csv");
string conversationFilePath = Path.Combine(infoTextPath, "NPCConversations.csv");
Dictionary<string, List<string>> xmlContent;
try
{
xmlContent = ConvertInfoTextToXML(File.ReadAllLines(textFilePath, Encoding.UTF8));
}
catch (Exception e)
{
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath, e);
return;
}
if (xmlContent == null)
{
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath);
return;
}
foreach (string language in xmlContent.Keys)
{
string languageNoWhitespace = language.Replace(" ", "");
string xmlFileFullPath = Path.Combine(outputTextsDirectory, $"{languageNoWhitespace}/{languageNoWhitespace}Vanilla.xml");
File.WriteAllLines(xmlFileFullPath, xmlContent[language], Encoding.UTF8);
DebugConsole.NewMessage("InfoText localization .xml file successfully created at: " + xmlFileFullPath);
}
if (convertConversations)
{
var conversationLinesAll = File.ReadAllLines(conversationFilePath, Encoding.UTF8);
foreach (string language in xmlContent.Keys)
{
List<string> convXmlContent = ConvertConversationsToXML(conversationLinesAll, language);
if (convXmlContent == null)
{
DebugConsole.ThrowError("NPCConversation Localization .csv to .xml conversion failed for: " + language);
continue;
}
string languageNoWhitespace = language.Replace(" ", "");
string xmlFileFullPath = Path.Combine(outputTextsDirectory, $"NpcConversations_{languageNoWhitespace}.xml");
File.WriteAllLines(xmlFileFullPath, convXmlContent, Encoding.UTF8);
DebugConsole.NewMessage("Conversation localization .xml file successfully created at: " + xmlFileFullPath);
}
}
}
[Obsolete]
public static void ConvertIndividualFiles()
{
if (GameSettings.CurrentConfig.Language != TextManager.DefaultLanguage)
{
@@ -89,8 +134,7 @@ namespace Barotrauma
for (int j = 0; j < infoTextFiles.Count; j++)
{
List<string> xmlContent = null;
List<string> xmlContent;
try
{
xmlContent = ConvertInfoTextToXML(File.ReadAllLines(infoTextFiles[j], Encoding.UTF8), language);
@@ -121,6 +165,109 @@ namespace Barotrauma
}
}
private static Dictionary<string, List<string>> ConvertInfoTextToXML(string[] csvContent)
{
Dictionary<string, List<string>> xmlContentByLanguage = new Dictionary<string, List<string>>();
//get all the languages from the header row
string headerRow = csvContent[0];
var headerContent = headerRow.Split(separator);
for (int i = 0; i < headerContent.Length; i++)
{
string languageName = headerContent[i];
if (languageName.Equals("tag", StringComparison.OrdinalIgnoreCase) ||
languageName.Equals("comments", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string translatedName = GetTranslatedName(languageName);
bool nowhitespace = TextManager.IsCJK(translatedName);
List<string> xmlContent = new List<string>()
{
xmlHeader,
$"<infotexts language=\"{languageName}\" nowhitespace=\"{nowhitespace.ToString().ToLower()}\" translatedname=\"{translatedName}\">"
};
xmlContentByLanguage.Add(headerContent[i], xmlContent);
}
for (int row = 1; row < csvContent.Length; row++) // Start at one to ignore header
{
if (!xmlContentByLanguage.Values.All(values => values.Count == xmlContentByLanguage["English"].Count))
{
throw new Exception($"Error while converting csv to xml: mismatching number of texts on line {row-1} ({csvContent[row - 1]}). Check that there's no extra newlines, separators or missing lines in the csv file.");
}
if (csvContent[row].Length == 0)
{
AddToAllLanguages(string.Empty);
}
else
{
string[] split = csvContent[row].Split(separator);
if (split.Length < xmlContentByLanguage.Count)
{
throw new Exception($"Error while converting csv to xml: not enough values on line {row} ({csvContent[row]}). Check that there's no extra newlines, separators or missing lines in the csv file.");
}
if (split.Length > 1) // Localization data
{
//all values empty = an empty line
if (split.All(s => s.IsNullOrEmpty()))
{
AddToAllLanguages(string.Empty);
}
//value is empty in all languages
else if (!split[0].IsNullOrEmpty() && split.Skip(2).All(s => s.IsNullOrEmpty()))
{
//first line is all lower-case and contains dot, assume it's an empty value
if (split[0].Contains(".") && !split[0].Any(char.IsUpper))
{
AddToAllLanguages($"<{split[0]}></{split[0]}>");
}
//otherwise assume it's a comment
else
{
AddToAllLanguages($"<!-- {split[0]} -->");
}
}
else
{
for (int j = 0; j < split.Length; j++)
{
string languageName = headerContent[j];
if (languageName.Equals("tag", StringComparison.OrdinalIgnoreCase) ||
languageName.Equals("comments", StringComparison.OrdinalIgnoreCase))
{
continue;
}
split[j] = split[j].Replace(" & ", " &amp; ");
xmlContentByLanguage[languageName].Add($"<{split[0]}>{split[j]}</{split[0]}>");
}
}
}
else // A header/comment
{
AddToAllLanguages($"<!-- {split[0]} -->");
}
}
}
AddToAllLanguages(string.Empty);
AddToAllLanguages("</infotexts>");
void AddToAllLanguages(string str)
{
foreach (var xmlContent in xmlContentByLanguage.Values)
{
xmlContent.Add(str);
}
}
return xmlContentByLanguage;
}
[Obsolete]
private static List<string> ConvertInfoTextToXML(string[] csvContent, string language)
{
List<string> xmlContent = new List<string>
@@ -147,12 +294,6 @@ namespace Barotrauma
if (split.Length >= 2) // Localization data
{
if (split.Length > 2 && !split[0].All(char.IsLower)) // Invalid header in line with localization data
{
split[0] = split[1];
split[1] = split[2];
split[2] = string.Empty;
}
split[1] = split[1].Replace(" & ", " &amp; ");
xmlContent.Add($"<{split[0]}>{split[1]}</{split[0]}>");
}
@@ -186,68 +327,39 @@ namespace Barotrauma
private static List<string> ConvertConversationsToXML(string[] csvContent, string language)
{
List<string> xmlContent = new List<string>();
xmlContent.Add(xmlHeader);
List<string> xmlContent = new List<string>
{
xmlHeader
};
string translatedName = GetTranslatedName(language);
bool nowhitespace = TextManager.IsCJK(translatedName);
int languageColumn = -1;
string[] headerSplit = csvContent[0].Split(separator);
for (int i = 0; i < headerSplit.Length; i++)
{
if (headerSplit[i] == language)
{
languageColumn = i;
break;
}
}
xmlContent.Add($"<Conversations identifier=\"vanillaconversations\" Language=\"{language}\" nowhitespace=\"{nowhitespace}\">");
xmlContent.Add(string.Empty);
xmlContent.Add("<!-- Personality traits -->");
int traitStart = -1;
for (int i = 0; i < csvContent.Length; i++)
{
if (csvContent[i].StartsWith("Personality"))
{
traitStart = i + 1;
break;
}
}
int conversationStart = -1;
for (int i = 0; i < csvContent.Length; i++)
{
if (csvContent[i].StartsWith("Generic"))
{
conversationStart = i;
break;
}
}
if (traitStart == -1)
{
DebugConsole.ThrowError("Invalid formatting of NPCConversations, no traits found!");
return null;
}
//DebugConsole.NewMessage("Count: " + NPCPersonalityTrait.List.Count);
var traits = NPCPersonalityTrait.GetAll(language.ToLanguageIdentifier()).ToArray();
for (int i = 0; i < traits.Length; i++) // Traits
{
//string[] split = SplitCSV(csvContent[traitStart + i].Trim(separator));
string[] split = csvContent[traitStart + i].Split(separator);
xmlContent.Add(
$"<PersonalityTrait " +
$"{GetVariable("name", split[1])}" +
$"{GetVariable("alloweddialogtags", string.Join(",", traits[i].AllowedDialogTags))}" +
$"{GetVariable("commonness", traits[i].Commonness.ToString(CultureInfo.InvariantCulture))}/>");
}
int conversationStart = 1;
xmlContent.Add(string.Empty);
for (int i = conversationStart; i < csvContent.Length; i++) // Conversations
{
string[] split = csvContent[i].Split(separator);
int emptyFields = 0;
for (int j = 0; j < split.Length; j++)
{
if (split[j] == string.Empty) emptyFields++;
if (split[j] == string.Empty) { emptyFields++; }
}
if (emptyFields == split.Length) // Empty line with only commas, indicates the end of the previous conversation
{
HandleClosingElements(xmlContent, 0);
@@ -260,10 +372,10 @@ namespace Barotrauma
continue;
}
string speaker = split[1];
int depthIndex = int.Parse(split[2]);
string line = split[languageColumn].Replace("\"", "");
string speaker = split[2];
int depthIndex = int.Parse(split[3]);
// 3 = original line
string line = split[3].Replace("\"", "");
string flags = split[4].Replace("\"", "");
string allowedJobs = split[5].Replace("\"", "");
string speakerTags = split[6].Replace("\"", "");
@@ -317,7 +429,7 @@ namespace Barotrauma
xmlContent.Add("</Conversations>");
return xmlContent;
}
}
private static void HandleClosingElements(List<string> xmlContent, int targetDepth)
{
@@ -332,24 +444,6 @@ namespace Barotrauma
}
}
private static string[] SplitCSV(string input) // Splits the .csv with regex, leaving commas inside quotation marks intact
{
List<string> list = new List<string>();
string curr = null;
foreach (Match match in csvSplit.Matches(input))
{
curr = match.Value;
if (0 == curr.Length)
{
list.Add("");
}
list.Add(curr.TrimStart(separator));
}
return list.ToArray();
}
private static string GetIndenting(int depthIndex)
{
string indenting = string.Empty;