v0.12.0.2

This commit is contained in:
Joonas Rikkonen
2021-02-10 17:08:21 +02:00
parent 5c80a59bdd
commit 694cdfee7b
353 changed files with 12897 additions and 5028 deletions

View File

@@ -47,6 +47,8 @@ namespace Barotrauma
set { maxZoom = MathHelper.Clamp(value, 1.0f, 10.0f); }
}
public float FreeCamMoveSpeed = 1.0f;
private float zoom;
private float offsetAmount;
@@ -197,10 +199,15 @@ namespace Barotrauma
private void CreateMatrices()
{
resolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
worldView = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
viewMatrix = Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0));
SetResolution(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight));
}
public void SetResolution(Point res)
{
resolution = res;
worldView = new Rectangle(0, 0, res.X, res.Y);
viewMatrix = Matrix.CreateTranslation(new Vector3(res.X / 2.0f, res.Y / 2.0f, 0));
globalZoomScale = (float)Math.Pow(new Vector2(GUI.UIWidth, resolution.Y).Length() / GUI.ReferenceResolution.Length(), 2);
}
@@ -265,17 +272,17 @@ namespace Barotrauma
{
if (GUI.KeyboardDispatcher.Subscriber == null)
{
if (PlayerInput.KeyDown(Keys.LeftShift)) moveSpeed *= 2.0f;
if (PlayerInput.KeyDown(Keys.LeftControl)) moveSpeed *= 0.5f;
if (PlayerInput.KeyDown(Keys.LeftShift)) { moveSpeed *= 2.0f; }
if (PlayerInput.KeyDown(Keys.LeftControl)) { moveSpeed *= 0.5f; }
if (GameMain.Config.KeyBind(InputType.Left).IsDown()) moveInput.X -= 1.0f;
if (GameMain.Config.KeyBind(InputType.Right).IsDown()) moveInput.X += 1.0f;
if (GameMain.Config.KeyBind(InputType.Down).IsDown()) moveInput.Y -= 1.0f;
if (GameMain.Config.KeyBind(InputType.Up).IsDown()) moveInput.Y += 1.0f;
if (GameMain.Config.KeyBind(InputType.Left).IsDown()) { moveInput.X -= 1.0f; }
if (GameMain.Config.KeyBind(InputType.Right).IsDown()) { moveInput.X += 1.0f; }
if (GameMain.Config.KeyBind(InputType.Down).IsDown()) { moveInput.Y -= 1.0f; }
if (GameMain.Config.KeyBind(InputType.Up).IsDown()) { moveInput.Y += 1.0f; }
}
velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f);
moveCam = velocity * moveSpeed * deltaTime * 60.0f;
moveCam = velocity * moveSpeed * deltaTime * FreeCamMoveSpeed * 60.0f;
if (Screen.Selected == GameMain.GameScreen && FollowSub)
{
@@ -291,14 +298,21 @@ namespace Barotrauma
{
Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition);
Vector2 diffViewCenter;
diffViewCenter = ((mouseInWorld - Position) * Zoom);
diffViewCenter = (mouseInWorld - Position) * Zoom;
targetZoom = MathHelper.Clamp(
targetZoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom,
targetZoom + PlayerInput.ScrollWheelSpeed / 1000.0f * zoom,
GameMain.DebugDraw ? MinZoom * 0.1f : MinZoom,
MaxZoom);
Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f);
if (!PlayerInput.KeyDown(Keys.F)) Position = mouseInWorld - (diffViewCenter / Zoom);
if (PlayerInput.KeyDown(Keys.LeftControl))
{
Zoom += (targetZoom - zoom) / (ZoomSmoothness * 10.0f);
}
else
{
Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f);
}
if (!PlayerInput.KeyDown(Keys.F)) { Position = mouseInWorld - (diffViewCenter / Zoom); }
}
}
else if (allowMove)

View File

@@ -31,57 +31,54 @@ namespace Barotrauma
GUI.DrawString(spriteBatch, pos + textOffset, Character.Name, Color.White, Color.Black);
if (ObjectiveManager != null)
var currentOrder = ObjectiveManager.CurrentOrder;
if (currentOrder != null)
{
var currentOrder = ObjectiveManager.CurrentOrder;
if (currentOrder != null)
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
else if (ObjectiveManager.WaitTimer > 0)
{
GUI.DrawString(spriteBatch, pos + new Vector2(0, 20), $"Waiting... {ObjectiveManager.WaitTimer.FormatZeroDecimal()}", Color.White, Color.Black);
}
var currentObjective = ObjectiveManager.CurrentObjective;
if (currentObjective != null)
{
int offset = currentOrder != null ? 20 : 0;
if (currentOrder == null || currentOrder.Priority <= 0)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20 + offset), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
else if (ObjectiveManager.WaitTimer > 0)
var subObjective = currentObjective.CurrentSubObjective;
if (subObjective != null)
{
GUI.DrawString(spriteBatch, pos + new Vector2(0, 20), $"Waiting... {ObjectiveManager.WaitTimer.FormatZeroDecimal()}", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40 + offset), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var currentObjective = ObjectiveManager.CurrentObjective;
if (currentObjective != null)
var activeObjective = ObjectiveManager.GetActiveObjective();
if (activeObjective != null)
{
int offset = currentOrder != null ? 20 : 0;
if (currentOrder == null || currentOrder.Priority <= 0)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20 + offset), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var subObjective = currentObjective.CurrentSubObjective;
if (subObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40 + offset), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var activeObjective = ObjectiveManager.GetActiveObjective();
if (activeObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60 + offset), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60 + offset), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
for (int i = 0; i < ObjectiveManager.Objectives.Count; i++)
}
for (int i = 0; i < ObjectiveManager.Objectives.Count; i++)
{
var objective = ObjectiveManager.Objectives[i];
int offsetMultiplier;
if (ObjectiveManager.CurrentOrder == null)
{
var objective = ObjectiveManager.Objectives[i];
int offsetMultiplier;
if (ObjectiveManager.CurrentOrder == null)
if (i == 0)
{
if (i == 0)
{
continue;
}
else
{
offsetMultiplier = i - 1;
}
continue;
}
else
{
offsetMultiplier = i + 1;
offsetMultiplier = i - 1;
}
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(120, offsetMultiplier * 18 + 100), $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f);
}
else
{
offsetMultiplier = i + 1;
}
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(120, offsetMultiplier * 18 + 100), $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f);
}
if (steeringManager is IndoorsSteeringManager pathSteering)
@@ -116,6 +113,14 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
if (Character.AnimController.InWater && objectiveManager.GetActiveObjective() is AIObjectiveGoTo gotoObjective && gotoObjective.TargetGap != null)
{
Vector2 gapPosition = gotoObjective.TargetGap.WorldPosition;
gapPosition.Y = -gapPosition.Y;
GUI.DrawRectangle(spriteBatch, gapPosition - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false);
GUI.DrawLine(spriteBatch, pos, gapPosition, Color.Orange * 0.5f, 0, 5);
}
//if (Character.IsKeyDown(InputType.Aim))
//{
// GUI.DrawLine(spriteBatch, pos, new Vector2(Character.CursorWorldPosition.X, -Character.CursorWorldPosition.Y), Color.Yellow, width: 4);

View File

@@ -481,13 +481,13 @@ namespace Barotrauma
var controller = character.SelectedConstruction?.GetComponent<Controller>();
if (controller != null && controller.ControlCharacterPose && controller.User == character)
{
if (controller.Item.SpriteDepth > maxDepth)
if (controller.Item.SpriteDepth <= maxDepth || controller.DrawUserBehind)
{
depthOffset = Math.Max(controller.Item.SpriteDepth - 0.0001f - maxDepth, 0.0f);
depthOffset = Math.Max(controller.Item.GetDrawDepth() + 0.0001f - minDepth, -minDepth);
}
else
{
depthOffset = Math.Max(controller.Item.SpriteDepth + 0.0001f - minDepth, -minDepth);
depthOffset = Math.Max(controller.Item.GetDrawDepth() - 0.0001f - maxDepth, 0.0f);
}
}
}

View File

@@ -46,7 +46,7 @@ namespace Barotrauma
if (sound != null)
{
SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range);
SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling);
}
}
}

View File

@@ -457,7 +457,7 @@ namespace Barotrauma
if (draggingItemToWorld)
{
if (item.OwnInventory == null ||
!item.OwnInventory.CanBePut(CharacterInventory.draggingItem) ||
!item.OwnInventory.CanBePut(CharacterInventory.DraggingItems.First()) ||
!CanAccessInventory(item.OwnInventory))
{
continue;
@@ -561,7 +561,7 @@ namespace Barotrauma
{
if (InvisibleTimer > 0.0f)
{
if (Controlled == null || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
if (Controlled == null || Controlled == this || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
{
InvisibleTimer = 0.0f;
}
@@ -579,15 +579,15 @@ namespace Barotrauma
{
soundTimer -= deltaTime;
}
else if (AIController != null)
else if (AIController is EnemyAIController enemyAI)
{
switch (AIController.State)
switch (enemyAI.State)
{
case AIState.Attack:
PlaySound(CharacterSound.SoundType.Attack);
break;
default:
var petBehavior = (AIController as EnemyAIController)?.PetBehavior;
var petBehavior = enemyAI.PetBehavior;
if (petBehavior != null && petBehavior.Happiness < petBehavior.MaxHappiness * 0.25f)
{
PlaySound(CharacterSound.SoundType.Unhappy);
@@ -741,7 +741,7 @@ namespace Barotrauma
if (speechBubbleTimer > 0.0f)
{
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 30,
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 5,
speechBubbleColor * Math.Min(speechBubbleTimer, 1.0f), 0.0f,
Math.Min(speechBubbleTimer, 1.0f));
}
@@ -803,7 +803,7 @@ namespace Barotrauma
Color nameColor = Color.White;
if (Controlled != null && TeamID != Controlled.TeamID)
{
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
nameColor = TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
}
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
{
@@ -902,7 +902,7 @@ namespace Barotrauma
}
var selectedSound = matchingSounds.GetRandom();
if (selectedSound?.Sound == null) { return; }
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: CurrentHull);
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: CurrentHull, ignoreMuffling: selectedSound.IgnoreMuffling);
soundTimer = soundInterval;
}

View File

@@ -57,7 +57,7 @@ namespace Barotrauma
!ConversationAction.FadeScreenToBlack;
}
private static string GetCachedHudText(string textTag, string keyBind)
public static string GetCachedHudText(string textTag, string keyBind)
{
if (cachedHudTexts.TryGetValue(textTag + keyBind, out string text))
{
@@ -76,10 +76,10 @@ namespace Barotrauma
{
if (character.Inventory != null)
{
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
for (int i = 0; i < character.Inventory.Capacity; i++)
{
var item = character.Inventory.Items[i];
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
var item = character.Inventory.GetItemAt(i);
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) { continue; }
foreach (ItemComponent ic in item.Components)
{
@@ -131,10 +131,10 @@ namespace Barotrauma
character.Inventory.ClearSubInventories();
}
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
for (int i = 0; i < character.Inventory.Capacity; i++)
{
var item = character.Inventory.Items[i];
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
var item = character.Inventory.GetItemAt(i);
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) { continue; }
foreach (ItemComponent ic in item.Components)
{
@@ -206,22 +206,31 @@ namespace Barotrauma
orderIndicatorCount.Clear();
foreach (Pair<Order, float?> activeOrder in GameMain.GameSession.CrewManager.ActiveOrders)
{
if (!DrawIcon(activeOrder.First)) { continue; }
if (activeOrder.Second.HasValue)
{
DrawOrderIndicator(spriteBatch, cam, character, activeOrder.First, iconAlpha: MathHelper.Clamp(activeOrder.Second.Value / 10.0f, 0.2f, 1.0f));
}
else
{
float iconAlpha = GetDistanceBasedIconAlpha(activeOrder.First.TargetSpatialEntity, maxDistance: 350.0f);
float iconAlpha = GetDistanceBasedIconAlpha(activeOrder.First.TargetSpatialEntity, maxDistance: 450.0f);
if (iconAlpha <= 0.0f) { continue; }
DrawOrderIndicator(spriteBatch, cam, character, activeOrder.First, iconAlpha: iconAlpha, createOffset: false, scaleMultiplier: 0.5f);
DrawOrderIndicator(spriteBatch, cam, character, activeOrder.First,
iconAlpha: iconAlpha, createOffset: false, scaleMultiplier: 0.5f, overrideAlpha: true);
}
}
if (character.CurrentOrder != null)
if (DrawIcon(character.CurrentOrder))
{
DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f);
}
static bool DrawIcon(Order o) =>
o != null &&
(!(o.TargetEntity is Item i) ||
o.DrawIconWhenContained ||
i.GetRootInventoryOwner() == i);
}
foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities)
@@ -231,7 +240,7 @@ namespace Barotrauma
foreach (Item brokenItem in brokenItems)
{
if (brokenItem.NonInteractable) { continue; }
if (!brokenItem.IsInteractable(character)) { continue; }
float alpha = GetDistanceBasedIconAlpha(brokenItem);
if (alpha <= 0.0f) continue;
GUI.DrawIndicator(spriteBatch, brokenItem.DrawPosition, cam, 100.0f, GUI.BrokenIcon,
@@ -244,7 +253,7 @@ namespace Barotrauma
return Math.Min((maxDistance - dist) / maxDistance * 2.0f, 1.0f);
}
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen && (!character.IsKeyDown(InputType.Aim) || character.SelectedItems.Any(it => it?.GetComponent<Sprayer>() == null)))
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen && (!character.IsKeyDown(InputType.Aim) || character.HeldItems.Any(it => it?.GetComponent<Sprayer>() == null)))
{
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
{
@@ -281,7 +290,7 @@ namespace Barotrauma
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
{
bool shiftDown = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
if(shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
{
shouldRecreateHudTexts = true;
heldDownShiftWhenGotHudTexts = shiftDown;
@@ -291,8 +300,8 @@ namespace Barotrauma
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
Vector2 textSize = GUI.Font.MeasureString(focusedItem.Name);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusedItem.Name);
Vector2 textSize = GUI.Font.MeasureString(hudTexts.First().Text);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(hudTexts.First().Text);
Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition);
startPos.Y -= (hudTexts.Count + 1) * textSize.Y;
@@ -307,11 +316,11 @@ namespace Barotrauma
float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f);
GUI.DrawString(spriteBatch, textPos, focusedItem.Name, GUI.Style.TextColor * alpha, Color.Black * alpha * 0.7f, 2, font: GUI.SubHeadingFont);
GUI.DrawString(spriteBatch, textPos, hudTexts.First().Text, hudTexts.First().Color * alpha, Color.Black * alpha * 0.7f, 2, font: GUI.SubHeadingFont);
startPos.X += dir * 10.0f * GUI.Scale;
textPos.X += dir * 10.0f * GUI.Scale;
textPos.Y += largeTextSize.Y;
foreach (ColoredText coloredText in hudTexts)
foreach (ColoredText coloredText in hudTexts.Skip(1))
{
if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X);
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont);
@@ -341,9 +350,8 @@ namespace Barotrauma
}
if (Character.Controlled.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.Items)
foreach (Item item in Character.Controlled.Inventory.AllItems)
{
if (item == null) { continue; }
if (Character.Controlled.HasEquippedItem(item))
{
item.DrawHUD(spriteBatch, cam, Character.Controlled);
@@ -355,10 +363,10 @@ namespace Barotrauma
if (character.Inventory != null)
{
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
for (int i = 0; i < character.Inventory.Capacity; i++)
{
var item = character.Inventory.Items[i];
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
var item = character.Inventory.GetItemAt(i);
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) { continue; }
foreach (ItemComponent ic in item.Components)
{
@@ -432,12 +440,16 @@ namespace Barotrauma
private static void DrawCharacterHoverTexts(SpriteBatch spriteBatch, Camera cam, Character character)
{
foreach (Item item in character.Inventory.Items)
var allItems = character.Inventory?.AllItems;
if (allItems != null)
{
var statusHUD = item?.GetComponent<StatusHUD>();
if (statusHUD != null && statusHUD.IsActive && statusHUD.VisibleCharacters.Contains(character.FocusedCharacter))
foreach (Item item in allItems)
{
return;
var statusHUD = item?.GetComponent<StatusHUD>();
if (statusHUD != null && statusHUD.IsActive && statusHUD.VisibleCharacters.Contains(character.FocusedCharacter))
{
return;
}
}
}
@@ -454,7 +466,7 @@ namespace Barotrauma
Color nameColor = GUI.Style.TextColor;
if (character.TeamID != character.FocusedCharacter.TeamID)
{
nameColor = character.FocusedCharacter.TeamID == Character.TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
nameColor = character.FocusedCharacter.TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
}
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
@@ -493,7 +505,9 @@ namespace Barotrauma
return character.ShouldLockHud();
}
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f, bool createOffset = true, float scaleMultiplier = 1.0f)
/// <param name="overrideAlpha">Override the distance-based alpha value with the iconAlpha parameter value</param>
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order,
float iconAlpha = 1.0f, bool createOffset = true, float scaleMultiplier = 1.0f, bool overrideAlpha = false)
{
if (order?.SymbolSprite == null) { return; }
if (order.IsReport && order.OrderGiver != character && !order.HasAppropriateJob(character)) { return; }
@@ -514,7 +528,8 @@ namespace Barotrauma
Vector2 drawPos = target is Entity ? (target as Entity).DrawPosition :
target.Submarine == null ? target.Position : target.Position + target.Submarine.DrawPosition;
drawPos += Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha, createOffset: createOffset, scaleMultiplier: scaleMultiplier);
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha,
createOffset: createOffset, scaleMultiplier: scaleMultiplier, overrideAlpha: overrideAlpha ? (float?)iconAlpha : null);
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
}

View File

@@ -152,34 +152,19 @@ namespace Barotrauma
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
{
if (TeamID == Character.TeamType.FriendlyNPC) { return; }
if (TeamID == CharacterTeamType.FriendlyNPC) { return; }
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
if (newLevel - prevLevel > 0.1f)
{
GUI.AddMessage(
"+" + ((int)((newLevel - prevLevel) * 100.0f)).ToString() + " XP",
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: false);
}
else if (prevLevel % 0.1f > 0.05f && newLevel % 0.1f < 0.05f)
{
GUI.AddMessage(
"+10 XP",
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: false);
}
if ((int)newLevel > (int)prevLevel)
{
int increase = Math.Max((int)newLevel - (int)prevLevel, 1);
GUI.AddMessage(
TextManager.GetWithVariables("SkillIncreased", new string[3] { "[name]", "[skillname]", "[newlevel]" },
new string[3] { Name, TextManager.Get("SkillName." + skillIdentifier), ((int)newLevel).ToString() },
new bool[3] { false, true, false }), GUI.Style.Green);
string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)),
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: false,
subId: Character?.Submarine?.ID ?? -1);
}
}

View File

@@ -349,7 +349,7 @@ namespace Barotrauma
{
string skillIdentifier = msg.ReadString();
float skillLevel = msg.ReadSingle();
info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f);
}
break;
case 4: //NetEntityEvent.Type.ExecuteAttack
@@ -434,7 +434,7 @@ namespace Barotrauma
CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);
character = Create(speciesName, position, seed, characterInfo: info, id: id, isRemotePlayer: ownerId > 0 && GameMain.Client.ID != ownerId, hasAi: hasAi);
character.TeamID = (TeamType)teamID;
character.TeamID = (CharacterTeamType)teamID;
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
{
@@ -487,7 +487,7 @@ namespace Barotrauma
character.ReadStatus(inc);
}
if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC && !character.IsDead)
if (character.IsHuman && character.TeamID != CharacterTeamType.FriendlyNPC && !character.IsDead)
{
CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);

View File

@@ -18,6 +18,11 @@ namespace Barotrauma
public float Range => roundSound == null ? 0.0f : roundSound.Range;
public Sound Sound => roundSound?.Sound;
public bool IgnoreMuffling
{
get { return roundSound?.IgnoreMuffling ?? false; }
}
public CharacterSound(CharacterParams.SoundParams soundParams)
{
Params = soundParams;

View File

@@ -72,7 +72,7 @@ namespace Barotrauma
FadeTimer = 1.0f;
if (!string.IsNullOrEmpty(textTag))
{
textTag = textTag;
this.textTag = textTag;
Text = TextManager.Get(textTag);
}
}

View File

@@ -10,6 +10,7 @@ namespace Barotrauma
{
partial void UpdateMessages()
{
if (Prefab is AfflictionPrefabHusk { SendMessages: false }) { return; }
switch (State)
{
case InfectionState.Dormant:

View File

@@ -912,7 +912,7 @@ namespace Barotrauma
lowSkillIndicator.Color = new Color(lowSkillIndicator.Color, MathHelper.Lerp(0.5f, 1.0f, (float)(Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) / 2.0f));
if (Inventory.draggingItem != null)
if (Inventory.DraggingItems.Any())
{
if (highlightedLimbIndex > -1)
{
@@ -1632,8 +1632,8 @@ namespace Barotrauma
}
//can't apply treatment to dead characters
if (Character.IsDead) return true;
if (item == null || !item.UseInHealthInterface) return true;
if (Character.IsDead) { return true; }
if (item == null || !item.UseInHealthInterface) { return true; }
if (!ignoreMousePos)
{
if (highlightedLimbIndex > -1)
@@ -1652,33 +1652,25 @@ namespace Barotrauma
private List<Item> GetAvailableMedicalItems()
{
List<Item> allInventoryItems = new List<Item>();
allInventoryItems.AddRange(Character.Inventory.Items);
allInventoryItems.AddRange(Character.Inventory.AllItems);
if (Character.SelectedCharacter?.Inventory != null && Character.CanAccessInventory(Character.SelectedCharacter.Inventory))
{
allInventoryItems.AddRange(Character.SelectedCharacter.Inventory.Items);
allInventoryItems.AddRange(Character.SelectedCharacter.Inventory.AllItems);
}
if (Character.SelectedBy?.Inventory != null)
{
allInventoryItems.AddRange(Character.SelectedBy.Inventory.Items);
allInventoryItems.AddRange(Character.SelectedBy.Inventory.AllItems);
}
List<Item> medicalItems = new List<Item>();
foreach (Item item in allInventoryItems)
{
if (item == null) continue;
var containedItems = item.ContainedItems;
if (containedItems != null)
foreach (Item containedItem in item.ContainedItems)
{
foreach (Item containedItem in containedItems)
{
if (containedItem == null) continue;
if (!containedItem.HasTag("medical") && !containedItem.HasTag("chem")) continue;
medicalItems.Add(containedItem);
}
if (!containedItem.HasTag("medical") && !containedItem.HasTag("chem")) { continue; }
medicalItems.Add(containedItem);
}
if (!item.HasTag("medical") && !item.HasTag("chem")) continue;
if (!item.HasTag("medical") && !item.HasTag("chem")) { continue; }
medicalItems.Add(item);
}
@@ -1804,24 +1796,27 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred, Lights.CustomBlendStates.Multiplicative);
float overlayScale = Math.Min(
drawArea.Width / (float)limbIndicatorOverlay.FrameSize.X,
drawArea.Height / (float)limbIndicatorOverlay.FrameSize.Y);
int frame = 0;
int frameCount = 17;
if (limbIndicatorOverlayAnimState >= frameCount * 2) limbIndicatorOverlayAnimState = 0.0f;
if (limbIndicatorOverlayAnimState < frameCount)
if (limbIndicatorOverlay != null)
{
frame = (int)limbIndicatorOverlayAnimState;
}
else
{
frame = frameCount - (int)(limbIndicatorOverlayAnimState - (frameCount - 1));
}
float overlayScale = Math.Min(
drawArea.Width / (float)limbIndicatorOverlay.FrameSize.X,
drawArea.Height / (float)limbIndicatorOverlay.FrameSize.Y);
limbIndicatorOverlay.Draw(spriteBatch, frame, drawArea.Center.ToVector2(), Color.Gray, origin: limbIndicatorOverlay.FrameSize.ToVector2() / 2, rotate: 0.0f,
scale: Vector2.One * overlayScale);
int frame = 0;
int frameCount = 17;
if (limbIndicatorOverlayAnimState >= frameCount * 2) limbIndicatorOverlayAnimState = 0.0f;
if (limbIndicatorOverlayAnimState < frameCount)
{
frame = (int)limbIndicatorOverlayAnimState;
}
else
{
frame = frameCount - (int)(limbIndicatorOverlayAnimState - (frameCount - 1));
}
limbIndicatorOverlay.Draw(spriteBatch, frame, drawArea.Center.ToVector2(), Color.Gray, origin: limbIndicatorOverlay.FrameSize.ToVector2() / 2, rotate: 0.0f,
scale: Vector2.One * overlayScale);
}
if (allowHighlight)
{

View File

@@ -22,8 +22,8 @@ namespace Barotrauma
float strength = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, MathHelper.Pi, diff));
float jointAngle = JointAngle * strength;
JointBendDeformation limbADeformation = LimbA.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
JointBendDeformation limbBDeformation = LimbB.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
JointBendDeformation limbADeformation = LimbA.ActiveDeformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
JointBendDeformation limbBDeformation = LimbB.ActiveDeformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
if (limbADeformation != null && limbBDeformation != null)
{
@@ -114,7 +114,10 @@ namespace Barotrauma
/// Note that different limbs can share the same deformations.
/// Use ragdoll.SpriteDeformations for a collection that cannot have duplicates.
/// </summary>
public List<SpriteDeformation> Deformations { get; private set; } = new List<SpriteDeformation>();
private List<SpriteDeformation> Deformations { get; set; } = new List<SpriteDeformation>();
private List<SpriteDeformation> NonConditionalDeformations { get; set; } = new List<SpriteDeformation>();
private List<(ConditionalSprite, IEnumerable<SpriteDeformation>)> ConditionalDeformations { get; set; } = new List<(ConditionalSprite, IEnumerable<SpriteDeformation>)>();
public List<SpriteDeformation> ActiveDeformations { get; set; } = new List<SpriteDeformation>();
public Sprite Sprite { get; protected set; }
@@ -178,6 +181,9 @@ namespace Barotrauma
{
public float RotationState;
public float OffsetState;
public Vector2 RandomOffsetMultiplier = new Vector2(Rand.Range(-1.0f, 1.0f), Rand.Range(-1.0f, 1.0f));
public float RandomRotationFactor = Rand.Range(0.0f, 1.0f);
public float RandomScaleFactor = Rand.Range(0.0f, 1.0f);
public bool IsActive = true;
}
@@ -282,12 +288,16 @@ namespace Barotrauma
ConditionalSprites.Add(conditionalSprite);
if (conditionalSprite.DeformableSprite != null)
{
CreateDeformations(subElement.GetChildElement("deformablesprite"));
var conditionalDeformations = CreateDeformations(subElement.GetChildElement("deformablesprite"));
Deformations.AddRange(conditionalDeformations);
ConditionalDeformations.Add((conditionalSprite, conditionalDeformations));
}
break;
case "deformablesprite":
_deformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams));
CreateDeformations(subElement);
var deformations = CreateDeformations(subElement);
Deformations.AddRange(deformations);
NonConditionalDeformations.AddRange(deformations);
break;
case "lightsource":
LightSource = new LightSource(subElement, GetConditionalTarget())
@@ -315,8 +325,9 @@ namespace Barotrauma
return targetEntity;
}
void CreateDeformations(XElement e)
IEnumerable<SpriteDeformation> CreateDeformations(XElement e)
{
List<SpriteDeformation> deformations = new List<SpriteDeformation>();
foreach (XElement animationElement in e.GetChildElements("spritedeformation"))
{
int sync = animationElement.GetAttributeInt("sync", -1);
@@ -340,14 +351,39 @@ namespace Barotrauma
}
if (deformation != null)
{
Deformations.Add(deformation);
deformations.Add(deformation);
}
}
return deformations;
}
}
LightSource?.CheckConditionals();
}
private void RefreshDeformations()
{
if (_deformSprite == null) { return; }
if (ConditionalSprites.None())
{
ActiveDeformations = Deformations;
}
else
{
ActiveDeformations.Clear();
if (_deformSprite == DeformSprite)
{
ActiveDeformations.AddRange(NonConditionalDeformations);
}
foreach (var conditionalDeformation in ConditionalDeformations)
{
if (conditionalDeformation.Item1.IsActive)
{
ActiveDeformations.AddRange(conditionalDeformation.Item2);
}
}
}
}
public void RecreateSprites()
{
if (Sprite != null)
@@ -390,18 +426,24 @@ namespace Barotrauma
character.Info?.CalculateHeadPosition(sprite);
}
private string _texturePath;
private string GetSpritePath(XElement element, SpriteParams spriteParams)
{
if (spriteParams != null)
if (_texturePath == null)
{
return GetSpritePath(spriteParams.GetTexturePath());
}
else
{
string texturePath = element.GetAttributeString("texture", null);
texturePath = string.IsNullOrWhiteSpace(texturePath) ? ragdoll.RagdollParams.Texture : texturePath;
return GetSpritePath(texturePath);
if (spriteParams != null)
{
string texturePath = character.Params.VariantFile?.Root?.GetAttributeString("texture", null) ?? spriteParams.GetTexturePath();
_texturePath = GetSpritePath(texturePath);
}
else
{
string texturePath = element.GetAttributeString("texture", null);
texturePath = string.IsNullOrWhiteSpace(texturePath) ? ragdoll.RagdollParams.Texture : texturePath;
_texturePath = GetSpritePath(texturePath);
}
}
return _texturePath;
}
/// <summary>
@@ -537,7 +579,7 @@ namespace Barotrauma
else
{
var spriteParams = Params.GetSprite();
if (spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
if (spriteParams != null && spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
{
deadTimer += deltaTime;
}
@@ -587,6 +629,7 @@ namespace Barotrauma
}
UpdateSpriteStates(deltaTime);
RefreshDeformations();
}
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
@@ -637,13 +680,13 @@ namespace Barotrauma
var deformSprite = DeformSprite;
if (deformSprite != null)
{
if (Deformations != null && Deformations.Any())
if (ActiveDeformations.Any())
{
var deformation = SpriteDeformation.GetDeformation(Deformations, deformSprite.Size);
var deformation = SpriteDeformation.GetDeformation(ActiveDeformations, deformSprite.Size);
deformSprite.Deform(deformation);
if (LightSource != null && LightSource.DeformableLightSprite != null)
{
deformation = SpriteDeformation.GetDeformation(Deformations, deformSprite.Size, dir == Direction.Left);
deformation = SpriteDeformation.GetDeformation(ActiveDeformations, deformSprite.Size, dir == Direction.Left);
LightSource.DeformableLightSprite.Deform(deformation);
}
}
@@ -666,9 +709,9 @@ namespace Barotrauma
if (conditionalSprite.DeformableSprite != null)
{
var defSprite = conditionalSprite.DeformableSprite;
if (Deformations != null && Deformations.Any())
if (ActiveDeformations.Any())
{
var deformation = SpriteDeformation.GetDeformation(Deformations, defSprite.Size);
var deformation = SpriteDeformation.GetDeformation(ActiveDeformations, defSprite.Size);
defSprite.Deform(deformation);
}
else
@@ -705,13 +748,13 @@ namespace Barotrauma
c = Color.Lerp(c, spriteParams.DeadColor, MathUtils.InverseLerp(0, Params.GetSprite().DeadColorTime, deadTimer));
}
c = overrideColor ?? c;
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * Scale;
var ca = (float)Math.Cos(-body.Rotation);
var sa = (float)Math.Sin(-body.Rotation);
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
-body.Rotation + rotation, decorativeSprite.Scale * Scale, spriteEffect,
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
depth: decorativeSprite.Sprite.Depth);
}
float depthStep = 0.000001f;

View File

@@ -13,6 +13,8 @@ using System.Globalization;
using FarseerPhysics;
using Barotrauma.Extensions;
using Barotrauma.Steam;
using System.Threading.Tasks;
using Barotrauma.MapCreatures.Behavior;
namespace Barotrauma
{
@@ -69,6 +71,8 @@ namespace Barotrauma
private static readonly ChatManager chatManager = new ChatManager(true, 64);
public static Dictionary<Keys, string> Keybinds = new Dictionary<Keys, string>();
public static void Init()
{
OpenAL.Alc.SetErrorReasonCallback((string msg) => NewMessage(msg, Color.Orange));
@@ -145,6 +149,17 @@ namespace Barotrauma
}
}
if (!IsOpen && GUI.KeyboardDispatcher.Subscriber == null)
{
foreach (var (key, command) in Keybinds)
{
if (PlayerInput.KeyHit(key))
{
ExecuteCommand(command);
}
}
}
activeQuestionText?.SetAsLastChild();
if (PlayerInput.KeyHit(Keys.F3))
@@ -227,6 +242,13 @@ namespace Barotrauma
case "fpscounter":
case "dumptofile":
case "findentityids":
case "setfreecamspeed":
case "togglevoicechatfilters":
case "bindkey":
case "savebinds":
case "unbindkey":
case "wikiimage_character":
case "wikiimage_sub":
return true;
default:
return client.HasConsoleCommandPermission(command);
@@ -235,20 +257,23 @@ namespace Barotrauma
public static void DequeueMessages()
{
while (queuedMessages.Count > 0)
lock (queuedMessages)
{
var newMsg = queuedMessages.Dequeue();
if (listBox == null)
while (queuedMessages.Count > 0)
{
//don't attempt to add to the listbox if it hasn't been created yet
Messages.Add(newMsg);
}
else
{
AddMessage(newMsg);
}
var newMsg = queuedMessages.Dequeue();
if (listBox == null)
{
//don't attempt to add to the listbox if it hasn't been created yet
Messages.Add(newMsg);
}
else
{
AddMessage(newMsg);
}
if (GameSettings.SaveDebugConsoleLogs) unsavedMessages.Add(newMsg);
if (GameSettings.SaveDebugConsoleLogs) unsavedMessages.Add(newMsg);
}
}
}
@@ -487,6 +512,24 @@ namespace Barotrauma
GameMain.CharacterEditorScreen.Select();
}));
commands.Add(new Command("quickstart", "Starts a singleplayer sandbox", (string[] args) =>
{
if (Screen.Selected != GameMain.MainMenuScreen)
{
ThrowError("This command can only be executed from the main menu.");
return;
}
string subName = args.Length > 0 ? args[0] : "";
if (string.IsNullOrWhiteSpace(subName))
{
ThrowError("No submarine specified.");
return;
}
GameMain.MainMenuScreen.QuickStart(fixedSeed: false, subName);
}, getValidArgs: () => new[] { SubmarineInfo.SavedSubmarines.Select(s => s.Name).Distinct().ToArray() }));
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks networking debug logging.", (string[] args) =>
{
SteamManager.NetworkingDebugLog = !SteamManager.NetworkingDebugLog;
@@ -497,6 +540,97 @@ namespace Barotrauma
{
NewMessage("Ready checks can only be commenced in multiplayer.", Color.Red);
}));
commands.Add(new Command("bindkey", "bindkey [key] [command]: Binds a key to a command.", (string[] args) =>
{
if (args.Length < 2)
{
ThrowError("No key or command specified.");
return;
}
string keyString = args[0];
string command = args[1];
if (Enum.TryParse(typeof(Keys), keyString, ignoreCase: true, out object outKey) && outKey is Keys key)
{
if (Keybinds.ContainsKey(key))
{
Keybinds[key] = command;
}
else
{
Keybinds.Add(key, command);
}
NewMessage($"\"{command}\" bound to {key}.", GUI.Style.Green);
if (GameMain.Config.keyMapping.FirstOrDefault(bind => bind.Key != Keys.None && bind.Key == key) is { } existingBind)
{
AddWarning($"\"{key}\" has already been bound to {(InputType)GameMain.Config.keyMapping.IndexOf(existingBind)}. The keybind will perform both actions when pressed.");
}
return;
}
ThrowError($"Invalid key {keyString}.");
}, isCheat: false, getValidArgs: () => new[] { Enum.GetNames(typeof(Keys)), new[] { "\"\"" } }));
commands.Add(new Command("unbindkey", "unbindkey [key]: Unbinds a command.", (string[] args) =>
{
if (args.Length < 1)
{
ThrowError("No key specified.");
return;
}
string keyString = args[0];
if (Enum.TryParse(typeof(Keys), keyString, ignoreCase: true, out object outKey) && outKey is Keys key)
{
if (Keybinds.ContainsKey(key))
{
Keybinds.Remove(key);
}
NewMessage("Keybind unbound.", GUI.Style.Green);
return;
}
ThrowError($"Invalid key {keyString}.");
}, isCheat: false, getValidArgs: () => new[] { Keybinds.Keys.Select(keys => keys.ToString()).Distinct().ToArray() }));
commands.Add(new Command("savebinds", "savebinds: Writes current keybinds into the config file.", (string[] args) =>
{
ShowQuestionPrompt($"Some keybinds may render the game unusable, are you sure you want to make these keybinds persistent? ({Keybinds.Count} keybind(s) assigned) Y/N",
(option2) =>
{
if (option2.ToLower() != "y")
{
NewMessage("Aborted.", GUI.Style.Red);
return;
}
GameSettings.ConsoleKeybinds = new Dictionary<Keys, string>(Keybinds);
GameMain.Config.SaveNewPlayerConfig();
NewMessage($"{Keybinds.Count} keybind(s) written to the config file.", GUI.Style.Green);
});
}, isCheat: false));
commands.Add(new Command("togglegrid", "Toggle visual snap grid in sub editor.", (string[] args) =>
{
SubEditorScreen.ShouldDrawGrid = !SubEditorScreen.ShouldDrawGrid;
NewMessage(SubEditorScreen.ShouldDrawGrid ? "Enabled submarine grid." : "Disabled submarine grid.", GUI.Style.Green);
}));
commands.Add(new Command("wikiimage_character", "Save an image of the currently controlled character with a transparent background.", (string[] args) =>
{
if (Character.Controlled == null) { return; }
WikiImage.Create(Character.Controlled);
}));
commands.Add(new Command("wikiimage_sub", "Save an image of the main submarine with a transparent background.", (string[] args) =>
{
if (Submarine.MainSub == null) { return; }
WikiImage.Create(Submarine.MainSub);
}));
AssignRelayToServer("kick", false);
AssignRelayToServer("kickid", false);
@@ -510,11 +644,18 @@ namespace Barotrauma
AssignRelayToServer("verboselogging", false);
AssignRelayToServer("freecam", false);
AssignRelayToServer("steamnetdebug", false);
AssignRelayToServer("quickstart", false);
AssignRelayToServer("togglegrid", false);
AssignRelayToServer("bindkey", false);
AssignRelayToServer("unbindkey", false);
AssignRelayToServer("savebinds", false);
#if DEBUG
AssignRelayToServer("crash", false);
AssignRelayToServer("showballastflorasprite", false);
AssignRelayToServer("simulatedlatency", false);
AssignRelayToServer("simulatedloss", false);
AssignRelayToServer("simulatedduplicateschance", false);
AssignRelayToServer("storeinfo", false);
#endif
commands.Add(new Command("clientlist", "", (string[] args) => { }));
@@ -998,6 +1139,17 @@ namespace Barotrauma
});
AssignRelayToServer("debugdraw", false);
AssignOnExecute("togglevoicechatfilters", (string[] args) =>
{
if (args.None() || !bool.TryParse(args[0], out bool state))
{
state = !GameMain.Config.DisableVoiceChatFilters;
}
GameMain.Config.DisableVoiceChatFilters = state;
NewMessage("Voice chat filters " + (GameMain.Config.DisableVoiceChatFilters ? "disabled" : "enabled"), Color.White);
});
AssignRelayToServer("togglevoicechatfilters", false);
commands.Add(new Command("fpscounter", "fpscounter: Toggle the FPS counter.", (string[] args) =>
{
GameMain.ShowFPS = !GameMain.ShowFPS;
@@ -1383,6 +1535,16 @@ namespace Barotrauma
File.WriteAllLines(filePath, debugLines);
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
}));
commands.Add(new Command("setfreecamspeed", "setfreecamspeed [speed]: Set the camera movement speed when not controlling a character. Defaults to 1.", (string[] args) =>
{
if (args.Length > 0)
{
float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float speed);
Screen.Selected.Cam.FreeCamMoveSpeed = speed;
}
}));
#if DEBUG
commands.Add(new Command("setplanthealth", "setplanthealth [value]: Sets the health of the selected plant in sub editor.", (string[] args) =>
{
@@ -1417,6 +1579,12 @@ namespace Barotrauma
}
}));
commands.Add(new Command("showballastflorasprite", "", (string[] args) =>
{
BallastFloraBehavior.AlwaysShowBallastFloraSprite = !BallastFloraBehavior.AlwaysShowBallastFloraSprite;
NewMessage("ok", GUI.Style.Green);
}));
commands.Add(new Command("printreceivertransfers", "", (string[] args) =>
{
GameMain.Client.PrintReceiverTransters();
@@ -1834,13 +2002,15 @@ namespace Barotrauma
#if DEBUG
commands.Add(new Command("querylobbies", "Queries all SteamP2P lobbies", (args) =>
{
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide();
Steamworks.Data.Lobby[] lobbies = lobbyQuery.RequestAsync().Result;
foreach (var lobby in lobbies)
{
DebugConsole.NewMessage(lobby.GetData("name") + ", " + lobby.GetData("lobbyowner"));
}
TaskPool.Add("DebugQueryLobbies",
SteamManager.LobbyQueryRequest(), (t) => {
var lobbies = ((Task<List<Steamworks.Data.Lobby>>)t).Result;
foreach (var lobby in lobbies)
{
NewMessage(lobby.GetData("name") + ", " + lobby.GetData("lobbyowner"), Color.Yellow);
}
NewMessage($"Retrieved a total of {lobbies.Count} lobbies", Color.Lime);
});
}));
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>

View File

@@ -210,9 +210,33 @@ namespace Barotrauma
}
};
double allowCloseTime = Timing.TotalTime + 0.5;
closeButton.Children.ForEach(child => child.SpriteEffects = SpriteEffects.FlipVertically);
closeButton.Frame.FadeIn(0.5f, 0.5f);
closeButton.SlideIn(0.5f, 0.33f, 16, SlideDirection.Down);
InputType? closeInput = null;
if (GameMain.Config.KeyBind(InputType.Use).MouseButton == MouseButton.None)
{
closeInput = InputType.Use;
}
else if (GameMain.Config.KeyBind(InputType.Select).MouseButton == MouseButton.None)
{
closeInput = InputType.Select;
}
if (closeInput.HasValue)
{
closeButton.ToolTip = TextManager.ParseInputTypes($"{TextManager.Get("Close")} ([InputType.{closeInput.Value}])");
closeButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
{
if (Timing.TotalTime > allowCloseTime && PlayerInput.KeyHit(closeInput.Value))
{
GUIButton btn = component as GUIButton;
btn?.OnClicked(btn, btn.UserData);
btn?.Flash(GUI.Style.Green);
}
};
}
}
for (int i = 0; i < optionButtons.Count; i++)

View File

@@ -43,15 +43,15 @@ namespace Barotrauma
}
GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + eventCoolDown, Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int) Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int) Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + (int)Math.Max(eventCoolDown, 0), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int) Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int) Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int) Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int) Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int) Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
#if DEBUG
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
@@ -86,15 +86,26 @@ namespace Barotrauma
new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, 0, 1);
y = graphRect.Bottom + 20;
if (eventCoolDown > 0.0f)
int x = graphRect.X;
if (isCrewAway && crewAwayDuration < settings.FreezeDurationWhenCrewAway)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Event cooldown active: " + (int) eventCoolDown, Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew away from sub): " + ToolBox.SecondsToReadableTime(settings.FreezeDurationWhenCrewAway - crewAwayDuration), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
y += 15;
}
else if (crewAwayResetTimer > 0.0f)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew just returned to the sub): " + ToolBox.SecondsToReadableTime(crewAwayResetTimer), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
y += 15;
}
else if (eventCoolDown > 0.0f)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), "Event cooldown active: " + ToolBox.SecondsToReadableTime(eventCoolDown), Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
y += 15;
}
else if (currentIntensity > eventThreshold)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
"Intensity too high for new events: " + (int) (currentIntensity * 100) + "%/" + (int) (eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y),
"Intensity too high for new events: " + (int)(currentIntensity * 100) + "%/" + (int)(eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
y += 15;
}
@@ -102,22 +113,27 @@ namespace Barotrauma
{
if (Submarine.MainSub == null) { break; }
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
if (eventSet.PerCave)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near cave", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
}
if (eventSet.PerWreck)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " submarine near the wreck", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the wreck", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
}
if (eventSet.PerRuin)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " submarine near the ruins", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the ruins", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
}
if (roundDuration < eventSet.MinMissionTime)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
GUI.DrawString(spriteBatch, new Vector2(x, y),
" " + (int) (eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int) (distanceTraveled * 100.0f) + " %)",
((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) ? Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, eventSet.MinDistanceTraveled - distanceTraveled) : GUI.Style.Green) * 0.8f, null, 0, GUI.SmallFont);
y += 12;
@@ -125,7 +141,7 @@ namespace Barotrauma
if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
GUI.DrawString(spriteBatch, new Vector2(x, y),
" intensity between " + ((int) eventSet.MinIntensity) + " and " + ((int) eventSet.MaxIntensity),
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
@@ -133,22 +149,28 @@ namespace Barotrauma
if (roundDuration < eventSet.MinMissionTime)
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
GUI.DrawString(spriteBatch, new Vector2(x, y),
" " + (int) (eventSet.MinMissionTime - roundDuration) + " s",
Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, (eventSet.MinMissionTime - roundDuration)), null, 0, GUI.SmallFont);
}
y += 15;
if (y > GameMain.GraphicsHeight * 0.9f)
{
y = graphRect.Bottom + 35;
x += 250;
}
}
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont);
y += 15;
foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
{
GUI.DrawString(spriteBatch, new Vector2(graphRect.X + 5, y), ev.ToString(), (!ev.IsFinished ? Color.White : Color.Red) * 0.8f, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x + 5, y), ev.ToString(), (!ev.IsFinished ? Color.White : Color.Red) * 0.8f, null, 0, GUI.SmallFont);
Rectangle rect = new Rectangle(new Point(graphRect.X + 5, y), GUI.SmallFont.MeasureString(ev.ToString()).ToPoint());
Rectangle rect = new Rectangle(new Point(x + 5, y), GUI.SmallFont.MeasureString(ev.ToString()).ToPoint());
Rectangle outlineRect = new Rectangle(rect.Location, rect.Size);
outlineRect.Inflate(4, 4);
@@ -176,6 +198,11 @@ namespace Barotrauma
}
y += 18;
if (y > GameMain.GraphicsHeight * 0.9f)
{
y = graphRect.Bottom + 35;
x += 250;
}
}
}
@@ -333,7 +360,7 @@ namespace Barotrauma
$"Spawn pending: {artifactEvent.SpawnPending.ColorizeObject()}\n" +
$"Spawn position: {artifactEvent.SpawnPos.ColorizeObject()}\n";
if (artifactEvent.Item != null)
if (artifactEvent.Item != null && !artifactEvent.Item.Removed)
{
Vector2 pos = artifactEvent.Item.WorldPosition;
positions.Add(new DebugLine(pos, Color.White));
@@ -364,7 +391,8 @@ namespace Barotrauma
foreach (Character monster in monsterEvent.Monsters)
{
text += $" {monster.ColorizeObject()} -> (Dead: {monster.IsDead.ColorizeObject()}, Health: {monster.HealthPercentage.ColorizeObject()}%, AIState: {(monster.AIController?.State).ColorizeObject()})\n";
text += $" {monster.ColorizeObject()} -> (Dead: {monster.IsDead.ColorizeObject()}, Health: {monster.HealthPercentage.ColorizeObject()}%, AIState: {(monster.AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle ).ColorizeObject()})\n";
if (monster.Removed) { continue; }
positions.Add(new DebugLine(monster.WorldPosition, Color.Red));
}
}

View File

@@ -1,7 +1,4 @@
using Barotrauma.Networking;
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma
{

View File

@@ -17,7 +17,7 @@ namespace Barotrauma
}
//team specific
return descriptions[GameMain.Client.Character.TeamID == Character.TeamType.Team1 ? 1 : 2];
return descriptions[GameMain.Client.Character.TeamID == CharacterTeamType.Team1 ? 1 : 2];
}
}

View File

@@ -12,6 +12,23 @@ namespace Barotrauma
{
public override void ClientReadInitial(IReadMessage msg)
{
byte caveCount = msg.ReadByte();
for (int i = 0; i < caveCount; i++)
{
byte selectedCave = msg.ReadByte();
if (selectedCave < 255 && Level.Loaded != null)
{
if (selectedCave < Level.Loaded.Caves.Count)
{
Level.Loaded.Caves[selectedCave].DisplayOnSonar = true;
}
else
{
DebugConsole.ThrowError($"Cave index out of bounds when reading nest mission data. Index: {selectedCave}, number of caves: {Level.Loaded.Caves.Count}");
}
}
}
for (int i = 0; i < ResourceClusters.Count; i++)
{
var amount = msg.ReadByte();

View File

@@ -8,9 +8,23 @@ namespace Barotrauma
{
public override void ClientReadInitial(IReadMessage msg)
{
byte selectedCaveIndex = msg.ReadByte();
nestPosition = new Vector2(
msg.ReadSingle(),
msg.ReadSingle());
if (selectedCaveIndex < 255 && Level.Loaded != null)
{
if (selectedCaveIndex < Level.Loaded.Caves.Count)
{
Level.Loaded.Caves[selectedCaveIndex].DisplayOnSonar = true;
SpawnNestObjects(Level.Loaded, Level.Loaded.Caves[selectedCaveIndex]);
}
else
{
DebugConsole.ThrowError($"Cave index out of bounds when reading nest mission data. Index: {selectedCaveIndex}, number of caves: {Level.Loaded.Caves.Count}");
}
}
ushort itemCount = msg.ReadUInt16();
for (int i = 0; i < itemCount; i++)
{

View File

@@ -287,6 +287,7 @@ namespace Barotrauma
{
lock (mutex)
{
usedIndicatorAngles.Clear();
if (ScreenChanged)
{
@@ -1117,15 +1118,26 @@ namespace Barotrauma
/// Set the cursor to an hourglass.
/// Will automatically revert after 10 seconds or when <see cref="ClearCursorWait"/> is called.
/// </summary>
public static void SetCursorWaiting()
public static void SetCursorWaiting(int waitSeconds = 10, Func<bool> endCondition = null)
{
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
static IEnumerable<object> WaitCursorCoroutine()
IEnumerable<object> WaitCursorCoroutine()
{
MouseCursor = CursorState.Waiting;
var timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
while (DateTime.Now < timeOut) { yield return CoroutineStatus.Running; }
var timeOut = DateTime.Now + new TimeSpan(0, 0, waitSeconds);
while (DateTime.Now < timeOut)
{
if (endCondition != null)
{
try
{
if (endCondition.Invoke()) { break; }
}
catch { break; }
}
yield return CoroutineStatus.Running;
}
if (MouseCursor == CursorState.Waiting) { MouseCursor = CursorState.Default; }
yield return CoroutineStatus.Success;
}
@@ -1219,7 +1231,7 @@ namespace Barotrauma
{
foreach (GUIMessage msg in messages)
{
if (msg.WorldSpace) continue;
if (msg.WorldSpace) { continue; }
msg.Timer -= deltaTime;
if (msg.Size.X > HUDLayoutSettings.MessageAreaTop.Width)
@@ -1244,7 +1256,7 @@ namespace Barotrauma
foreach (GUIMessage msg in messages)
{
if (!msg.WorldSpace) continue;
if (!msg.WorldSpace) { continue; }
msg.Timer -= deltaTime;
msg.Pos += msg.Velocity * deltaTime;
}
@@ -1256,18 +1268,21 @@ namespace Barotrauma
#region Element drawing
private static List<float> usedIndicatorAngles = new List<float>();
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color, bool createOffset = true, float scaleMultiplier = 1.0f)
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color,
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
{
Vector2 diff = worldPosition - cam.WorldViewCenter;
float dist = diff.Length();
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier;
if (dist > hideDist)
if (overrideAlpha.HasValue || dist > hideDist)
{
float alpha = Math.Min((dist - hideDist) / 100.0f, 1.0f);
float alpha = overrideAlpha ?? Math.Min((dist - hideDist) / 100.0f, 1.0f);
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
if (!createOffset)
@@ -1279,6 +1294,28 @@ namespace Barotrauma
float screenDist = Vector2.Distance(cam.WorldToScreen(cam.WorldViewCenter), targetScreenPos);
float angle = MathUtils.VectorToAngle(diff);
float minAngleDiff = 0.05f;
bool overlapFound = true;
int iterations = 0;
while (overlapFound && iterations < 10)
{
overlapFound = false;
foreach (float usedIndicatorAngle in usedIndicatorAngles)
{
float shortestAngle = MathUtils.GetShortestAngle(angle, usedIndicatorAngle);
if (MathUtils.NearlyEqual(shortestAngle, 0.0f)) { shortestAngle = 0.01f; }
if (Math.Abs(shortestAngle) < minAngleDiff)
{
angle -= Math.Sign(shortestAngle) * (minAngleDiff - Math.Abs(shortestAngle));
overlapFound = true;
break;
}
}
iterations++;
}
usedIndicatorAngles.Add(angle);
Vector2 unclampedDiff = new Vector2(
(float)Math.Cos(angle) * screenDist,
(float)-Math.Sin(angle) * screenDist);
@@ -1489,12 +1526,12 @@ namespace Barotrauma
foreach (GUIMessage msg in messages)
{
if (msg.WorldSpace) continue;
if (msg.WorldSpace) { continue; }
Vector2 drawPos = new Vector2(HUDLayoutSettings.MessageAreaTop.Right, HUDLayoutSettings.MessageAreaTop.Center.Y);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.Pos + Vector2.One, Color.Black, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.Pos, msg.Color, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos + Vector2.One, Color.Black, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos, msg.Color, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
break;
}
@@ -1507,14 +1544,14 @@ namespace Barotrauma
foreach (GUIMessage msg in messages)
{
if (!msg.WorldSpace) continue;
if (!msg.WorldSpace) { continue; }
if (cam != null)
{
float alpha = 1.0f;
if (msg.Timer < 1.0f) alpha -= 1.0f - msg.Timer;
if (msg.Timer < 1.0f) { alpha -= 1.0f - msg.Timer; }
Vector2 drawPos = cam.WorldToScreen(msg.Pos);
Vector2 drawPos = cam.WorldToScreen(msg.DrawPos);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + Vector2.One, Color.Black * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
msg.Font.DrawString(spriteBatch, msg.Text, drawPos, msg.Color * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
}
@@ -1608,7 +1645,8 @@ namespace Barotrauma
public static Texture2D CreateCapsule(int radius, int height)
{
int textureWidth = radius * 2, textureHeight = height + radius * 2;
int textureWidth = Math.Max(radius * 2, 1);
int textureHeight = Math.Max(height + radius * 2, 1);
Color[] data = new Color[textureWidth * textureHeight];
@@ -2079,7 +2117,7 @@ namespace Barotrauma
if (pauseMenuOpen)
{
Inventory.draggingItem = null;
Inventory.DraggingItems.Clear();
Inventory.DraggingInventory = null;
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas, Anchor.Center), style: null);
@@ -2288,9 +2326,10 @@ namespace Barotrauma
if (playSound) SoundPlayer.PlayUISound(GUISoundType.UIMessage);
}
public static void AddMessage(string message, Color color, Vector2 worldPos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage)
public static void AddMessage(string message, Color color, Vector2 pos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage, int subId = -1)
{
messages.Add(new GUIMessage(message, color, worldPos, velocity, lifeTime, Alignment.Center, LargeFont));
Submarine sub = Submarine.Loaded.FirstOrDefault(s => s.ID == subId);
messages.Add(new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, LargeFont, sub: sub));
if (playSound) SoundPlayer.PlayUISound(soundType);
}

View File

@@ -0,0 +1,210 @@
#nullable enable
using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace Barotrauma
{
public class GUIColorPicker : GUIComponent
{
public delegate bool OnColorSelectedHandler(GUIColorPicker component, Color color);
public OnColorSelectedHandler? OnColorSelected;
public float SelectedHue;
public float SelectedSaturation;
public float SelectedValue;
public Color CurrentColor = Color.Black;
private Rectangle MainArea,
HueArea;
private Texture2D? mainTexture,
hueTexture;
private Color[]? colorData;
private Rectangle selectedRect;
private bool mouseHeld;
private bool isInitialized;
private readonly Color transparentWhite = Color.White * 0.8f,
transparentBlack = Color.Black * 0.8f;
public GUIColorPicker(RectTransform rectT, string? style = null) : base(style, rectT) { }
~GUIColorPicker()
{
DisposeTextures();
}
private void Init()
{
int tWidth = Rect.Width;
int sliceWidth = Rect.Width / 8;
int mainWidth = tWidth - sliceWidth;
int hueWidth = sliceWidth;
MainArea = new Rectangle(0, 0, mainWidth, Rect.Height);
HueArea = new Rectangle(mainWidth, 0, hueWidth, Rect.Height);
colorData = new Color[MainArea.Width * MainArea.Height];
if (mainTexture == null)
{
int width = MainArea.Width,
height = MainArea.Height;
GenerateGradient(ref colorData!, width, height, DrawHVArea);
mainTexture = CreateGradientTexture(colorData!, MainArea.Width, MainArea.Height);
}
if (hueTexture == null)
{
int width = HueArea.Width,
height = HueArea.Height;
Color[] hueData = new Color[width * height];
GenerateGradient(ref hueData, width, height, DrawHueArea);
hueTexture = CreateGradientTexture(hueData, width, height);
}
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (mainTexture == null || hueTexture == null || !isInitialized) { return; }
Rectangle mainArea = MainArea,
hueArea = HueArea;
hueArea.Location += Rect.Location;
mainArea.Location += Rect.Location;
Vector2 mainLocation = mainArea.Location.ToVector2(),
hueLocation = hueArea.Location.ToVector2();
spriteBatch.Draw(mainTexture, mainLocation, Color.White);
spriteBatch.Draw(hueTexture, hueLocation, Color.White);
float hueY = hueLocation.Y + ((SelectedHue / 360f) * hueArea.Height);
spriteBatch.DrawLine(hueArea.Left, hueY, hueArea.Right, hueY, transparentWhite, thickness: 3);
spriteBatch.DrawLine(hueArea.Left, hueY, hueArea.Right, hueY, transparentBlack, thickness: 1);
float saturationX = mainLocation.X + SelectedSaturation * MainArea.Width;
float valueY = mainLocation.Y + (1.0f - SelectedValue) * MainArea.Height;
spriteBatch.DrawLine(saturationX, mainArea.Top,saturationX, mainArea.Bottom, transparentWhite, thickness: 3);
spriteBatch.DrawLine(mainArea.Left,valueY, mainArea.Right, valueY, transparentWhite, thickness: 3);
spriteBatch.DrawLine(saturationX, mainArea.Top,saturationX, mainArea.Bottom, transparentBlack, thickness: 1);
spriteBatch.DrawLine(mainArea.Left,valueY, mainArea.Right, valueY, transparentBlack, thickness: 1);
}
protected override void Update(float deltaTime)
{
base.Update(deltaTime);
if (!isInitialized)
{
Init();
isInitialized = true;
}
if (!PlayerInput.PrimaryMouseButtonHeld())
{
mouseHeld = false;
}
if (GUI.MouseOn != this) { return; }
Rectangle mainArea = MainArea,
hueArea = HueArea;
hueArea.Location += Rect.Location;
mainArea.Location += Rect.Location;
if (PlayerInput.PrimaryMouseButtonDown())
{
mouseHeld = true;
if (hueArea.Contains(PlayerInput.MousePosition))
{
selectedRect = HueArea;
}
else if (mainArea.Contains(PlayerInput.MousePosition))
{
selectedRect = MainArea;
}
else
{
mouseHeld = false;
}
}
if (!PlayerInput.PrimaryMouseButtonHeld())
{
mouseHeld = false;
}
if (mouseHeld && (PlayerInput.MouseSpeed != Vector2.Zero || PlayerInput.PrimaryMouseButtonDown()))
{
if (selectedRect == HueArea)
{
Vector2 pos = PlayerInput.MousePosition - hueArea.Location.ToVector2();
SelectedHue = Math.Clamp(pos.Y / hueArea.Height * 360f, 0, 360);
RefreshHue();
}
else if (selectedRect == MainArea)
{
var (x, y) = PlayerInput.MousePosition - mainArea.Location.ToVector2();
SelectedSaturation = Math.Clamp(x / mainArea.Width, 0, 1);
SelectedValue = Math.Clamp(1f - (y / mainArea.Height), 0, 1);
}
CurrentColor = ToolBox.HSVToRGB(SelectedHue, SelectedSaturation, SelectedValue);
OnColorSelected?.Invoke(this, CurrentColor);
}
}
public void DisposeTextures()
{
mainTexture?.Dispose();
hueTexture?.Dispose();
}
public void RefreshHue()
{
if (colorData == null || mainTexture == null) { return; }
GenerateGradient(ref colorData, mainTexture.Width, mainTexture.Height, DrawHVArea);
mainTexture.SetData(colorData);
}
private Texture2D CreateGradientTexture(Color[] data, int width, int height)
{
Texture2D texture = new Texture2D(GameMain.GraphicsDeviceManager.GraphicsDevice, width, height);
texture.SetData(data);
return texture;
}
private void GenerateGradient(ref Color[] data, int width, int height, Func<float, float, Color> algorithm)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
float relativeX = x / (float) width,
relativeY = y / (float) height;
data[y * width + x] = algorithm(relativeX, relativeY);
}
}
}
private Color DrawHVArea(float x, float y) => ToolBox.HSVToRGB(SelectedHue, x, 1.0f - y);
private Color DrawHueArea(float x, float y) => ToolBox.HSVToRGB(y * 360f, 1f, 1f);
}
}

View File

@@ -510,10 +510,10 @@ namespace Barotrauma
for (int i = 0; i < Content.CountChildren; i++)
{
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
if (child == null) continue;
if (child == null || !child.Visible) { continue; }
// selecting
if (Enabled && CanBeFocused && child.CanBeFocused && (GUI.IsMouseOn(child)) && child.Rect.Contains(PlayerInput.MousePosition))
if (Enabled && CanBeFocused && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
{
child.State = ComponentState.Hover;

View File

@@ -55,6 +55,20 @@ namespace Barotrauma
private set;
}
public Submarine Submarine
{
get;
private set;
}
public Vector2 DrawPos
{
get
{
return Submarine == null ? Pos : Pos + Submarine.DrawPosition;
}
}
public GUIMessage(string text, Color color, float lifeTime, ScalableFont font = null)
{
coloredText = new ColoredText(text, color, false, false);
@@ -67,11 +81,11 @@ namespace Barotrauma
Font = font;
}
public GUIMessage(string text, Color color, Vector2 worldPosition, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null)
public GUIMessage(string text, Color color, Vector2 position, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null, Submarine sub = null)
{
coloredText = new ColoredText(text, color, false, false);
WorldSpace = true;
pos = worldPosition;
pos = position;
Timer = lifeTime;
Velocity = velocity;
this.lifeTime = lifeTime;
@@ -92,6 +106,8 @@ namespace Barotrauma
if (textAlignment.HasFlag(Alignment.Bottom))
Origin.Y += size.Y * 0.5f;
Submarine = sub;
}
}
}

View File

@@ -67,6 +67,8 @@ namespace Barotrauma
private readonly Type type;
public Type MessageBoxType => type;
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
public GUIMessageBox(string headerText, string text, Vector2? relativeSize = null, Point? minSize = null)
@@ -210,6 +212,29 @@ namespace Barotrauma
}
};
InputType? closeInput = null;
if (GameMain.Config.KeyBind(InputType.Use).MouseButton == MouseButton.None)
{
closeInput = InputType.Use;
}
else if (GameMain.Config.KeyBind(InputType.Select).MouseButton == MouseButton.None)
{
closeInput = InputType.Select;
}
if (closeInput.HasValue)
{
Buttons[0].ToolTip = TextManager.ParseInputTypes($"{TextManager.Get("Close")} ([InputType.{closeInput.Value}])");
Buttons[0].OnAddedToGUIUpdateList += (GUIComponent component) =>
{
if (!closing && openState >= 1.0f && PlayerInput.KeyHit(closeInput.Value))
{
GUIButton btn = component as GUIButton;
btn?.OnClicked(btn, btn.UserData);
btn?.Flash(GUI.Style.Green);
}
};
}
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true);
GUI.Style.Apply(Header, "", this);
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
@@ -291,7 +316,8 @@ namespace Barotrauma
{
if (Draggable)
{
if ((GUI.MouseOn == InnerFrame || InnerFrame.IsParentOf(GUI.MouseOn)) && !(GUI.MouseOn is GUIButton))
GUIComponent parent = GUI.MouseOn?.Parent?.Parent;
if ((GUI.MouseOn == InnerFrame || InnerFrame.IsParentOf(GUI.MouseOn)) && !(GUI.MouseOn is GUIButton || GUI.MouseOn is GUIColorPicker || GUI.MouseOn is GUITextBox || parent is GUITextBox))
{
GUI.MouseCursor = CursorState.Move;
if (PlayerInput.PrimaryMouseButtonDown())

View File

@@ -70,6 +70,7 @@ namespace Barotrauma
public Color ColorInventoryHalf { get; private set; } = Color.Orange;
public Color ColorInventoryFull { get; private set; } = Color.LightGreen;
public Color ColorInventoryBackground { get; private set; } = Color.Gray;
public Color ColorInventoryEmptyOverlay { get; private set; } = Color.Red;
public Color TextColor { get; private set; } = Color.White * 0.8f;
public Color TextColorBright { get; private set; } = Color.White * 0.9f;
@@ -150,6 +151,9 @@ namespace Barotrauma
case "colorinventorybackground":
ColorInventoryBackground = subElement.GetAttributeColor("color", ColorInventoryBackground);
break;
case "colorinventoryemptyoverlay":
ColorInventoryEmptyOverlay = subElement.GetAttributeColor("color", ColorInventoryEmptyOverlay);
break;
case "textcolordark":
TextColorDark = subElement.GetAttributeColor("color", TextColorDark);
break;
@@ -344,7 +348,7 @@ namespace Barotrauma
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
uint overrideFontSize = GetFontSize(subElement, 0);
if (overrideFontSize > 0) { return overrideFontSize; }
if (overrideFontSize > 0) { return (uint)Math.Round(overrideFontSize * GameSettings.TextScale); }
}
}
@@ -354,10 +358,10 @@ namespace Barotrauma
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{
return (uint)subElement.GetAttributeInt("size", 14);
return (uint)Math.Round(subElement.GetAttributeInt("size", 14) * GameSettings.TextScale);
}
}
return defaultSize;
return (uint)Math.Round(defaultSize * GameSettings.TextScale);
}
private string GetFontFilePath(XElement element)

View File

@@ -240,20 +240,20 @@ namespace Barotrauma
public class StrikethroughSettings
{
private Color color = GUI.Style.Red;
public Color Color { get; set; } = GUI.Style.Red;
private int thickness;
private int expand;
public StrikethroughSettings(Color? color = null, int thickness = 1, int expand = 0)
{
if (color != null) this.color = color.Value;
if (color != null) { Color = color.Value; }
this.thickness = thickness;
this.expand = expand;
}
public void Draw(SpriteBatch spriteBatch, float textSizeHalf, float xPos, float yPos)
{
ShapeExtensions.DrawLine(spriteBatch, new Vector2(xPos - textSizeHalf - expand, yPos), new Vector2(xPos + textSizeHalf + expand, yPos), color, thickness);
ShapeExtensions.DrawLine(spriteBatch, new Vector2(xPos - textSizeHalf - expand, yPos), new Vector2(xPos + textSizeHalf + expand, yPos), Color, thickness);
}
}

View File

@@ -251,7 +251,7 @@ namespace Barotrauma
public bool Readonly { get; set; }
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, ScalableFont font = null,
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false)
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
: base(style, rectT)
{
HoverCursor = CursorState.IBeam;
@@ -283,7 +283,7 @@ namespace Barotrauma
clearButtonWidth = (int)(clearButton.Rect.Width * 1.2f);
}
if (this.style != null && this.style.ChildStyles.ContainsKey("textboxicon"))
if (this.style != null && this.style.ChildStyles.ContainsKey("textboxicon") && createPenIcon)
{
icon = new GUIImage(new RectTransform(new Vector2(0.6f, 0.6f), frame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5 + clearButtonWidth, 0) }, null, scaleToFit: true);
icon.ApplyStyle(this.style.ChildStyles["textboxicon"]);
@@ -457,6 +457,11 @@ namespace Barotrauma
isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
}
if (mouseHeldInside && !PlayerInput.PrimaryMouseButtonHeld())
{
mouseHeldInside = false;
}
if (CaretEnabled)
{
if (textBlock.OverflowClipActive)

View File

@@ -24,9 +24,17 @@ namespace Barotrauma
private int buyTotal, sellTotal;
private GUITextBlock merchantBalanceBlock;
private GUILayoutGroup valueChangeGroup;
private GUITextBlock currentSellValueBlock, newSellValueBlock;
private GUIImage sellValueChangeArrow;
private GUIDropDown sortingDropDown;
private GUITextBox searchBox;
private GUIListBox storeDealsList, storeBuyList, storeSellList;
private GUIListBox storeBuyList, storeSellList;
/// <summary>
/// Can be null when there are no deals at the current location
/// </summary>
private GUILayoutGroup storeDailySpecialsGroup, storeRequestedGoodGroup;
private Color storeSpecialColor;
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList;
private GUITextBlock shoppingCrateTotal;
@@ -49,7 +57,6 @@ namespace Barotrauma
private enum StoreTab
{
Deals,
Buy,
Sell
}
@@ -78,19 +85,19 @@ namespace Barotrauma
CurrentLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
}
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += () => { needsBuyingRefresh = true; };
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsBuyingRefresh = true; };
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsRefresh = true; };
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += () => { needsSellingRefresh = true; };
campaignUI.Campaign.CargoManager.OnSoldItemsChanged += () =>
{
needsItemsToSellRefresh = true;
needsSellingRefresh = true;
needsRefresh = true;
};
}
public void Refresh()
public void Refresh(bool updateOwned = true)
{
hadPermissions = HasPermissions;
UpdateOwnedItems();
if (updateOwned) { UpdateOwnedItems(); }
RefreshBuying(updateOwned: false);
RefreshSelling(updateOwned: false);
needsRefresh = false;
@@ -100,10 +107,8 @@ namespace Barotrauma
{
if (updateOwned) { UpdateOwnedItems(); }
RefreshShoppingCrateBuyList();
//RefreshStoreDealsList();
RefreshStoreBuyList();
var hasPermissions = HasPermissions;
//storeDealsList.Enabled = hasPermissions;
storeBuyList.Enabled = hasPermissions;
shoppingCrateBuyList.Enabled = hasPermissions;
needsBuyingRefresh = false;
@@ -166,7 +171,12 @@ namespace Barotrauma
};
// Merchant balance ------------------------------------------------
var merchantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), storeContent.RectTransform))
var balanceAndValueGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), storeContent.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.005f
};
var merchantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
{
RelativeSpacing = 0.005f
};
@@ -177,29 +187,111 @@ namespace Barotrauma
ForceUpperCase = true
};
merchantBalanceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform),
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopLeft)
"", font: GUI.SubHeadingFont)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = () =>
{
var balance = CurrentLocation != null ? CurrentLocation.StoreCurrentBalance : 0;
if (balance < (int)(0.25f * Location.StoreInitialBalance))
if (CurrentLocation != null)
{
merchantBalanceBlock.TextColor = Color.Red;
}
else if (balance < (int)(0.5f * Location.StoreInitialBalance))
{
merchantBalanceBlock.TextColor = Color.Orange;
merchantBalanceBlock.TextColor = CurrentLocation.BalanceColor;
return GetCurrencyFormatted(CurrentLocation.StoreCurrentBalance);
}
else
{
merchantBalanceBlock.TextColor = Color.White;
merchantBalanceBlock.TextColor = Color.Red;
return GetCurrencyFormatted(0);
}
return GetCurrencyFormatted(balance);
}
};
// Item sell value ------------------------------------------------
var sellValueContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
{
CanBeFocused = false,
RelativeSpacing = 0.005f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform),
TextManager.Get("campaignstore.sellvalue"), font: GUI.Font, textAlignment: Alignment.BottomLeft)
{
AutoScaleVertical = true,
CanBeFocused = false,
ForceUpperCase = true
};
valueChangeGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
CanBeFocused = true,
RelativeSpacing = 0.02f
};
float blockWidth = GUI.IsFourByThree() ? 0.32f : 0.28f;
Point blockMaxSize = new Point((int)(GameSettings.TextScale * 60), valueChangeGroup.Rect.Height);
currentSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
"", font: GUI.SubHeadingFont)
{
AutoScaleVertical = true,
CanBeFocused = false,
TextScale = 1.1f,
TextGetter = () =>
{
if (CurrentLocation != null)
{
int balanceAfterTransaction = IsBuying ?
CurrentLocation.StoreCurrentBalance + buyTotal :
CurrentLocation.StoreCurrentBalance - sellTotal;
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
{
var newStatus = Location.GetStoreBalanceStatus(balanceAfterTransaction);
if (CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
{
string tooltipTag = newStatus.SellPriceModifier > CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier ?
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
valueChangeGroup.ToolTip = TextManager.Get(tooltipTag);
currentSellValueBlock.TextColor = newStatus.Color;
sellValueChangeArrow.Color = newStatus.Color;
sellValueChangeArrow.Visible = true;
newSellValueBlock.TextColor = newStatus.Color;
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
}
}
valueChangeGroup.ToolTip = null;
currentSellValueBlock.TextColor = CurrentLocation.BalanceColor;
sellValueChangeArrow.Visible = false;
newSellValueBlock.Text = null;
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
}
else
{
valueChangeGroup.ToolTip = null;
sellValueChangeArrow.Visible = false;
newSellValueBlock.Text = null;
return null;
}
}
};
Vector4 newPadding = currentSellValueBlock.Padding;
newPadding.Z = 0;
currentSellValueBlock.Padding = newPadding;
float relativeHeight = 0.45f;
float relativeWidth = (relativeHeight * valueChangeGroup.Rect.Height) / valueChangeGroup.Rect.Width;
sellValueChangeArrow = new GUIImage(new RectTransform(new Vector2(relativeWidth, relativeHeight), valueChangeGroup.RectTransform), "StoreArrow", scaleToFit: true)
{
CanBeFocused = false,
Visible = false
};
newSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
"", font: GUI.SubHeadingFont)
{
AutoScaleVertical = true,
CanBeFocused = false,
TextScale = 1.1f
};
newPadding = newSellValueBlock.Padding;
newPadding.X = 0;
newSellValueBlock.Padding = newPadding;
// Store mode buttons ------------------------------------------------
var modeButtonFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f / 14.0f), storeContent.RectTransform), style: null);
var modeButtonContainer = new GUILayoutGroup(new RectTransform(Vector2.One, modeButtonFrame.RectTransform), isHorizontal: true);
@@ -209,8 +301,6 @@ namespace Barotrauma
tabSortingMethods.Clear();
foreach (StoreTab tab in tabs)
{
// TODO: Remove the row below once the deal page is implemented
if (tab == StoreTab.Deals) { continue; }
var tabButton = new GUIButton(new RectTransform(new Vector2(1.0f / (tabs.Length + 1), 1.0f), modeButtonContainer.RectTransform),
text: TextManager.Get("campaignstoretab." + tab), style: "GUITabButton")
{
@@ -309,24 +399,22 @@ namespace Barotrauma
searchBox.OnTextChanged += (textBox, text) => { FilterStoreItems(null, text); return true; };
var storeItemListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.92f), sortFilterListContainer.RectTransform), style: null);
storeDealsList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
{
AutoHideScrollBar = false,
Visible = false
};
tabLists.Clear();
tabLists.Add(StoreTab.Deals, storeDealsList);
storeBuyList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
{
AutoHideScrollBar = false,
Visible = false
};
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
tabLists.Add(StoreTab.Buy, storeBuyList);
storeSellList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
{
AutoHideScrollBar = false,
Visible = false
};
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
tabLists.Add(StoreTab.Sell, storeSellList);
// Shopping Crate ------------------------------------------------------------------------------------------------------------------------------------------
@@ -428,6 +516,26 @@ namespace Barotrauma
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
}
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList)
{
var elementHeight = (int)(GUI.yScale * 80);
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, 4 * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
frame.UserData = "deals";
var dealsGroup = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter);
var dealsHeader = new GUILayoutGroup(new RectTransform(new Point((int)(0.95f * parentList.Content.Rect.Width), elementHeight), parent: dealsGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
dealsHeader.UserData = "header";
var iconWidth = (0.9f * dealsHeader.Rect.Height) / dealsHeader.Rect.Width;
var dealsIcon = new GUIImage(new RectTransform(new Vector2(iconWidth, 0.9f), dealsHeader.RectTransform), "StoreDealIcon", scaleToFit: true);
var text = TextManager.Get(parentList == storeBuyList ? "campaignstore.dailyspecials" : "campaignstore.requestedgoods");
var dealsText = new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 0.9f), dealsHeader.RectTransform), text, font: GUI.LargeFont);
storeSpecialColor = dealsIcon.Color;
dealsText.TextColor = storeSpecialColor;
var divider = new GUIImage(new RectTransform(new Point(dealsGroup.Rect.Width, 3), dealsGroup.RectTransform), "HorizontalLine");
divider.UserData = "divider";
frame.CanBeFocused = dealsGroup.CanBeFocused = dealsHeader.CanBeFocused = dealsIcon.CanBeFocused = dealsText.CanBeFocused = divider.CanBeFocused = false;
return dealsGroup;
}
private void UpdateLocation(Location prevLocation, Location newLocation)
{
if (prevLocation == newLocation) { return; }
@@ -464,17 +572,8 @@ namespace Barotrauma
SetConfirmButtonBehavior();
SetConfirmButtonStatus();
FilterStoreItems();
if (tab == StoreTab.Deals)
if (tab == StoreTab.Buy)
{
storeBuyList.Visible = false;
storeSellList.Visible = false;
storeDealsList.Visible = true;
shoppingCrateSellList.Visible = false;
shoppingCrateBuyList.Visible = true;
}
else if (tab == StoreTab.Buy)
{
storeDealsList.Visible = false;
storeSellList.Visible = false;
storeBuyList.Visible = true;
shoppingCrateSellList.Visible = false;
@@ -482,7 +581,6 @@ namespace Barotrauma
}
else if (tab == StoreTab.Sell)
{
storeDealsList.Visible = false;
storeBuyList.Visible = false;
storeSellList.Visible = true;
shoppingCrateBuyList.Visible = false;
@@ -525,37 +623,71 @@ namespace Barotrauma
bool hasPermissions = HasPermissions;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any())
{
if (storeDailySpecialsGroup == null)
{
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
storeDailySpecialsGroup.Parent.SetAsFirstChild();
}
else
{
storeBuyList.RemoveChild(storeDailySpecialsGroup.Parent);
storeDailySpecialsGroup = null;
}
storeBuyList.RecalculateChildren();
}
foreach (PurchasedItem item in CurrentLocation.StoreStock)
{
if (item.ItemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
}
foreach (ItemPrefab itemPrefab in CurrentLocation.DailySpecials)
{
if (CurrentLocation.StoreStock.Any(pi => pi.ItemPrefab == itemPrefab)) { continue; }
CreateOrUpdateItemFrame(itemPrefab, 0);
}
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int quantity)
{
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
{
var itemFrame = storeBuyList.Content.Children.FirstOrDefault(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == item.ItemPrefab);
var quantity = item.Quantity;
if (CargoManager.PurchasedItems.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem purchasedItem)
var isDailySpecial = CurrentLocation.DailySpecials.Contains(itemPrefab);
var itemFrame = isDailySpecial ?
storeDailySpecialsGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
storeBuyList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
if (CargoManager.PurchasedItems.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem purchasedItem)
{
quantity = Math.Max(quantity - purchasedItem.Quantity, 0);
}
if (CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem itemInBuyCrate)
if (CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInBuyCrate)
{
quantity = Math.Max(quantity - itemInBuyCrate.Quantity, 0);
}
if (itemFrame == null)
{
itemFrame = CreateItemFrame(new PurchasedItem(item.ItemPrefab, quantity), priceInfo, storeBuyList, forceDisable: !hasPermissions);
var parentComponent = isDailySpecial ? storeDailySpecialsGroup : storeBuyList as GUIComponent;
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, quantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
}
else
{
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
SetQuantityLabelText(StoreTab.Buy, itemFrame);
SetOwnedLabelText(itemFrame);
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
}
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
existingItemFrames.Add(itemFrame);
}
}
var removedItemFrames = storeBuyList.Content.Children.Except(existingItemFrames).ToList();
removedItemFrames.ForEach(f => storeBuyList.Content.RemoveChild(f));
var removedItemFrames = storeBuyList.Content.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList();
if (storeDailySpecialsGroup != null)
{
removedItemFrames.AddRange(storeDailySpecialsGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
}
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
if (IsBuying) { FilterStoreItems(); }
SortItems(StoreTab.Buy);
@@ -567,36 +699,72 @@ namespace Barotrauma
{
float prevSellListScroll = storeSellList.BarScroll;
float prevShoppingCrateScroll = shoppingCrateSellList.BarScroll;
bool hasPermissions = HasPermissions;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
foreach (PurchasedItem item in itemsToSell)
if ((storeRequestedGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
{
PriceInfo priceInfo = item.ItemPrefab.GetPriceInfo(CurrentLocation);
if (priceInfo == null) { continue; }
var itemFrame = storeSellList.Content.FindChild(c => c.UserData is PurchasedItem i && i.ItemPrefab == item.ItemPrefab);
var quantity = item.Quantity;
if (CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem itemInSellCrate)
if (storeRequestedGoodGroup == null)
{
quantity = Math.Max(quantity - itemInSellCrate.Quantity, 0);
}
if (itemFrame == null)
{
itemFrame = CreateItemFrame(new PurchasedItem(item.ItemPrefab, quantity), priceInfo, storeSellList, forceDisable: !hasPermissions);
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
storeRequestedGoodGroup.Parent.SetAsFirstChild();
}
else
{
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
storeSellList.RemoveChild(storeRequestedGoodGroup.Parent);
storeRequestedGoodGroup = null;
}
storeSellList.RecalculateChildren();
}
foreach (PurchasedItem item in itemsToSell)
{
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
}
foreach (var requestedGood in CurrentLocation.RequestedGoods)
{
if (itemsToSell.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
CreateOrUpdateItemFrame(requestedGood, 0);
}
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
{
PriceInfo priceInfo = itemPrefab.GetPriceInfo(CurrentLocation);
if (priceInfo == null) { return; }
var isRequestedGood = CurrentLocation.RequestedGoods.Contains(itemPrefab);
var itemFrame = isRequestedGood ?
storeRequestedGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
storeSellList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
if (CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInSellCrate)
{
itemQuantity = Math.Max(itemQuantity - itemInSellCrate.Quantity, 0);
}
if (itemFrame == null)
{
var parentComponent = isRequestedGood ? storeRequestedGoodGroup : storeSellList as GUIComponent;
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
}
else
{
(itemFrame.UserData as PurchasedItem).Quantity = itemQuantity;
SetQuantityLabelText(StoreTab.Sell, itemFrame);
SetOwnedLabelText(itemFrame);
SetItemFrameStatus(itemFrame, hasPermissions);
}
if (quantity < 1) { itemFrame.Visible = false; }
SetItemFrameStatus(itemFrame, hasPermissions && itemQuantity > 0);
if (itemQuantity < 1 && !isRequestedGood)
{
itemFrame.Visible = false;
}
existingItemFrames.Add(itemFrame);
}
var removedItemFrames = storeSellList.Content.Children.Except(existingItemFrames).ToList();
removedItemFrames.ForEach(f => storeSellList.Content.RemoveChild(f));
var removedItemFrames = storeSellList.Content.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList();
if (storeRequestedGoodGroup != null)
{
removedItemFrames.AddRange(storeRequestedGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
}
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
if (IsSelling) { FilterStoreItems(); }
SortItems(StoreTab.Sell);
@@ -673,13 +841,10 @@ namespace Barotrauma
}
suppressBuySell = false;
if (priceInfo != null)
{
var price = listBox == shoppingCrateBuyList ?
CurrentLocation.GetAdjustedItemBuyPrice(priceInfo) :
CurrentLocation.GetAdjustedItemSellPrice(priceInfo);
totalPrice += item.Quantity * price;
}
var price = listBox == shoppingCrateBuyList ?
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
totalPrice += item.Quantity * price;
}
var removedItemFrames = listBox.Content.Children.Except(existingItemFrames).ToList();
@@ -711,32 +876,138 @@ namespace Barotrauma
if (sortingMethod == SortingMethod.AlphabeticalAsc || sortingMethod == SortingMethod.AlphabeticalDesc)
{
list.Content.RectTransform.SortChildren(
(x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name));
if (sortingMethod == SortingMethod.AlphabeticalDesc) { list.Content.RectTransform.ReverseChildren(); }
list.Content.RectTransform.SortChildren(CompareByName);
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
{
specialsGroup.RectTransform.SortChildren(CompareByName);
specialsGroup.Recalculate();
}
int CompareByName(RectTransform x, RectTransform y)
{
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
{
var sortResult = itemX.ItemPrefab.Name.CompareTo(itemY.ItemPrefab.Name);
if (sortingMethod == SortingMethod.AlphabeticalDesc) { sortResult *= -1; }
return sortResult;
}
else
{
return CompareByElement(x, y);
}
}
}
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
{
SortItems(list, SortingMethod.AlphabeticalAsc);
if (list == storeSellList || list == shoppingCrateSellList)
{
list.Content.RectTransform.SortChildren(
(x, y) => CurrentLocation.GetAdjustedItemSellPrice((x.GUIComponent.UserData as PurchasedItem).ItemPrefab).CompareTo(
CurrentLocation.GetAdjustedItemSellPrice((y.GUIComponent.UserData as PurchasedItem).ItemPrefab)));
list.Content.RectTransform.SortChildren(CompareBySellPrice);
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
{
specialsGroup.RectTransform.SortChildren(CompareBySellPrice);
specialsGroup.Recalculate();
}
int CompareBySellPrice(RectTransform x, RectTransform y)
{
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
{
var sortResult = CurrentLocation.GetAdjustedItemSellPrice(itemX.ItemPrefab).CompareTo(
CurrentLocation.GetAdjustedItemSellPrice(itemY.ItemPrefab));
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
return sortResult;
}
else
{
return CompareByElement(x, y);
}
}
}
else
{
list.Content.RectTransform.SortChildren(
(x, y) => CurrentLocation.GetAdjustedItemBuyPrice((x.GUIComponent.UserData as PurchasedItem).ItemPrefab).CompareTo(
CurrentLocation.GetAdjustedItemBuyPrice((y.GUIComponent.UserData as PurchasedItem).ItemPrefab)));
list.Content.RectTransform.SortChildren(CompareByBuyPrice);
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
{
specialsGroup.RectTransform.SortChildren(CompareByBuyPrice);
specialsGroup.Recalculate();
}
int CompareByBuyPrice(RectTransform x, RectTransform y)
{
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
{
var sortResult = CurrentLocation.GetAdjustedItemBuyPrice(itemX.ItemPrefab).CompareTo(
CurrentLocation.GetAdjustedItemBuyPrice(itemY.ItemPrefab));
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
return sortResult;
}
else
{
return CompareByElement(x, y);
}
}
}
if (sortingMethod == SortingMethod.PriceDesc) { list.Content.RectTransform.ReverseChildren(); }
}
else if (sortingMethod == SortingMethod.CategoryAsc)
{
SortItems(list, SortingMethod.AlphabeticalAsc);
list.Content.RectTransform.SortChildren((x, y) =>
(x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Category.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Category));
list.Content.RectTransform.SortChildren(CompareByCategory);
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
{
specialsGroup.RectTransform.SortChildren(CompareByCategory);
specialsGroup.Recalculate();
}
static int CompareByCategory(RectTransform x, RectTransform y)
{
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
{
return itemX.ItemPrefab.Category.CompareTo(itemY.ItemPrefab.Category);
}
else
{
return CompareByElement(x, y);
}
}
}
GUILayoutGroup GetSpecialsGroup()
{
if (list == storeBuyList)
{
return storeDailySpecialsGroup;
}
else if (list == storeSellList)
{
return storeRequestedGoodGroup;
}
else
{
return null;
}
}
static int CompareByElement(RectTransform x, RectTransform y)
{
if (ShouldBeOnTop(x) || ShouldBeOnBottom(y))
{
return -1;
}
else if (ShouldBeOnBottom(x) || ShouldBeOnTop(y))
{
return 1;
}
else
{
return 0;
}
static bool ShouldBeOnTop(RectTransform rt) =>
rt.GUIComponent.UserData is string id && (id == "deals" || id == "header");
static bool ShouldBeOnBottom(RectTransform rt) =>
rt.GUIComponent.UserData is string id && id == "divider";
}
}
@@ -750,7 +1021,7 @@ namespace Barotrauma
private void SortActiveTabItems(SortingMethod sortingMethod) => SortItems(activeTab, sortingMethod);
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, bool forceDisable = false)
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIComponent parentComponent, bool forceDisable = false)
{
var tooltip = pi.ItemPrefab.Name;
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
@@ -758,7 +1029,21 @@ namespace Barotrauma
tooltip += "\n" + pi.ItemPrefab.Description;
}
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.yScale * 80)), parent: listBox.Content.RectTransform), style: "ListBoxElement")
GUIListBox parentListBox = parentComponent as GUIListBox;
int width = 0;
RectTransform parent = null;
if (parentListBox != null)
{
width = parentListBox.Content.Rect.Width;
parent = parentListBox.Content.RectTransform;
}
else
{
width = parentComponent.Rect.Width;
parent = parentComponent.RectTransform;
}
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, (int)(GUI.yScale * 80)), parent: parent), style: "ListBoxElement")
{
ToolTip = tooltip,
UserData = pi
@@ -788,33 +1073,58 @@ namespace Barotrauma
img.RectTransform.MaxSize = img.Rect.Size;
}
GUILayoutGroup nameAndQuantityGroup = new GUILayoutGroup(new RectTransform(new Vector2(nameAndIconRelativeWidth - iconRelativeWidth, 1.0f), mainGroup.RectTransform))
GUIFrame nameAndQuantityFrame = new GUIFrame(new RectTransform(new Vector2(nameAndIconRelativeWidth - iconRelativeWidth, 1.0f), mainGroup.RectTransform), style: null)
{
CanBeFocused = false
};
GUILayoutGroup nameAndQuantityGroup = new GUILayoutGroup(new RectTransform(Vector2.One, nameAndQuantityFrame.RectTransform))
{
CanBeFocused = false,
Stretch = true
};
var isSellingRelatedList = parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup || parentComponent == shoppingCrateSellList;
var locationHasDealOnItem = isSellingRelatedList ?
CurrentLocation.RequestedGoods.Contains(pi.ItemPrefab) : CurrentLocation.DailySpecials.Contains(pi.ItemPrefab);
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
pi.ItemPrefab.Name, font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft)
{
CanBeFocused = false,
Shadow = locationHasDealOnItem,
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
TextScale = 0.85f,
UserData = "name"
};
if (locationHasDealOnItem)
{
var relativeWidth = (0.9f * nameAndQuantityFrame.Rect.Height) / nameAndQuantityFrame.Rect.Width;
var dealIcon = new GUIImage(
new RectTransform(new Vector2(relativeWidth, 0.9f), nameAndQuantityFrame.RectTransform, anchor: Anchor.CenterLeft)
{
AbsoluteOffset = new Point((int)nameBlock.Padding.X, 0)
},
"StoreDealIcon", scaleToFit: true)
{
CanBeFocused = false
};
dealIcon.SetAsFirstChild();
}
var isParentOnLeftSideOfInterface = parentComponent == storeBuyList || parentComponent == storeDailySpecialsGroup ||
parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup;
GUILayoutGroup shoppingCrateAmountGroup = null;
GUINumberInput amountInput = null;
if (listBox == storeBuyList || listBox == storeSellList)
if (isParentOnLeftSideOfInterface)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), nameAndQuantityGroup.RectTransform),
CreateQuantityLabelText(listBox == storeSellList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
CreateQuantityLabelText(isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
{
CanBeFocused = false,
Shadow = locationHasDealOnItem,
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
TextScale = 0.85f,
UserData = "quantitylabel"
};
}
else if (listBox == shoppingCrateBuyList || listBox == shoppingCrateSellList)
else if (!isParentOnLeftSideOfInterface)
{
var relativePadding = nameBlock.Padding.X / nameBlock.Rect.Width;
shoppingCrateAmountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativePadding, 0.6f), nameAndQuantityGroup.RectTransform) { RelativeOffset = new Vector2(relativePadding, 0) },
@@ -825,7 +1135,7 @@ namespace Barotrauma
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), GUINumberInput.NumberType.Int)
{
MinValueInt = 0,
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, listBox == shoppingCrateBuyList ? StoreTab.Buy : StoreTab.Sell),
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy),
UserData = pi,
IntValue = pi.Quantity
};
@@ -856,6 +1166,7 @@ namespace Barotrauma
textAlignment: shoppingCrateAmountGroup == null ? Alignment.TopLeft : Alignment.CenterLeft)
{
CanBeFocused = false,
Shadow = locationHasDealOnItem,
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
TextScale = 0.85f,
UserData = "owned"
@@ -864,22 +1175,53 @@ namespace Barotrauma
var buttonRelativeWidth = (0.9f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
var priceFrame = new GUIFrame(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), style: null)
{
CanBeFocused = false
};
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), priceFrame.RectTransform, anchor: Anchor.Center),
"0 MK", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
{
CanBeFocused = false,
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
TextColor = locationHasDealOnItem ? storeSpecialColor : Color.White,
UserData = "price"
};
if (listBox == storeSellList || listBox == shoppingCrateSellList)
priceBlock.Color *= (forceDisable ? 0.5f : 1.0f);
priceBlock.CalculateHeightFromText();
if (isSellingRelatedList)
{
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemSellPrice(priceInfo) ?? 0);
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab, priceInfo: priceInfo) ?? 0);
}
else
{
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemBuyPrice(priceInfo) ?? 0);
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab, priceInfo: priceInfo) ?? 0);
}
if (locationHasDealOnItem)
{
var undiscounterPriceBlock = new GUITextBlock(
new RectTransform(new Vector2(1.0f, 0.25f), priceFrame.RectTransform, anchor: Anchor.Center)
{
AbsoluteOffset = new Point(0, priceBlock.RectTransform.ScaledSize.Y)
}, "", font: GUI.SmallFont, textAlignment: Alignment.Center)
{
CanBeFocused = false,
Strikethrough = new GUITextBlock.StrikethroughSettings(color: priceBlock.TextColor, expand: 1),
TextColor = priceBlock.TextColor,
UserData = "undiscountedprice"
};
if (isSellingRelatedList)
{
undiscounterPriceBlock.TextGetter = () => GetCurrencyFormatted(
CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab, priceInfo: priceInfo, considerRequestedGoods: false) ?? 0);
}
else
{
undiscounterPriceBlock.TextGetter = () => GetCurrencyFormatted(
CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab, priceInfo: priceInfo, considerDailySpecials: false) ?? 0);
}
}
if (listBox == storeDealsList || listBox == storeBuyList || listBox == storeSellList)
if (isParentOnLeftSideOfInterface)
{
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreAddToCrateButton")
{
@@ -902,7 +1244,14 @@ namespace Barotrauma
};
}
listBox.RecalculateChildren();
if (parentListBox != null)
{
parentListBox.RecalculateChildren();
}
else if (parentComponent is GUILayoutGroup parentLayoutGroup)
{
parentLayoutGroup.Recalculate();
}
mainGroup.Recalculate();
mainGroup.RectTransform.RecalculateChildren(true, true);
amountInput?.LayoutGroup.Recalculate();
@@ -923,15 +1272,20 @@ namespace Barotrauma
.ForEach(i => AddToOwnedItems(i.Prefab));
// Add items in character inventories
foreach (Character c in GameMain.GameSession.CrewManager.GetCharacters())
foreach (var item in Item.ItemList)
{
Item.ItemList.Where(i => i != null && i.GetRootInventoryOwner() == c)
.ForEach(i => AddToOwnedItems(i.Prefab));
if (item == null || item.Removed) { continue; }
var rootInventoryOwner = item.GetRootInventoryOwner();
var ownedByCrewMember = GameMain.GameSession.CrewManager.GetCharacters().Any(c => c == rootInventoryOwner);
if (!ownedByCrewMember) { continue; }
AddToOwnedItems(item.Prefab);
}
// Add items already purchased
CargoManager?.PurchasedItems?.ForEach(pi => AddToOwnedItems(pi.ItemPrefab, amount: pi.Quantity));
ownedItemsUpdateTimer = 0.0f;
void AddToOwnedItems(ItemPrefab itemPrefab, int amount = 1)
{
if (OwnedItems.ContainsKey(itemPrefab))
@@ -977,14 +1331,22 @@ namespace Barotrauma
numberInput.Enabled = enabled;
}
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock owned)
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock ownedBlock)
{
owned.TextColor = color;
ownedBlock.TextColor = color;
}
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock price)
var isDiscounted = false;
if (itemFrame.FindChild("undiscountedprice", recursive: true) is GUITextBlock undiscountedPriceBlock)
{
price.TextColor = color;
undiscountedPriceBlock.TextColor = color;
undiscountedPriceBlock.Strikethrough.Color = color;
isDiscounted = true;
}
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock priceBlock)
{
priceBlock.TextColor = isDiscounted ? storeSpecialColor * (enabled ? 1.0f : 0.5f) : color;
}
if (itemFrame.FindChild("addbutton", recursive: true) is GUIButton addButton)
@@ -1101,7 +1463,7 @@ namespace Barotrauma
itemsToRemove.Add(item);
continue;
}
totalPrice += item.Quantity * CurrentLocation.GetAdjustedItemBuyPrice(priceInfo);
totalPrice += item.Quantity * CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
}
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
@@ -1135,7 +1497,7 @@ namespace Barotrauma
}
if (item.ItemPrefab.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
{
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(priceInfo);
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
}
else
{
@@ -1197,16 +1559,38 @@ namespace Barotrauma
private void SetClearAllButtonStatus() => clearAllButton.Enabled =
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any();
public void Update()
private float ownedItemsUpdateTimer = 0.0f;
private readonly float ownedItemsUpdateInterval = 1.5f;
public void Update(float deltaTime)
{
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
{
CreateUI();
needsRefresh = false;
}
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(); }
if (needsBuyingRefresh) { RefreshBuying(); }
else
{
// Update the owned items at short intervals and check if the interface should be refreshed
ownedItemsUpdateTimer += deltaTime;
if (ownedItemsUpdateTimer >= ownedItemsUpdateInterval)
{
var prevOwnedItems = new Dictionary<ItemPrefab, int>(OwnedItems);
UpdateOwnedItems();
var refresh = (prevOwnedItems.Count != OwnedItems.Count) ||
(prevOwnedItems.Select(kvp => kvp.Value).Sum() != OwnedItems.Select(kvp => kvp.Value).Sum()) ||
(OwnedItems.Any(kvp => kvp.Value > 0 && !prevOwnedItems.ContainsKey(kvp.Key)) ||
prevOwnedItems.Any(kvp => !OwnedItems.TryGetValue(kvp.Key, out var itemCount) || kvp.Value != itemCount));
if (refresh)
{
needsItemsToSellRefresh = true;
needsRefresh = true;
}
}
}
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
if (needsBuyingRefresh) { RefreshBuying(); }
if (needsSellingRefresh) { RefreshSelling(); }
}
}

View File

@@ -610,8 +610,8 @@ namespace Barotrauma
{
if (GameMain.Client == null)
{
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(newSub);
RefreshSubmarineDisplay(true);
}
else
@@ -645,8 +645,8 @@ namespace Barotrauma
if (GameMain.Client == null)
{
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(newSub);
RefreshSubmarineDisplay(true);
}
else

View File

@@ -29,7 +29,7 @@ namespace Barotrauma
private float sizeMultiplier = 1f;
private IEnumerable<Character> crew;
private List<Character.TeamType> teamIDs;
private List<CharacterTeamType> teamIDs;
private const string inLobbyString = "\u2022 \u2022 \u2022";
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
@@ -281,11 +281,11 @@ namespace Barotrauma
// Show own team first when there's more than one team
if (teamIDs.Count > 1 && GameMain.Client?.Character != null)
{
Character.TeamType ownTeam = GameMain.Client.Character.TeamID;
CharacterTeamType ownTeam = GameMain.Client.Character.TeamID;
teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
}
if (!teamIDs.Any()) teamIDs.Add(Character.TeamType.None);
if (!teamIDs.Any()) { teamIDs.Add(CharacterTeamType.None); }
var content = new GUILayoutGroup(new RectTransform(Vector2.One, crewFrame.RectTransform));
@@ -465,15 +465,14 @@ namespace Barotrauma
{
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
{
if (!(character is AICharacter) && connectedClients.Find(c => c.Character == null && c.Name == character.Name) != null) continue;
CreateMultiPlayerCharacterElement(character, GameMain.Client.ConnectedClients.Find(c => c.Character == character), i);
if (!(character is AICharacter) && connectedClients.Any(c => c.Character == null && c.Name == character.Name)) { continue; }
CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), i);
}
}
for (int j = 0; j < connectedClients.Count; j++)
{
Client client = connectedClients[j];
if (!client.InGame || client.Character == null || client.Character.IsDead)
{
CreateMultiPlayerClientElement(client);
@@ -565,7 +564,7 @@ namespace Barotrauma
private int GetTeamIndex(Client client)
{
if (teamIDs.Count <= 1) return 0;
if (teamIDs.Count <= 1) { return 0; }
if (client.Character != null)
{
@@ -707,7 +706,7 @@ namespace Barotrauma
{
GUIComponent paddedFrame;
if (client.Character == null)
if (client.Character?.Info == null)
{
paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) })
{

View File

@@ -625,13 +625,19 @@ namespace Barotrauma
selectedUpgradeCategoryLayout?.ClearChildren();
GUIFrame frame = new GUIFrame(rectT(1, 0.4f, selectedUpgradeCategoryLayout));
GUIListBox prefabList = new GUIListBox(rectT(0.93f, 0.9f, frame, Anchor.Center)) { UserData = "prefablist" };
List<Item> entitiesOnSub = null;
if (!category.IsWallUpgrade)
{
entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true)).ToList();
}
foreach (UpgradePrefab prefab in prefabs)
{
CreateUpgradeEntry(prefab, category, prefabList.Content);
CreateUpgradeEntry(prefab, category, prefabList.Content, entitiesOnSub);
}
}
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent)
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent, List<Item> itemsOnSubmarine)
{
/* UPGRADE PREFAB ENTRY
* |------------------------------------------------------------------|
@@ -680,12 +686,14 @@ namespace Barotrauma
progressLayout.Recalculate();
buyButtonLayout.Recalculate();
if (!HasPermission)
if (!HasPermission || itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab)))
{
prefabFrame.Enabled = false;
description.Enabled = false;
name.Enabled = false;
icon.Color = Color.Gray;
buyButton.Enabled = false;
buyButtonLayout.UserData = null; // prevent UpdateUpgradeEntry() from enabling the button
}
buyButton.OnClicked += (button, o) =>
@@ -731,7 +739,7 @@ namespace Barotrauma
// include pending upgrades into the tooltip
foreach (var (prefab, category, level) in Campaign.UpgradeManager.PendingUpgrades)
{
if (entity is Item item && category.CanBeApplied(item) || entity is Structure && category.IsWallUpgrade)
if (entity is Item item && category.CanBeApplied(item, prefab) || entity is Structure && category.IsWallUpgrade)
{
bool found = false;
foreach (GUITextBlock textBlock in upgradeList.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>())
@@ -786,7 +794,7 @@ namespace Barotrauma
foreach (UpgradeCategory category in UpgradeCategory.Categories)
{
if (entitiesOnSub.Any(item => category.CanBeApplied(item) && !item.disallowedUpgrades.Contains(category.Identifier)))
if (entitiesOnSub.Any(item => category.CanBeApplied(item, null)))
{
applicableCategories.Add(category);
}
@@ -826,7 +834,7 @@ namespace Barotrauma
HoveredItem = item;
if (PlayerInput.PrimaryMouseButtonClicked() && selectedUpgradTab == UpgradeTab.Upgrade && currentStoreLayout != null)
{
ScrollToCategory(data => data.Category.CanBeApplied(item));
ScrollToCategory(data => data.Category.CanBeApplied(item, null));
}
found = true;
break;
@@ -895,7 +903,7 @@ namespace Barotrauma
submarineInfoFrame.RectTransform.ScreenSpaceOffset = new Point(0, (int)(16 * GUI.Scale));
description.Padding = new Vector4(description.Padding.X, 24 * GUI.Scale, description.Padding.Z, description.Padding.W);
List<Entity> pointsOfInterest = (from category in UpgradeCategory.Categories from item in submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs) where category.CanBeApplied(item) && !item.NonInteractable select item).Cast<Entity>().ToList();
List<Entity> pointsOfInterest = (from category in UpgradeCategory.Categories from item in submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs) where category.CanBeApplied(item, null) && item.IsPlayerTeamInteractable select item).Cast<Entity>().ToList();
List<ushort> ids = GameMain.GameSession.SubmarineInfo?.LeftBehindDockingPortIDs ?? new List<ushort>();
pointsOfInterest.AddRange(submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs).Where(item => ids.Contains(item.ID)));
@@ -1112,7 +1120,7 @@ namespace Barotrauma
List<GUIFrame> frames = new List<GUIFrame>();
foreach (var (item, guiFrame) in itemPreviews)
{
if (category.CanBeApplied(item))
if (category.CanBeApplied(item, null))
{
frames.Add(guiFrame);
}

View File

@@ -557,6 +557,7 @@ namespace Barotrauma
GameModePreset.Init();
SaveUtil.DeleteDownloadedSubs();
SubmarineInfo.RefreshSavedSubs();
TitleScreen.LoadState = 65.0f;
@@ -1113,7 +1114,6 @@ namespace Barotrauma
{
new Pair<string, string>(TextManager.Get("EditorDisclaimerWikiLink"), TextManager.Get("EditorDisclaimerWikiUrl")),
new Pair<string, string>(TextManager.Get("EditorDisclaimerDiscordLink"), TextManager.Get("EditorDisclaimerDiscordUrl")),
new Pair<string, string>(TextManager.Get("EditorDisclaimerForumLink"), TextManager.Get("EditorDisclaimerForumUrl")),
};
foreach (var link in links)
{

View File

@@ -39,61 +39,37 @@ namespace Barotrauma
private List<SoldEntity> SoldEntities { get; } = new List<SoldEntity>();
public List<Item> GetSellableItems(Character character)
public IEnumerable<Item> GetSellableItems(Character character)
{
if (character == null) { return new List<Item>(); }
// Only consider items which have been:
// a) sold in singleplayer or confirmed by server (SellStatus.Confirmed); or
// b) sold locally in multiplayer (SellStatus.Local), but the client has not received a campaing state update yet after selling them
var soldEntities = SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
var sellables = Item.ItemList.FindAll(i => i?.Prefab != null && !i.Removed &&
i.GetRootInventoryOwner() == character &&
!i.SpawnedInOutpost &&
(i.ContainedItems == null || i.ContainedItems.None() || i.ContainedItems.All(ci => soldEntities.Any(se => se.Item == ci))) &&
(i.Condition >= 0.9f * i.MaxCondition || i.Prefab.AllowSellingWhenBroken) && soldEntities.None(se => se.Item == i));
// Prevent selling items in equipment slots
var confirmedSoldEntities = SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
// The bag slot is intentionally left out since we want to be able to sell items from there
var equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
foreach (InvSlotType slot in equipmentSlots)
return character.Inventory.FindAllItems(item =>
{
var index = character.Inventory.FindLimbSlot(slot);
if (character.Inventory.Items[index] is Item item)
{
// Don't prevent selling of items which can only be put in equipment slots (like diving suits)
if (item.AllowedSlots.Contains(InvSlotType.Any))
{
sellables.Remove(item);
}
}
}
if (item.SpawnedInOutpost) { return false; }
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
// There must be no contained items or the contained items must be confirmed as sold
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
// Item must be in a non-equipment slot if possible
if (!item.AllowedSlots.All(s => equipmentSlots.Contains(s)) && IsInEquipmentSlot(item)) { return false; }
// Item must not be contained inside an item in an equipment slot
if (item.GetRootContainer() is Item rootContainer && IsInEquipmentSlot(rootContainer)) { return false; }
return true;
}, recursive: true).Distinct();
// Prevent selling items contained inside equipped items
foreach (InvSlotType slot in equipmentSlots)
bool IsInEquipmentSlot(Item item)
{
var index = character.Inventory.FindLimbSlot(slot);
if (character.Inventory.Items[index] is Item item &&
item.ContainedItems != null && item.AllowedSlots.Contains(InvSlotType.Any))
foreach (InvSlotType slot in equipmentSlots)
{
RemoveContainedFromSellables(item);
if (character.Inventory.IsInLimbSlot(item, slot)) { return true; }
}
return false;
}
void RemoveContainedFromSellables(Item item)
{
foreach (Item containedItem in item.ContainedItems)
{
if (containedItem == null) { continue; }
if (containedItem.ContainedItems != null)
{
RemoveContainedFromSellables(containedItem);
}
sellables.Remove(containedItem);
}
}
return sellables;
}
public void SetItemsInBuyCrate(List<PurchasedItem> items)
@@ -149,15 +125,20 @@ namespace Barotrauma
var canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
var sellerId = GameMain.Client?.ID ?? 0;
// Check all the prices before starting the transaction
// to make sure the modifiers stay the same for the whole transaction
Dictionary<ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
foreach (PurchasedItem item in itemsToSell)
{
var itemValue = GetSellValueAtCurrentLocation(item.ItemPrefab, quantity: item.Quantity);
var itemValue = item.Quantity * sellValues[item.ItemPrefab];
// check if the store can afford the item
if (Location.StoreCurrentBalance < itemValue) { continue; }
var matchingItems = itemsInInventory.FindAll(i => i.Prefab == item.ItemPrefab);
if (matchingItems.Count <= item.Quantity)
// TODO: Write logic for prioritizing certain items over others (e.g. lone Battery Cell should be preferred over one inside a Stun Baton)
var matchingItems = itemsInInventory.Where(i => i.Prefab == item.ItemPrefab);
if (matchingItems.Count() <= item.Quantity)
{
foreach (Item i in matchingItems)
{
@@ -170,7 +151,7 @@ namespace Barotrauma
{
for (int i = 0; i < item.Quantity; i++)
{
var matchingItem = matchingItems[i];
var matchingItem = matchingItems.ElementAt(i);
SoldItems.Add(new SoldItem(matchingItem.Prefab, matchingItem.ID, canAddToRemoveQueue, sellerId));
SoldEntities.Add(campaign.IsSinglePlayer ? SoldEntity.CreateInSinglePlayer(matchingItem) : SoldEntity.CreateInMultiPlayer(matchingItem));
if (canAddToRemoveQueue) { Entity.Spawner.AddToRemoveQueue(matchingItem); }

View File

@@ -134,6 +134,7 @@ namespace Barotrauma
isScrollBarOnDefaultSide: false)
{
AutoHideScrollBar = false,
CanBeFocused = false,
OnSelected = (component, userData) => false,
SelectMultiple = false,
Spacing = (int)(GUI.Scale * 10)
@@ -232,7 +233,7 @@ namespace Barotrauma
};
}
var reports = Order.PrefabList.FindAll(o => o.IsReport && o.SymbolSprite != null);
var reports = Order.PrefabList.FindAll(o => o.IsReport && o.SymbolSprite != null && !o.Hidden);
if (reports.None())
{
DebugConsole.ThrowError("No valid orders for report buttons found! Cannot create report buttons. The orders for the report buttons must have 'targetallcharacters' attribute enabled and a valid 'symbolsprite' defined.");
@@ -252,7 +253,7 @@ namespace Barotrauma
//report buttons
foreach (Order order in reports)
{
if (!order.IsReport || order.SymbolSprite == null) { continue; }
if (!order.IsReport || order.SymbolSprite == null || order.Hidden) { continue; }
var btn = new GUIButton(new RectTransform(new Point(ReportButtonFrame.Rect.Width), ReportButtonFrame.RectTransform), style: null)
{
OnClicked = (GUIButton button, object userData) =>
@@ -602,11 +603,11 @@ namespace Barotrauma
private WifiComponent GetHeadset(Character character, bool requireEquipped)
{
if (character?.Inventory == null) return null;
if (character?.Inventory == null) { return null; }
var radioItem = character.Inventory.Items.FirstOrDefault(it => it != null && it.GetComponent<WifiComponent>() != null);
if (radioItem == null) return null;
if (requireEquipped && !character.HasEquippedItem(radioItem)) return null;
var radioItem = character.Inventory.AllItems.FirstOrDefault(it => it.GetComponent<WifiComponent>() != null);
if (radioItem == null) { return null; }
if (requireEquipped && !character.HasEquippedItem(radioItem)) { return null; }
return radioItem.GetComponent<WifiComponent>();
}
@@ -687,18 +688,10 @@ namespace Barotrauma
else if(order.IsIgnoreOrder)
{
WallSection ws = null;
if (order.TargetType == Order.OrderTargetType.Entity && order.TargetEntity is MapEntity me)
if (order.TargetType == Order.OrderTargetType.Entity && order.TargetEntity is IIgnorable ignorable)
{
if (order.Identifier == "ignorethis")
{
me.SetIgnoreByAI(true);
AddOrder(new Order(order.Prefab ?? order, order.TargetEntity, order.TargetItemComponent, orderGiver), null);
}
else
{
me.SetIgnoreByAI(false);
ActiveOrders.RemoveAll(p => p.First.Identifier == "ignorethis" && p.First.TargetEntity == order.TargetEntity);
}
ignorable.OrderedToBeIgnored = order.Identifier == "ignorethis";
AddOrder(new Order(order.Prefab ?? order, order.TargetEntity, order.TargetItemComponent, orderGiver), null);
}
else if (order.TargetType == Order.OrderTargetType.WallSection && order.TargetEntity is Structure s)
{
@@ -706,18 +699,14 @@ namespace Barotrauma
ws = s.GetSection(wallSectionIndex);
if (ws != null)
{
if (order.Identifier == "ignorethis")
{
ws.SetIgnoreByAI(true);
AddOrder(new Order(order.Prefab ?? order, s, wallSectionIndex, orderGiver), null);
}
else
{
ws.SetIgnoreByAI(false);
ActiveOrders.RemoveAll(p => p.First.Identifier == "ignorethis" && p.First.TargetEntity == s && p.First.WallSectionIndex == wallSectionIndex);
}
ws.OrderedToBeIgnored = order.Identifier == "ignorethis";
AddOrder(new Order(order.Prefab ?? order, s, wallSectionIndex, orderGiver), null);
}
}
else
{
return;
}
if (ws != null)
{
@@ -781,7 +770,16 @@ namespace Barotrauma
{
currentOrderInfo = (OrderInfo)currentOrderIcon.UserData;
// No need to recreate icons if the current order matches the new order
if (currentOrderInfo.Value.MatchesOrder(order, option)) { return; }
if (currentOrderInfo.Value.MatchesOrder(order, option))
{
currentOrderIcon.UserData = new OrderInfo(order, option);
if (currentOrderIcon.FindChild(c => (string)c.UserData == "colorsource") is GUIImage image)
{
image.Sprite = GetOrderIconSprite(order, option);
image.ToolTip = CreateOrderTooltip(order, option);
}
return;
}
}
// Remove the current order icon
@@ -826,7 +824,10 @@ namespace Barotrauma
}
};
CreateNodeIcon(orderFrame.RectTransform, order.SymbolSprite, order.Color, tooltip: order.Name);
CreateNodeIcon(orderFrame.RectTransform,
GetOrderIconSprite(order, option),
order.Color,
tooltip: CreateOrderTooltip(order, option));
new GUIImage(new RectTransform(Vector2.One, orderFrame.RectTransform), cancelIcon, scaleToFit: true)
{
@@ -870,11 +871,10 @@ namespace Barotrauma
new RectTransform(new Vector2(0.8f), prevOrderFrame.RectTransform, anchor: Anchor.BottomLeft),
style: null);
CreateNodeIcon(
prevOrderIconFrame.RectTransform,
previousOrderInfo.Order.SymbolSprite,
CreateNodeIcon(prevOrderIconFrame.RectTransform,
GetOrderIconSprite(previousOrderInfo),
previousOrderInfo.Order.Color,
tooltip: previousOrderInfo.Order.Name);
tooltip: CreateOrderTooltip(previousOrderInfo));
foreach (GUIComponent c in prevOrderIconFrame.Children)
{
@@ -947,6 +947,48 @@ namespace Barotrauma
private IEnumerable<GUIComponent> GetPreviousOrderIcons(GUILayoutGroup characterComponent) =>
characterComponent?.FindChildren(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
private string CreateOrderTooltip(Order order, string option)
{
if (order == null) { return ""; }
if (!string.IsNullOrEmpty(option))
{
return TextManager.GetWithVariables("crewlistordericontooltip",
new string[2] { "[ordername]", "[orderoption]" },
new string[2] { order.Name, order.GetOptionName(option) });
}
else if (order.TargetEntity is Item targetItem && order.MinimapIcons.ContainsKey(targetItem.Prefab.Identifier))
{
return TextManager.GetWithVariables("crewlistordericontooltip",
new string[2] { "[ordername]", "[orderoption]" },
new string[2] { order.Name, targetItem.Name });
}
else
{
return order.Name;
}
}
private string CreateOrderTooltip(OrderInfo orderInfo) =>
CreateOrderTooltip(orderInfo.Order, orderInfo.OrderOption);
private Sprite GetOrderIconSprite(Order order, string option)
{
if (order == null) { return null; }
Sprite sprite = null;
if (option != null && order.Prefab.OptionSprites.Any())
{
order.Prefab.OptionSprites.TryGetValue(option, out sprite);
}
if (sprite == null && order.TargetEntity is Item targetItem && order.MinimapIcons.Any())
{
order.MinimapIcons.TryGetValue(targetItem.Prefab.Identifier, out sprite);
}
return sprite ?? order.SymbolSprite;
}
private Sprite GetOrderIconSprite(OrderInfo orderInfo) =>
GetOrderIconSprite(orderInfo.Order, orderInfo.OrderOption);
#endregion
#region Updating and drawing the UI
@@ -982,7 +1024,7 @@ namespace Barotrauma
public void CreateModerationContextMenu(Point mousePos, Client client)
{
if (IsSinglePlayer || client == null || (GameMain.NetworkMember?.ConnectedClients?.All(match => match != client) ?? true)) { return; }
if (IsSinglePlayer || client == null || (!GameMain.Client?.PreviouslyConnectedClients?.Contains(client) ?? true)) { return; }
contextMenu = new GUIFrame(new RectTransform(new Vector2(0.1f, 0.15f), GUI.Canvas) { ScreenSpaceOffset = mousePos }, style: "GUIToolTip") { UserData = client };
@@ -1032,19 +1074,22 @@ namespace Barotrauma
UserData = "promote"
};
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get(client.MutedLocally ? "unmute" : "mute"), font: GUI.SmallFont)
if (GameMain.Client.ConnectedClients.Contains(client))
{
Padding = new Vector4(4),
Enabled = client.ID != GameMain.Client?.ID,
UserData = "mute"
};
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get(client.MutedLocally ? "unmute" : "mute"), font: GUI.SmallFont)
{
Padding = new Vector4(4),
Enabled = client.ID != GameMain.Client?.ID,
UserData = "mute"
};
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get(canKick ? "kick" : "votetokick"), font: GUI.SmallFont)
{
Padding = new Vector4(4),
Enabled = client.ID != GameMain.Client?.ID && client.AllowKicking,
UserData = canKick ? "kick" : "votekick"
};
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get(canKick ? "kick" : "votetokick"), font: GUI.SmallFont)
{
Padding = new Vector4(4),
Enabled = client.ID != GameMain.Client?.ID && client.AllowKicking,
UserData = canKick ? "kick" : "votekick"
};
}
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get("ban"), font: GUI.SmallFont)
{
@@ -1363,23 +1408,13 @@ namespace Barotrauma
isSelectionHighlighted = false;
}
if (!CanIssueOrders)
{
DisableCommandUI();
}
else if (PlayerInput.SecondaryMouseButtonClicked() && characterContext == null &&
(optionNodes.Any(n => GUI.IsMouseOn(n.Item1)) || shortcutNodes.Any(n => GUI.IsMouseOn(n))))
{
var node = optionNodes.Find(n => GUI.IsMouseOn(n.Item1))?.Item1 ?? shortcutNodes.Find(n => GUI.IsMouseOn(n));
// Make sure the node is for an option-less order or an order option
if ((node.UserData is Order order && !order.HasOptions && (!order.MustSetTarget || itemContext != null)) || node.UserData is Tuple<Order, string>)
{
CreateAssignmentNodes(node);
}
}
// When using Deselect to close the interface, make sure it's not a seconday mouse button click on a node
// That should be reserved for opening manual assignment
var hitDeselect = PlayerInput.KeyHit(InputType.Deselect) && (!PlayerInput.SecondaryMouseButtonClicked() ||
(optionNodes.None(n => GUI.IsMouseOn(n.Item1)) && shortcutNodes.None(n => GUI.IsMouseOn(n))));
// TODO: Consider using HUD.CloseHUD() instead of KeyHit(Escape), the former method is also used for health UI
else if ((PlayerInput.KeyHit(InputType.Command) && selectedNode == null && !clicklessSelectionActive) ||
PlayerInput.KeyHit(InputType.Deselect) || PlayerInput.KeyHit(Keys.Escape))
if (hitDeselect || PlayerInput.KeyHit(Keys.Escape) || !CanIssueOrders ||
(PlayerInput.KeyHit(InputType.Command) && selectedNode == null && !clicklessSelectionActive))
{
DisableCommandUI();
}
@@ -1438,7 +1473,14 @@ namespace Barotrauma
timeSelected += deltaTime;
if (timeSelected >= selectionTime)
{
selectedNode.OnClicked?.Invoke(selectedNode, selectedNode.UserData);
if (PlayerInput.IsShiftDown() && selectedNode.OnSecondaryClicked != null)
{
selectedNode.OnSecondaryClicked.Invoke(selectedNode, selectedNode.UserData);
}
else
{
selectedNode.OnClicked?.Invoke(selectedNode, selectedNode.UserData);
}
ResetNodeSelection();
}
else if (timeSelected >= 0.15f && !isSelectionHighlighted)
@@ -1463,7 +1505,15 @@ namespace Barotrauma
{
if (node.Item2 != Keys.None && PlayerInput.KeyHit(node.Item2))
{
(node.Item1 as GUIButton)?.OnClicked?.Invoke(node.Item1 as GUIButton, node.Item1.UserData);
var b = node.Item1 as GUIButton;
if (PlayerInput.IsShiftDown() && b?.OnSecondaryClicked != null)
{
b.OnSecondaryClicked.Invoke(node.Item1 as GUIButton, node.Item1.UserData);
}
else
{
b?.OnClicked?.Invoke(node.Item1 as GUIButton, node.Item1.UserData);
}
ResetNodeSelection();
hotkeyHit = true;
break;
@@ -1947,7 +1997,12 @@ namespace Barotrauma
}
// When the mini map is shown, always position the return node on the bottom
var offset = node?.UserData is Order order && order.GetMatchingItems(true).Count > 1 ?
List<Item> matchingItems = null;
if (node?.UserData is Order order)
{
matchingItems = order.GetMatchingItems(true, interactableFor: characterContext ?? Character.Controlled);
}
var offset = matchingItems != null && matchingItems.Count > 1 ?
new Point(0, (int)(returnNodeDistanceModifier * nodeDistance)) :
node.RectTransform.AbsoluteOffset.Multiply(-returnNodeDistanceModifier);
SetReturnNode(centerNode, offset);
@@ -2027,6 +2082,7 @@ namespace Barotrauma
SetCharacterTooltip(c, characterContext);
}
node.OnClicked = null;
node.OnSecondaryClicked = null;
centerNode = node;
}
@@ -2042,6 +2098,7 @@ namespace Barotrauma
c.ToolTip = TextManager.Get("commandui.return");
}
node.OnClicked = NavigateBackward;
node.OnSecondaryClicked = null;
returnNode = node;
}
@@ -2072,11 +2129,14 @@ namespace Barotrauma
private void RemoveOptionNodes()
{
optionNodes.ForEach(node => commandFrame.RemoveChild(node.Item1));
if (commandFrame != null)
{
optionNodes.ForEach(node => commandFrame.RemoveChild(node.Item1));
shortcutNodes.ForEach(node => commandFrame.RemoveChild(node));
commandFrame.RemoveChild(expandNode);
}
optionNodes.Clear();
shortcutNodes.ForEach(node => commandFrame.RemoveChild(node));
shortcutNodes.Clear();
commandFrame.RemoveChild(expandNode);
expandNode = null;
expandNodeHotkey = Keys.None;
RemoveExtraOptionNodes();
@@ -2084,7 +2144,10 @@ namespace Barotrauma
private void RemoveExtraOptionNodes()
{
extraOptionNodes.ForEach(node => commandFrame.RemoveChild(node));
if (commandFrame != null)
{
extraOptionNodes.ForEach(node => commandFrame.RemoveChild(node));
}
extraOptionNodes.Clear();
}
@@ -2125,7 +2188,8 @@ namespace Barotrauma
shortcutNodes.Clear();
if (shortcutNodes.Count < maxShortCutNodeCount && sub.GetItems(false).Find(i => i.HasTag("reactor") && !i.NonInteractable)?.GetComponent<Reactor>() is Reactor reactor)
if (shortcutNodes.Count < maxShortCutNodeCount &&
sub.GetItems(false).Find(i => i.HasTag("reactor") && i.IsPlayerTeamInteractable)?.GetComponent<Reactor>() is Reactor reactor)
{
var reactorOutput = -reactor.CurrPowerConsumption;
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
@@ -2144,7 +2208,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 (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("captain")) &&
sub.GetItems(false).Find(i => i.HasTag("navterminal") && !i.NonInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
sub.GetItems(false).Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
{
shortcutNodes.Add(
@@ -2195,7 +2259,7 @@ namespace Barotrauma
(n.UserData is Tuple<Order, string> orderWithOption && orderWithOption.Item1.Identifier == orderIdentifier)) &&
!orderPrefab.IsReport && orderPrefab.Category != null)
{
if (!orderPrefab.MustSetTarget || orderPrefab.GetMatchingItems(sub, true).Any())
if (!orderPrefab.MustSetTarget || orderPrefab.GetMatchingItems(sub, true, interactableFor: characterContext ?? Character.Controlled).Any())
{
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, orderPrefab, -1));
}
@@ -2245,7 +2309,8 @@ namespace Barotrauma
{
order = orders[i];
disableNode = !CanSomeoneHearCharacter() ||
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) && order.GetMatchingItems(true).None());
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) &&
order.GetMatchingItems(true, interactableFor: characterContext ?? Character.Controlled).None());
optionNodes.Add(new Tuple<GUIComponent, Keys>(
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), order, (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
!disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
@@ -2262,7 +2327,7 @@ namespace Barotrauma
string orderIdentifier;
// Check if targeting an item or a hull
if (itemContext != null && !itemContext.NonInteractable)
if (itemContext != null && itemContext.IsPlayerTeamInteractable)
{
ItemComponent targetComponent;
foreach (Order p in Order.PrefabList)
@@ -2314,9 +2379,12 @@ namespace Barotrauma
if (contextualOrders.None())
{
orderIdentifier = "cleanupitems";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false))
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
if (AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false) || AIObjectiveCleanupItems.IsValidContainer(itemContext, Character.Controlled))
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
}
}
}
@@ -2332,6 +2400,35 @@ namespace Barotrauma
}
}
void AddIgnoreOrder(IIgnorable target)
{
var orderIdentifier = "ignorethis";
if (!target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
{
AddOrder();
}
else
{
orderIdentifier = "unignorethis";
if (target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
{
AddOrder();
}
}
void AddOrder()
{
if (target is WallSection ws)
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled));
}
else
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled));
}
}
}
orderIdentifier = "wait";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
{
@@ -2366,35 +2463,6 @@ namespace Barotrauma
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), contextualOrders[i], (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
!disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
}
void AddIgnoreOrder(ISpatialEntity target)
{
var orderIdentifier = "ignorethis";
if (!target.IgnoreByAI && contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
{
AddOrder(orderIdentifier, target);
}
else
{
orderIdentifier = "unignorethis";
if (target.IgnoreByAI && contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
{
AddOrder(orderIdentifier, target);
}
}
void AddOrder(string id, ISpatialEntity target)
{
if (target is WallSection ws)
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled));
}
else
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled));
}
}
}
}
// TODO: there's duplicate logic here and above -> would be better to refactor so that the conditions are only defined in one place
@@ -2404,6 +2472,7 @@ namespace Barotrauma
if (Order.PrefabList.Any(o => item.HasTag(o.TargetItems))) { return true; }
if (Order.PrefabList.Any(o => o.TryGetTargetItemComponent(item, out _))) { return true; }
if (AIObjectiveCleanupItems.IsValidTarget(item, Character.Controlled, checkInventory: false)) { return true; }
if (AIObjectiveCleanupItems.IsValidContainer(item, Character.Controlled)) { return true; }
if (item.Repairables.Any(r => item.ConditionPercentage < r.RepairThreshold)) { return true; }
var operateWeaponsPrefab = Order.GetPrefab("operateweapons");
@@ -2435,7 +2504,7 @@ namespace Barotrauma
// so we know to directly target that with the order
if (!mustSetOptionOrTarget && order.MustSetTarget && itemContext == null)
{
var matchingItems = order.GetMatchingItems(GetTargetSubmarine(), true);
var matchingItems = order.GetMatchingItems(GetTargetSubmarine(), true, interactableFor: characterContext ?? Character.Controlled);
if (matchingItems.Count > 1)
{
mustSetOptionOrTarget = true;
@@ -2470,9 +2539,14 @@ namespace Barotrauma
}
return true;
};
// TODO: Might need to edit the tooltip
if (CanOpenManualAssignment(node))
{
node.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
}
var showAssignmentTooltip = !mustSetOptionOrTarget && characterContext == null && !order.MustManuallyAssign && !order.TargetAllCharacters;
var orderName = GetOrderNameBasedOnContextuality(order);
var icon = CreateNodeIcon(node.RectTransform, order.SymbolSprite, order.Color,
tooltip: mustSetOptionOrTarget || characterContext != null ? order.Name : order.Name +
tooltip: !showAssignmentTooltip ? orderName : orderName +
"\n" + (!PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.leftmouse") : TextManager.Get("input.rightmouse")) + ": " + TextManager.Get("commandui.quickassigntooltip") +
"\n" + (!PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.rightmouse") : TextManager.Get("input.leftmouse")) + ": " + TextManager.Get("commandui.manualassigntooltip"));
@@ -2491,7 +2565,7 @@ namespace Barotrauma
private void CreateOrderOptions(Order order)
{
Submarine submarine = GetTargetSubmarine();
var matchingItems = (itemContext == null && order.MustSetTarget) ? order.GetMatchingItems(submarine, true) : new List<Item>();
var matchingItems = (itemContext == null && order.MustSetTarget) ? order.GetMatchingItems(submarine, true, interactableFor: characterContext ?? Character.Controlled) : new List<Item>();
//more than one target item -> create a minimap-like selection with a pic of the sub
if (itemContext == null && matchingItems.Count > 1)
@@ -2572,30 +2646,33 @@ namespace Barotrauma
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), optionContainer.RectTransform), item != null ? item.Name : order.Name);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), optionContainer.RectTransform),
item?.Name ?? GetOrderNameBasedOnContextuality(order));
for (int i = 0; i < order.Options.Length; i++)
{
optionNodes.Add(new Tuple<GUIComponent, Keys>(
new GUIButton(
new RectTransform(new Vector2(1.0f, 0.2f), optionContainer.RectTransform),
text: order.GetOptionName(i),
style: "GUITextBox")
var optionButton = new GUIButton(
new RectTransform(new Vector2(1.0f, 0.2f), optionContainer.RectTransform),
text: order.GetOptionName(i), style: "GUITextBox")
{
UserData = new Tuple<Order, string>(
item == null ? order : new Order(order, item, order.GetTargetItemComponent(item)),
order.Options[i]),
Font = GUI.SmallFont,
OnClicked = (_, userData) =>
{
UserData = new Tuple<Order, string>(
item == null ? order : new Order(order, item, order.GetTargetItemComponent(item)),
order.Options[i]),
Font = GUI.SmallFont,
OnClicked = (_, userData) =>
{
if (!CanIssueOrders) { return false; }
var o = userData as Tuple<Order, string>;
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, Character.Controlled);
DisableCommandUI();
return true;
}
},
Keys.None));
if (!CanIssueOrders) { return false; }
var o = userData as Tuple<Order, string>;
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, Character.Controlled);
DisableCommandUI();
return true;
}
};
if (CanOpenManualAssignment(optionButton))
{
optionButton.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
}
optionNodes.Add(new Tuple<GUIComponent, Keys>(optionButton, Keys.None));
}
}
else
@@ -2610,7 +2687,7 @@ namespace Barotrauma
{
UserData = userData,
Font = GUI.SmallFont,
ToolTip = item?.Name ?? order.Name,
ToolTip = item?.Name ?? GetOrderNameBasedOnContextuality(order),
OnClicked = (_, userData) =>
{
if (!CanIssueOrders) { return false; }
@@ -2620,7 +2697,10 @@ namespace Barotrauma
return true;
}
};
if (CanOpenManualAssignment(optionElement))
{
optionElement.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
}
Sprite icon = null;
order.MinimapIcons?.TryGetValue(item.Prefab.Identifier, out icon);
if (item.Prefab.MinimapIcon != null)
@@ -2677,11 +2757,16 @@ namespace Barotrauma
return true;
}
};
if (CanOpenManualAssignment(node))
{
node.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
}
node.RectTransform.MoveOverTime(offset, CommandNodeAnimDuration);
GUIImage icon = null;
if (order.Prefab.OptionSprites.TryGetValue(option, out Sprite sprite))
{
var showAssignmentTooltip = characterContext == null && !order.MustManuallyAssign && !order.TargetAllCharacters;
icon = CreateNodeIcon(node.RectTransform, sprite, order.Color,
tooltip: characterContext != null ? optionName : optionName +
"\n" + (!PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.leftmouse") : TextManager.Get("input.rightmouse")) + ": " + TextManager.Get("commandui.quickassigntooltip") +
@@ -2700,13 +2785,13 @@ namespace Barotrauma
return node;
}
private void CreateAssignmentNodes(GUIComponent node)
private bool CreateAssignmentNodes(GUIComponent node)
{
var order = (node.UserData is Order) ?
new Tuple<Order, string>(node.UserData as Order, null) :
node.UserData as Tuple<Order, string>;
var characters = GetCharactersForManualAssignment(order.Item1);
if (characters.None()) { return; }
if (characters.None()) { return false; }
if (!(optionNodes.Find(n => n.Item1 == node) is Tuple<GUIComponent, Keys> optionNode) || !optionNodes.Remove(optionNode))
{
@@ -2791,7 +2876,7 @@ namespace Barotrauma
CreateHotkeyIcon(returnNode.RectTransform, hotkey % 10, true);
returnNodeHotkey = Keys.D0 + hotkey % 10;
expandNodeHotkey = Keys.None;
return;
return true;
}
extraOptionCharacters.Clear();
@@ -2816,6 +2901,7 @@ namespace Barotrauma
expandNodeHotkey = Keys.D0 + hotkey % 10;
CreateHotkeyIcon(returnNode.RectTransform, ++hotkey % 10, true);
returnNodeHotkey = Keys.D0 + hotkey % 10;
return true;
}
private Vector2[] GetAssignmentNodeOffsets(int characters, bool firstRing = true)
@@ -3083,7 +3169,7 @@ namespace Barotrauma
if (Character.Controlled != null)
{
// Pick the second main sub when we have two teams (in combat mission)
if (Character.Controlled.TeamID == Character.TeamType.Team2 && Submarine.MainSubs.Length > 1)
if (Character.Controlled.TeamID == CharacterTeamType.Team2 && Submarine.MainSubs.Length > 1)
{
sub = Submarine.MainSubs[1];
}
@@ -3105,7 +3191,29 @@ namespace Barotrauma
component.ToolTip = tooltip;
}
private string GetOrderNameBasedOnContextuality(Order order)
{
if (order == null) { return ""; }
if (isContextual) { return order.ContextualName; }
return order.Name;
}
#region Crew Member Assignment Logic
private bool CanOpenManualAssignment(GUIComponent node)
{
if (node == null || characterContext != null) { return false; }
if (node.UserData is Tuple<Order, string> orderInfo)
{
return !orderInfo.Item1.TargetAllCharacters;
}
if (node.UserData is Order order)
{
return !order.TargetAllCharacters && !order.HasOptions &&
(!order.MustSetTarget || itemContext != null ||
order.GetMatchingItems(GetTargetSubmarine(), true, interactableFor: Character.Controlled).Count < 2);
}
return false;
}
private Character GetCharacterForQuickAssignment(Order order)
{
@@ -3145,7 +3253,7 @@ namespace Barotrauma
// 4. Prioritize bots over player controlled characters
.ThenByDescending(c => c.IsBot)
// 5. Use the priority value of the current objective
.ThenBy(c => c.AIController?.ObjectiveManager.CurrentObjective?.Priority)
.ThenBy(c => c.AIController is HumanAIController humanAI ? humanAI.ObjectiveManager.CurrentObjective?.Priority : 0)
// 6. Prioritize those with the best skill for the order
.ThenByDescending(c => c.GetSkillLevel(order.AppropriateSkill));
}

View File

@@ -450,7 +450,7 @@ namespace Barotrauma
{
if (mb is GUIMessageBox msgBox)
{
if (mb.UserData is Pair<string, ushort> pair && pair.First.Equals("conversationaction", StringComparison.OrdinalIgnoreCase))
if (ReadyCheck.IsReadyCheck(mb) || mb.UserData is Pair<string, ushort> pair && pair.First.Equals("conversationaction", StringComparison.OrdinalIgnoreCase))
{
msgBox.Close();
}
@@ -812,8 +812,7 @@ namespace Barotrauma
return;
}
Load(doc.Root.Element("MultiPlayerCampaign"));
SubmarineInfo selectedSub;
GameMain.GameSession.OwnedSubmarines = SaveUtil.LoadOwnedSubmarines(doc, out selectedSub);
GameMain.GameSession.OwnedSubmarines = SaveUtil.LoadOwnedSubmarines(doc, out SubmarineInfo selectedSub);
GameMain.GameSession.SubmarineInfo = selectedSub;
}
}

View File

@@ -11,6 +11,8 @@ namespace Barotrauma
{
class SinglePlayerCampaign : CampaignMode
{
public const int MinimumInitialMoney = 0;
public override bool Paused
{
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition") || ShowCampaignUI && CampaignUI.SelectedTab == InteractionType.Map; }
@@ -105,7 +107,6 @@ namespace Barotrauma
}
CampaignMetadata ??= new CampaignMetadata(this);
UpgradeManager ??= new UpgradeManager(this);
InitCampaignData();
@@ -113,6 +114,9 @@ namespace Barotrauma
InitUI();
Money = element.GetAttributeInt("money", 0);
PurchasedLostShuttles = element.GetAttributeBool("purchasedlostshuttles", false);
PurchasedHullRepairs = element.GetAttributeBool("purchasedhullrepairs", false);
PurchasedItemRepairs = element.GetAttributeBool("purchaseditemrepairs", false);
CheatsEnabled = element.GetAttributeBool("cheatsenabled", false);
if (CheatsEnabled)
{
@@ -137,7 +141,7 @@ namespace Barotrauma
/// <summary>
/// Start a completely new single player campaign
/// </summary>
public static SinglePlayerCampaign StartNew(string mapSeed)
public static SinglePlayerCampaign StartNew(string mapSeed, SubmarineInfo selectedSub)
{
var campaign = new SinglePlayerCampaign(mapSeed);
return campaign;
@@ -699,6 +703,9 @@ namespace Barotrauma
{
XElement modeElement = new XElement("SinglePlayerCampaign",
new XAttribute("money", Money),
new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
new XAttribute("cheatsenabled", CheatsEnabled));
//save and remove all items that are in someone's inventory so they don't get included in the sub file as well

View File

@@ -182,7 +182,7 @@ namespace Barotrauma.Tutorials
+ " Equip a screwdriver by pulling it to either of the slots with a hand symbol, and then use it on the terminal by left clicking.");
while (Controlled.SelectedConstruction != steering.Item ||
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "screwdriver") == null)
Controlled.HeldItems.FirstOrDefault(i => i.Prefab.Identifier == "screwdriver") == null)
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
@@ -203,16 +203,16 @@ namespace Barotrauma.Tutorials
while ((Controlled.SelectedConstruction != junctionBox.Item &&
Controlled.SelectedConstruction != steering.Item) ||
Controlled.SelectedItems.FirstOrDefault(i => i != null && i.Prefab.Identifier == "screwdriver") == null)
!Controlled.HeldItems.Any(i => i.Prefab.Identifier == "screwdriver"))
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
if (Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent<Wire>() != null) == null)
if (!Controlled.HeldItems.Any(i => i.GetComponent<Wire>() != null))
{
infoBox = CreateInfoFrame("", "Equip the wire by dragging it to one of the slots with a hand symbol.");
while (Controlled.SelectedItems.FirstOrDefault(i => i != null && i.GetComponent<Wire>() != null) == null)
while (!Controlled.HeldItems.Any(i => i.GetComponent<Wire>() != null))
{
yield return Controlled.IsDead ? CoroutineStatus.Success : CoroutineStatus.Running;
}
@@ -501,7 +501,7 @@ namespace Barotrauma.Tutorials
do
{
var weldingTool = Controlled.Inventory.Items.FirstOrDefault(i => i != null && i.Prefab.Identifier == "weldingtool");
var weldingTool = Controlled.Inventory.FindItemByIdentifier("weldingtool");
if (weldingTool != null &&
weldingTool.ContainedItems.FirstOrDefault(contained => contained != null && contained.Prefab.Identifier == "weldingfueltank") != null) break;
@@ -661,7 +661,10 @@ namespace Barotrauma.Tutorials
//TODO: reimplement
//enemy.Health = 50.0f;
enemy.AIController.State = AIState.Idle;
if (enemy.AIController is EnemyAIController enemyAI)
{
enemyAI.State = AIState.Idle;
}
Vector2 targetPos = Character.Controlled.WorldPosition + new Vector2(0.0f, 3000.0f);

View File

@@ -101,7 +101,7 @@ namespace Barotrauma.Tutorials
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("medicaldoctor"));
captain_medic = Character.Create(medicInfo, captain_medicSpawnPos, "medicaldoctor");
captain_medic.TeamID = Character.TeamType.Team1;
captain_medic.TeamID = CharacterTeamType.Team1;
captain_medic.GiveJobItems(null);
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
@@ -124,17 +124,17 @@ namespace Barotrauma.Tutorials
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("mechanic"));
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "mechanic");
captain_mechanic.TeamID = Character.TeamType.Team1;
captain_mechanic.TeamID = CharacterTeamType.Team1;
captain_mechanic.GiveJobItems();
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("securityofficer"));
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "securityofficer");
captain_security.TeamID = Character.TeamType.Team1;
captain_security.TeamID = CharacterTeamType.Team1;
captain_security.GiveJobItems();
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer"));
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "engineer");
captain_engineer.TeamID = Character.TeamType.Team1;
captain_engineer.TeamID = CharacterTeamType.Team1;
captain_engineer.GiveJobItems();
captain_mechanic.CanSpeak = captain_security.CanSpeak = captain_engineer.CanSpeak = false;

View File

@@ -80,34 +80,34 @@ namespace Barotrauma.Tutorials
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("assistant"));
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
patient1.TeamID = Character.TeamType.Team1;
patient1.TeamID = CharacterTeamType.Team1;
patient1.GiveJobItems(null);
patient1.CanSpeak = false;
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 45.0f) }, stun: 0, playSound: false);
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, "", JobPrefab.Get("assistant"));
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
patient2.TeamID = Character.TeamType.Team1;
patient2.TeamID = CharacterTeamType.Team1;
patient2.GiveJobItems(null);
patient2.CanSpeak = false;
patient2.AIController.Enabled = false;
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer"));
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient1.TeamID = Character.TeamType.Team1;
subPatient1.TeamID = CharacterTeamType.Team1;
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, "", JobPrefab.Get("securityofficer"));
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient2.TeamID = Character.TeamType.Team1;
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, "", JobPrefab.Get("engineer"));
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "3");
subPatient3.TeamID = Character.TeamType.Team1;
subPatient3.TeamID = CharacterTeamType.Team1;
subPatient3.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient3);
@@ -200,18 +200,18 @@ namespace Barotrauma.Tutorials
do
{
for (int i = 0; i < doctor_suppliesCabinet.Inventory.Items.Length; i++)
for (int i = 0; i < doctor_suppliesCabinet.Inventory.Capacity; i++)
{
if (doctor_suppliesCabinet.Inventory.Items[i] != null)
if (doctor_suppliesCabinet.Inventory.GetItemAt(i) != null)
{
HighlightInventorySlot(doctor_suppliesCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_suppliesCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.slots.Length; i++)
for (int i = 0; i < doctor.Inventory.Capacity; i++)
{
if (doctor.Inventory.Items[i] == null) HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f);
if (doctor.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
yield return null;
@@ -309,16 +309,16 @@ namespace Barotrauma.Tutorials
{
for (int i = 0; i < 3; i++)
{
if (doctor_medBayCabinet.Inventory.Items[i] != null)
if (doctor_medBayCabinet.Inventory.GetItemAt(i) != null)
{
HighlightInventorySlot(doctor_medBayCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (doctor.SelectedConstruction == doctor_medBayCabinet.Item)
{
for (int i = 0; i < doctor.Inventory.slots.Length; i++)
for (int i = 0; i < doctor.Inventory.Capacity; i++)
{
if (doctor.Inventory.Items[i] == null) HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f);
if (doctor.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(doctor.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
yield return null;

View File

@@ -247,30 +247,30 @@ namespace Barotrauma.Tutorials
if (!firstSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[0] == null) firstSlotRemoved = true;
if (engineer_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
if (engineer_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
if (engineer_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
}
if (!fourthSlotRemoved)
{
HighlightInventorySlot(engineer_equipmentCabinet.Inventory, 3, highlightColor, .5f, .5f, 0f);
if (engineer_equipmentCabinet.Inventory.Items[2] == null) fourthSlotRemoved = true;
if (engineer_equipmentCabinet.Inventory.GetItemAt(2) == null) { fourthSlotRemoved = true; }
}
for (int i = 0; i < engineer.Inventory.slots.Length; i++)
for (int i = 0; i < engineer.Inventory.visualSlots.Length; i++)
{
if (engineer.Inventory.Items[i] == null) HighlightInventorySlot(engineer.Inventory, i, highlightColor, .5f, .5f, 0f);
if (engineer.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(engineer.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
@@ -299,12 +299,12 @@ namespace Barotrauma.Tutorials
} while (!engineer_reactor.PowerOn);
do
{
if (IsSelectedItem(engineer_reactor.Item) && engineer_reactor.Item.OwnInventory.slots != null)
if (IsSelectedItem(engineer_reactor.Item) && engineer_reactor.Item.OwnInventory.visualSlots != null)
{
engineer_reactor.AutoTemp = false;
HighlightInventorySlot(engineer.Inventory, "fuelrod", highlightColor, 0.5f, 0.5f, 0f);
for (int i = 0; i < engineer_reactor.Item.OwnInventory.slots.Length; i++)
for (int i = 0; i < engineer_reactor.Item.OwnInventory.visualSlots.Length; i++)
{
HighlightInventorySlot(engineer_reactor.Item.OwnInventory, i, highlightColor, 0.5f, 0.5f, 0f);
}

View File

@@ -165,21 +165,23 @@ namespace Barotrauma.Tutorials
// Room 6
mechanic_divingSuitObjectiveSensor = Item.ItemList.Find(i => i.HasTag("mechanic_divingsuitobjectivesensor")).GetComponent<MotionSensor>();
mechanic_divingSuitContainer = Item.ItemList.Find(i => i.HasTag("mechanic_divingsuitcontainer")).GetComponent<ItemContainer>();
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.Items.Length; i++)
foreach (Item item in mechanic_divingSuitContainer.Inventory.AllItems)
{
foreach (ItemComponent ic in mechanic_divingSuitContainer.Inventory.Items[i].Components)
{
ic.CanBePicked = true;
}
}
mechanic_oxygenContainer = Item.ItemList.Find(i => i.HasTag("mechanic_oxygencontainer")).GetComponent<ItemContainer>();
for (int i = 0; i < mechanic_oxygenContainer.Inventory.Items.Length; i++)
{
foreach (ItemComponent ic in mechanic_oxygenContainer.Inventory.Items[i].Components)
foreach (ItemComponent ic in item.Components)
{
ic.CanBePicked = true;
}
}
mechanic_oxygenContainer = Item.ItemList.Find(i => i.HasTag("mechanic_oxygencontainer")).GetComponent<ItemContainer>();
foreach (Item item in mechanic_oxygenContainer.Inventory.AllItems)
{
foreach (ItemComponent ic in item.Components)
{
ic.CanBePicked = true;
}
}
tutorial_mechanicFinalDoor = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoor")).GetComponent<Door>();
tutorial_mechanicFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_mechanicfinaldoorlight")).GetComponent<LightComponent>();
@@ -266,24 +268,24 @@ namespace Barotrauma.Tutorials
if (!firstSlotRemoved)
{
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
if (mechanic_equipmentCabinet.Inventory.Items[0] == null) firstSlotRemoved = true;
if (mechanic_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (mechanic_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
if (mechanic_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(mechanic_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (mechanic_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
if (mechanic_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
}
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
@@ -355,16 +357,16 @@ namespace Barotrauma.Tutorials
{
if (mechanic.SelectedConstruction == mechanic_craftingCabinet.Item)
{
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
if (mechanic.Inventory.FindItemByIdentifier("oxygentank") == null && mechanic.Inventory.FindItemByIdentifier("aluminium") == null)
{
for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
for (int i = 0; i < mechanic_craftingCabinet.Capacity; i++)
{
Item item = mechanic_craftingCabinet.Inventory.Items[i];
Item item = mechanic_craftingCabinet.Inventory.GetItemAt(i);
if (item != null && item.prefab.Identifier == "oxygentank")
{
HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
@@ -374,9 +376,9 @@ namespace Barotrauma.Tutorials
if (mechanic.Inventory.FindItemByIdentifier("sodium") == null)
{
for (int i = 0; i < mechanic_craftingCabinet.Inventory.Items.Length; i++)
for (int i = 0; i < mechanic_craftingCabinet.Inventory.Capacity; i++)
{
Item item = mechanic_craftingCabinet.Inventory.Items[i];
Item item = mechanic_craftingCabinet.Inventory.GetItemAt(i);
if (item != null && item.prefab.Identifier == "sodium")
{
HighlightInventorySlot(mechanic_craftingCabinet.Inventory, i, highlightColor, .5f, .5f, 0f);
@@ -408,9 +410,9 @@ namespace Barotrauma.Tutorials
{
HighlightInventorySlot(mechanic_deconstructor.OutputContainer.Inventory, "aluminium", highlightColor, .5f, .5f, 0f);
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
for (int i = 0; i < mechanic.Inventory.Capacity; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
if (mechanic.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
else
@@ -418,14 +420,10 @@ namespace Barotrauma.Tutorials
if (mechanic.Inventory.FindItemByIdentifier("oxygentank") != null && mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") == null)
{
HighlightInventorySlot(mechanic.Inventory, "oxygentank", highlightColor, .5f, .5f, 0f);
if (mechanic_deconstructor.InputContainer.Inventory.slots != null)
for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.Capacity; i++)
{
for (int i = 0; i < mechanic_deconstructor.InputContainer.Inventory.slots.Length; i++)
{
HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
HighlightInventorySlot(mechanic_deconstructor.InputContainer.Inventory, i, highlightColor, .5f, .5f, 0f);
}
}
if (mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") != null && !mechanic_deconstructor.IsActive)
@@ -461,7 +459,7 @@ namespace Barotrauma.Tutorials
{
HighlightInventorySlot(mechanic_fabricator.OutputContainer.Inventory, "extinguisher", highlightColor, .5f, .5f, 0f);
/*for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
/*for (int i = 0; i < mechanic.Inventory.Capacity; i++)
{
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
}*/
@@ -478,12 +476,12 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(mechanic.Inventory, "aluminium", highlightColor, .5f, .5f, 0f);
HighlightInventorySlot(mechanic.Inventory, "sodium", highlightColor, .5f, .5f, 0f);
if (mechanic_fabricator.InputContainer.Inventory.Items[0] == null)
if (mechanic_fabricator.InputContainer.Inventory.GetItemAt(0) == null)
{
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 0, highlightColor, .5f, .5f, 0f);
}
if (mechanic_fabricator.InputContainer.Inventory.Items[1] == null)
if (mechanic_fabricator.InputContainer.Inventory.GetItemAt(1) == null)
{
HighlightInventorySlot(mechanic_fabricator.InputContainer.Inventory, 1, highlightColor, .5f, .5f, 0f);
}
@@ -524,9 +522,9 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(mechanic_divingSuitContainer.Item))
{
if (mechanic_divingSuitContainer.Inventory.slots != null)
if (mechanic_divingSuitContainer.Inventory.visualSlots != null)
{
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.slots.Length; i++)
for (int i = 0; i < mechanic_divingSuitContainer.Inventory.Capacity; i++)
{
HighlightInventorySlot(mechanic_divingSuitContainer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}

View File

@@ -234,24 +234,24 @@ namespace Barotrauma.Tutorials
if (!firstSlotRemoved)
{
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 0, highlightColor, .5f, .5f, 0f);
if (officer_equipmentCabinet.Inventory.Items[0] == null) firstSlotRemoved = true;
if (officer_equipmentCabinet.Inventory.GetItemAt(0) == null) { firstSlotRemoved = true; }
}
if (!secondSlotRemoved)
{
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 1, highlightColor, .5f, .5f, 0f);
if (officer_equipmentCabinet.Inventory.Items[1] == null) secondSlotRemoved = true;
if (officer_equipmentCabinet.Inventory.GetItemAt(1) == null) { secondSlotRemoved = true; }
}
if (!thirdSlotRemoved)
{
HighlightInventorySlot(officer_equipmentCabinet.Inventory, 2, highlightColor, .5f, .5f, 0f);
if (officer_equipmentCabinet.Inventory.Items[2] == null) thirdSlotRemoved = true;
if (officer_equipmentCabinet.Inventory.GetItemAt(2) == null) { thirdSlotRemoved = true; }
}
for (int i = 0; i < officer.Inventory.slots.Length; i++)
for (int i = 0; i < officer.Inventory.visualSlots.Length; i++)
{
if (officer.Inventory.Items[i] == null) HighlightInventorySlot(officer.Inventory, i, highlightColor, .5f, .5f, 0f);
if (officer.Inventory.GetItemAt(i) == null) { HighlightInventorySlot(officer.Inventory, i, highlightColor, .5f, .5f, 0f); }
}
}
@@ -298,7 +298,7 @@ namespace Barotrauma.Tutorials
TriggerTutorialSegment(3); // Arm coilgun
do
{
SetHighlight(officer_coilgunLoader.Item, officer_coilgunLoader.Inventory.Items[0] == null || officer_coilgunLoader.Inventory.Items[0].Condition == 0);
SetHighlight(officer_coilgunLoader.Item, officer_coilgunLoader.Inventory.GetItemAt(0) == null || officer_coilgunLoader.Inventory.GetItemAt(0).Condition == 0);
HighlightInventorySlot(officer_coilgunLoader.Inventory, 0, highlightColor, .5f, .5f, 0f);
SetHighlight(officer_superCapacitor.Item, officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate);
SetHighlight(officer_ammoShelf_1.Item, officer_coilgunLoader.Item.ExternalHighlight );
@@ -308,7 +308,7 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(officer.Inventory, "coilgunammobox", highlightColor, .5f, .5f, 0f);
}
yield return null;
} while (officer_coilgunLoader.Inventory.Items[0] == null || officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate || officer_coilgunLoader.Inventory.Items[0].Condition == 0);
} while (officer_coilgunLoader.Inventory.GetItemAt(0) == null || officer_superCapacitor.RechargeSpeed < superCapacitorRechargeRate || officer_coilgunLoader.Inventory.GetItemAt(0).Condition == 0);
SetHighlight(officer_coilgunLoader.Item, false);
SetHighlight(officer_superCapacitor.Item, false);
SetHighlight(officer_ammoShelf_1.Item, false);
@@ -371,12 +371,11 @@ namespace Barotrauma.Tutorials
{
if (IsSelectedItem(officer_rangedWeaponCabinet.Item))
{
if (officer_rangedWeaponCabinet.Inventory.slots != null)
if (officer_rangedWeaponCabinet.Inventory.visualSlots != null)
{
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Items.Length; i++)
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Capacity; i++)
{
if (officer_rangedWeaponCabinet.Inventory.Items[i] == null) continue;
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
if (officer_rangedWeaponCabinet.Inventory.GetItemAt(i)?.Prefab.Identifier == "shotgunshell")
{
HighlightInventorySlot(officer_rangedWeaponCabinet.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
@@ -384,10 +383,9 @@ namespace Barotrauma.Tutorials
}
}
for (int i = 0; i < officer.Inventory.Items.Length; i++)
for (int i = 0; i < officer.Inventory.Capacity; i++)
{
if (officer.Inventory.Items[i] == null) continue;
if (officer.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
if (officer.Inventory.GetItemAt(i)?.Prefab.Identifier == "shotgunshell")
{
HighlightInventorySlot(officer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
}
@@ -398,7 +396,7 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(officer.Inventory, "shotgun", highlightColor, 0.5f, 0.5f, 0f);
}
yield return null;
} while (!shotGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
} while (!shotGunChamber.Inventory.IsFull(takeStacksIntoAccount: true)); // Wait until all six harpoons loaded
RemoveCompletedObjective(segments[5]);
SetHighlight(officer_rangedWeaponCabinet.Item, false);
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);
@@ -425,8 +423,8 @@ namespace Barotrauma.Tutorials
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.Submarine"), ChatMessageType.Radio, null);
do
{
SetHighlight(officer_subLoader_1.Item, officer_subLoader_1.Inventory.Items[0] == null || officer_subLoader_1.Inventory.Items[0].Condition == 0);
SetHighlight(officer_subLoader_2.Item, officer_subLoader_2.Inventory.Items[0] == null || officer_subLoader_2.Inventory.Items[0].Condition == 0);
SetHighlight(officer_subLoader_1.Item, officer_subLoader_1.Inventory.GetItemAt(0) == null || officer_subLoader_1.Inventory.GetItemAt(0).Condition == 0);
SetHighlight(officer_subLoader_2.Item, officer_subLoader_2.Inventory.GetItemAt(0) == null || officer_subLoader_2.Inventory.GetItemAt(0).Condition == 0);
HighlightInventorySlot(officer_subLoader_1.Inventory, 0, highlightColor, .5f, .5f, 0f);
HighlightInventorySlot(officer_subLoader_2.Inventory, 0, highlightColor, .5f, .5f, 0f);

View File

@@ -122,7 +122,7 @@ namespace Barotrauma.Tutorials
}
character = Character.Create(charInfo, wayPoint.WorldPosition, "", isRemotePlayer: false, hasAi: false);
character.TeamID = Character.TeamType.Team1;
character.TeamID = CharacterTeamType.Team1;
Character.Controlled = character;
character.GiveJobItems(null);

View File

@@ -264,7 +264,7 @@ namespace Barotrauma.Tutorials
protected virtual void TriggerTutorialSegment(int index, params object[] args)
{
Inventory.draggingItem = null;
Inventory.DraggingItems.Clear();
ContentRunning = true;
activeContentSegment = segments[index];
segments[index].Args = args;
@@ -410,7 +410,7 @@ namespace Barotrauma.Tutorials
private void ReplaySegmentVideo(TutorialSegment segment)
{
if (ContentRunning) return;
Inventory.draggingItem = null;
Inventory.DraggingItems.Clear();
ContentRunning = true;
LoadVideo(segment);
//videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false);
@@ -419,7 +419,7 @@ namespace Barotrauma.Tutorials
private void ShowSegmentText(TutorialSegment segment)
{
if (ContentRunning) return;
Inventory.draggingItem = null;
Inventory.DraggingItems.Clear();
ContentRunning = true;
string tutorialText = TextManager.GetFormatted(segment.TextContent.GetAttributeString("tag", ""), true, segment.Args);
@@ -609,10 +609,10 @@ namespace Barotrauma.Tutorials
#region Highlights
protected void HighlightInventorySlot(Inventory inventory, string identifier, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
if (inventory.slots == null) { return; }
for (int i = 0; i < inventory.Items.Length; i++)
if (inventory.visualSlots == null) { return; }
for (int i = 0; i < inventory.Capacity; i++)
{
if (inventory.Items[i] != null && inventory.Items[i].Prefab.Identifier == identifier)
if (inventory.GetItemAt(i)?.Prefab.Identifier == identifier)
{
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
@@ -621,10 +621,10 @@ namespace Barotrauma.Tutorials
protected void HighlightInventorySlotWithTag(Inventory inventory, string tag, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
if (inventory.slots == null) { return; }
for (int i = 0; i < inventory.Items.Length; i++)
if (inventory.visualSlots == null) { return; }
for (int i = 0; i < inventory.Capacity; i++)
{
if (inventory.Items[i] != null && inventory.Items[i].HasTag(tag))
if (inventory.GetItemAt(i)?.HasTag(tag) ?? false)
{
HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
@@ -633,8 +633,8 @@ namespace Barotrauma.Tutorials
protected void HighlightInventorySlot(Inventory inventory, int index, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount)
{
if (inventory.slots == null || index < 0 || inventory.slots[index].HighlightTimer > 0) return;
inventory.slots[index].ShowBorderHighlight(color, fadeInDuration, fadeOutDuration, scaleUpAmount);
if (inventory.visualSlots == null || index < 0 || inventory.visualSlots[index].HighlightTimer > 0) { return; }
inventory.visualSlots[index].ShowBorderHighlight(color, fadeInDuration, fadeOutDuration, scaleUpAmount);
}
#endregion
}

View File

@@ -33,6 +33,8 @@ namespace Barotrauma
public static DateTime lastReadyCheck = DateTime.MinValue;
public static bool IsReadyCheck(GUIComponent? msgBox) => msgBox?.UserData as string == PromptData || msgBox?.UserData as string == ResultData;
private void CreateMessageBox(string author)
{
Vector2 relativeSize = new Vector2(GUI.IsFourByThree() ? 0.3f : 0.2f, 0.15f);
@@ -120,7 +122,10 @@ namespace Barotrauma
int second = (int) Math.Ceiling(time);
if (second < lastSecond)
{
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
if (msgBox != null && !msgBox.Closed)
{
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
}
lastSecond = second;
}
}

View File

@@ -87,12 +87,12 @@ namespace Barotrauma
TextManager.Get("crew"), textAlignment: Alignment.TopLeft, font: GUI.SubHeadingFont);
crewHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader.Rect.Height * 2.0f));
CreateCrewList(crewContent, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID != Character.TeamType.Team2));
CreateCrewList(crewContent, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID != CharacterTeamType.Team2));
//another crew frame for the 2nd team in combat missions
if (gameSession.Mission is CombatMission)
{
crewHeader.Text = CombatMission.GetTeamName(Character.TeamType.Team1);
crewHeader.Text = CombatMission.GetTeamName(CharacterTeamType.Team1);
GUIFrame crewFrame2 = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.55f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
rightPanels.Add(crewFrame2);
GUIFrame crewFrameInner2 = new GUIFrame(new RectTransform(new Point(crewFrame2.Rect.Width - padding * 2, crewFrame2.Rect.Height - padding * 2), crewFrame2.RectTransform, Anchor.Center), style: "InnerFrame");
@@ -101,9 +101,9 @@ namespace Barotrauma
Stretch = true
};
var crewHeader2 = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), crewContent2.RectTransform),
CombatMission.GetTeamName(Character.TeamType.Team2), textAlignment: Alignment.TopLeft, font: GUI.SubHeadingFont);
CombatMission.GetTeamName(CharacterTeamType.Team2), textAlignment: Alignment.TopLeft, font: GUI.SubHeadingFont);
crewHeader2.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader2.Rect.Height * 2.0f));
CreateCrewList(crewContent2, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID == Character.TeamType.Team2));
CreateCrewList(crewContent2, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID == CharacterTeamType.Team2));
}
//header -------------------------------------------------------------------------------

View File

@@ -68,6 +68,9 @@ namespace Barotrauma
keyMapping[(int)InputType.PreviousFireMode] = new KeyOrMouse(MouseButton.MouseWheelDown);
keyMapping[(int)InputType.NextFireMode] = new KeyOrMouse(MouseButton.MouseWheelUp);
keyMapping[(int)InputType.TakeHalfFromInventorySlot] = new KeyOrMouse(Keys.LeftShift);
keyMapping[(int)InputType.TakeOneFromInventorySlot] = new KeyOrMouse(Keys.LeftControl);
if (Language == "French")
{
keyMapping[(int)InputType.Up] = new KeyOrMouse(Keys.Z);
@@ -173,6 +176,13 @@ namespace Barotrauma
{
foreach (XAttribute attribute in element.Attributes())
{
//backwards compatibility
if (attribute.Name.ToString() == "TakeAllFromInventorySlot")
{
keyMapping[(int)InputType.TakeHalfFromInventorySlot] = new KeyOrMouse(Keys.LeftShift);
keyMapping[(int)InputType.TakeOneFromInventorySlot] = new KeyOrMouse(Keys.LeftControl);
}
if (!Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType)) { continue; }
if (int.TryParse(attribute.Value.ToString(), out int mouseButtonInt))
@@ -223,6 +233,40 @@ namespace Barotrauma
{
LoadInventoryKeybinds(inventoryKeyMapping);
}
XElement debugConsoleMapping = doc.Root.Element("debugconsolemapping");
if (debugConsoleMapping == null) { return; }
ConsoleKeybinds.Clear();
DebugConsole.Keybinds.Clear();
foreach (XElement element in debugConsoleMapping.Elements())
{
string keyString = element.GetAttributeString("key", string.Empty);
string command = element.GetAttributeString("command", string.Empty);
if (string.IsNullOrWhiteSpace(keyString) || string.IsNullOrWhiteSpace(command)) { continue; }
if (Enum.TryParse(typeof(Keys), keyString, ignoreCase: true, out object @out) && @out is Keys key)
{
ConsoleKeybinds.TryAdd(key, command);
}
}
DebugConsole.Keybinds = new Dictionary<Keys, string>(ConsoleKeybinds);
}
private void LoadSubEditorImages(XDocument doc)
{
XElement element = doc.Root?.Element("editorimages");
if (element == null)
{
SubEditorScreen.ImageManager.Clear(alsoPending: true);
return;
}
SubEditorScreen.ImageManager.Load(element);
}
public KeyOrMouse KeyBind(InputType inputType)
@@ -242,7 +286,7 @@ namespace Barotrauma
private GUIListBox contentPackageList;
private bool ChangeSliderText(GUIScrollBar scrollBar, float barScroll)
private bool ChangeSliderText(GUIScrollBar scrollBar, float scale)
{
UnsavedSettings = true;
GUITextBlock text = scrollBar.UserData as GUITextBlock;
@@ -261,7 +305,7 @@ namespace Barotrauma
}
label = text.Text.Substring(0, index);
}
text.Text = label + " " + (int)(barScroll * 100) + "%";
text.Text = label + " " + (int)Math.Round(scale * 100) + "%";
return true;
}
@@ -705,6 +749,18 @@ namespace Barotrauma
}
};*/
new GUITickBox(new RectTransform(tickBoxScale, rightColumn.RectTransform), TextManager.Get("RadialDistortion"))
{
ToolTip = TextManager.Get("RadialDistortionToolTip"),
Selected = EnableRadialDistortion,
OnSelected = (tickBox) =>
{
EnableRadialDistortion = tickBox.Selected;
UnsavedSettings = true;
return true;
}
};
new GUITickBox(new RectTransform(tickBoxScale, rightColumn.RectTransform), TextManager.Get("ChromaticAberration"))
{
ToolTip = TextManager.Get("ChromaticAberrationToolTip"),
@@ -725,13 +781,12 @@ namespace Barotrauma
BarScroll = (HUDScale - MinHUDScale) / (MaxHUDScale - MinHUDScale),
OnMoved = (scrollBar, scroll) =>
{
ChangeSliderText(scrollBar, scroll);
HUDScale = MathHelper.Lerp(MinHUDScale, MaxHUDScale, scroll);
UnsavedSettings = true;
ChangeSliderText(scrollBar, HUDScale);
OnHUDScaleChanged?.Invoke();
return true;
},
Step = 0.05f
Step = 0.02f
};
HUDScaleScrollBar.OnMoved(HUDScaleScrollBar, HUDScaleScrollBar.BarScroll);
@@ -743,15 +798,31 @@ namespace Barotrauma
BarScroll = (InventoryScale - MinInventoryScale) / (MaxInventoryScale - MinInventoryScale),
OnMoved = (scrollBar, scroll) =>
{
ChangeSliderText(scrollBar, scroll);
InventoryScale = MathHelper.Lerp(MinInventoryScale, MaxInventoryScale, scroll);
UnsavedSettings = true;
ChangeSliderText(scrollBar, InventoryScale);
return true;
},
Step = 0.05f
Step = 0.02f
};
inventoryScaleScrollBar.OnMoved(inventoryScaleScrollBar, inventoryScaleScrollBar.BarScroll);
GUITextBlock textScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("TextScale"), font: GUI.SubHeadingFont);
GUIScrollBar textScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
style: "GUISlider", barSize: 0.1f)
{
UserData = textScaleText,
BarScroll = (TextScale - MinTextScale) / (MaxTextScale - MinTextScale),
OnMoved = (scrollBar, scroll) =>
{
TextScale = MathHelper.Lerp(MinTextScale, MaxTextScale, scroll);
textScaleDirty = true;
ChangeSliderText(scrollBar, TextScale);
return true;
},
Step = 0.01f
};
textScaleScrollBar.OnMoved(textScaleScrollBar, textScaleScrollBar.BarScroll);
/// Audio tab ----------------------------------------------------------------
var audioContent = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.97f), tabs[(int)Tab.Audio].RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
@@ -809,8 +880,7 @@ namespace Barotrauma
ChangeSliderText(scrollBar, scroll);
SoundVolume = scroll;
return true;
},
Step = 0.05f
}
};
soundScrollBar.OnMoved(soundScrollBar, soundScrollBar.BarScroll);
@@ -825,8 +895,7 @@ namespace Barotrauma
ChangeSliderText(scrollBar, scroll);
MusicVolume = scroll;
return true;
},
Step = 0.05f
}
};
musicScrollBar.OnMoved(musicScrollBar, musicScrollBar.BarScroll);
@@ -835,8 +904,7 @@ namespace Barotrauma
style: "GUISlider", barSize: 0.05f)
{
UserData = voiceChatVolumeText,
Range = new Vector2(0.0f, 2.0f),
Step = 0.05f
Range = new Vector2(0.0f, 2.0f)
};
voiceChatScrollBar.BarScrollValue = VoiceChatVolume;
voiceChatScrollBar.OnMoved = (scrollBar, scroll) =>
@@ -1014,6 +1082,19 @@ namespace Barotrauma
{
Visible = VoiceSetting != VoiceMode.Disabled
};
GUITickBox localVoiceByDefault = new GUITickBox(
new RectTransform(tickBoxScale, voiceActivityGroup.RectTransform), TextManager.Get("LocalVoiceByDefault"))
{
Visible = VoiceSetting == VoiceMode.Activity,
Selected = UseLocalVoiceByDefault,
ToolTip = TextManager.Get("LocalVoiceByDefaultTooltip"),
OnSelected = (tickBox) =>
{
UseLocalVoiceByDefault = tickBox.Selected;
UnsavedSettings = true;
return true;
}
};
GUITextBlock noiseGateText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), voiceActivityGroup.RectTransform), TextManager.Get("NoiseGateThreshold"), font: GUI.SubHeadingFont)
{
Visible = VoiceSetting == VoiceMode.Activity,
@@ -1140,6 +1221,7 @@ namespace Barotrauma
noiseGateText.Visible = (vMode == VoiceMode.Activity);
noiseGateSlider.Visible = (vMode == VoiceMode.Activity);
localVoiceByDefault.Visible = (vMode == VoiceMode.Activity);
voiceActivityGroup.Visible = (vMode != VoiceMode.Disabled);
voiceInputContainerHorizontal.Visible = (vMode == VoiceMode.PushToTalk);
UnsavedSettings = true;
@@ -1183,7 +1265,7 @@ namespace Barotrauma
AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll);
return true;
},
Step = 0.1f
Step = 0.01f
};
aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll);
@@ -1199,19 +1281,21 @@ namespace Barotrauma
}
};
var inputFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f), controlsLayoutGroup.RectTransform), isHorizontal: true)
{ Stretch = true, RelativeSpacing = 0.03f };
var controlListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.75f), controlsLayoutGroup.RectTransform));
var inputFrame = new GUILayoutGroup(new RectTransform(Vector2.One, controlListBox.Content.RectTransform), isHorizontal: true)
{ Stretch = true, RelativeSpacing = 0.01f };
var inputColumnLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), inputFrame.RectTransform))
{ Stretch = true, RelativeSpacing = 0.02f };
{ Stretch = true, RelativeSpacing = 0.005f };
var inputColumnRight = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), inputFrame.RectTransform))
{ Stretch = true, RelativeSpacing = 0.02f };
{ Stretch = true, RelativeSpacing = 0.005f };
var inputNames = Enum.GetValues(typeof(InputType));
var inputNameBlocks = new List<GUITextBlock>();
for (int i = 0; i < inputNames.Length; i++)
{
var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f),(i <= (inputNames.Length / 2.2f) ? inputColumnLeft : inputColumnRight).RectTransform))
var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f),(i <= (inputNames.Length / 2) ? inputColumnLeft : inputColumnRight).RectTransform))
{ Stretch = true, IsHorizontal = true, RelativeSpacing = 0.01f, Color = new Color(12, 14, 15, 215) };
var inputName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(100, 0) },
TextManager.Get("InputType." + ((InputType)i)), font: GUI.SmallFont) { ForceUpperCase = true };
@@ -1226,14 +1310,17 @@ namespace Barotrauma
{
keyBox.Text = ToolBox.LimitString(keyText, keyBox.Font, (int)(keyBox.Rect.Width - keyBox.Padding.X - keyBox.Padding.Z));
};
inputContainer.RectTransform.MinSize = keyBox.RectTransform.MinSize;
keyBox.OnSelected += KeyBoxSelected;
keyBox.SelectedColor = Color.Gold * 0.3f;
}
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), inputColumnRight.RectTransform, minSize: inputColumnRight.Children.First().RectTransform.MinSize), style: null);
for (int i = 0; i < inventoryHotkeyCount; i++)
{
var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), ((i + 1) <= inventoryHotkeyCount / 2 ? inputColumnLeft : inputColumnRight).RectTransform))
{ Stretch = true, IsHorizontal = true, RelativeSpacing = 0.01f, Color = new Color(12, 14, 15, 215) };
{ Stretch = true, IsHorizontal = true, RelativeSpacing = 0.01f, Color = new Color(12, 14, 15, 215), CanBeFocused = true };
var inputName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(100, 0) },
TextManager.GetWithVariable("inventoryslotkeybind", "[slotnumber]", (i + 1).ToString()), font: GUI.SmallFont)
{ ForceUpperCase = true };
@@ -1244,11 +1331,20 @@ namespace Barotrauma
UserData = i
};
keyBox.Text = ToolBox.LimitString(keyBox.Text, keyBox.Font, (int)(keyBox.Rect.Width - keyBox.Padding.X - keyBox.Padding.Z));
inputContainer.RectTransform.MinSize = keyBox.RectTransform.MinSize;
keyBox.OnSelected += InventoryKeyBoxSelected;
keyBox.SelectedColor = Color.Gold * 0.3f;
}
GUITextBlock.AutoScaleAndNormalize(inputNameBlocks);
inputNameBlocks.First().RectTransform.SizeChanged += () =>
{
GUITextBlock.AutoScaleAndNormalize(inputNameBlocks);
};
inputFrame.RectTransform.MinSize = new Point(0,
(int)Math.Max(
inputColumnLeft.Children.Sum(c => c.Rect.Height * (1.0f + inputColumnLeft.RelativeSpacing)),
inputColumnRight.Children.Sum(c => c.Rect.Height * (1.0f + inputColumnLeft.RelativeSpacing))));
var resetControlsArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.07f), controlsLayoutGroup.RectTransform), style: null);
var resetControlsHolder = new GUILayoutGroup(new RectTransform(new Vector2(buttonArea.RectTransform.RelativeSize.X / controlsLayoutGroup.RectTransform.RelativeSize.X / rightPanel.RectTransform.RelativeSize.X, 1.0f), resetControlsArea.RectTransform, Anchor.Center),
@@ -1597,7 +1693,7 @@ namespace Barotrauma
if (!EnabledRegularPackages.Contains(contentPackage)) { return; }
}
ContentPackage.SortContentPackages(cp => listBox.Content.GetChildIndex(listBox.Content.GetChildByUserData(cp)), true);
ContentPackage.SortContentPackages(cp => listBox.Content.GetChildIndex(listBox.Content.GetChildByUserData(cp)), true, this);
UnsavedSettings = true;
}
@@ -1616,7 +1712,9 @@ namespace Barotrauma
{
DisableRegularPackage(contentPackage);
}
ContentPackage.SortContentPackages(cp => contentPackageList.Content.GetChildIndex(contentPackageList.Content.GetChildByUserData(cp)), false, this);
UnsavedSettings = true;
return true;
}
@@ -1707,22 +1805,11 @@ namespace Barotrauma
SettingsFrame.Flash(GUI.Style.Green);
if (GameMain.WindowMode != GameMain.Config.WindowMode || GameMain.Config.GraphicsWidth != GameMain.GraphicsWidth || GameMain.Config.GraphicsHeight != GameMain.GraphicsHeight)
if (textScaleDirty || GameMain.WindowMode != GameMain.Config.WindowMode || GameMain.Config.GraphicsWidth != GameMain.GraphicsWidth || GameMain.Config.GraphicsHeight != GameMain.GraphicsHeight)
{
GameMain.Instance.ApplyGraphicsSettings();
textScaleDirty = false;
}
/*if (GameMain.GraphicsWidth != GameMain.Config.GraphicsWidth || GameMain.GraphicsHeight != GameMain.Config.GraphicsHeight)
{
#if OSX
if (GameMain.Config.WindowMode != WindowMode.BorderlessWindowed)
{
#endif
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredResolution"));
#if OSX
}
#endif
}*/
}
private bool ApplyClicked(GUIButton button, object userData)

View File

@@ -94,8 +94,8 @@ namespace Barotrauma
get { return personalSlotArea; }
}
private GUIImage[] indicators = new GUIImage[5];
private int[] indicatorIndexes = new int[5];
private readonly GUIImage[] indicators = new GUIImage[5];
private readonly int[] indicatorIndices = new int[5];
private Vector2 indicatorSpriteSize;
private GUILayoutGroup indicatorGroup;
@@ -117,11 +117,11 @@ namespace Barotrauma
indicators[3] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadwear");
indicators[4] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadphones");
indicatorIndexes[0] = FindLimbSlot(InvSlotType.OuterClothes);
indicatorIndexes[1] = FindLimbSlot(InvSlotType.Card);
indicatorIndexes[2] = FindLimbSlot(InvSlotType.InnerClothes);
indicatorIndexes[3] = FindLimbSlot(InvSlotType.Head);
indicatorIndexes[4] = FindLimbSlot(InvSlotType.Headset);
indicatorIndices[0] = FindLimbSlot(InvSlotType.OuterClothes);
indicatorIndices[1] = FindLimbSlot(InvSlotType.Card);
indicatorIndices[2] = FindLimbSlot(InvSlotType.InnerClothes);
indicatorIndices[3] = FindLimbSlot(InvSlotType.Head);
indicatorIndices[4] = FindLimbSlot(InvSlotType.Headset);
for (int i = 0; i < indicators.Length; i++)
{
@@ -143,7 +143,7 @@ namespace Barotrauma
protected override ItemInventory GetActiveEquippedSubInventory(int slotIndex)
{
var item = Items[slotIndex];
Item item = slots[slotIndex].FirstOrDefault();
if (item == null) { return null; }
var container = item.GetComponent<ItemContainer>();
@@ -162,38 +162,35 @@ namespace Barotrauma
public override void RemoveItem(Item item)
{
if (!Items.Contains(item)) { return; }
if (!Contains(item)) { return; }
base.RemoveItem(item);
CreateSlots();
}
public override void CreateSlots()
{
if (slots == null) { slots = new InventorySlot[capacity]; }
if (visualSlots == null) { visualSlots = new VisualSlot[capacity]; }
float multiplier = !GUI.IsFourByThree() ? UIScale : UIScale * 0.925f;
for (int i = 0; i < capacity; i++)
{
InventorySlot prevSlot = slots[i];
VisualSlot prevSlot = visualSlots[i];
Sprite slotSprite = SlotSpriteSmall;
Rectangle slotRect = new Rectangle(
(int)(SlotPositions[i].X),
(int)(SlotPositions[i].Y),
(int)SlotPositions[i].X,
(int)SlotPositions[i].Y,
(int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));
if (Items[i] != null)
ItemContainer itemContainer = slots[i].FirstOrDefault()?.GetComponent<ItemContainer>();
if (itemContainer != null)
{
ItemContainer itemContainer = Items[i].GetComponent<ItemContainer>();
if (itemContainer != null)
{
if (itemContainer.InventoryTopSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryTopSprite.size.X * UIScale));
if (itemContainer.InventoryBottomSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryBottomSprite.size.X * UIScale));
}
}
if (itemContainer.InventoryTopSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryTopSprite.size.X * UIScale));
if (itemContainer.InventoryBottomSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryBottomSprite.size.X * UIScale));
}
slots[i] = new InventorySlot(slotRect)
visualSlots[i] = new VisualSlot(slotRect)
{
SubInventoryDir = Math.Sign(GameMain.GraphicsHeight / 2 - slotRect.Center.Y),
Disabled = false,
@@ -202,13 +199,13 @@ namespace Barotrauma
};
if (prevSlot != null)
{
slots[i].DrawOffset = prevSlot.DrawOffset;
slots[i].Color = prevSlot.Color;
visualSlots[i].DrawOffset = prevSlot.DrawOffset;
visualSlots[i].Color = prevSlot.Color;
prevSlot.MoveBorderHighlight(visualSlots[i]);
}
if (selectedSlot?.ParentInventory == this && selectedSlot.SlotIndex == i)
{
selectedSlot = new SlotReference(this, slots[i], i, selectedSlot.IsSubSlot, selectedSlot.Inventory);
selectedSlot = new SlotReference(this, visualSlots[i], i, selectedSlot.IsSubSlot, selectedSlot.Inventory);
}
}
@@ -217,9 +214,9 @@ namespace Barotrauma
highlightedSubInventorySlots.RemoveWhere(s => s.Inventory.OpenState <= 0.0f);
foreach (var subSlot in highlightedSubInventorySlots)
{
if (subSlot.ParentInventory == this && subSlot.SlotIndex > 0 && subSlot.SlotIndex < slots.Length)
if (subSlot.ParentInventory == this && subSlot.SlotIndex > 0 && subSlot.SlotIndex < visualSlots.Length)
{
subSlot.Slot = slots[subSlot.SlotIndex];
subSlot.Slot = visualSlots[subSlot.SlotIndex];
}
}
@@ -235,10 +232,10 @@ namespace Barotrauma
if (HideSlot(i)) continue;
if (frame == Rectangle.Empty)
{
frame = slots[i].Rect;
frame = visualSlots[i].Rect;
continue;
}
frame = Rectangle.Union(frame, slots[i].Rect);
frame = Rectangle.Union(frame, visualSlots[i].Rect);
}
frame.Inflate(10, 30);
frame.Location -= new Point(0, 25);
@@ -247,26 +244,25 @@ namespace Barotrauma
protected override bool HideSlot(int i)
{
if (slots[i].Disabled || (hideEmptySlot[i] && Items[i] == null)) return true;
if (visualSlots[i].Disabled || (slots[i].HideIfEmpty && slots[i].Empty())) { return true; }
if (layout == Layout.Default)
{
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(slots[i].Rect.Center + slots[i].DrawOffset.ToPoint())) return true;
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(visualSlots[i].Rect.Center + visualSlots[i].DrawOffset.ToPoint())) { return true; }
}
Item item = slots[i].FirstOrDefault();
//no need to draw the right hand slot if the item is in both hands
if (Items[i] != null && SlotTypes[i] == InvSlotType.RightHand && IsInLimbSlot(Items[i], InvSlotType.LeftHand))
if (item != null && SlotTypes[i] == InvSlotType.RightHand && IsInLimbSlot(item, InvSlotType.LeftHand))
{
return true;
}
//don't show the equip slot if the item is also in the default inventory
if (SlotTypes[i] != InvSlotType.Any && Items[i] != null)
//don't show the limb-specific slot if the item is also in an Any slot
if (item != null && SlotTypes[i] != InvSlotType.Any)
{
for (int j = 0; j < capacity; j++)
{
if (SlotTypes[j] == InvSlotType.Any && Items[j] == Items[i]) return true;
}
if (IsInLimbSlot(item, InvSlotType.Any)) { return true; }
}
return false;
@@ -308,7 +304,8 @@ namespace Barotrauma
SlotSize = !isFourByThree ? (SlotSpriteSmall.size * UIScale).ToPoint() : (SlotSpriteSmall.size * UIScale * .925f).ToPoint();
int bottomOffset = SlotSize.Y + Spacing * 2 + ContainedIndicatorHeight;
if (slots == null) { CreateSlots(); }
if (visualSlots == null) { CreateSlots(); }
if (visualSlots.None()) { return; }
hideButton.Visible = false;
@@ -359,7 +356,7 @@ namespace Barotrauma
{
int x = HUDLayoutSettings.InventoryAreaLower.Right;
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
for (int i = 0; i < slots.Length; i++)
for (int i = 0; i < visualSlots.Length; i++)
{
if (HideSlot(i)) continue;
if (PersonalSlots.HasFlag(SlotTypes[i]))
@@ -380,12 +377,12 @@ namespace Barotrauma
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
personalSlotX -= slots[i].Rect.Width + Spacing;
personalSlotX -= visualSlots[i].Rect.Width + Spacing;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + Spacing;
x += visualSlots[i].Rect.Width + Spacing;
}
}
@@ -393,7 +390,7 @@ namespace Barotrauma
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
x -= slots[i].Rect.Width + Spacing;
x -= visualSlots[i].Rect.Width + Spacing;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
}
}
@@ -410,19 +407,19 @@ namespace Barotrauma
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
personalSlotX += slots[i].Rect.Width + Spacing;
personalSlotX += visualSlots[i].Rect.Width + Spacing;
}
else
{
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + Spacing;
x += visualSlots[i].Rect.Width + Spacing;
}
}
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += slots[i].Rect.Width + Spacing;
x += visualSlots[i].Rect.Width + Spacing;
}
}
break;
@@ -438,10 +435,10 @@ namespace Barotrauma
if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
x += slots[i].Rect.Width + Spacing;
x += visualSlots[i].Rect.Width + Spacing;
}
}
y += slots[0].Rect.Height + Spacing + ContainedIndicatorHeight + slots[0].EquipButtonRect.Height;
y += visualSlots[0].Rect.Height + Spacing + ContainedIndicatorHeight + visualSlots[0].EquipButtonRect.Height;
x = startX;
int n = 0;
for (int i = 0; i < SlotPositions.Length; i++)
@@ -450,12 +447,12 @@ namespace Barotrauma
if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
x += slots[i].Rect.Width + Spacing;
x += visualSlots[i].Rect.Width + Spacing;
n++;
if (n >= columns)
{
x = startX;
y += slots[i].Rect.Height + Spacing + ContainedIndicatorHeight + slots[i].EquipButtonRect.Height;
y += visualSlots[i].Rect.Height + Spacing + ContainedIndicatorHeight + visualSlots[i].EquipButtonRect.Height;
n = 0;
}
}
@@ -467,7 +464,7 @@ namespace Barotrauma
CreateSlots();
if (layout == Layout.Default)
{
HUDLayoutSettings.InventoryTopY = slots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
}
}
@@ -484,7 +481,8 @@ namespace Barotrauma
public override void Update(float deltaTime, Camera cam, bool isSubInventory = false)
{
if (!AccessibleWhenAlive && !character.IsDead)
// Need to update the infiltrator's inventory because they use id cards to access the sub. TODO: We don't probably need to update everything.
if (!AccessibleWhenAlive && !character.IsDead && (character.Params.AI == null || !character.Params.AI.Infiltrate))
{
syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
return;
@@ -493,7 +491,7 @@ namespace Barotrauma
base.Update(deltaTime, cam);
bool hoverOnInventory = GUI.MouseOn == null &&
((selectedSlot != null && selectedSlot.IsSubSlot) || (draggingItem != null && (draggingSlot == null || !draggingSlot.MouseOn())));
((selectedSlot != null && selectedSlot.IsSubSlot) || (DraggingItems.Any() && (DraggingSlot == null || !DraggingSlot.MouseOn())));
if (CharacterHealth.OpenHealthWindow != null) hoverOnInventory = true;
if (layout == Layout.Default && (Screen.Selected != GameMain.SubEditorScreen || Screen.Selected is SubEditorScreen editor && editor.WiringMode))
@@ -508,16 +506,16 @@ namespace Barotrauma
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
bool personalSlotsMoving = hidePersonalSlotsState > 0 && hidePersonalSlotsState < 1f;
for (int i = 0; i < slots.Length; i++)
for (int i = 0; i < visualSlots.Length; i++)
{
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
if (HidePersonalSlots)
{
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
if (selectedSlot?.Slot == visualSlots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == visualSlots[i]);
}
slots[i].IsMoving = personalSlotsMoving;
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
visualSlots[i].IsMoving = personalSlotsMoving;
visualSlots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
}
}
}
@@ -530,13 +528,15 @@ namespace Barotrauma
//force personal slots open if an item is running out of battery/fuel/oxygen/etc
if (hidePersonalSlots)
{
for (int i = 0; i < slots.Length; i++)
for (int i = 0; i < visualSlots.Length; i++)
{
if (Items[i]?.OwnInventory != null && Items[i].OwnInventory.Capacity == 1 && PersonalSlots.HasFlag(SlotTypes[i]))
var item = slots[i].FirstOrDefault();
if (item?.OwnInventory != null && item.OwnInventory.Capacity == 1 && PersonalSlots.HasFlag(SlotTypes[i]))
{
if (Items[i].OwnInventory.Items[0] != null &&
Items[i].OwnInventory.Items[0].Condition > 0.0f &&
Items[i].OwnInventory.Items[0].Condition / Items[i].OwnInventory.Items[0].MaxCondition < 0.15f)
var containedItem = item.OwnInventory.AllItems.FirstOrDefault();
if (containedItem != null &&
containedItem.Condition > 0.0f &&
containedItem.Condition / containedItem.MaxCondition < 0.15f)
{
hidePersonalSlots = false;
}
@@ -547,7 +547,7 @@ namespace Barotrauma
List<SlotReference> hideSubInventories = new List<SlotReference>();
highlightedSubInventorySlots.RemoveWhere(s =>
s.ParentInventory == this &&
((s.SlotIndex < 0 || s.SlotIndex >= Items.Length || Items[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
((s.SlotIndex < 0 || s.SlotIndex >= slots.Length || slots[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
{
if (highlightedSubInventorySlot.ParentInventory == this)
@@ -558,7 +558,7 @@ namespace Barotrauma
if (!highlightedSubInventorySlot.Inventory.IsInventoryHoverAvailable(character, null)) continue;
Rectangle hoverArea = GetSubInventoryHoverArea(highlightedSubInventorySlot);
if (highlightedSubInventorySlot.Inventory?.slots == null || (!hoverArea.Contains(PlayerInput.MousePosition)))
if (highlightedSubInventorySlot.Inventory?.visualSlots == null || (!hoverArea.Contains(PlayerInput.MousePosition)))
{
hideSubInventories.Add(highlightedSubInventorySlot);
}
@@ -585,19 +585,19 @@ namespace Barotrauma
// In sub editor we cannot hover over the slot because they are not rendered so we override it here
if (Screen.Selected is SubEditorScreen subEditor && !subEditor.WiringMode)
{
for (int i = 0; i < slots.Length; i++)
for (int i = 0; i < visualSlots.Length; i++)
{
var subInventory = GetSubInventory(i);
if (subInventory != null)
{
ShowSubInventory(new SlotReference(this, slots[i], i, false, Items[i].GetComponent<ItemContainer>().Inventory), deltaTime, cam, hideSubInventories, true);
ShowSubInventory(new SlotReference(this, visualSlots[i], i, false, subInventory), deltaTime, cam, hideSubInventories, true);
}
}
}
foreach (var subInventorySlot in hideSubInventories)
{
if (subInventorySlot.Inventory == null) continue;
if (subInventorySlot.Inventory == null) { continue; }
subInventorySlot.Inventory.HideTimer -= deltaTime;
if (subInventorySlot.Inventory.HideTimer < 0.25f)
{
@@ -614,10 +614,10 @@ namespace Barotrauma
for (int i = 0; i < capacity; i++)
{
var item = Items[i];
var item = slots[i].FirstOrDefault();
if (item != null)
{
if (HideSlot(i)) continue;
if (HideSlot(i)) { continue; }
if (character.HasEquippedItem(item)) // Keep a subinventory display open permanently when the container is equipped
{
var itemContainer = item.GetComponent<ItemContainer>();
@@ -626,24 +626,32 @@ namespace Barotrauma
character.CanAccessInventory(itemContainer.Inventory) &&
!highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory))
{
ShowSubInventory(new SlotReference(this, slots[i], i, false, itemContainer.Inventory), deltaTime, cam, hideSubInventories, true);
ShowSubInventory(new SlotReference(this, visualSlots[i], i, false, itemContainer.Inventory), deltaTime, cam, hideSubInventories, true);
}
}
}
}
}
if (doubleClickedItem != null)
if (doubleClickedItems.Any())
{
QuickUseItem(doubleClickedItem, true, true, true);
var quickUseAction = GetQuickUseAction(doubleClickedItems.First(), true, true, true);
foreach (Item doubleClickedItem in doubleClickedItems)
{
QuickUseItem(doubleClickedItem, true, true, true, quickUseAction, playSound: doubleClickedItem == doubleClickedItems.First());
if (quickUseAction == QuickUseAction.Equip || quickUseAction == QuickUseAction.UseTreatment)
{
break;
}
}
}
for (int i = 0; i < capacity; i++)
{
var item = Items[i];
var item = slots[i].FirstOrDefault();
if (item != null)
{
var slot = slots[i];
var slot = visualSlots[i];
if (item.AllowedSlots.Any(a => a != InvSlotType.Any))
{
HandleButtonEquipStates(item, slot, deltaTime);
@@ -652,10 +660,10 @@ namespace Barotrauma
}
//cancel dragging if too far away from the container of the dragged item
if (draggingItem != null)
if (DraggingItems.Any())
{
var rootContainer = draggingItem.GetRootContainer();
var rootInventory = draggingItem.ParentInventory;
var rootContainer = DraggingItems.First().GetRootContainer();
var rootInventory = DraggingItems.First().ParentInventory;
if (rootContainer != null)
{
@@ -673,27 +681,39 @@ namespace Barotrauma
Character.Controlled.SelectedConstruction != null &&
rootContainer.linkedTo.Contains(Character.Controlled.SelectedConstruction)))
{
draggingItem = null;
DraggingItems.Clear();
}
}
}
doubleClickedItem = null;
doubleClickedItems.Clear();
}
public void UpdateSlotInput()
{
for (int i = 0; i < capacity; i++)
{
if (Items[i] != null && Items[i] != draggingItem && Character.Controlled?.Inventory == this &&
GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen && PlayerInput.InventoryKeyHit(slots[i].InventoryKeyIndex))
var firstItem = slots[i].FirstOrDefault();
if (firstItem != null && !DraggingItems.Contains(firstItem) && Character.Controlled?.Inventory == this &&
GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen && PlayerInput.InventoryKeyHit(visualSlots[i].InventoryKeyIndex))
{
QuickUseItem(Items[i], true, false, true);
#if LINUX
// some window managers on Linux use windows key + number to change workspaces or perform other actions
if (PlayerInput.KeyDown(Keys.RightWindows) || PlayerInput.KeyDown(Keys.LeftWindows)) { continue; }
#endif
var quickUseAction = GetQuickUseAction(firstItem, true, false, true);
foreach (Item itemToUse in slots[i].Items.ToList())
{
QuickUseItem(itemToUse, true, true, true, quickUseAction, playSound: itemToUse == firstItem);
if (quickUseAction == QuickUseAction.Equip || quickUseAction == QuickUseAction.UseTreatment)
{
break;
}
}
}
}
}
private void HandleButtonEquipStates(Item item, InventorySlot slot, float deltaTime)
private void HandleButtonEquipStates(Item item, VisualSlot slot, float deltaTime)
{
slot.EquipButtonState = slot.EquipButtonRect.Contains(PlayerInput.MousePosition) ?
GUIComponent.ComponentState.Hover : GUIComponent.ComponentState.None;
@@ -713,7 +733,7 @@ namespace Barotrauma
if (quickUseAction != QuickUseAction.Drop)
{
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.SelectedItems.FirstOrDefault(i => i != null)?.Name);
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", item?.Name);
if (PlayerInput.PrimaryMouseButtonDown()) { slot.EquipButtonState = GUIComponent.ComponentState.Pressed; }
if (PlayerInput.PrimaryMouseButtonClicked())
{
@@ -726,8 +746,8 @@ namespace Barotrauma
{
for (int i = 0; i < indicators.Length; i++)
{
if (indicatorIndexes[i] < 0) { continue; }
Item item = Items[indicatorIndexes[i]];
if (indicatorIndices[i] < 0) { continue; }
Item item = slots[indicatorIndices[i]].FirstOrDefault();
if (item != null)
{
Wearable wearable = item.GetComponent<Wearable>();
@@ -795,12 +815,12 @@ namespace Barotrauma
public void AssignQuickUseNumKeys()
{
int keyBindIndex = 0;
for (int i = 0; i < slots.Length; i++)
for (int i = 0; i < visualSlots.Length; i++)
{
if (HideSlot(i)) continue;
if (SlotTypes[i] == InvSlotType.Any)
{
slots[i].InventoryKeyIndex = keyBindIndex;
visualSlots[i].InventoryKeyIndex = keyBindIndex;
keyBindIndex++;
}
}
@@ -824,7 +844,7 @@ namespace Barotrauma
{
if (item.Container == null || character.Inventory.FindIndex(item.Container) == -1) // Not a subinventory in the character's inventory
{
if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)))
if (character.HeldItems.Any(i => i.OwnInventory != null && i.OwnInventory.CanBePut(item)))
{
return QuickUseAction.PutToEquippedItem;
}
@@ -875,7 +895,7 @@ namespace Barotrauma
{
return QuickUseAction.TakeFromCharacter;
}
else if (character.SelectedItems.Any(i => i?.OwnInventory != null && i.OwnInventory.CanBePut(item)) && allowInventorySwap)
else if (character.HeldItems.Any(i => i.OwnInventory != null && i.OwnInventory.CanBePut(item)) && allowInventorySwap)
{
return QuickUseAction.PutToEquippedItem;
}
@@ -901,23 +921,20 @@ namespace Barotrauma
return QuickUseAction.None;
}
private void QuickUseItem(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
private void QuickUseItem(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment, QuickUseAction? action = null, bool playSound = true)
{
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && !Submarine.Unloading)
{
// Find the slot the item was contained in and flash it
if (item.ParentInventory?.slots != null)
if (item.ParentInventory?.visualSlots != null)
{
var invSlots = item.ParentInventory.slots;
var invItems = item.ParentInventory.Items;
var invSlots = item.ParentInventory.visualSlots;
for (int i = 0; i < invSlots.Length; i++)
{
if (i < 0 || invSlots.Length <= i || i < 0 || invItems.Length <= i) { break; }
if (i < 0 || invSlots.Length <= i || i < 0 || item.ParentInventory.Capacity <= i) { break; }
var slot = invSlots[i];
var slotItem = invItems[i];
if (slotItem == item)
if (item.ParentInventory.GetItemAt(i) == item)
{
slot.ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.4f);
SoundPlayer.PlayUISound(GUISoundType.PickItem);
@@ -931,8 +948,8 @@ namespace Barotrauma
item.Remove();
return;
}
var quickUseAction = GetQuickUseAction(item, allowEquip, allowInventorySwap, allowApplyTreatment);
QuickUseAction quickUseAction = action ?? GetQuickUseAction(item, allowEquip, allowInventorySwap, allowApplyTreatment);
bool success = false;
switch (quickUseAction)
{
@@ -963,7 +980,7 @@ namespace Barotrauma
//attempt to put in a free slot first
for (int i = capacity - 1; i >= 0; i--)
{
if (Items[i] != null) { continue; }
if (!slots[i].Empty()) { continue; }
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
success = TryPutItem(item, i, true, false, Character.Controlled, true);
if (success) { break; }
@@ -975,9 +992,10 @@ namespace Barotrauma
{
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
// something else already equipped in a hand slot, attempt to unequip it so items aren't unnecessarily swapped to it
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any) && (SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand))
if (!slots[i].Empty() && slots[i].First().AllowedSlots.Contains(InvSlotType.Any) &&
(SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand))
{
TryPutItem(Items[i], Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
TryPutItem(slots[i].First(), Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
}
success = TryPutItem(item, i, true, false, Character.Controlled, true);
if (success) { break; }
@@ -1040,15 +1058,15 @@ namespace Barotrauma
}
break;
case QuickUseAction.PutToEquippedItem:
for (int i = 0; i < character.SelectedItems.Length; i++)
foreach (Item heldItem in character.HeldItems)
{
if (character.SelectedItems[i]?.OwnInventory != null &&
character.SelectedItems[i].OwnInventory.TryPutItem(item, Character.Controlled))
if (heldItem.OwnInventory != null &&
heldItem.OwnInventory.TryPutItem(item, Character.Controlled))
{
success = true;
for (int j = 0; j < capacity; j++)
{
if (Items[j] == character.SelectedItems[i]) slots[j].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f);
if (slots[j].Contains(heldItem)) { visualSlots[j].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f); }
}
break;
}
@@ -1060,18 +1078,21 @@ namespace Barotrauma
{
for (int i = 0; i < capacity; i++)
{
if (Items[i] == item) slots[i].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f);
if (slots[i].Contains(item)) { visualSlots[i].ShowBorderHighlight(GUI.Style.Green, 0.1f, 0.4f); }
}
}
draggingItem = null;
SoundPlayer.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
DraggingItems.Clear();
if (playSound)
{
SoundPlayer.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
}
}
public void DrawOwn(SpriteBatch spriteBatch)
{
if (!AccessibleWhenAlive && !character.IsDead) { return; }
if (slots == null) { CreateSlots(); }
if (visualSlots == null) { CreateSlots(); }
if (GameMain.GraphicsWidth != screenResolution.X ||
GameMain.GraphicsHeight != screenResolution.Y ||
prevUIScale != UIScale ||
@@ -1096,12 +1117,10 @@ namespace Barotrauma
{
if (HideSlot(i)) { continue; }
Rectangle interactRect = slots[i].InteractRect;
interactRect.Location += slots[i].DrawOffset.ToPoint();
//don't draw the item if it's being dragged out of the slot
bool drawItem = draggingItem == null || draggingItem != Items[i] || interactRect.Contains(PlayerInput.MousePosition);
DrawSlot(spriteBatch, this, slots[i], Items[i], i, drawItem, SlotTypes[i]);
bool drawItem = !DraggingItems.Any() || !slots[i].Items.All(it => DraggingItems.Contains(it)) || visualSlots[i].MouseOn();
DrawSlot(spriteBatch, this, visualSlots[i], slots[i].FirstOrDefault(), i, drawItem, SlotTypes[i]);
}
if (hideButton != null && hideButton.Visible && !Locked)
@@ -1109,48 +1128,48 @@ namespace Barotrauma
hideButton.DrawManually(spriteBatch, alsoChildren: true);
}
InventorySlot highlightedQuickUseSlot = null;
VisualSlot highlightedQuickUseSlot = null;
Rectangle inventoryArea = Rectangle.Empty;
for (int i = 0; i < capacity; i++)
{
if (HideSlot(i)) { continue; }
inventoryArea = inventoryArea == Rectangle.Empty ? slots[i].InteractRect : Rectangle.Union(inventoryArea, slots[i].InteractRect);
inventoryArea = inventoryArea == Rectangle.Empty ? visualSlots[i].InteractRect : Rectangle.Union(inventoryArea, visualSlots[i].InteractRect);
if (Items[i] == null ||
(draggingItem == Items[i] && !slots[i].InteractRect.Contains(PlayerInput.MousePosition)) ||
!Items[i].AllowedSlots.Any(a => a != InvSlotType.Any))
if (slots[i].Empty() ||
(DraggingItems.Any(it => slots[i].Contains(it)) && !visualSlots[i].InteractRect.Contains(PlayerInput.MousePosition)) ||
!slots[i].First().AllowedSlots.Any(a => a != InvSlotType.Any))
{
//draw limb icons on empty slots
if (LimbSlotIcons.ContainsKey(SlotTypes[i]))
{
var icon = LimbSlotIcons[SlotTypes[i]];
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUI.Style.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
icon.Draw(spriteBatch, visualSlots[i].Rect.Center.ToVector2() + visualSlots[i].DrawOffset, GUI.Style.EquipmentSlotIconColor, origin: icon.size / 2, scale: visualSlots[i].Rect.Width / icon.size.X);
}
continue;
}
if (draggingItem == Items[i] && !slots[i].IsHighlighted) { continue; }
if (DraggingItems.Any(it => slots[i].Contains(it)) && !visualSlots[i].IsHighlighted) { continue; }
//draw hand icons if the item is equipped in a hand slot
if (IsInLimbSlot(Items[i], InvSlotType.LeftHand))
if (IsInLimbSlot(slots[i].First(), InvSlotType.LeftHand))
{
var icon = LimbSlotIcons[InvSlotType.LeftHand];
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.X, slots[i].Rect.Bottom) + slots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
icon.Draw(spriteBatch, new Vector2(visualSlots[i].Rect.X, visualSlots[i].Rect.Bottom) + visualSlots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: visualSlots[i].Rect.Width / icon.size.X * 0.7f);
}
if (IsInLimbSlot(Items[i], InvSlotType.RightHand))
if (IsInLimbSlot(slots[i].First(), InvSlotType.RightHand))
{
var icon = LimbSlotIcons[InvSlotType.RightHand];
icon.Draw(spriteBatch, new Vector2(slots[i].Rect.Right, slots[i].Rect.Bottom) + slots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: slots[i].Rect.Width / icon.size.X * 0.7f);
icon.Draw(spriteBatch, new Vector2(visualSlots[i].Rect.Right, visualSlots[i].Rect.Bottom) + visualSlots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: visualSlots[i].Rect.Width / icon.size.X * 0.7f);
}
GUIComponent.ComponentState state = slots[i].EquipButtonState;
GUIComponent.ComponentState state = visualSlots[i].EquipButtonState;
if (state == GUIComponent.ComponentState.Hover)
{
highlightedQuickUseSlot = slots[i];
highlightedQuickUseSlot = visualSlots[i];
}
if (!Items[i].AllowedSlots.Any(a => a == InvSlotType.Any))
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any))
{
continue;
}
@@ -1161,20 +1180,20 @@ namespace Barotrauma
color *= 0.5f;
}
if (character.HasEquippedItem(Items[i]))
if (character.HasEquippedItem(slots[i].First()))
{
switch (state)
{
case GUIComponent.ComponentState.None:
EquippedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
EquippedIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Hover:
EquippedHoverIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
EquippedHoverIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Pressed:
case GUIComponent.ComponentState.Selected:
case GUIComponent.ComponentState.HoverSelected:
EquippedClickedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
EquippedClickedIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
}
}
@@ -1183,15 +1202,15 @@ namespace Barotrauma
switch (state)
{
case GUIComponent.ComponentState.None:
UnequippedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
UnequippedIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Hover:
UnequippedHoverIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
UnequippedHoverIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
case GUIComponent.ComponentState.Pressed:
case GUIComponent.ComponentState.Selected:
case GUIComponent.ComponentState.HoverSelected:
UnequippedClickedIndicator.Draw(spriteBatch, slots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
UnequippedClickedIndicator.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, UIScale * IndicatorScaleAdjustment);
break;
}
}

View File

@@ -12,16 +12,14 @@ namespace Barotrauma.Items.Components
get { return item.Rect.Size.ToVector2(); }
}
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (!IsActive || picker == null || !CanBeAttached(picker) || !picker.IsKeyDown(InputType.Aim) || picker != Character.Controlled)
if (!IsActive || picker == null || !CanBeAttached(picker) || !picker.IsKeyDown(InputType.Aim) || picker != Character.Controlled)
{
Drawable = false;
return;
return;
}
Vector2 gridPos = picker.Position;
Vector2 roundedGridPos = new Vector2(
MathUtils.RoundTowardsClosest(picker.Position.X, Submarine.GridSize.X),
@@ -49,7 +47,7 @@ namespace Barotrauma.Items.Components
attachPos += item.Submarine.Position;
}
Submarine.DrawGrid(spriteBatch, 14, gridPos, roundedGridPos, alpha: 0.7f);
Submarine.DrawGrid(spriteBatch, 14, gridPos, roundedGridPos, alpha: 0.4f);
item.Sprite.Draw(
spriteBatch,

View File

@@ -130,7 +130,7 @@ namespace Barotrauma.Items.Components
if (body.UserData is Item item)
{
var door = item.GetComponent<Door>();
if (door != null && door.IsOpen || door.IsBroken) continue;
if (door != null && door.CanBeTraversed) { continue; }
}
targetHull = null;
@@ -239,7 +239,7 @@ namespace Barotrauma.Items.Components
{
if (targetSections.Count == 0) { return; }
Item liquidItem = liquidContainer?.Inventory.Items[0];
Item liquidItem = liquidContainer?.Inventory.FirstOrDefault();
if (liquidItem == null) { return; }
bool isCleaning = false;

View File

@@ -15,7 +15,8 @@ namespace Barotrauma.Items.Components
Random,
CharacterSpecific,
ItemSpecific,
All
All,
Manual
}
class ItemSound
@@ -259,6 +260,7 @@ namespace Barotrauma.Items.Components
loopingSoundChannel = null;
loopingSound = null;
}
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
@@ -271,6 +273,21 @@ namespace Barotrauma.Items.Components
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
loopingSoundChannel.Far = loopingSound.Range;
}
// Looping sound with manual selection mode should be changed if value of ManuallySelectedSound has changed
// Otherwise the sound won't change until the sound condition (such as being active) is disabled and re-enabled
if (loopingSoundChannel != null && loopingSoundChannel.IsPlaying && soundSelectionModes[type] == SoundSelectionMode.Manual)
{
var playingIndex = sounds[type].IndexOf(loopingSound);
var shouldBePlayingIndex = Math.Clamp(ManuallySelectedSound, 0, sounds[type].Count);
if (playingIndex != shouldBePlayingIndex)
{
loopingSoundChannel.FadeOutAndDispose();
loopingSoundChannel = null;
loopingSound = null;
}
}
return;
}
@@ -295,6 +312,10 @@ namespace Barotrauma.Items.Components
}
return;
}
else if (soundSelectionMode == SoundSelectionMode.Manual)
{
index = Math.Clamp(ManuallySelectedSound, 0, matchingSounds.Count);
}
else
{
index = Rand.Int(matchingSounds.Count);
@@ -335,7 +356,7 @@ namespace Barotrauma.Items.Components
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0001f) { return; }
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, itemSound.RoundSound.GetRandomFrequencyMultiplier(), item.CurrentHull);
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, itemSound.RoundSound.GetRandomFrequencyMultiplier(), item.CurrentHull, ignoreMuffling: itemSound.RoundSound.IgnoreMuffling);
if (channel != null) { playingOneshotSoundChannels.Add(channel); }
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -32,6 +33,12 @@ namespace Barotrauma.Items.Components
private set;
}
public Sprite ContainedStateIndicatorEmpty
{
get;
private set;
}
#if DEBUG
[Editable]
#endif
@@ -55,6 +62,11 @@ namespace Barotrauma.Items.Components
[Serialize(null, false, description: "An optional text displayed above the item's inventory.")]
public string UILabel { get; set; }
public GUIComponentStyle IndicatorStyle { get; set; }
[Serialize(null, false)]
public string ContainedStateIndicatorStyle { get; set; }
[Serialize(true, false, description: "Should an indicator displaying the state of the contained items be displayed on this item's inventory slot. "+
"If this item can only contain one item, the indicator will display the condition of the contained item, otherwise it will indicate how full the item is.")]
public bool ShowContainedStateIndicator { get; set; }
@@ -98,6 +110,26 @@ namespace Barotrauma.Items.Components
case "containedstateindicator":
ContainedStateIndicator = new Sprite(subElement);
break;
case "containedstateindicatorempty":
ContainedStateIndicatorEmpty = new Sprite(subElement);
break;
}
}
if (string.IsNullOrEmpty(ContainedStateIndicatorStyle))
{
//if neither a style or a custom sprite is defined, use default style
if (ContainedStateIndicator == null)
{
IndicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator.Default");
}
}
else
{
IndicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator." + ContainedStateIndicatorStyle);
if (ContainedStateIndicator != null || ContainedStateIndicatorEmpty != null)
{
DebugConsole.AddWarning($"Item \"{item.Name}\" defines both a contained state indicator style and a custom indicator sprite. Will use the custom sprite...");
}
}
if (GuiFrame == null)
@@ -173,15 +205,9 @@ namespace Barotrauma.Items.Components
}
//if holding 2 different "always open" items in different hands, don't force them to stay open
if (character.SelectedItems[0] != null &&
character.SelectedItems[1] != null &&
character.SelectedItems[0] != character.SelectedItems[1])
if (character.HeldItems.Count() > 1 && character.HeldItems.All(it => it.GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false))
{
if ((character.SelectedItems[0].GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false) &&
(character.SelectedItems[1].GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false))
{
return false;
}
return false;
}
return true;
@@ -260,10 +286,8 @@ namespace Barotrauma.Items.Components
bool isWiringMode = SubEditorScreen.TransparentWiringMode && SubEditorScreen.IsWiringMode();
int i = 0;
foreach (Item containedItem in Inventory.Items)
foreach (Item containedItem in Inventory.AllItems)
{
if (containedItem == null) continue;
if (AutoInteractWithContained)
{
containedItem.IsHighlighted = item.IsHighlighted;
@@ -313,7 +337,7 @@ namespace Barotrauma.Items.Components
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (item.NonInteractable) { return; }
if (!item.IsInteractable(character)) { return; }
if (Inventory.RectTransform != null)
{
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;

View File

@@ -21,11 +21,17 @@ namespace Barotrauma.Items.Components
private float[] charWidths;
private Vector4 padding;
[Serialize("0,0,0,0", true, description: "The amount of padding around the text in pixels (left,top,right,bottom).")]
public Vector4 Padding
{
get { return TextBlock.Padding; }
set { TextBlock.Padding = value; }
get { return padding; }
set
{
padding = value;
TextBlock.Padding = value * item.Scale;
}
}
private string text;
@@ -41,15 +47,22 @@ namespace Barotrauma.Items.Components
{
textBlock = null;
}
text = value;
DisplayText = TextManager.Get(text, returnNull: true) ?? value;
TextBlock.Text = DisplayText;
if (Screen.Selected == GameMain.SubEditorScreen && Scrollable)
{
TextBlock.Text = ToolBox.LimitString(DisplayText, textBlock.Font, item.Rect.Width);
}
SetScrollingText();
SetDisplayText(value);
}
}
private bool ignoreLocalization;
[Editable, Serialize(false, true, "Whether or not to skip localization and always display the raw value.")]
public bool IgnoreLocalization
{
get => ignoreLocalization;
set
{
ignoreLocalization = value;
SetDisplayText(Text);
}
}
@@ -107,13 +120,7 @@ namespace Barotrauma.Items.Components
{
if (textBlock == null)
{
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
textColor: textColor, font: GUI.UnscaledSmallFont, textAlignment: scrollable ? Alignment.CenterLeft : Alignment.Center, wrap: true, style: null)
{
TextDepth = item.SpriteDepth - 0.00001f,
RoundToNearestPixel = false,
TextScale = TextScale
};
RecreateTextBlock();
}
return textBlock;
}
@@ -126,7 +133,7 @@ namespace Barotrauma.Items.Components
private void SetScrollingText()
{
if (!scrollable) return;
if (!scrollable) { return; }
float totalWidth = textBlock.Font.MeasureString(DisplayText).X;
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
@@ -143,6 +150,7 @@ namespace Barotrauma.Items.Components
//whole text can fit in the textblock, no need to scroll
needsScrolling = false;
scrollingText = DisplayText;
scrollPadding = 0;
scrollAmount = 0.0f;
scrollIndex = 0;
return;
@@ -161,16 +169,40 @@ namespace Barotrauma.Items.Components
scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length);
}
private void SetDisplayText(string value)
{
DisplayText = IgnoreLocalization ? value : TextManager.Get(value, returnNull: true) ?? value;
TextBlock.Text = DisplayText;
if (Screen.Selected == GameMain.SubEditorScreen && Scrollable)
{
TextBlock.Text = ToolBox.LimitString(DisplayText, TextBlock.Font, item.Rect.Width);
}
SetScrollingText();
}
private void RecreateTextBlock()
{
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
textColor: textColor, font: GUI.UnscaledSmallFont, textAlignment: scrollable ? Alignment.CenterLeft : Alignment.Center, wrap: !scrollable, style: null)
{
TextDepth = item.SpriteDepth - 0.00001f,
RoundToNearestPixel = false,
TextScale = TextScale,
Padding = padding * item.Scale
};
}
public override void Update(float deltaTime, Camera cam)
{
if (!scrollable) return;
if (!scrollable) { return; }
if (scrollingText == null)
{
SetScrollingText();
}
if (!needsScrolling) return;
if (!needsScrolling) { return; }
scrollAmount -= deltaTime * ScrollSpeed;
@@ -204,11 +236,33 @@ namespace Barotrauma.Items.Components
}
}
TextBlock.Text = sb.ToString();
TextBlock.Text = sb.ToString();
}
public override void OnScaleChanged()
{
RecreateTextBlock();
SetDisplayText(Text);
prevScale = item.Scale;
prevRect = item.Rect;
}
private float prevScale;
private Rectangle prevRect;
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (editing)
{
if (!MathUtils.NearlyEqual(prevScale, item.Scale) || prevRect != item.Rect)
{
RecreateTextBlock();
SetDisplayText(Text);
prevScale = item.Scale;
prevRect = item.Rect;
}
}
var drawPos = new Vector2(
item.DrawPosition.X - item.Rect.Width / 2.0f,
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
@@ -223,7 +277,7 @@ namespace Barotrauma.Items.Components
}
textBlock.TextDepth = item.SpriteDepth - 0.0001f;
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + new Vector2(scrollAmount + scrollPadding, 0.0f);
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + (editing ? Vector2.Zero : new Vector2(scrollAmount + scrollPadding, 0.0f));
textBlock.DrawManually(spriteBatch);
}

View File

@@ -38,12 +38,6 @@ namespace Barotrauma.Items.Components
light.Color = LightColor.Multiply(brightness);
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
SetLightSourceState(IsActive, lightBrightness);
}
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
@@ -51,7 +45,7 @@ namespace Barotrauma.Items.Components
Vector2 origin = light.LightSprite.Origin;
if ((light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = light.LightSprite.SourceRect.Width - origin.X; }
if ((light.LightSpriteEffect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically) { origin.Y = light.LightSprite.SourceRect.Height - origin.Y; }
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, origin, -light.Rotation, item.Scale, light.LightSpriteEffect, item.SpriteDepth - 0.0001f);
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, origin, -light.Rotation, item.Scale, light.LightSpriteEffect, itemDepth - 0.0001f);
}
}

View File

@@ -95,11 +95,11 @@ namespace Barotrauma.Items.Components
// TODO, This works fine as of now but if GUI.PreventElementOverlap ever gets fixed this block of code may become obsolete or detrimental.
// Only do this if there's only one linked component. If you link more containers then may
// GUI.PreventElementOverlap have mercy on your HUD layout
if (GuiFrame != null && item.linkedTo.Count(entity => entity is Item item && item.DisplaySideBySideWhenLinked) == 1)
if (GuiFrame != null && item.linkedTo.Count(entity => entity is Item { DisplaySideBySideWhenLinked: true }) == 1)
{
foreach (MapEntity linkedTo in item.linkedTo)
{
if (!(linkedTo is Item linkedItem) || !linkedItem.DisplaySideBySideWhenLinked) { continue; }
if (!(linkedTo is Item { DisplaySideBySideWhenLinked: true } linkedItem)) { continue; }
if (!linkedItem.Components.Any()) { continue; }
var itemContainer = linkedItem.GetComponent<ItemContainer>();
@@ -108,8 +108,8 @@ namespace Barotrauma.Items.Components
// how much spacing do we want between the components
var padding = (int) (8 * GUI.Scale);
// Move the linked container to the right and move the deconstructor to the left
itemContainer.GuiFrame.RectTransform.AbsoluteOffset = new Point(100, 0);
GuiFrame.RectTransform.AbsoluteOffset = new Point(-100, 0);
itemContainer.GuiFrame.RectTransform.AbsoluteOffset = new Point(GuiFrame.Rect.Width / -2 - padding, 0);
GuiFrame.RectTransform.AbsoluteOffset = new Point(itemContainer.GuiFrame.Rect.Width / 2 + padding, 0);
}
}
return base.Select(character);
@@ -126,7 +126,7 @@ namespace Barotrauma.Items.Components
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
var lastSlot = inputContainer.Inventory.slots.Last();
var lastSlot = inputContainer.Inventory.visualSlots.Last();
GUI.DrawRectangle(spriteBatch,
new Rectangle(

View File

@@ -144,16 +144,15 @@ namespace Barotrauma.Items.Components
Vector2 drawPos = item.DrawPosition;
drawPos += PropellerPos;
drawPos.Y = -drawPos.Y;
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
}
if (editing && !GUI.DisableHUD)
if (editing && !DisablePropellerDamage && propellerDamage != null && !GUI.DisableHUD)
{
Vector2 drawPos = item.DrawPosition;
drawPos += PropellerPos;
drawPos += PropellerPos * item.Scale;
drawPos.Y = -drawPos.Y;
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, GUI.Style.Red);
spriteBatch.DrawCircle(drawPos, propellerDamage.DamageRange * item.Scale, 16, GUI.Style.Red, thickness: 2);
}
}

View File

@@ -190,7 +190,7 @@ namespace Barotrauma.Items.Components
};
}
new GUITextBlock(new RectTransform(new Vector2(0.85f, 1f), container.RectTransform), fi.DisplayName)
new GUITextBlock(new RectTransform(new Vector2(0.85f, 1f), container.RectTransform), GetRecipeNameAndAmount(fi))
{
Padding = Vector4.Zero,
AutoScaleVertical = true,
@@ -199,6 +199,21 @@ namespace Barotrauma.Items.Components
}
}
private string GetRecipeNameAndAmount(FabricationRecipe fabricationRecipe)
{
if (fabricationRecipe == null) { return ""; }
if (fabricationRecipe.Amount > 1)
{
return TextManager.GetWithVariables("fabricationrecipenamewithamount",
new string[2] { "[name]", "[amount]" },
new string[2] { fabricationRecipe.DisplayName, fabricationRecipe.Amount.ToString() });
}
else
{
return fabricationRecipe.DisplayName;
}
}
partial void OnItemLoadedProjSpecific()
{
inputContainer.AllowUIOverlap = true;
@@ -212,11 +227,11 @@ namespace Barotrauma.Items.Components
// TODO, This works fine as of now but if GUI.PreventElementOverlap ever gets fixed this block of code may become obsolete or detrimental.
// Only do this if there's only one linked component. If you link more containers then may
// GUI.PreventElementOverlap have mercy on your HUD layout
if (GuiFrame != null && item.linkedTo.Count(entity => entity is Item item && item.DisplaySideBySideWhenLinked) == 1)
if (GuiFrame != null && item.linkedTo.Count(entity => entity is Item { DisplaySideBySideWhenLinked: true }) == 1)
{
foreach (MapEntity linkedTo in item.linkedTo)
{
if (!(linkedTo is Item linkedItem) || !linkedItem.DisplaySideBySideWhenLinked) { continue; }
if (!(linkedTo is Item { DisplaySideBySideWhenLinked: true } linkedItem)) { continue; }
if (!linkedItem.Components.Any()) { continue; }
var itemContainer = linkedItem.GetComponent<ItemContainer>();
@@ -225,8 +240,8 @@ namespace Barotrauma.Items.Components
// how much spacing do we want between the components
var padding = (int) (8 * GUI.Scale);
// Move the linked container to the right and move the fabricator to the left
itemContainer.GuiFrame.RectTransform.AbsoluteOffset = new Point(-100, 0);
GuiFrame.RectTransform.AbsoluteOffset = new Point(100, 0);
itemContainer.GuiFrame.RectTransform.AbsoluteOffset = new Point(GuiFrame.Rect.Width / -2 - padding, 0);
GuiFrame.RectTransform.AbsoluteOffset = new Point(itemContainer.GuiFrame.Rect.Width / 2 + padding, 0);
}
}
@@ -287,9 +302,8 @@ namespace Barotrauma.Items.Components
missingItems.Add(requiredItem);
}
}
foreach (Item item in inputContainer.Inventory.Items)
foreach (Item item in inputContainer.Inventory.AllItems)
{
if (item == null) { continue; }
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefabs.Contains(item.prefab)));
}
@@ -297,7 +311,7 @@ namespace Barotrauma.Items.Components
foreach (FabricationRecipe.RequiredItem requiredItem in missingItems)
{
while (slotIndex < inputContainer.Capacity && inputContainer.Inventory.Items[slotIndex] != null)
while (slotIndex < inputContainer.Capacity && inputContainer.Inventory.GetItemAt(slotIndex) != null)
{
slotIndex++;
}
@@ -307,17 +321,17 @@ namespace Barotrauma.Items.Components
{
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
{
int availableSlotIndex = Array.IndexOf(item.ParentInventory.Items, item);
int availableSlotIndex = item.ParentInventory.FindIndex(item);
//slots are null if the inventory has never been displayed
//(linked item, but the UI is not set to be displayed at the same time)
if (item.ParentInventory.slots != null)
if (item.ParentInventory.visualSlots != null)
{
if (item.ParentInventory.slots[availableSlotIndex].HighlightTimer <= 0.0f)
if (item.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
{
item.ParentInventory.slots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
item.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
{
inputContainer.Inventory.slots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
}
}
}
@@ -327,7 +341,7 @@ namespace Barotrauma.Items.Components
if (slotIndex >= inputContainer.Capacity) { break; }
var itemIcon = requiredItem.ItemPrefabs.First().InventoryIcon ?? requiredItem.ItemPrefabs.First().sprite;
Rectangle slotRect = inputContainer.Inventory.slots[slotIndex].Rect;
Rectangle slotRect = inputContainer.Inventory.visualSlots[slotIndex].Rect;
itemIcon.Draw(
spriteBatch,
slotRect.Center.ToVector2(),
@@ -367,14 +381,12 @@ namespace Barotrauma.Items.Components
{
overlayComponent.RectTransform.SetAsLastChild();
if (outputContainer.Inventory.Items.First() != null) { return; }
FabricationRecipe targetItem = fabricatedItem ?? selectedItem;
if (targetItem != null)
{
var itemIcon = targetItem.TargetItem.InventoryIcon ?? targetItem.TargetItem.sprite;
Rectangle slotRect = outputContainer.Inventory.slots[0].Rect;
Rectangle slotRect = outputContainer.Inventory.visualSlots[0].Rect;
if (fabricatedItem != null)
{
@@ -449,8 +461,10 @@ namespace Barotrauma.Items.Components
Color = selectedItem.TargetItem.InventoryIconColor
};
}*/
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
selectedItem.TargetItem.Name, textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont)
GetRecipeNameAndAmount(selectedItem), textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont)
{
AutoScaleHorizontal = true
};
@@ -539,7 +553,7 @@ namespace Barotrauma.Items.Components
private bool StartButtonClicked(GUIButton button, object obj)
{
if (selectedItem == null) { return false; }
if (!outputContainer.Inventory.IsEmpty())
if (fabricatedItem == null && !outputContainer.Inventory.CanBePut(selectedItem.TargetItem))
{
outputSlot.Flash(GUI.Style.Red);
return false;

View File

@@ -71,10 +71,14 @@ namespace Barotrauma.Items.Components
private float showDirectionalIndicatorTimer;
private List<LevelObject> nearbyObjects = new List<LevelObject>();
private readonly List<LevelObject> nearbyObjects = new List<LevelObject>();
private const float NearbyObjectUpdateInterval = 1.0f;
float nearbyObjectUpdateTimer;
private List<Submarine> connectedSubs = new List<Submarine>();
private const float ConnectedSubUpdateInterval = 1.0f;
float connectedSubUpdateTimer;
//Vector2 = vector from the ping source to the position of the disruption
//float = strength of the disruption, between 0-1
private readonly List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
@@ -135,6 +139,8 @@ namespace Barotrauma.Items.Components
private bool isConnectedToSteering;
private static string caveLabel;
private bool AllowUsingMineralScanner =>
HasMineralScanner && !isConnectedToSteering;
@@ -143,6 +149,10 @@ namespace Barotrauma.Items.Components
System.Diagnostics.Debug.Assert(Enum.GetValues(typeof(BlipType)).Cast<BlipType>().All(t => blipColorGradient.ContainsKey(t)));
sonarBlips = new List<SonarBlip>();
caveLabel =
TextManager.Get("cave", returnNull: true) ??
TextManager.Get("missiontype.nest");
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -413,6 +423,26 @@ namespace Barotrauma.Items.Components
networkUpdateTimer -= deltaTime;
}
connectedSubUpdateTimer -= deltaTime;
if (connectedSubUpdateTimer <= 0.0f)
{
connectedSubs.Clear();
if (UseTransducers)
{
foreach (var transducer in connectedTransducers)
{
if (transducer.Transducer.Item.Submarine == null) { continue; }
if (connectedSubs.Contains(transducer.Transducer.Item.Submarine)) { continue; }
connectedSubs = transducer.Transducer.Item.Submarine?.GetConnectedSubs();
}
}
else if (item.Submarine != null)
{
connectedSubs = item.Submarine?.GetConnectedSubs();
}
connectedSubUpdateTimer = ConnectedSubUpdateInterval;
}
if (sonarView.Rect.Contains(PlayerInput.MousePosition))
{
float scrollSpeed = PlayerInput.ScrollWheelSpeed / 1000.0f;
@@ -848,10 +878,22 @@ namespace Barotrauma.Items.Components
displayScale, center, DisplayRadius);
}
for (int i = 0; i < Level.Loaded.Caves.Count; i++)
{
var cave = Level.Loaded.Caves[i];
if (!cave.DisplayOnSonar) { continue; }
DrawMarker(spriteBatch,
caveLabel,
"cave",
"cave" + i,
cave.StartPos.ToVector2(), transducerCenter,
displayScale, center, DisplayRadius);
}
foreach (AITarget aiTarget in AITarget.List)
{
if (!aiTarget.Enabled) continue;
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) continue;
if (!aiTarget.Enabled) { continue; }
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) { continue; }
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
{
@@ -902,16 +944,11 @@ namespace Barotrauma.Items.Components
foreach (Submarine sub in Submarine.Loaded)
{
if (!sub.ShowSonarMarker) { continue; }
if (UseTransducers ?
connectedTransducers.Any(t => sub == t.Transducer.Item.Submarine || sub.DockedTo.Contains(t.Transducer.Item.Submarine)) :
(sub == item.Submarine || sub.DockedTo.Contains(item.Submarine)))
{
continue;
}
if (connectedSubs.Contains(sub)) { continue; }
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
DrawMarker(spriteBatch,
sub.Info.DisplayName,
DrawMarker(spriteBatch,
sub.Info.DisplayName,
sub.Info.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
sub,
sub.WorldPosition, transducerCenter,
@@ -931,10 +968,8 @@ namespace Barotrauma.Items.Components
foreach (Submarine submarine in Submarine.Loaded)
{
if (UseTransducers ?
!connectedTransducers.Any(t => submarine == t.Transducer.Item.Submarine || submarine.DockedTo.Contains(t.Transducer.Item.Submarine)) :
submarine != item.Submarine && !submarine.DockedTo.Contains(item.Submarine)) continue;
if (submarine.HullVertices == null) continue;
if (!connectedSubs.Contains(submarine)) { continue; }
if (submarine.HullVertices == null) { continue; }
Vector2 offset = ConvertUnits.ToSimUnits(submarine.WorldPosition - transducerCenter);
@@ -1018,8 +1053,8 @@ namespace Barotrauma.Items.Components
//don't show the docking ports of the opposing team on the sonar
if (item.Submarine != null)
{
if ((dockingPort.Item.Submarine.TeamID == Character.TeamType.Team1 && item.Submarine.TeamID == Character.TeamType.Team2) ||
(dockingPort.Item.Submarine.TeamID == Character.TeamType.Team2 && item.Submarine.TeamID == Character.TeamType.Team1))
if ((dockingPort.Item.Submarine.TeamID == CharacterTeamType.Team1 && item.Submarine.TeamID == CharacterTeamType.Team2) ||
(dockingPort.Item.Submarine.TeamID == CharacterTeamType.Team2 && item.Submarine.TeamID == CharacterTeamType.Team1))
{
continue;
}
@@ -1226,19 +1261,10 @@ namespace Barotrauma.Items.Components
foreach (Submarine submarine in Submarine.Loaded)
{
if (submarine.HullVertices == null) continue;
if (submarine.HullVertices == null) { continue; }
if (!DetectSubmarineWalls)
{
if (UseTransducers)
{
if (connectedTransducers.Any(t => submarine == t.Transducer.Item.Submarine ||
submarine.DockedTo.Contains(t.Transducer.Item.Submarine))) continue;
}
else
{
if (item.Submarine == submarine) continue;
if (item.Submarine != null && item.Submarine.DockedTo.Contains(submarine)) continue;
}
if (connectedSubs.Contains(submarine)) { continue; }
}
for (int i = 0; i < submarine.HullVertices.Count; i++)

View File

@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
private GUIComponent steerArea;
private GUITextBlock pressureWarningText;
private GUITextBlock pressureWarningText, iceSpireWarningText;
private GUITextBlock tipContainer;
@@ -311,6 +311,7 @@ namespace Barotrauma.Items.Components
{
Vector2 vel = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
var realWorldVel = ConvertUnits.ToDisplayUnits(vel.X * Physics.DisplayToRealWorldRatio) * 3.6f;
if (controlledSub != null && controlledSub.FlippedX) { realWorldVel *= -1; }
return ((int)realWorldVel).ToString();
};
break;
@@ -440,8 +441,13 @@ namespace Barotrauma.Items.Components
(spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null);
steerRadius = steerArea.Rect.Width / 2;
pressureWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), steerArea.RectTransform, Anchor.Center, Pivot.TopCenter),
TextManager.Get("SteeringDepthWarning"), Color.Red, GUI.LargeFont, Alignment.Center)
iceSpireWarningText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.25f), steerArea.RectTransform, Anchor.Center, Pivot.TopCenter),
TextManager.Get("NavTerminalIceSpireWarning"), GUI.Style.Red, GUI.SubHeadingFont, Alignment.Center, color: Color.Black * 0.8f, wrap: true)
{
Visible = false
};
pressureWarningText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.25f), steerArea.RectTransform, Anchor.Center, Pivot.TopCenter),
TextManager.Get("SteeringDepthWarning"), GUI.Style.Red, GUI.SubHeadingFont, Alignment.Center, color: Color.Black * 0.8f)
{
Visible = false
};
@@ -471,7 +477,11 @@ namespace Barotrauma.Items.Components
public void AttachToSonarHUD(GUICustomComponent sonarView)
{
steerArea.Visible = false;
sonarView.OnDraw += (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); };
sonarView.OnDraw += (spriteBatch, guiCustomComponent) =>
{
DrawHUD(spriteBatch, guiCustomComponent.Rect);
steerArea.DrawChildren(spriteBatch, recursive: true);
};
}
public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
@@ -712,12 +722,13 @@ namespace Barotrauma.Items.Components
}
}
pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.5f;
pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.8f;
iceSpireWarningText.Visible = item.Submarine != null && !pressureWarningText.Visible && showIceSpireWarning && Timing.TotalTime % 1.0f < 0.8f;
if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
{
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen &&
(!GameMain.GameSession?.Campaign?.ShowCampaignUI ?? true) && !GUIMessageBox.MessageBoxes.Any())
(!GameMain.GameSession?.Campaign?.ShowCampaignUI ?? true) && !GUIMessageBox.MessageBoxes.Any(msgBox => msgBox is GUIMessageBox { MessageBoxType: GUIMessageBox.Type.Default }))
{
Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2();
inputPos.Y = -inputPos.Y;

View File

@@ -113,25 +113,28 @@ namespace Barotrauma.Items.Components
}
}
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem)
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, bool showProgressBar)
{
float progressBarState = targetItem.ConditionPercentage / 100.0f;
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState) || prevProgressBarTarget != targetItem)
if (showProgressBar)
{
var door = targetItem.GetComponent<Door>();
if (door == null || door.Stuck <= 0)
float progressBarState = targetItem.ConditionPercentage / 100.0f;
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState) || prevProgressBarTarget != targetItem)
{
Vector2 progressBarPos = targetItem.DrawPosition;
var progressBar = user?.UpdateHUDProgressBar(
targetItem,
progressBarPos,
progressBarState,
GUI.Style.Red, GUI.Style.Green,
progressBarState < prevProgressBarState ? "progressbar.cutting" : "");
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
var door = targetItem.GetComponent<Door>();
if (door == null || door.Stuck <= 0)
{
Vector2 progressBarPos = targetItem.DrawPosition;
var progressBar = user?.UpdateHUDProgressBar(
targetItem,
progressBarPos,
progressBarState,
GUI.Style.Red, GUI.Style.Green,
progressBarState < prevProgressBarState ? "progressbar.cutting" : "");
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
}
prevProgressBarState = progressBarState;
prevProgressBarTarget = targetItem;
}
prevProgressBarState = progressBarState;
prevProgressBarTarget = targetItem;
}
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);

View File

@@ -53,13 +53,9 @@ namespace Barotrauma.Items.Components
{
//if the Character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
for (int i = 0; i < character.SelectedItems.Length; i++)
foreach (Item item in character.HeldItems)
{
Item selectedItem = character.SelectedItems[i];
if (selectedItem == null) { continue; }
Wire wireComponent = selectedItem.GetComponent<Wire>();
Wire wireComponent = item.GetComponent<Wire>();
if (wireComponent != null)
{
equippedWire = wireComponent;
@@ -94,7 +90,8 @@ namespace Barotrauma.Items.Components
int linkIndex = c.FindWireIndex(DraggingConnected.Item);
if (linkIndex > -1 || panel.DisconnectedWires.Contains(DraggingConnected))
{
Inventory.draggingItem = DraggingConnected.Item;
Inventory.DraggingItems.Clear();
Inventory.DraggingItems.Add(DraggingConnected.Item);
}
}
}
@@ -182,7 +179,11 @@ namespace Barotrauma.Items.Components
new Vector2(x + width / 2, y + height),
null, panel, "");
if (DraggingConnected == equippedWire) { Inventory.draggingItem = equippedWire.Item; }
if (DraggingConnected == equippedWire)
{
Inventory.DraggingItems.Clear();
Inventory.DraggingItems.Add(equippedWire.Item);
}
}
}
@@ -207,7 +208,7 @@ namespace Barotrauma.Items.Components
//(so we don't drop the item when dropping the wire on a connection)
if (mouseInRect || (GUI.MouseOn?.UserData is ConnectionPanel && GUI.MouseOn.MouseRect.Contains(PlayerInput.MousePosition)))
{
Inventory.draggingItem = null;
Inventory.DraggingItems.Clear();
}
}
@@ -236,7 +237,7 @@ namespace Barotrauma.Items.Components
{
float connectorSpriteScale = (35.0f / connectionSprite.SourceRect.Width) * panel.Scale;
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null || wires[i].Hidden || (DraggingConnected == wires[i] && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
if (wires[i].HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }

View File

@@ -122,7 +122,7 @@ namespace Barotrauma.Items.Components
msg.ReadUInt16(); //user ID
foreach (Connection connection in Connections)
{
for (int i = 0; i < Connection.MaxLinked; i++)
for (int i = 0; i < connection.MaxWires; i++)
{
msg.ReadUInt16();
}
@@ -168,7 +168,7 @@ namespace Barotrauma.Items.Components
foreach (Connection connection in Connections)
{
for (int i = 0; i < Connection.MaxLinked; i++)
for (int i = 0; i < connection.MaxWires; i++)
{
ushort wireId = msg.ReadUInt16();

View File

@@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -15,7 +14,7 @@ namespace Barotrauma.Items.Components
private Point ElementMaxSize => new Point(uiElementContainer.Rect.Width, (int)(65 * GUI.yScale));
partial void InitProjSpecific(XElement element)
partial void InitProjSpecific()
{
CreateGUI();
}
@@ -37,41 +36,70 @@ namespace Barotrauma.Items.Components
float elementSize = Math.Min(1.0f / visibleElements.Count(), 1);
foreach (CustomInterfaceElement ciElement in visibleElements)
{
if (!string.IsNullOrEmpty(ciElement.PropertyName))
if (ciElement.HasPropertyName)
{
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.02f,
UserData = ciElement
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label);
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), "", style: "GUITextBoxNoIcon")
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal: true)
{
OverflowClip = true,
RelativeSpacing = 0.02f,
UserData = ciElement
};
//reset size restrictions set by the Style to make sure the elements can fit the interface
textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize = new Point(0, 0);
textBox.RectTransform.MaxSize = textBox.Frame.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
textBox.OnDeselected += (tb, key) =>
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label);
if (!ciElement.IsIntegerInput)
{
if (GameMain.Client == null)
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), ciElement.Signal, style: "GUITextBoxNoIcon")
{
TextChanged(tb.UserData as CustomInterfaceElement, textBox.Text);
}
else
OverflowClip = true,
UserData = ciElement
};
//reset size restrictions set by the Style to make sure the elements can fit the interface
textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize = new Point(0, 0);
textBox.RectTransform.MaxSize = textBox.Frame.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
textBox.OnDeselected += (tb, key) =>
{
item.CreateClientEvent(this);
}
};
if (GameMain.Client == null)
{
TextChanged(tb.UserData as CustomInterfaceElement, textBox.Text);
}
else
{
item.CreateClientEvent(this);
}
};
textBox.OnEnterPressed += (tb, text) =>
textBox.OnEnterPressed += (tb, text) =>
{
tb.Deselect();
return true;
};
uiElements.Add(textBox);
}
else
{
tb.Deselect();
return true;
};
uiElements.Add(textBox);
int.TryParse(ciElement.Signal, out int signal);
var numberInput = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), GUINumberInput.NumberType.Int)
{
UserData = ciElement,
MinValueInt = ciElement.NumberInputMin,
MaxValueInt = ciElement.NumberInputMax,
IntValue = Math.Clamp(signal, ciElement.NumberInputMin, ciElement.NumberInputMax)
};
//reset size restrictions set by the Style to make sure the elements can fit the interface
numberInput.RectTransform.MinSize = numberInput.LayoutGroup.RectTransform.MinSize = new Point(0, 0);
numberInput.RectTransform.MaxSize = numberInput.LayoutGroup.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
numberInput.OnValueChanged += (ni) =>
{
if (GameMain.Client == null)
{
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
}
else
{
item.CreateClientEvent(this);
}
};
uiElements.Add(numberInput);
}
}
else if (ciElement.ContinuousSignal)
{
@@ -175,7 +203,7 @@ namespace Barotrauma.Items.Components
foreach (var uiElement in uiElements)
{
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || !string.IsNullOrEmpty(element.PropertyName) || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
if (visible) { visibleElementCount++; }
if (uiElement.Visible != visible)
{
@@ -203,36 +231,29 @@ namespace Barotrauma.Items.Components
{
if (uiElements[i] is GUIButton button)
{
button.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
button.Text = CreateLabelText(i);
button.TextBlock.Wrap = button.Text.Contains(' ');
}
else if (uiElements[i] is GUITickBox tickBox)
{
tickBox.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
tickBox.Text = CreateLabelText(i);
tickBox.TextBlock.Wrap = tickBox.Text.Contains(' ');
}
if (uiElements[i] is GUITextBox textBox)
else if (uiElements[i] is GUITextBox || uiElements[i] is GUINumberInput)
{
var textBlock = textBox.Parent.GetChild<GUITextBlock>();
textBlock.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
var textBlock = uiElements[i].Parent.GetChild<GUITextBlock>();
textBlock.Text = CreateLabelText(i);
textBlock.Wrap = textBlock.Text.Contains(' ');
foreach (ISerializableEntity e in item.AllPropertyObjects)
{
if (e.SerializableProperties.ContainsKey(customInterfaceElementList[i].PropertyName))
{
textBox.Text = e.SerializableProperties[customInterfaceElementList[i].PropertyName].GetValue(e) as string;
}
}
}
}
string CreateLabelText(int elementIndex)
{
return string.IsNullOrWhiteSpace(customInterfaceElementList[elementIndex].Label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (elementIndex + 1).ToString()) :
customInterfaceElementList[elementIndex].Label;
}
uiElementContainer.Recalculate();
var textBlocks = new List<GUITextBlock>();
foreach (GUIComponent element in uiElementContainer.Children)
@@ -258,14 +279,40 @@ namespace Barotrauma.Items.Components
GUITextBlock.AutoScaleAndNormalize(textBlocks);
}
partial void UpdateSignalsProjSpecific()
{
for (int i = 0; i < signals.Length && i < uiElements.Count; i++)
{
if (uiElements[i] is GUITextBox tb)
{
tb.Text = customInterfaceElementList[i].Signal;
}
else if (uiElements[i] is GUINumberInput ni)
{
if (ni.InputType == GUINumberInput.NumberType.Int)
{
int.TryParse(customInterfaceElementList[i].Signal, out int value);
ni.IntValue = value;
}
}
}
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
if (customInterfaceElementList[i].HasPropertyName)
{
msg.Write(((GUITextBox)uiElements[i]).Text);
if (!customInterfaceElementList[i].IsIntegerInput)
{
msg.Write(((GUITextBox)uiElements[i]).Text);
}
else
{
msg.Write(((GUINumberInput)uiElements[i]).IntValue.ToString());
}
}
else if (customInterfaceElementList[i].ContinuousSignal)
{
@@ -282,9 +329,17 @@ namespace Barotrauma.Items.Components
{
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
if (customInterfaceElementList[i].HasPropertyName)
{
TextChanged(customInterfaceElementList[i], msg.ReadString());
if (!customInterfaceElementList[i].IsIntegerInput)
{
TextChanged(customInterfaceElementList[i], msg.ReadString());
}
else
{
int.TryParse(msg.ReadString(), out int value);
ValueChanged(customInterfaceElementList[i], value);
}
}
else
{
@@ -300,6 +355,8 @@ namespace Barotrauma.Items.Components
}
}
}
UpdateSignalsProjSpecific();
}
}
}

View File

@@ -214,7 +214,10 @@ namespace Barotrauma.Items.Components
roundedGridPos += item.Submarine.Position;
}
Submarine.DrawGrid(spriteBatch, 14, gridPos, roundedGridPos, alpha: 0.7f);
if (!SubEditorScreen.IsSubEditor() || !SubEditorScreen.ShouldDrawGrid)
{
Submarine.DrawGrid(spriteBatch, 14, gridPos, roundedGridPos, alpha: 0.25f);
}
WireSection.Draw(
spriteBatch, this,
@@ -286,10 +289,8 @@ namespace Barotrauma.Items.Components
public static void UpdateEditing(List<Wire> wires)
{
var doubleClicked = PlayerInput.DoubleClicked();
Wire equippedWire =
Character.Controlled?.SelectedItems[0]?.GetComponent<Wire>() ??
Character.Controlled?.SelectedItems[1]?.GetComponent<Wire>();
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)
@@ -329,6 +330,9 @@ namespace Barotrauma.Items.Components
nodeWorldPos = nodeWorldPos - sub.HiddenSubPosition - sub.Position;
}
if (selectedNodeIndex.HasValue && selectedNodeIndex.Value >= draggingWire.nodes.Count) { selectedNodeIndex = null; }
if (highlightedNodeIndex.HasValue && highlightedNodeIndex.Value >= draggingWire.nodes.Count) { highlightedNodeIndex = null; }
if (selectedNodeIndex.HasValue)
{
if (!PlayerInput.IsShiftDown())
@@ -342,14 +346,15 @@ namespace Barotrauma.Items.Components
}
else
{
if ((highlightedNodeIndex.HasValue && Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X) ||
float dragDistance = Submarine.GridSize.X * Submarine.GridSize.Y;
dragDistance *= 0.5f;
if ((highlightedNodeIndex.HasValue && Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) >= dragDistance) ||
PlayerInput.IsShiftDown())
{
selectedNodeIndex = highlightedNodeIndex;
}
}
MapEntity.SelectEntity(draggingWire.item);
}
@@ -396,6 +401,13 @@ namespace Barotrauma.Items.Components
if (closestIndex > -1)
{
highlightedNodeIndex = closestIndex;
Vector2 nudge = MapEntity.GetNudgeAmount(doHold: false);
if (nudge != Vector2.Zero && closestIndex < selectedWire.nodes.Count)
{
selectedWire.MoveNode(closestIndex, nudge);
}
//start dragging the node
if (PlayerInput.PrimaryMouseButtonHeld())
{

View File

@@ -148,20 +148,20 @@ namespace Barotrauma.Items.Components
List<string> texts = new List<string>();
List<Color> textColors = new List<Color>();
if (target.Info != null)
{
texts.Add(target.Name);
textColors.Add(GUI.Style.TextColor);
}
texts.Add(target.Info == null ? target.DisplayName : target.Info.DisplayName);
textColors.Add(GUI.Style.TextColor);
if (target.IsDead)
{
texts.Add(TextManager.Get("Deceased"));
textColors.Add(GUI.Style.Red);
texts.Add(
target.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
TextManager.AddPunctuation(':', TextManager.Get("CauseOfDeath"), TextManager.Get("CauseOfDeath." + target.CauseOfDeath.Type.ToString())));
textColors.Add(GUI.Style.Red);
if (target.CauseOfDeath != null)
{
texts.Add(
target.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
TextManager.AddPunctuation(':', TextManager.Get("CauseOfDeath"), TextManager.Get("CauseOfDeath." + target.CauseOfDeath.Type.ToString())));
textColors.Add(GUI.Style.Red);
}
}
else
{
@@ -170,6 +170,21 @@ namespace Barotrauma.Items.Components
texts.Add(target.customInteractHUDText);
textColors.Add(GUI.Style.Green);
}
if (!target.IsIncapacitated && target.IsPet)
{
texts.Add(CharacterHUD.GetCachedHudText("PlayHint", GameMain.Config.KeyBindText(InputType.Use)));
textColors.Add(GUI.Style.Green);
}
if (target.CharacterHealth.UseHealthWindow && equipper?.FocusedCharacter == target && equipper.CanInteractWith(target, 160f, false))
{
texts.Add(CharacterHUD.GetCachedHudText("HealHint", GameMain.Config.KeyBindText(InputType.Health)));
textColors.Add(GUI.Style.Green);
}
if (target.CanBeDragged)
{
texts.Add(CharacterHUD.GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)));
textColors.Add(GUI.Style.Green);
}
if (target.IsUnconscious)
{
@@ -181,7 +196,7 @@ namespace Barotrauma.Items.Components
texts.Add(TextManager.Get("Stunned"));
textColors.Add(GUI.Style.Orange);
}
int oxygenTextIndex = MathHelper.Clamp((int)Math.Floor((1.0f - (target.Oxygen / 100.0f)) * OxygenTexts.Length), 0, OxygenTexts.Length - 1);
texts.Add(OxygenTexts[oxygenTextIndex]);
textColors.Add(Color.Lerp(GUI.Style.Red, GUI.Style.Green, target.Oxygen / 100.0f));

View File

@@ -181,14 +181,14 @@ namespace Barotrauma.Items.Components
{
if (moveSoundChannel == null && startMoveSound != null)
{
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, item.WorldPosition, startMoveSound.Volume, startMoveSound.Range);
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, item.WorldPosition, startMoveSound.Volume, startMoveSound.Range, ignoreMuffling: startMoveSound.IgnoreMuffling);
}
else if (moveSoundChannel == null || !moveSoundChannel.IsPlaying)
{
if (moveSound != null)
{
moveSoundChannel.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, item.WorldPosition, moveSound.Volume, moveSound.Range);
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, item.WorldPosition, moveSound.Volume, moveSound.Range, ignoreMuffling: moveSound.IgnoreMuffling);
if (moveSoundChannel != null) moveSoundChannel.Looping = true;
}
}
@@ -200,7 +200,7 @@ namespace Barotrauma.Items.Components
if (endMoveSound != null && moveSoundChannel.Sound != endMoveSound.Sound)
{
moveSoundChannel.FadeOutAndDispose();
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, item.WorldPosition, endMoveSound.Volume, endMoveSound.Range);
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, item.WorldPosition, endMoveSound.Volume, endMoveSound.Range, ignoreMuffling: endMoveSound.IgnoreMuffling);
if (moveSoundChannel != null) moveSoundChannel.Looping = false;
}
else if (!moveSoundChannel.IsPlaying)
@@ -286,40 +286,26 @@ namespace Barotrauma.Items.Components
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
if (!GameMain.DebugDraw && (!editing || GUI.DisableHUD || !item.IsSelected)) { return; }
if (!editing || GUI.DisableHUD || !item.IsSelected) { return; }
const float widgetRadius = 60.0f;
Vector2 center = new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2));
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * widgetRadius,
drawPos + center * widgetRadius,
Color.LightGreen);
if (GameMain.DebugDraw)
{
center = new Vector2((float)Math.Cos(targetRotation), (float)Math.Sin(targetRotation));
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + center * widgetRadius,
Color.Red);
for (int i = 0; i < 5; i++)
{
center = new Vector2((float)Math.Cos(rotation + (angularVelocity * 0.05f * i)), (float)Math.Sin(rotation + (angularVelocity * 0.05f * i)));
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + center * widgetRadius,
Color.Lerp(Color.Black, Color.Yellow, i * 0.25f));
}
}
const float coneRadius = 300.0f;
float radians = maxRotation - minRotation;
float circleRadius = coneRadius / Screen.Selected.Cam.Zoom * GUI.Scale;
float lineThickness = 1f / Screen.Selected.Cam.Zoom;
if (radians > Math.PI * 2)
if (Math.Abs(minRotation - maxRotation) < 0.02f)
{
spriteBatch.DrawLine(drawPos, drawPos + center * circleRadius, GUI.Style.Green, thickness: lineThickness);
}
else if (radians > Math.PI * 2)
{
spriteBatch.DrawCircle(drawPos, circleRadius, 180, GUI.Style.Red, thickness: lineThickness);
}
@@ -510,13 +496,8 @@ namespace Barotrauma.Items.Components
List<Item> availableAmmo = new List<Item>();
foreach (MapEntity e in item.linkedTo)
{
var linkedItem = e as Item;
if (linkedItem == null) continue;
var itemContainer = linkedItem.GetComponent<ItemContainer>();
if (itemContainer?.Inventory?.Items == null) continue;
availableAmmo.AddRange(itemContainer.Inventory.Items);
if (!(e is Item linkedItem)) { continue; }
availableAmmo.AddRange(linkedItem.ContainedItems);
}
float chargeRate =
@@ -558,7 +539,7 @@ namespace Barotrauma.Items.Components
{
// TODO: Optimize? Creates multiple new objects per frame?
Inventory.DrawSlot(spriteBatch, null,
new InventorySlot(new Rectangle(invSlotPos + new Point((i % slotsPerRow) * (slotSize.X + spacing), (int)Math.Floor(i / (float)slotsPerRow) * (slotSize.Y + spacing)), slotSize)),
new VisualSlot(new Rectangle(invSlotPos + new Point((i % slotsPerRow) * (slotSize.X + spacing), (int)Math.Floor(i / (float)slotsPerRow) * (slotSize.Y + spacing)), slotSize)),
availableAmmo[i], -1, true);
}
if (flashNoAmmo)

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
using Barotrauma.MapCreatures.Behavior;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
@@ -15,7 +16,7 @@ namespace Barotrauma
{
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
{
public static bool ShowItems = true;
public static bool ShowItems = true, ShowWires = true;
private readonly List<PosInfo> positionBuffer = new List<PosInfo>();
@@ -29,6 +30,7 @@ namespace Barotrauma
private bool editingHUDRefreshPending;
private float editingHUDRefreshTimer;
private ContainedItemSprite activeContainedSprite;
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
@@ -103,13 +105,10 @@ namespace Barotrauma
Color color = spriteColor;
if (Prefab.UseContainedSpriteColor && ownInventory != null)
{
for (int i = 0; i < ownInventory.Items.Length; i++)
foreach (Item item in ContainedItems)
{
if (ownInventory.Items[i] != null)
{
color = ownInventory.Items[i].ContainerColor;
break;
}
color = item.ContainerColor;
break;
}
}
return color;
@@ -120,13 +119,10 @@ namespace Barotrauma
Color color = InventoryIconColor;
if (Prefab.UseContainedInventoryIconColor && ownInventory != null)
{
for (int i = 0; i < ownInventory.Items.Length; i++)
foreach (Item item in ContainedItems)
{
if (ownInventory.Items[i] != null)
{
color = ownInventory.Items[i].ContainerColor;
break;
}
color = item.ContainerColor;
break;
}
}
return color;
@@ -135,6 +131,7 @@ namespace Barotrauma
partial void SetActiveSpriteProjSpecific()
{
activeSprite = prefab.sprite;
activeContainedSprite = null;
Holdable holdable = GetComponent<Holdable>();
if (holdable != null && holdable.Attached)
{
@@ -142,7 +139,9 @@ namespace Barotrauma
{
if (containedSprite.UseWhenAttached)
{
activeSprite = containedSprite.Sprite;
activeContainedSprite = containedSprite;
activeSprite = containedSprite.Sprite;
UpdateSpriteStates(0.0f);
return;
}
}
@@ -154,7 +153,9 @@ namespace Barotrauma
{
if (containedSprite.MatchesContainer(Container))
{
activeContainedSprite = containedSprite;
activeSprite = containedSprite.Sprite;
UpdateSpriteStates(0.0f);
return;
}
}
@@ -187,6 +188,7 @@ namespace Barotrauma
decorativeSprite.Sprite.EnsureLazyLoaded();
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
}
SetActiveSprite();
UpdateSpriteStates(0.0f);
}
@@ -240,7 +242,15 @@ namespace Barotrauma
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!Visible || (!editing && HiddenInGame)) { return; }
if (editing && !ShowItems) { return; }
if (editing)
{
if (isWire)
{
if (!ShowWires) { return; }
}
else if (!ShowItems) { return; }
}
Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange : GetSpriteColor();
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
@@ -305,7 +315,7 @@ namespace Barotrauma
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
decorativeSprite.Sprite.DrawTiled(spriteBatch,
@@ -328,7 +338,7 @@ namespace Barotrauma
}
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
if (Infector != null && Infector.ParentBallastFlora.HasBrokenThrough)
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
{
Prefab.InfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, Prefab.InfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.001f);
Prefab.DamagedInfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, Infector.HealthColor, Prefab.DamagedInfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.002f);
@@ -336,12 +346,12 @@ namespace Barotrauma
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
rotationRad + rot, decorativeSprite.Scale * Scale, activeSprite.effects,
rotationRad + rot, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
}
}
@@ -353,7 +363,7 @@ namespace Barotrauma
{
if (!back) { return; }
float depthStep = 0.000001f;
if (holdable.Picker.SelectedItems[0] == this)
if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightHand);
if (holdLimb?.ActiveSprite != null)
@@ -365,7 +375,7 @@ namespace Barotrauma
}
}
}
else if (holdable.Picker.SelectedItems[1] == this)
else if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == this)
{
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftHand);
if (holdLimb?.ActiveSprite != null)
@@ -384,8 +394,8 @@ namespace Barotrauma
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
var ca = (float)Math.Cos(-body.Rotation);
@@ -393,7 +403,7 @@ namespace Barotrauma
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + transformedOffset.X, -(DrawPosition.Y + transformedOffset.Y)), color,
-body.Rotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
}
@@ -405,12 +415,12 @@ namespace Barotrauma
foreach (var decorativeSprite in upgradeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, activeSprite.effects,
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
}
@@ -505,12 +515,39 @@ namespace Barotrauma
public void UpdateSpriteStates(float deltaTime)
{
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
if (activeContainedSprite != null)
{
if (activeContainedSprite.DecorativeSpriteBehavior == ContainedItemSprite.DecorativeSpriteBehaviorType.HideWhenVisible)
{
foreach (DecorativeSprite decorativeSprite in Prefab.DecorativeSprites)
{
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = false;
}
return;
}
}
else
{
foreach (var containedSprite in Prefab.ContainedSprites)
{
if (containedSprite.Sprite != activeSprite && containedSprite.DecorativeSpriteBehavior == ContainedItemSprite.DecorativeSpriteBehaviorType.HideWhenNotVisible)
{
foreach (DecorativeSprite decorativeSprite in Prefab.DecorativeSprites)
{
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = false;
}
return;
}
}
}
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
foreach (var upgrade in Upgrades)
{
var upgradeSprites = GetUpgradeSprites(upgrade);
var upgradeSprites = GetUpgradeSprites(upgrade);
foreach (var decorativeSprite in upgradeSprites)
{
var spriteState = spriteAnimState[decorativeSprite];
@@ -1035,6 +1072,28 @@ namespace Barotrauma
// Always create the texts if they have not yet been created
if (texts.Any() && !recreateHudTexts) { return texts; }
texts.Clear();
string nameText = Name;
if (Prefab.Identifier == "idcard" || Tags.Contains("despawncontainer"))
{
string[] readTags = Tags.Split(',');
string idName = null;
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
if (s[0] == "name")
{
idName = s[1];
break;
}
}
if (idName != null)
{
nameText += $" ({idName})";
}
}
texts.Add(new ColoredText(nameText, GUI.Style.TextColor, false, false));
foreach (ItemComponent ic in components)
{
if (string.IsNullOrEmpty(ic.DisplayMsg)) { continue; }
@@ -1259,7 +1318,7 @@ namespace Barotrauma
{
if (GameMain.Client == null) { return; }
if (parentInventory != null || body == null || !body.Enabled || Removed)
if (parentInventory != null || body == null || !body.Enabled || Removed || (GetComponent<Projectile>()?.IsStuckToTarget ?? false))
{
positionBuffer.Clear();
return;
@@ -1267,12 +1326,7 @@ namespace Barotrauma
isActive = true;
Vector2 newVelocity = body.LinearVelocity;
Vector2 newPosition = body.SimPosition;
float newAngularVelocity = body.AngularVelocity;
float newRotation = body.Rotation;
body.CorrectPosition(positionBuffer, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);
body.CorrectPosition(positionBuffer, out Vector2 newPosition, out Vector2 newVelocity, out float newRotation, out float newAngularVelocity);
body.LinearVelocity = newVelocity;
body.AngularVelocity = newAngularVelocity;
if (Vector2.DistanceSquared(newPosition, body.SimPosition) > 0.0001f ||
@@ -1490,7 +1544,7 @@ namespace Barotrauma
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
{
wifiComponent.TeamID = (Character.TeamType)teamID;
wifiComponent.TeamID = (CharacterTeamType)teamID;
}
if (descriptionChanged) { item.Description = itemDesc; }
if (tagsChanged) { item.Tags = tags; }
@@ -1521,10 +1575,10 @@ namespace Barotrauma
partial void RemoveProjSpecific()
{
if (Inventory.draggingItem == this)
if (Inventory.DraggingItems.Contains(this))
{
Inventory.draggingItem = null;
Inventory.draggingSlot = null;
Inventory.DraggingItems.Clear();
Inventory.DraggingSlot = null;
}
}
}

View File

@@ -24,14 +24,14 @@ namespace Barotrauma
protected override void CalculateBackgroundFrame()
{
var firstSlot = slots.FirstOrDefault();
var firstSlot = visualSlots.FirstOrDefault();
if (firstSlot == null) { return; }
Rectangle frame = firstSlot.Rect;
frame.Location += firstSlot.DrawOffset.ToPoint();
for (int i = 1; i < capacity; i++)
{
Rectangle slotRect = slots[i].Rect;
slotRect.Location += slots[i].DrawOffset.ToPoint();
Rectangle slotRect = visualSlots[i].Rect;
slotRect.Location += visualSlots[i].DrawOffset.ToPoint();
frame = Rectangle.Union(frame, slotRect);
}
BackgroundFrame = new Rectangle(
@@ -43,7 +43,7 @@ namespace Barotrauma
public override void Draw(SpriteBatch spriteBatch, bool subInventory = false)
{
if (slots != null && slots.Length > 0)
if (visualSlots != null && visualSlots.Length > 0)
{
CalculateBackgroundFrame();
if (container.InventoryBackSprite == null)
@@ -70,7 +70,7 @@ namespace Barotrauma
if (container.InventoryBottomSprite != null && !subInventory)
{
container.InventoryBottomSprite.Draw(spriteBatch,
new Vector2(BackgroundFrame.Center.X, BackgroundFrame.Bottom) + slots[0].DrawOffset,
new Vector2(BackgroundFrame.Center.X, BackgroundFrame.Bottom) + visualSlots[0].DrawOffset,
0.0f, UIScale);
}

View File

@@ -27,8 +27,14 @@ namespace Barotrauma
class ContainedItemSprite
{
public enum DecorativeSpriteBehaviorType
{
None, HideWhenVisible, HideWhenNotVisible
}
public readonly Sprite Sprite;
public readonly bool UseWhenAttached;
public readonly DecorativeSpriteBehaviorType DecorativeSpriteBehavior;
public readonly string[] AllowedContainerIdentifiers;
public readonly string[] AllowedContainerTags;
@@ -36,6 +42,7 @@ namespace Barotrauma
{
Sprite = new Sprite(element, path, lazyLoad: lazyLoad);
UseWhenAttached = element.GetAttributeBool("usewhenattached", false);
Enum.TryParse(element.GetAttributeString("decorativespritebehavior", "None"), ignoreCase: true, out DecorativeSpriteBehavior);
AllowedContainerIdentifiers = element.GetAttributeStringArray("allowedcontaineridentifiers", new string[0], convertToLowerInvariant: true);
AllowedContainerTags = element.GetAttributeStringArray("allowedcontainertags", new string[0], convertToLowerInvariant: true);
}

View File

@@ -65,6 +65,8 @@ namespace Barotrauma.MapCreatures.Behavior
public readonly List<DamageParticle> DamageParticles = new List<DamageParticle>();
public readonly List<DamageParticle> DeathParticles = new List<DamageParticle>();
public static bool AlwaysShowBallastFloraSprite = false;
partial void LoadPrefab(XElement element)
{
string? branchAtlasPath = element.GetAttributeString("branchatlas", null);
@@ -125,7 +127,7 @@ namespace Barotrauma.MapCreatures.Behavior
float particleAmount = Rand.Range(16, 32);
for (int i = 0; i < particleAmount; i++)
{
GameMain.ParticleManager.CreateParticle("shrapnel", pos, Rand.Vector(Rand.Range(-50f, 50.0f)));
GameMain.ParticleManager.CreateParticle("shrapnel", pos, Rand.Vector(Rand.Range(0f, 250.0f)), Rand.Range(0f, 360.0f));
}
}

View File

@@ -43,10 +43,10 @@ namespace Barotrauma
}
}
public void DrawFront(SpriteBatch spriteBatch, Camera cam)
public void DrawDebugOverlay(SpriteBatch spriteBatch, Camera cam)
{
if (renderer == null) { return; }
renderer.Draw(spriteBatch, cam);
renderer.DrawDebugOverlay(spriteBatch, cam);
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
{
@@ -114,10 +114,13 @@ namespace Barotrauma
graphics.Clear(BackgroundColor);
if (renderer == null) return;
renderer.DrawBackground(spriteBatch, cam, LevelObjectManager, backgroundCreatureManager);
renderer?.DrawBackground(spriteBatch, cam, LevelObjectManager, backgroundCreatureManager);
}
public void DrawFront(SpriteBatch spriteBatch, Camera cam)
{
renderer?.DrawForeground(spriteBatch, cam, LevelObjectManager);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool isGlobalUpdate = msg.ReadBoolean();

View File

@@ -241,6 +241,7 @@ namespace Barotrauma
private void UpdateDeformations(float deltaTime)
{
if (ActivePrefab.DeformableSprite == null) { return; }
foreach (SpriteDeformation deformation in spriteDeformations)
{
if (deformation is PositionalDeformation positionalDeformation)

View File

@@ -10,6 +10,7 @@ namespace Barotrauma
partial class LevelObjectManager
{
private readonly List<LevelObject> visibleObjectsBack = new List<LevelObject>();
private readonly List<LevelObject> visibleObjectsMid = new List<LevelObject>();
private readonly List<LevelObject> visibleObjectsFront = new List<LevelObject>();
private double NextRefreshTime;
@@ -26,6 +27,10 @@ namespace Barotrauma
{
obj.Update(deltaTime);
}
foreach (LevelObject obj in visibleObjectsMid)
{
obj.Update(deltaTime);
}
foreach (LevelObject obj in visibleObjectsFront)
{
obj.Update(deltaTime);
@@ -34,7 +39,7 @@ namespace Barotrauma
public IEnumerable<LevelObject> GetVisibleObjects()
{
return visibleObjectsBack.Union(visibleObjectsFront);
return visibleObjectsBack.Union(visibleObjectsMid).Union(visibleObjectsFront);
}
/// <summary>
@@ -43,6 +48,7 @@ namespace Barotrauma
private void RefreshVisibleObjects(Rectangle currentIndices, float zoom)
{
visibleObjectsBack.Clear();
visibleObjectsMid.Clear();
visibleObjectsFront.Clear();
float minSizeToDraw = MathHelper.Lerp(10.0f, 5.0f, Math.Min(zoom * 20.0f, 1.0f));
@@ -70,7 +76,10 @@ namespace Barotrauma
}
}
var objectList = obj.Position.Z >= 0 ? visibleObjectsBack : visibleObjectsFront;
var objectList =
obj.Position.Z >= 0 ?
visibleObjectsBack :
(obj.Position.Z < -1 ? visibleObjectsFront : visibleObjectsMid);
int drawOrderIndex = 0;
for (int i = 0; i < objectList.Count; i++)
{
@@ -102,8 +111,31 @@ namespace Barotrauma
currentGridIndices = currentIndices;
}
/// <summary>
/// Draw the objects behind the level walls
/// </summary>
public void DrawObjectsBack(SpriteBatch spriteBatch, Camera cam)
{
DrawObjects(spriteBatch, cam, visibleObjectsBack);
}
public void DrawObjects(SpriteBatch spriteBatch, Camera cam, bool drawFront)
/// <summary>
/// Draw the objects in front of the level walls, but behind characters
/// </summary>
public void DrawObjectsMid(SpriteBatch spriteBatch, Camera cam)
{
DrawObjects(spriteBatch, cam, visibleObjectsMid);
}
/// <summary>
/// Draw the objects in front of the level walls and characters
/// </summary>
public void DrawObjectsFront(SpriteBatch spriteBatch, Camera cam)
{
DrawObjects(spriteBatch, cam, visibleObjectsFront);
}
private void DrawObjects(SpriteBatch spriteBatch, Camera cam, List<LevelObject> objectList)
{
Rectangle indices = Rectangle.Empty;
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
@@ -132,7 +164,6 @@ namespace Barotrauma
}
}
var objectList = drawFront ? visibleObjectsFront : visibleObjectsBack;
foreach (LevelObject obj in objectList)
{
Vector2 camDiff = new Vector2(obj.Position.X, obj.Position.Y) - cam.WorldViewCenter;

View File

@@ -220,7 +220,7 @@ namespace Barotrauma
SamplerState.LinearWrap, DepthStencilState.DepthRead, null, null,
cam.Transform);
backgroundSpriteManager?.DrawObjects(spriteBatch, cam, drawFront: false);
backgroundSpriteManager?.DrawObjectsBack(spriteBatch, cam);
if (cam.Zoom > 0.05f)
{
backgroundCreatureManager?.Draw(spriteBatch, cam);
@@ -262,8 +262,6 @@ namespace Barotrauma
color: Color.White * alpha, textureScale: new Vector2(texScale));
}
}
spriteBatch.End();
RenderWalls(GameMain.Instance.GraphicsDevice, cam);
@@ -272,11 +270,21 @@ namespace Barotrauma
BlendState.NonPremultiplied,
SamplerState.LinearClamp, DepthStencilState.DepthRead, null, null,
cam.Transform);
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: true);
backgroundSpriteManager?.DrawObjectsMid(spriteBatch, cam);
spriteBatch.End();
}
public void Draw(SpriteBatch spriteBatch, Camera cam)
public void DrawForeground(SpriteBatch spriteBatch, Camera cam, LevelObjectManager backgroundSpriteManager = null)
{
spriteBatch.Begin(SpriteSortMode.Deferred,
BlendState.NonPremultiplied,
SamplerState.LinearClamp, DepthStencilState.DepthRead, null, null,
cam.Transform);
backgroundSpriteManager?.DrawObjectsFront(spriteBatch, cam);
spriteBatch.End();
}
public void DrawDebugOverlay(SpriteBatch spriteBatch, Camera cam)
{
if (GameMain.DebugDraw && cam.Zoom > 0.1f)
{

View File

@@ -391,7 +391,7 @@ namespace Barotrauma.Lights
if (GUI.DisableItemHighlights) { return false; }
highlightedEntities.Clear();
if (Character.Controlled != null && (!Character.Controlled.IsKeyDown(InputType.Aim) || Character.Controlled.SelectedItems.Any(it => it?.GetComponent<Sprayer>() == null)))
if (Character.Controlled != null && (!Character.Controlled.IsKeyDown(InputType.Aim) || Character.Controlled.HeldItems.Any(it => it.GetComponent<Sprayer>() == null)))
{
if (Character.Controlled.FocusedItem != null)
{

View File

@@ -222,7 +222,7 @@ namespace Barotrauma
return !tileDiscovered[MathHelper.Clamp(x, 0, tileDiscovered.Length), MathHelper.Clamp(y, 0, tileDiscovered.Length)];
}
partial void ChangeLocationType(Location location, string prevName, LocationTypeChange change)
partial void ChangeLocationTypeProjSpecific(Location location, string prevName, LocationTypeChange change)
{
if (change.Messages.Any())
{
@@ -383,11 +383,11 @@ namespace Barotrauma
Level.Loaded.DebugSetEndLocation(null);
CurrentLocation.Discovered = true;
CurrentLocation.CreateStore();
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
SelectLocation(-1);
if (GameMain.Client == null)
{
CurrentLocation.CreateStore();
ProgressWorld();
}
else
@@ -550,7 +550,7 @@ namespace Barotrauma
location.Type.Sprite.Draw(spriteBatch, pos, color,
scale: generationParams.LocationIconSize / location.Type.Sprite.size.X * iconScale * zoom);
if (location.TypeChangeTimer <= 0 && !string.IsNullOrEmpty(location.LastTypeChangeMessage) && generationParams.TypeChangeIcon != null)
if (location.TimeSinceLastTypeChange < 1 && !string.IsNullOrEmpty(location.LastTypeChangeMessage) && generationParams.TypeChangeIcon != null)
{
Vector2 typeChangeIconPos = pos + new Vector2(1.35f, -0.35f) * generationParams.LocationIconSize * 0.5f * zoom;
float typeChangeIconScale = 18.0f / generationParams.TypeChangeIcon.SourceRect.Width;
@@ -610,7 +610,7 @@ namespace Barotrauma
Vector2 nameSize = GUI.LargeFont.MeasureString(HighlightedLocation.Name);
Vector2 typeSize = GUI.Font.MeasureString(HighlightedLocation.Type.Name);
Vector2 size = new Vector2(Math.Max(nameSize.X, typeSize.X), nameSize.Y + typeSize.Y);
bool showReputation = HighlightedLocation.Discovered && HighlightedLocation.Type.HasOutpost && HighlightedLocation.Reputation != null;
bool showReputation = hudVisibility > 0.0f && HighlightedLocation.Discovered && HighlightedLocation.Type.HasOutpost && HighlightedLocation.Reputation != null;
string repLabelText = null, repValueText = null;
Vector2 repLabelSize = Vector2.Zero, repBarSize = Vector2.Zero;
if (showReputation)

View File

@@ -214,7 +214,7 @@ namespace Barotrauma
}
else if (PlayerInput.KeyHit(Keys.V))
{
Paste(cam.WorldViewCenter);
Paste(cam.ScreenToWorld(PlayerInput.MousePosition));
}
else if (PlayerInput.KeyHit(Keys.G))
{
@@ -279,31 +279,10 @@ namespace Barotrauma
if (GUI.KeyboardDispatcher.Subscriber == null)
{
int up = PlayerInput.KeyDown(Keys.Up) ? 1 : 0,
down = PlayerInput.KeyDown(Keys.Down) ? -1 : 0,
left = PlayerInput.KeyDown(Keys.Left) ? -1 : 0,
right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0;
int xKeysDown = (left + right);
int yKeysDown = (up + down);
if (xKeysDown != 0 || yKeysDown != 0) { keyDelay += (float) Timing.Step; } else { keyDelay = 0; }
Vector2 nudgeAmount = Vector2.Zero;
if (keyDelay >= 0.5f)
Vector2 nudge = GetNudgeAmount();
if (nudge != Vector2.Zero)
{
nudgeAmount.Y = yKeysDown;
nudgeAmount.X = xKeysDown;
}
if (PlayerInput.KeyHit(Keys.Up)) nudgeAmount.Y = 1f;
if (PlayerInput.KeyHit(Keys.Down)) nudgeAmount.Y = -1f;
if (PlayerInput.KeyHit(Keys.Left)) nudgeAmount.X = -1f;
if (PlayerInput.KeyHit(Keys.Right)) nudgeAmount.X = 1f;
if (nudgeAmount != Vector2.Zero)
{
foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudgeAmount); }
foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudge); }
}
}
else
@@ -476,6 +455,8 @@ namespace Barotrauma
{
if (PlayerInput.PrimaryMouseButtonHeld() &&
PlayerInput.KeyUp(Keys.Space) &&
PlayerInput.KeyUp(Keys.LeftAlt) &&
PlayerInput.KeyUp(Keys.RightAlt) &&
(highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
{
//if clicking a selected entity, start moving it
@@ -491,6 +472,37 @@ namespace Barotrauma
}
}
public static Vector2 GetNudgeAmount(bool doHold = true)
{
Vector2 nudgeAmount = Vector2.Zero;
if (doHold)
{
int up = PlayerInput.KeyDown(Keys.Up) ? 1 : 0,
down = PlayerInput.KeyDown(Keys.Down) ? -1 : 0,
left = PlayerInput.KeyDown(Keys.Left) ? -1 : 0,
right = PlayerInput.KeyDown(Keys.Right) ? 1 : 0;
int xKeysDown = (left + right);
int yKeysDown = (up + down);
if (xKeysDown != 0 || yKeysDown != 0) { keyDelay += (float) Timing.Step; } else { keyDelay = 0; }
if (keyDelay >= 0.5f)
{
nudgeAmount.Y = yKeysDown;
nudgeAmount.X = xKeysDown;
}
}
if (PlayerInput.KeyHit(Keys.Up)) nudgeAmount.Y = 1f;
if (PlayerInput.KeyHit(Keys.Down)) nudgeAmount.Y = -1f;
if (PlayerInput.KeyHit(Keys.Left)) nudgeAmount.X = -1f;
if (PlayerInput.KeyHit(Keys.Right)) nudgeAmount.X = 1f;
return nudgeAmount;
}
public MapEntity GetReplacementOrThis()
{
return ReplacedBy?.GetReplacementOrThis() ?? this;
@@ -511,7 +523,7 @@ namespace Barotrauma
{
if (entities == null)
{
if (potentialContainer.OwnInventory != null && potentialContainer.ParentInventory == null && !potentialContainer.OwnInventory.IsFull())
if (potentialContainer.OwnInventory != null && potentialContainer.ParentInventory == null && !potentialContainer.OwnInventory.IsFull(takeStacksIntoAccount: true))
{
targetContainer = potentialContainer;
break;

View File

@@ -45,7 +45,10 @@ namespace Barotrauma
{
CreateInstance(newRect);
placePosition = Vector2.Zero;
selected = null;
if (!PlayerInput.IsShiftDown())
{
selected = null;
}
}
newRect.Y = -newRect.Y;

View File

@@ -191,10 +191,11 @@ namespace Barotrauma
Vector2 max = new Vector2(worldRect.Right, worldRect.Y);
foreach (DecorativeSprite decorativeSprite in Prefab.DecorativeSprites)
{
min.X = Math.Min(worldPos.X - decorativeSprite.Sprite.size.X * decorativeSprite.Sprite.RelativeOrigin.X * decorativeSprite.Scale * Scale, min.X);
max.X = Math.Max(worldPos.X + decorativeSprite.Sprite.size.X * (1.0f - decorativeSprite.Sprite.RelativeOrigin.X) * decorativeSprite.Scale * Scale, max.X);
min.Y = Math.Min(worldPos.Y - decorativeSprite.Sprite.size.Y * (1.0f - decorativeSprite.Sprite.RelativeOrigin.Y) * decorativeSprite.Scale * Scale, min.Y);
max.Y = Math.Max(worldPos.Y + decorativeSprite.Sprite.size.Y * decorativeSprite.Sprite.RelativeOrigin.Y * decorativeSprite.Scale * Scale, max.Y);
float scale = decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale;
min.X = Math.Min(worldPos.X - decorativeSprite.Sprite.size.X * decorativeSprite.Sprite.RelativeOrigin.X * scale, min.X);
max.X = Math.Max(worldPos.X + decorativeSprite.Sprite.size.X * (1.0f - decorativeSprite.Sprite.RelativeOrigin.X) * scale, max.X);
min.Y = Math.Min(worldPos.Y - decorativeSprite.Sprite.size.Y * (1.0f - decorativeSprite.Sprite.RelativeOrigin.Y) * scale, min.Y);
max.Y = Math.Max(worldPos.Y + decorativeSprite.Sprite.size.Y * decorativeSprite.Sprite.RelativeOrigin.Y * scale, max.Y);
}
if (min.X > worldView.Right || max.X < worldView.X) { return false; }
@@ -220,9 +221,14 @@ namespace Barotrauma
Draw(spriteBatch, editing, false, damageEffect);
}
private float GetRealDepth()
{
return SpriteDepthOverrideIsSet ? SpriteOverrideDepth : prefab.sprite.Depth;
}
public float GetDrawDepth()
{
return GetDrawDepth(SpriteDepthOverrideIsSet ? SpriteOverrideDepth : prefab.sprite.Depth, prefab.sprite);
return GetDrawDepth(GetRealDepth(), prefab.sprite);
}
private void Draw(SpriteBatch spriteBatch, bool editing, bool back = true, Effect damageEffect = null)
@@ -320,7 +326,7 @@ namespace Barotrauma
}
}
if (back == depth > 0.5f)
if (back == GetRealDepth() > 0.5f)
{
SpriteEffects oldEffects = prefab.sprite.effects;
prefab.sprite.effects ^= SpriteEffects;
@@ -377,10 +383,10 @@ namespace Barotrauma
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * Scale;
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
rotation, decorativeSprite.Scale * Scale, prefab.sprite.effects,
rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, prefab.sprite.effects,
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.sprite.Depth), 0.999f));
}
prefab.sprite.effects = oldEffects;

View File

@@ -62,7 +62,11 @@ namespace Barotrauma
};
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity> { structure }, false));
selected = null;
placePosition = Vector2.Zero;
if (!PlayerInput.IsShiftDown())
{
selected = null;
}
return;
}
}

View File

@@ -22,6 +22,8 @@ namespace Barotrauma
public readonly float Range;
public readonly Vector2 FrequencyMultiplierRange;
public readonly bool Stream;
public readonly bool IgnoreMuffling;
public string Filename
{
@@ -55,7 +57,7 @@ namespace Barotrauma
{
DebugConsole.ThrowError($"Loaded frequency range exceeds max value: {FrequencyMultiplierRange} (original string was \"{freqMultAttr}\")");
}
sound.IgnoreMuffling = element.GetAttributeBool("dontmuffle", false);
IgnoreMuffling = element.GetAttributeBool("dontmuffle", false);
}
public float GetRandomFrequencyMultiplier()
@@ -376,22 +378,19 @@ namespace Barotrauma
public static void DrawGrid(SpriteBatch spriteBatch, int gridCells, Vector2 gridCenter, Vector2 roundedGridCenter, float alpha = 1.0f)
{
var horizontalLine = GUI.Style.GetComponentStyle("HorizontalLine").GetDefaultSprite();
var verticalLine = GUI.Style.GetComponentStyle("VerticalLine").GetDefaultSprite();
Vector2 topLeft = roundedGridCenter - Vector2.One * GridSize * gridCells / 2;
Vector2 bottomRight = roundedGridCenter + Vector2.One * GridSize * gridCells / 2;
for (int i = 0; i < gridCells; i++)
{
float distFromGridX = (MathUtils.RoundTowardsClosest(gridCenter.X, GridSize.X) - gridCenter.X) / GridSize.X;
float distFromGridY = (MathUtils.RoundTowardsClosest(gridCenter.X, GridSize.Y) - gridCenter.X) / GridSize.Y;
float distFromGridY = (MathUtils.RoundTowardsClosest(gridCenter.Y, GridSize.Y) - gridCenter.Y) / GridSize.Y;
float normalizedDistX = Math.Abs(i + distFromGridX - gridCells / 2) / (gridCells / 2);
float normalizedDistY = Math.Abs(i - distFromGridY - gridCells / 2) / (gridCells / 2);
float expandX = MathHelper.Lerp(30.0f, 0.0f, normalizedDistX);
float expandY = MathHelper.Lerp(30.0f, 0.0f, normalizedDistY);
float expandX = MathHelper.Lerp(30.0f, 0.0f, normalizedDistY);
float expandY = MathHelper.Lerp(30.0f, 0.0f, normalizedDistX);
GUI.DrawLine(spriteBatch,
new Vector2(topLeft.X - expandX, -bottomRight.Y + i * GridSize.Y),
@@ -420,9 +419,10 @@ namespace Barotrauma
parent.RectTransform, Anchor.Center),
style: null);
var connectedSubs = GetConnectedSubs();
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine != this && !(DockedTo.Contains(hull.Submarine))) continue;
if (hull.Submarine != this && !connectedSubs.Contains(hull.Submarine)) { continue; }
if (ignoreOutpost && !IsEntityFoundOnThisSub(hull, true)) { continue; }
Vector2 relativeHullPos = new Vector2(
@@ -533,11 +533,11 @@ namespace Barotrauma
for (int i = 0; i < item.Connections.Count; i++)
{
int wireCount = item.Connections[i].Wires.Count(w => w != null);
if (doorLinks + wireCount > Connection.MaxLinked)
if (doorLinks + wireCount > item.Connections[i].MaxWires)
{
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
new string[] { "[doorcount]", "[freeconnectioncount]" },
new string[] { doorLinks.ToString(), (Connection.MaxLinked - wireCount).ToString() }));
new string[] { doorLinks.ToString(), (item.Connections[i].MaxWires - wireCount).ToString() }));
break;
}
}

View File

@@ -10,6 +10,7 @@ namespace Barotrauma.Networking
{
public string Name;
public string PreferredJob;
public CharacterTeamType PreferredTeam;
public UInt16 NameID;
public UInt64 SteamID;
public byte ID;

View File

@@ -81,7 +81,7 @@ namespace Barotrauma.Networking
private byte myID;
private List<Client> otherClients;
private readonly List<Client> otherClients;
public readonly List<SubmarineInfo> ServerSubmarines = new List<SubmarineInfo>();
@@ -94,13 +94,13 @@ namespace Barotrauma.Networking
private UInt16 lastSentChatMsgID = 0; //last message this client has successfully sent
private UInt16 lastQueueChatMsgID = 0; //last message added to the queue
private List<ChatMessage> chatMsgQueue = new List<ChatMessage>();
private readonly List<ChatMessage> chatMsgQueue = new List<ChatMessage>();
public UInt16 LastSentEntityEventID;
private ClientEntityEventManager entityEventManager;
private readonly ClientEntityEventManager entityEventManager;
private FileReceiver fileReceiver;
private readonly FileReceiver fileReceiver;
#if DEBUG
public void PrintReceiverTransters()
@@ -138,6 +138,12 @@ namespace Barotrauma.Networking
}
}
private readonly List<Client> previouslyConnectedClients = new List<Client>();
public IEnumerable<Client> PreviouslyConnectedClients
{
get { return previouslyConnectedClients; }
}
public FileReceiver FileReceiver
{
get { return fileReceiver; }
@@ -153,9 +159,9 @@ namespace Barotrauma.Networking
get { return entityEventManager; }
}
private object serverEndpoint;
private int ownerKey;
private bool steamP2POwner;
private readonly object serverEndpoint;
private readonly int ownerKey;
private readonly bool steamP2POwner;
public bool IsServerOwner
{
@@ -852,7 +858,7 @@ namespace Barotrauma.Networking
endMessage = inc.ReadString();
bool missionSuccessful = inc.ReadBoolean();
Character.TeamType winningTeam = (Character.TeamType)inc.ReadByte();
CharacterTeamType winningTeam = (CharacterTeamType)inc.ReadByte();
if (missionSuccessful && GameMain.GameSession?.Mission != null)
{
GameMain.GameSession.WinningTeam = winningTeam;
@@ -1634,7 +1640,7 @@ namespace Barotrauma.Networking
{
if (Submarine.MainSubs[i] == null) { break; }
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
var teamID = i == 0 ? CharacterTeamType.Team1 : CharacterTeamType.Team2;
Submarine.MainSubs[i].TeamID = teamID;
foreach (Item item in Item.ItemList)
{
@@ -1828,6 +1834,7 @@ namespace Barotrauma.Networking
UInt16 nameId = inc.ReadUInt16();
string name = inc.ReadString();
string preferredJob = inc.ReadString();
byte preferredTeam = inc.ReadByte();
UInt16 characterID = inc.ReadUInt16();
float karma = inc.ReadSingle();
bool muted = inc.ReadBoolean();
@@ -1844,6 +1851,7 @@ namespace Barotrauma.Networking
SteamID = steamId,
Name = name,
PreferredJob = preferredJob,
PreferredTeam = (CharacterTeamType)preferredTeam,
CharacterID = characterID,
Karma = karma,
Muted = muted,
@@ -1878,6 +1886,7 @@ namespace Barotrauma.Networking
}
existingClient.NameID = tc.NameID;
existingClient.PreferredJob = tc.PreferredJob;
existingClient.PreferredTeam = tc.PreferredTeam;
existingClient.Character = null;
existingClient.Karma = tc.Karma;
existingClient.Muted = tc.Muted;
@@ -1917,6 +1926,17 @@ namespace Barotrauma.Networking
refreshCampaignUI = true;
}
}
foreach (Client client in ConnectedClients)
{
if (!previouslyConnectedClients.Any(c => c.ID == client.ID))
{
while (previouslyConnectedClients.Count > 100)
{
previouslyConnectedClients.RemoveAt(0);
}
previouslyConnectedClients.Add(client);
}
}
if (updateClientListId) { LastClientListUpdateID = listId; }
if (clientPeer is SteamP2POwnerPeer)
@@ -2142,6 +2162,7 @@ namespace Barotrauma.Networking
}
break;
case ServerNetObject.ENTITY_POSITION:
bool isItem = inc.ReadBoolean();
UInt16 id = inc.ReadUInt16();
uint msgLength = inc.ReadVariableUInt32();
int msgEndPos = (int)(inc.BitPosition + msgLength * 8);
@@ -2156,8 +2177,15 @@ namespace Barotrauma.Networking
entities.Add(entity);
if (entity != null && (entity is Item || entity is Character || entity is Submarine))
{
entity.ClientRead(objHeader.Value, inc, sendingTime);
}
if (entity is Item != isItem)
{
DebugConsole.AddWarning($"Received a potentially invalid ENTITY_POSITION message. Entity type does not match (server entity is {(isItem ? "an item" : "not an item")}, client entity is {(entity?.GetType().ToString() ?? "null")}). Ignoring the message...");
}
else
{
entity.ClientRead(objHeader.Value, inc, sendingTime);
}
}
//force to the correct position in case the entity doesn't exist
//or the message wasn't read correctly for whatever reason
@@ -2230,9 +2258,9 @@ namespace Barotrauma.Networking
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, string.Join("\n", errorLines));
DebugConsole.ThrowError("Writing object data to \"crashreport_object.log\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
DebugConsole.ThrowError("Writing object data to \"networkerror_data.log\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
using (FileStream fl = File.Open("crashreport_object.log", System.IO.FileMode.Create))
using (FileStream fl = File.Open("networkerror_data.log", System.IO.FileMode.Create))
{
using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fl))
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fl))
@@ -2245,7 +2273,7 @@ namespace Barotrauma.Networking
}
}
}
throw new Exception("Read error: please send us \"crashreport_object.bin\"!");
throw new Exception("Read error: please send us \"networkerror_data.log\"!");
}
}
@@ -2269,6 +2297,7 @@ namespace Barotrauma.Networking
{
outmsg.Write("");
}
outmsg.Write((byte)GameMain.Config.TeamPreference);
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaign.LastSaveID == 0)
{
@@ -3241,12 +3270,12 @@ namespace Barotrauma.Networking
public virtual bool SelectCrewCharacter(Character character, GUIComponent frame)
{
if (character == null) return false;
if (character == null) { return false; }
if (character != myCharacter)
{
var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.Character == character);
if (client == null) return false;
var client = previouslyConnectedClients.Find(c => c.Character == character);
if (client == null) { return false; }
CreateSelectionRelatedButtons(client, frame);
}
@@ -3256,7 +3285,7 @@ namespace Barotrauma.Networking
public virtual bool SelectCrewClient(Client client, GUIComponent frame)
{
if (client == null || client.ID == ID) return false;
if (client == null || client.ID == ID) { return false; }
CreateSelectionRelatedButtons(client, frame);
return true;
}

View File

@@ -38,6 +38,7 @@ namespace Barotrauma
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(DamageEnemyKarmaIncrease));
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(ItemRepairKarmaIncrease));
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, nameof(ExtinguishFireKarmaIncrease));
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(BallastFloraKarmaIncrease));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.12f), parent.RectTransform), TextManager.Get("Karma.NegativeActions"),
textAlignment: Alignment.Center, font: GUI.SubHeadingFont)
@@ -61,7 +62,6 @@ namespace Barotrauma
CreateLabeledNumberInput(parent, 0, 20, nameof(AllowedWireDisconnectionsPerMinute));
CreateLabeledSlider(parent, 0.0f, 20.0f, 0.5f, nameof(WireDisconnectionKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, nameof(SpamFilterKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(BallastFloraKarmaIncrease));
//hide these for now if a localized text is not available
if (TextManager.ContainsTag("Karma." + nameof(DangerousItemStealKarmaDecrease)))

View File

@@ -226,7 +226,7 @@ namespace Barotrauma.Networking
}
else
{
long msgPosition = msg.BitPosition;
int msgPosition = msg.BitPosition;
if (GameSettings.VerboseLogging)
{
DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")",
@@ -242,9 +242,9 @@ namespace Barotrauma.Networking
{
string errorMsg = "Message byte position incorrect after reading an event for the entity \"" + entity.ToString()
+ "\". Read " + (msg.BitPosition - msgPosition) + " bits, expected message length was " + (msgLength * 8) + " bits.";
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#endif
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
//TODO: force the BitPosition to correct place? Having some entity in a potentially incorrect state is not as bad as a desync kick

View File

@@ -168,7 +168,19 @@ namespace Barotrauma.Networking
{
Close(disableReconnect: true);
string missingModNames = "\n- " + string.Join("\n\n- ", missingPackages.Select(p => GetPackageStr(p))) + "\n\n";
string missingModNames = "\n";
int displayedModCount = 0;
foreach (ServerContentPackage missingPackage in missingPackages)
{
missingModNames += "\n- " + GetPackageStr(missingPackage);
displayedModCount++;
if (GUI.Font.MeasureString(missingModNames).Y > GameMain.GraphicsHeight * 0.5f)
{
missingModNames += "\n\n" + TextManager.GetWithVariable("workshopitemdownloadprompttruncated", "[number]", (missingPackages.Count - displayedModCount).ToString());
break;
}
}
missingModNames += "\n\n";
var msgBox = new GUIMessageBox(
TextManager.Get("WorkshopItemDownloadTitle"),
@@ -189,6 +201,7 @@ namespace Barotrauma.Networking
if (!contentPackageOrderReceived)
{
GameMain.Config.BackUpModOrder();
GameMain.Config.SwapPackages(corePackage.CorePackage, regularPackages.Select(p => p.RegularPackage).ToList());
contentPackageOrderReceived = true;
}

View File

@@ -195,10 +195,11 @@ namespace Barotrauma.Networking
{
foreach (var data in line.RichData)
{
UInt64 id = 0;
if (!UInt64.TryParse(data.Metadata, out id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
if (!UInt64.TryParse(data.Metadata, out ulong id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
if (client != null && client.Karma < 40.0f)
{
textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
@@ -243,10 +244,11 @@ namespace Barotrauma.Networking
Data = data,
OnClick = (component, area) =>
{
UInt64 id = 0;
if (!UInt64.TryParse(area.Data.Metadata, out id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
if (!UInt64.TryParse(area.Data.Metadata, out UInt64 id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
if (client == null) { return; }
GameMain.NetLobbyScreen.SelectPlayer(client);
}

View File

@@ -269,14 +269,13 @@ namespace Barotrauma.Steam
}
}
//TODO: find a better strategy to fetch all lobbies, this is gonna take forever if we actually have 10000 lobbies
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide().WithMaxResults(10000);
Steamworks.Dispatch.OnDebugCallback = (callbackType, contents, isServer) =>
{
DebugConsole.NewMessage($"{callbackType}: " + contents, Color.Yellow);
};
TaskPool.Add("LobbyQueryRequest", lobbyQuery.RequestAsync(),
TaskPool.Add("LobbyQueryRequest", LobbyQueryRequest(),
(t) =>
{
Steamworks.Dispatch.OnDebugCallback = null;
@@ -286,7 +285,7 @@ namespace Barotrauma.Steam
taskDone();
return;
}
var lobbies = ((Task<Steamworks.Data.Lobby[]>)t).Result;
var lobbies = ((Task<List<Steamworks.Data.Lobby>>)t).Result;
if (lobbies != null)
{
foreach (var lobby in lobbies)
@@ -373,6 +372,32 @@ namespace Barotrauma.Steam
return true;
}
public static async Task<List<Steamworks.Data.Lobby>> LobbyQueryRequest()
{
List<Steamworks.Data.Lobby> allLobbies = new List<Steamworks.Data.Lobby>();
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery()
.FilterDistanceWorldwide()
.WithMaxResults(50);
//steamworks seems to unable to retrieve more than 50
//lobbies per request; to work around this, we'll make
//up to 10 requests, asking to ignore all previous results
//in each subsequent request
for (int i = 0; i < 10; i++)
{
Steamworks.Data.Lobby[] lobbies = await lobbyQuery.RequestAsync();
if (lobbies == null) { break; }
foreach (var l in lobbies)
{
lobbyQuery = lobbyQuery
.WithoutKeyValue("lobbyowner", l.GetData("lobbyowner"));
}
allLobbies.AddRange(lobbies);
}
//make sure all returned lobbies are distinct, don't want any duplicates here
return allLobbies.Select(l => l.Id).Distinct().Select(i => allLobbies.Find(l => l.Id == i)).ToList();
}
public static void AssignLobbyDataToServerInfo(Steamworks.Data.Lobby lobby, ServerInfo serverInfo)
{
serverInfo.OwnerVerified = true;
@@ -1173,7 +1198,7 @@ namespace Barotrauma.Steam
foreach (ContentFile contentFile in contentPackage.Files)
{
contentFile.Path = contentFile.Path.CleanUpPath();
contentFile.Path = contentFile.Path.CleanUpPathCrossPlatform(correctFilenameCase: true, item?.Directory);
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
if (!File.Exists(sourceFile))
{

View File

@@ -239,7 +239,7 @@ namespace Barotrauma.Networking
bool allowEnqueue = false;
if (GameMain.WindowActive)
{
ForceLocal = captureTimer > 0 ? ForceLocal : false;
ForceLocal = captureTimer > 0 ? ForceLocal : GameMain.Config.UseLocalVoiceByDefault;
bool pttDown = false;
if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) &&
GUI.KeyboardDispatcher.Subscriber == null)

View File

@@ -101,7 +101,7 @@ namespace Barotrauma.Networking
var messageType = !client.VoipQueue.ForceLocal && ChatMessage.CanUseRadio(client.Character, out radio) ? ChatMessageType.Radio : ChatMessageType.Default;
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio;
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio && !GameMain.Config.DisableVoiceChatFilters;
if (client.VoipSound.UseRadioFilter)
{
client.VoipSound.SetRange(radio.Range * 0.8f, radio.Range);
@@ -110,7 +110,7 @@ namespace Barotrauma.Networking
{
client.VoipSound.SetRange(ChatMessage.SpeakRange * 0.4f, ChatMessage.SpeakRange);
}
if (!client.VoipSound.UseRadioFilter && Character.Controlled != null)
if (!client.VoipSound.UseRadioFilter && Character.Controlled != null && !GameMain.Config.DisableVoiceChatFilters)
{
client.VoipSound.UseMuffleFilter = SoundPlayer.ShouldMuffleSound(Character.Controlled, client.Character.WorldPosition, ChatMessage.SpeakRange, client.Character.CurrentHull);
}

View File

@@ -11,15 +11,15 @@ namespace Barotrauma
{
class CampaignSetupUI
{
private GUIComponent newGameContainer, loadGameContainer;
private readonly GUIComponent newGameContainer, loadGameContainer;
private GUIListBox subList;
private GUIListBox saveList;
private List<GUITickBox> subTickBoxes;
private GUITextBox saveNameBox, seedBox;
private readonly GUITextBox saveNameBox, seedBox;
private GUILayoutGroup subPreviewContainer;
private readonly GUILayoutGroup subPreviewContainer;
private GUIButton loadGameButton, deleteMpSaveButton;
@@ -35,6 +35,12 @@ namespace Barotrauma
private set;
}
public GUITextBlock InitialMoneyText
{
get;
private set;
}
private readonly bool isMultiplayer;
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
@@ -122,10 +128,10 @@ namespace Barotrauma
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.TopRight);
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
if (!isMultiplayer) { buttonContainer.IgnoreLayoutGroups = true; }
StartButton = new GUIButton(new RectTransform(new Vector2(0.45f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
{
OnClicked = (GUIButton btn, object userData) =>
{
@@ -224,6 +230,27 @@ namespace Barotrauma
}
};
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "",
font: isMultiplayer ? GUI.Style.SmallFont : GUI.Style.Font, textColor: GUI.Style.Green)
{
TextGetter = () =>
{
int initialMoney = CampaignMode.InitialMoney;
if (isMultiplayer)
{
if (GameMain.NetLobbyScreen.SelectedSub != null)
{
initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
}
}
else if (subList.SelectedData is SubmarineInfo subInfo)
{
initialMoney -= subInfo.Price;
}
initialMoney = Math.Max(initialMoney, isMultiplayer ? MultiPlayerCampaign.MinimumInitialMoney : 0);
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
}
};
if (!isMultiplayer)
{
@@ -366,7 +393,7 @@ namespace Barotrauma
if (!(obj is SubmarineInfo sub)) { return true; }
#if !DEBUG
if (!isMultiplayer && sub.Price > CampaignMode.MaxInitialSubmarinePrice && !GameMain.DebugDraw)
if (!isMultiplayer && sub.Price > CampaignMode.InitialMoney && !GameMain.DebugDraw)
{
StartButton.Enabled = false;
return false;
@@ -419,13 +446,14 @@ namespace Barotrauma
}
else
{
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass).ToList();
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
}
subsToShow.Sort((s1, s2) =>
{
int p1 = s1.Price > CampaignMode.MaxInitialSubmarinePrice ? 10 : 0;
int p2 = s2.Price > CampaignMode.MaxInitialSubmarinePrice ? 10 : 0;
int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0;
int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0;
return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
});
@@ -450,13 +478,13 @@ namespace Barotrauma
var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
TextColor = sub.Price > CampaignMode.MaxInitialSubmarinePrice ? GUI.Style.Red : textBlock.TextColor * 0.8f,
TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f,
ToolTip = textBlock.ToolTip
};
#if !DEBUG
if (!GameMain.DebugDraw)
{
if (sub.Price > CampaignMode.MaxInitialSubmarinePrice || !sub.IsCampaignCompatible)
if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible)
{
textBlock.CanBeFocused = false;
textBlock.TextColor *= 0.5f;
@@ -466,7 +494,7 @@ namespace Barotrauma
}
if (SubmarineInfo.SavedSubmarines.Any())
{
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.MaxInitialSubmarinePrice).ToList();
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList();
if (validSubs.Count > 0)
{
subList.Select(validSubs[Rand.Int(validSubs.Count)]);

View File

@@ -326,7 +326,7 @@ namespace Barotrauma
break;
case CampaignMode.InteractionType.Store:
Store?.Update();
Store?.Update(deltaTime);
break;
}
}

View File

@@ -820,6 +820,7 @@ namespace Barotrauma.CharacterEditor
}
}
}
spriteBatch.End();
// Lights
@@ -860,10 +861,7 @@ namespace Barotrauma.CharacterEditor
}
if (isDrawingLimb)
{
if (spriteSheetRect.Contains(PlayerInput.MousePosition))
{
GUI.DrawRectangle(spriteBatch, newLimbRect, Color.Yellow);
}
GUI.DrawRectangle(spriteBatch, newLimbRect, Color.Yellow);
}
if (jointCreationMode != JointCreationMode.None)
{
@@ -1131,32 +1129,25 @@ namespace Barotrauma.CharacterEditor
{
SetToggle(limbsToggle, true);
}
if (spriteSheetRect.Contains(PlayerInput.MousePosition))
if (PlayerInput.PrimaryMouseButtonHeld())
{
if (PlayerInput.PrimaryMouseButtonHeld())
if (newLimbRect == Rectangle.Empty)
{
if (newLimbRect == Rectangle.Empty)
{
newLimbRect = new Rectangle((int)PlayerInput.MousePosition.X, (int)PlayerInput.MousePosition.Y, 0, 0);
}
else
{
newLimbRect.Size = new Point((int)PlayerInput.MousePosition.X - newLimbRect.X, (int)PlayerInput.MousePosition.Y - newLimbRect.Y);
}
newLimbRect.Size = new Point(Math.Max(newLimbRect.Width, 2), Math.Max(newLimbRect.Height, 2));
newLimbRect = new Rectangle((int)PlayerInput.MousePosition.X, (int)PlayerInput.MousePosition.Y, 0, 0);
}
if (PlayerInput.PrimaryMouseButtonClicked())
else
{
// Take the offset and the zoom into account
newLimbRect.Location = new Point(newLimbRect.X - spriteSheetOffsetX, newLimbRect.Y - spriteSheetOffsetY);
newLimbRect = newLimbRect.Divide(spriteSheetZoom);
CreateNewLimb(newLimbRect);
isDrawingLimb = false;
newLimbRect = Rectangle.Empty;
newLimbRect.Size = new Point((int)PlayerInput.MousePosition.X - newLimbRect.X, (int)PlayerInput.MousePosition.Y - newLimbRect.Y);
}
newLimbRect.Size = new Point(Math.Max(newLimbRect.Width, 2), Math.Max(newLimbRect.Height, 2));
}
else
if (PlayerInput.PrimaryMouseButtonClicked())
{
// Take the offset and the zoom into account
newLimbRect.Location = new Point(newLimbRect.X - spriteSheetOffsetX, newLimbRect.Y - spriteSheetOffsetY);
newLimbRect = newLimbRect.Divide(spriteSheetZoom);
CreateNewLimb(newLimbRect);
isDrawingLimb = false;
newLimbRect = Rectangle.Empty;
}
}
@@ -1449,7 +1440,11 @@ namespace Barotrauma.CharacterEditor
{
if (allFiles == null)
{
#if DEBUG
allFiles = CharacterPrefab.ConfigFilePaths.OrderBy(p => p).ToList();
#else
allFiles = CharacterPrefab.ConfigFilePaths.Where(p => !p.Contains("variant", StringComparison.OrdinalIgnoreCase)).OrderBy(p => p).ToList();
#endif
allFiles.ForEach(f => DebugConsole.NewMessage(f, Color.White));
}
return allFiles;
@@ -1780,7 +1775,7 @@ namespace Barotrauma.CharacterEditor
// Animations
AnimationParams.ClearCache();
string animFolder = AnimationParams.GetFolder(name, contentPackage);
string animFolder = AnimationParams.GetFolder(name);
if (animations != null)
{
if (!Directory.Exists(animFolder))
@@ -1791,7 +1786,7 @@ namespace Barotrauma.CharacterEditor
{
XElement element = animation.MainElement;
element.SetAttributeValue("type", name);
string fullPath = AnimationParams.GetDefaultFile(name, animation.AnimationType, contentPackage);
string fullPath = AnimationParams.GetDefaultFile(name, animation.AnimationType);
element.Name = AnimationParams.GetDefaultFileName(name, animation.AnimationType);
#if DEBUG
element.Save(fullPath);
@@ -1816,7 +1811,7 @@ namespace Barotrauma.CharacterEditor
default: continue;
}
Type type = AnimationParams.GetParamTypeFromAnimType(animType, isHumanoid);
string fullPath = AnimationParams.GetDefaultFile(name, animType, contentPackage);
string fullPath = AnimationParams.GetDefaultFile(name, animType);
AnimationParams.Create(fullPath, name, animType, type);
}
}
@@ -1836,9 +1831,8 @@ namespace Barotrauma.CharacterEditor
private void ShowWearables()
{
if (character.Inventory == null) { return; }
foreach (var item in character.Inventory.Items)
foreach (var item in character.Inventory.AllItems)
{
if (item == null) { continue; }
// Temp condition, todo: remove
if (item.AllowedSlots.Contains(InvSlotType.Head) || item.AllowedSlots.Contains(InvSlotType.Headset)) { continue; }
item.Equip(character);
@@ -1847,7 +1841,7 @@ namespace Barotrauma.CharacterEditor
private void HideWearables()
{
character.Inventory?.Items.ForEachMod(i => i?.Unequip(character));
character.Inventory?.AllItemsMod.ForEach(i => i.Unequip(character));
}
#endregion
@@ -2787,8 +2781,10 @@ namespace Barotrauma.CharacterEditor
}
return true;
};
// Spacing
new GUIFrame(new RectTransform(buttonSize / 2, layoutGroup.RectTransform), style: null) { CanBeFocused = false };
Vector2 messageBoxRelSize = new Vector2(0.5f, 0.7f);
var saveRagdollButton = new GUIButton(new RectTransform(buttonSize, layoutGroup.RectTransform), GetCharacterEditorTranslation("SaveRagdoll"));
saveRagdollButton.OnClicked += (button, userData) =>
@@ -3573,15 +3569,33 @@ namespace Barotrauma.CharacterEditor
return rect;
}
// TODO: refactor this so that it can be used in all cases
private void UpdateSourceRect(Limb limb, Rectangle newRect)
private void UpdateSourceRect(Limb limb, Rectangle newRect, bool resize)
{
limb.ActiveSprite.SourceRect = newRect;
Sprite activeSprite = limb.ActiveSprite;
activeSprite.SourceRect = newRect;
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
Vector2 colliderSize = new Vector2(ConvertUnits.ToSimUnits(newRect.Width), ConvertUnits.ToSimUnits(newRect.Height));
if (resize)
{
if (recalculateCollider)
{
RecalculateCollider(limb, colliderSize);
}
}
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(activeSprite));
var originWidget = GetLimbEditWidget($"{limb.Params.ID}_origin", limb);
if (!resize && originWidget != null)
{
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(limb, newOrigin);
}
else
{
RecalculateOrigin(limb);
}
RecalculateOrigin(limb);
TryUpdateLimbParam(limb, "sourcerect", newRect);
if (limbPairEditing)
{
@@ -3592,30 +3606,25 @@ namespace Barotrauma.CharacterEditor
{
otherLimb.DamagedSprite.SourceRect = newRect;
}
if (resize)
{
if (recalculateCollider)
{
RecalculateCollider(otherLimb, colliderSize);
}
}
if (!resize && originWidget != null)
{
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(otherLimb, newOrigin);
}
else
{
RecalculateOrigin(otherLimb);
}
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
RecalculateOrigin(otherLimb);
});
};
void RecalculateOrigin(Limb l)
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
// TODO:
//if (lockSpriteOrigin)
//{
// // Keeps the absolute origin unchanged. The relative origin will be recalculated.
// var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(l));
// l.ActiveSprite.Origin = (originWidget.DrawPos - spritePos - l.ActiveSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
// TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
//}
//else
//{
// // Keeps the relative origin unchanged. The absolute origin will be recalculated.
// l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
//}
}
}
private void CalculateSpritesheetZoom()
@@ -4765,7 +4774,7 @@ namespace Barotrauma.CharacterEditor
w.refresh();
w.MouseHeld += dTime =>
{
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb));
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb.ActiveSprite));
w.DrawPos = PlayerInput.MousePosition.Clamp(spritePos + GetTopLeft() * spriteSheetZoom, spritePos + GetBottomRight() * spriteSheetZoom);
sprite.Origin = (w.DrawPos - spritePos - sprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
if (limb.DamagedSprite != null)
@@ -4796,14 +4805,14 @@ namespace Barotrauma.CharacterEditor
};
w.PreDraw += (sb, dTime) =>
{
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb));
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb.ActiveSprite));
w.DrawPos = (spritePos + (sprite.Origin + sprite.SourceRect.Location.ToVector2()) * spriteSheetZoom)
.Clamp(spritePos + GetTopLeft() * spriteSheetZoom, spritePos + GetBottomRight() * spriteSheetZoom);
w.refresh();
};
});
originWidget.Draw(spriteBatch, deltaTime);
if (!lockSpritePosition)
if (!lockSpritePosition && (limb.type != LimbType.Head || !character.IsHuman))
{
var positionWidget = GetLimbEditWidget($"{limb.Params.ID}_position", limb, widgetSize, Widget.Shape.Rectangle, initMethod: w =>
{
@@ -4812,17 +4821,20 @@ namespace Barotrauma.CharacterEditor
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
var newRect = limb.ActiveSprite.SourceRect;
Sprite activeSprite = limb.ActiveSprite;
var newRect = activeSprite.SourceRect;
newRect.Location = new Point(
(int)((PlayerInput.MousePosition.X + halfSize - spriteSheetOffsetX) / spriteSheetZoom),
(int)((PlayerInput.MousePosition.Y + halfSize - GetOffsetY(limb)) / spriteSheetZoom));
limb.ActiveSprite.SourceRect = newRect;
(int)((PlayerInput.MousePosition.Y + halfSize - GetOffsetY(activeSprite)) / spriteSheetZoom));
activeSprite.SourceRect = newRect;
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
RecalculateOrigin(limb);
TryUpdateLimbParam(limb, "sourcerect", newRect);
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(activeSprite));
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(limb, newOrigin);
if (limbPairEditing)
{
UpdateOtherLimbs(limb, otherLimb =>
@@ -4833,24 +4845,9 @@ namespace Barotrauma.CharacterEditor
otherLimb.DamagedSprite.SourceRect = newRect;
}
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
RecalculateOrigin(otherLimb);
RecalculateOrigin(otherLimb, newOrigin);
});
};
void RecalculateOrigin(Limb l)
{
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(l));
l.ActiveSprite.Origin = (originWidget.DrawPos - spritePos - l.ActiveSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
}
}
};
w.PreDraw += (sb, dTime) => w.refresh();
});
@@ -4860,7 +4857,7 @@ namespace Barotrauma.CharacterEditor
}
positionWidget.Draw(spriteBatch, deltaTime);
}
if (!lockSpriteSize)
if (!lockSpriteSize && (limb.type != LimbType.Head || !character.IsHuman))
{
var sizeWidget = GetLimbEditWidget($"{limb.Params.ID}_size", limb, widgetSize, Widget.Shape.Rectangle, initMethod: w =>
{
@@ -4869,22 +4866,24 @@ namespace Barotrauma.CharacterEditor
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
var newRect = limb.ActiveSprite.SourceRect;
float offset_y = limb.ActiveSprite.SourceRect.Y * spriteSheetZoom + GetOffsetY(limb);
float offset_x = limb.ActiveSprite.SourceRect.X * spriteSheetZoom + spriteSheetOffsetX;
Sprite activeSprite = limb.ActiveSprite;
Rectangle newRect = activeSprite.SourceRect;
float offset_y = activeSprite.SourceRect.Y * spriteSheetZoom + GetOffsetY(activeSprite);
float offset_x = activeSprite.SourceRect.X * spriteSheetZoom + spriteSheetOffsetX;
int width = (int)((PlayerInput.MousePosition.X - halfSize - offset_x) / spriteSheetZoom);
int height = (int)((PlayerInput.MousePosition.Y - halfSize - offset_y) / spriteSheetZoom);
newRect.Size = new Point(width, height);
limb.ActiveSprite.SourceRect = newRect;
limb.ActiveSprite.size = new Vector2(width, height);
activeSprite.SourceRect = newRect;
activeSprite.size = new Vector2(width, height);
Vector2 colliderSize = new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height));
if (recalculateCollider)
{
RecalculateCollider(limb);
RecalculateCollider(limb, colliderSize);
}
RecalculateOrigin(limb);
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
TryUpdateLimbParam(limb, "sourcerect", newRect);
if (limbPairEditing)
@@ -4895,7 +4894,7 @@ namespace Barotrauma.CharacterEditor
RecalculateOrigin(otherLimb);
if (recalculateCollider)
{
RecalculateCollider(otherLimb);
RecalculateCollider(otherLimb, colliderSize);
}
if (otherLimb.DamagedSprite != null)
{
@@ -4904,29 +4903,6 @@ namespace Barotrauma.CharacterEditor
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
});
};
void RecalculateCollider(Limb l)
{
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
float multiplier = 0.9f;
l.body.SetSize(new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * l.Scale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.height / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
}
void RecalculateOrigin(Limb l)
{
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
l.ActiveSprite.Origin = l.ActiveSprite.Origin;
TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
}
}
};
w.PreDraw += (sb, dTime) => w.refresh();
});
@@ -4955,22 +4931,48 @@ namespace Barotrauma.CharacterEditor
}
offsetY += (int)(texture.Height * spriteSheetZoom);
}
}
int GetTextureHeight(Limb limb)
private int GetTextureHeight(Sprite sprite)
{
int textureIndex = Textures.IndexOf(sprite.Texture);
int height = 0;
foreach (var t in Textures)
{
int textureIndex = Textures.IndexOf(limb.ActiveSprite.Texture);
int height = 0;
foreach (var t in Textures)
if (Textures.IndexOf(t) < textureIndex)
{
if (Textures.IndexOf(t) < textureIndex)
{
height += t.Height;
}
height += t.Height;
}
return (int)(height * spriteSheetZoom);
}
return (int)(height * spriteSheetZoom);
}
int GetOffsetY(Limb limb) => spriteSheetOffsetY + GetTextureHeight(limb);
private int GetOffsetY(Sprite sprite) => spriteSheetOffsetY + GetTextureHeight(sprite);
private void RecalculateCollider(Limb l, Vector2 size)
{
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
float multiplier = 0.9f;
l.body.SetSize(new Vector2(size.X, size.Y) * l.Scale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.height / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
}
private void RecalculateOrigin(Limb l, Vector2? newOrigin = null)
{
Sprite activeSprite = l.ActiveSprite;
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
activeSprite.Origin = newOrigin ?? activeSprite.Origin;
TryUpdateLimbParam(l, "origin", activeSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
activeSprite.RelativeOrigin = activeSprite.RelativeOrigin;
}
}
private void DrawSpritesheetJointEditor(SpriteBatch spriteBatch, float deltaTime, Limb limb, Vector2 limbScreenPos, float spriteRotation = 0)
@@ -5175,61 +5177,81 @@ namespace Barotrauma.CharacterEditor
case Keys.Left:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Width--;
}
else
{
if (lockSpritePosition) { return; }
newRect.X--;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Right:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Width++;
}
else
{
if (lockSpritePosition) { return; }
newRect.X++;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Down:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Height++;
}
else
{
if (lockSpritePosition) { return; }
newRect.Y++;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Up:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Height--;
}
else
{
if (lockSpritePosition) { return; }
newRect.Y--;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
}

View File

@@ -0,0 +1,571 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
class EditorImageManager
{
private struct EditorImageContainer
{
public float Rotation;
public float Scale;
public Vector2 Position;
public string Path;
public float Opacity;
public EditorImage.DrawTargetType DrawTarget;
public EditorImage CreateImage()
{
return new EditorImage(Path, Position)
{
Position = Position,
Scale = Scale,
Opacity = Opacity,
Rotation = Rotation,
DrawTarget = DrawTarget
};
}
public static EditorImageContainer? Load(XElement element)
{
string path = element.GetAttributeString("path", "");
if (string.IsNullOrWhiteSpace(path)) { return null; }
Vector2 pos = element.GetAttributeVector2("pos", Vector2.Zero);
float scale = element.GetAttributeFloat("scale", 1f);
float rotation = element.GetAttributeFloat("rotation", 0f);
float opacity = element.GetAttributeFloat("opacity", 1f);
string drawTargetString = element.GetAttributeString("drawtarget", "");
if (!Enum.TryParse<EditorImage.DrawTargetType>(drawTargetString, out var drawTarget))
{
drawTarget = EditorImage.DrawTargetType.World;
}
return new EditorImageContainer
{
Path = path,
Rotation = rotation,
Opacity = opacity,
Position = pos,
Scale = scale,
DrawTarget = drawTarget
};
}
public static EditorImageContainer ImageToContainer(EditorImage img)
{
return new EditorImageContainer
{
Path = img.ImagePath,
Rotation = img.Rotation,
Position = img.Position,
Opacity = img.Opacity,
Scale = img.Scale,
DrawTarget = img.DrawTarget
};
}
public static XElement SerializeImage(EditorImageContainer image)
{
return new XElement("image",
new XAttribute("pos", XMLExtensions.Vector2ToString(image.Position)),
new XAttribute("rotation", image.Rotation),
new XAttribute("opacity", image.Opacity),
new XAttribute("path", image.Path),
new XAttribute("scale", image.Scale),
new XAttribute("drawtarget", image.DrawTarget.ToString()));
}
}
private readonly List<EditorImageContainer> PendingImages = new List<EditorImageContainer>();
public readonly List<EditorImage> Images = new List<EditorImage>();
private readonly List<EditorImage> screenImages = new List<EditorImage>(),
worldImages = new List<EditorImage>();
public bool EditorMode;
private string editModeText = "";
private Vector2 textSize = Vector2.Zero;
public void Save(XElement element)
{
XElement saveElement = new XElement("editorimages");
foreach (EditorImage image in Images)
{
EditorImageContainer container = EditorImageContainer.ImageToContainer(image);
saveElement.Add(EditorImageContainer.SerializeImage(container));
}
foreach (EditorImageContainer container in PendingImages)
{
saveElement.Add(EditorImageContainer.SerializeImage(container));
}
element.Add(saveElement);
}
public void Load(XElement element)
{
Clear(alsoPending: true);
foreach (XElement subElement in element.Elements())
{
EditorImageContainer? tempImage = EditorImageContainer.Load(subElement);
if (tempImage != null)
{
PendingImages.Add(tempImage.Value);
}
}
}
public void OnEditorSelected()
{
editModeText = TextManager.Get("SubEditor.ImageEditingMode");
textSize = GUI.LargeFont.MeasureString(editModeText);
TryLoadPendingImages();
}
private void TryLoadPendingImages()
{
if (PendingImages.Count == 0) { return; }
Clear(alsoPending: false);
foreach (EditorImageContainer pendingImage in PendingImages)
{
EditorImage img = pendingImage.CreateImage();
if (img.Image == null) { continue; }
Images.Add(img);
img.UpdateRectangle();
}
UpdateImageCategories();
PendingImages.Clear();
}
public void Clear(bool alsoPending = false)
{
foreach (EditorImage img in Images)
{
img.Image?.Dispose();
}
Images.Clear();
screenImages.Clear();
worldImages.Clear();
if (alsoPending)
{
PendingImages.Clear();
}
}
public void Update(float deltaTime)
{
if (!EditorMode) { return; }
foreach (EditorImage image in Images)
{
image.Update(deltaTime);
}
if (PlayerInput.PrimaryMouseButtonDown())
{
EditorImage? hover = Images.FirstOrDefault(img => img.IsMouseOn());
if (hover != null)
{
foreach (EditorImage image in Images)
{
image.Selected = false;
}
hover.Selected = true;
}
}
if (PlayerInput.KeyHit(Keys.Delete) || (PlayerInput.IsCtrlDown() && PlayerInput.KeyHit(Keys.D)))
{
Images.RemoveAll(img => img.Selected);
UpdateImageCategories();
}
if (PlayerInput.KeyHit(Keys.Space))
{
foreach (EditorImage image in Images)
{
if (image.Selected)
{
if (image.DrawTarget == EditorImage.DrawTargetType.World)
{
Vector2 pos = image.Position;
pos.Y = -pos.Y;
pos = Screen.Selected.Cam.WorldToScreen(pos);
if (PlayerInput.IsShiftDown())
{
pos = new Vector2(GameMain.GraphicsWidth / 2f, GameMain.GraphicsHeight / 2f);
}
image.Position = pos;
image.DrawTarget = EditorImage.DrawTargetType.Camera;
image.Scale *= Screen.Selected.Cam.Zoom;
image.UpdateRectangle();
}
else
{
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(image.Position);
pos.Y = -pos.Y;
image.Position = pos;
image.DrawTarget = EditorImage.DrawTargetType.World;
image.Scale /= Screen.Selected.Cam.Zoom;
image.UpdateRectangle();
}
}
}
UpdateImageCategories();
}
MapEntity.DisableSelect = true;
}
private void UpdateImageCategories()
{
screenImages.Clear();
worldImages.Clear();
foreach (EditorImage image in Images)
{
switch (image.DrawTarget)
{
case EditorImage.DrawTargetType.World:
worldImages.Add(image);
break;
default:
screenImages.Add(image);
break;
}
}
}
public void CreateImageWizard(Vector2 positon)
{
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
if (!Directory.Exists(home)) { return; }
FileSelection.OnFileSelected = file =>
{
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(positon);
pos.Y = -pos.Y;
Images.Add(new EditorImage(file, pos) { DrawTarget = EditorImage.DrawTargetType.World });
UpdateImageCategories();
GameMain.Config.SaveNewPlayerConfig();
};
FileSelection.ClearFileTypeFilters();
FileSelection.AddFileTypeFilter("PNG", "*.png");
FileSelection.AddFileTypeFilter("JPEG", "*.jpg, *.jpeg");
FileSelection.AddFileTypeFilter("All files", "*.*");
FileSelection.SelectFileTypeFilter("*.png");
FileSelection.CurrentDirectory = home;
FileSelection.Open = true;
}
public void DrawEditing(SpriteBatch spriteBatch, Camera cam)
{
if (!EditorMode) { return; }
DrawImages(spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
Vector2 textPos = new Vector2(GameMain.GraphicsWidth / 2f - (textSize.X / 2f), GameMain.GraphicsHeight / 10f - (textSize.Y / 2f));
GUI.DrawString(spriteBatch, textPos, editModeText, GUI.Style.Yellow, Color.Black * 0.4f, 8, GUI.LargeFont);
spriteBatch.End();
}
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (EditorMode) { return; }
DrawImages(spriteBatch, cam);
}
private void DrawImages(SpriteBatch spriteBatch, Camera cam)
{
if (screenImages.Count > 0)
{
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
foreach (EditorImage image in screenImages)
{
image.Draw(spriteBatch);
if (EditorMode) { image.DrawEditing(spriteBatch, cam); }
}
spriteBatch.End();
}
if (worldImages.Count > 0)
{
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, transformMatrix: cam.Transform);
foreach (EditorImage image in worldImages)
{
image.Draw(spriteBatch);
if (EditorMode) { image.DrawEditing(spriteBatch, cam); }
}
spriteBatch.End();
}
}
}
class EditorImage
{
public enum DrawTargetType
{
Camera,
World
}
public Texture2D? Image;
public string ImagePath;
public Vector2 Position;
public float Rotation;
public float Opacity = 1f;
public float Scale = 1f;
public DrawTargetType DrawTarget;
public bool Selected;
public Rectangle Bounds;
private float prevAngle;
private bool disableMove;
private bool isDragging;
private readonly Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
public EditorImage(string path, Vector2 pos)
{
Image = Sprite.LoadTexture(path, out Sprite _, compress: false);
ImagePath = path;
Position = pos;
UpdateRectangle();
}
public bool IsMouseOn() => Bounds.Contains(GetMousePos());
public Vector2 GetMousePos()
{
switch (DrawTarget)
{
case DrawTargetType.Camera:
return PlayerInput.MousePosition;
case DrawTargetType.World:
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition);
pos.Y = -pos.Y;
return pos;
default:
return PlayerInput.MousePosition;
}
}
public void Update(float deltaTime)
{
if (!Selected) { return; }
if (widgets.Values.Any(w => w.IsSelected)) { return; }
if (PlayerInput.PrimaryMouseButtonDown() && !disableMove && IsMouseOn())
{
isDragging = true;
}
if (isDragging)
{
Camera cam = Screen.Selected.Cam;
if (PlayerInput.MouseSpeed != Vector2.Zero)
{
Vector2 mouseSpeed = PlayerInput.MouseSpeed;
if (DrawTarget == DrawTargetType.World)
{
mouseSpeed /= cam.Zoom;
}
Position += mouseSpeed;
UpdateRectangle();
}
}
if (PlayerInput.KeyDown(Keys.OemPlus) || PlayerInput.KeyDown(Keys.Up))
{
Opacity += 0.01f;
}
if (PlayerInput.KeyDown(Keys.OemMinus) || PlayerInput.KeyDown(Keys.Down))
{
Opacity -= 0.01f;
}
if (PlayerInput.KeyHit(Keys.D0))
{
Opacity = 1f;
}
Opacity = Math.Clamp(Opacity, 0, 1f);
if (!PlayerInput.PrimaryMouseButtonHeld())
{
isDragging = false;
}
}
private void DrawWidgets(SpriteBatch spriteBatch)
{
float widgetSize = Image == null ? 100f : Math.Max(Image.Width, Image.Height) / 2f;
int width = 3;
int size = 32;
if (DrawTarget == DrawTargetType.World)
{
width = Math.Max(width, (int) (width / Screen.Selected.Cam.Zoom));
}
Widget currentWidget = GetWidget("transform", size, width, widget =>
{
widget.MouseDown += () =>
{
widget.color = GUI.Style.Green;
prevAngle = Rotation;
disableMove = true;
};
widget.Deselected += () =>
{
widget.color = Color.Yellow;
disableMove = false;
};
widget.MouseHeld += (deltaTime) =>
{
Rotation = GetRotationAngle(Position) + (float) Math.PI / 2f;
float distance = Vector2.Distance(Position, GetMousePos());
Scale = Math.Abs(distance) / widgetSize;
if (PlayerInput.IsShiftDown())
{
const float rotationStep = (float) (Math.PI / 4f);
Rotation = (float) Math.Round(Rotation / rotationStep) * rotationStep;
}
if (PlayerInput.IsCtrlDown())
{
const float scaleStep = 0.1f;
Scale = (float) Math.Round(Scale / scaleStep) * scaleStep;
}
UpdateRectangle();
};
widget.PreUpdate += (deltaTime) =>
{
if (DrawTarget != DrawTargetType.World) { return; }
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
widget.DrawPos = Screen.Selected.Cam.WorldToScreen(widget.DrawPos);
};
widget.PostUpdate += (deltaTime) =>
{
if (DrawTarget != DrawTargetType.World) { return; }
widget.DrawPos = Screen.Selected.Cam.ScreenToWorld(widget.DrawPos);
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
};
widget.PreDraw += (sprtBtch, deltaTime) =>
{
widget.tooltip = $"Scale: {Math.Round(Scale, 2)}\n" +
$"Rotation: {(int) MathHelper.ToDegrees(Rotation)}";
float rotation = Rotation - (float) Math.PI / 2f;
widget.DrawPos = Position + new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation)) * (Scale * widgetSize);
widget.Update(deltaTime);
};
});
currentWidget.Draw(spriteBatch, (float) Timing.Step);
GUI.DrawLine(spriteBatch, Position, currentWidget.DrawPos, GUI.Style.Green, width: width);
}
private float GetRotationAngle(Vector2 drawPosition)
{
Vector2 rotationVector = GetMousePos() - drawPosition;
rotationVector.Normalize();
double angle = Math.Atan2(MathHelper.ToRadians(rotationVector.Y), MathHelper.ToRadians(rotationVector.X));
if (angle < 0)
{
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle + Math.PI * 2) - prevAngle) ? angle : angle + Math.PI * 2;
}
else if (angle > 0)
{
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle - Math.PI * 2) - prevAngle) ? angle : angle - Math.PI * 2;
}
angle = MathHelper.Clamp((float) angle, -((float) Math.PI * 2), (float) Math.PI * 2);
prevAngle = (float) angle;
return (float) angle;
}
private Widget GetWidget(string id, int size, float thickness = 1f, Action<Widget>? initMethod = null)
{
if (!widgets.TryGetValue(id, out Widget? widget))
{
widget = new Widget(id, size, Widget.Shape.Rectangle)
{
color = Color.Yellow,
RequireMouseOn = false
};
widgets.Add(id, widget);
initMethod?.Invoke(widget);
}
widget.size = size;
widget.thickness = thickness;
return widget;
}
public void UpdateRectangle()
{
if (Image == null)
{
Bounds = new Rectangle((int) Position.X, (int) Position.Y, 512, 512);
return;
}
Vector2 size = new Vector2(Image.Width * Scale, Image.Height * Scale);
Bounds = new Rectangle((Position - size / 2f).ToPoint(), size.ToPoint());
}
public void Draw(SpriteBatch spriteBatch)
{
if (Image == null) { return; }
spriteBatch.Draw(Image, Position, null, Color.White * Opacity, Rotation, new Vector2(Image.Width / 2f, Image.Height / 2f), scale: Scale, SpriteEffects.None, 0f);
}
public void DrawEditing(SpriteBatch spriteBatch, Camera cam)
{
Rectangle bounds = Bounds;
int width = 4;
if (DrawTarget == DrawTargetType.World)
{
width = (int) (width / cam.Zoom);
}
GUI.DrawRectangle(spriteBatch, bounds, Selected ? GUI.Style.Red : GUI.Style.Green, thickness: width);
if (Selected)
{
DrawWidgets(spriteBatch);
}
}
}
}

View File

@@ -399,7 +399,7 @@ namespace Barotrauma
else
{
newNode = new CustomNode(subElement.Name.ToString()) { Position = new Vector2(ident, 0), ID = CreateID() };
foreach (XAttribute attribute in subElement.Attributes())
foreach (XAttribute attribute in subElement.Attributes().Where(attribute => !attribute.ToString().StartsWith("_")))
{
newNode.Connections.Add(new NodeConnection(newNode, NodeConnectionType.Value, attribute.Name.ToString(), typeof(string)));
}
@@ -525,6 +525,7 @@ namespace Barotrauma
public override void Select()
{
GUI.PreventPauseMenuToggle = false;
projectName = TextManager.Get("EventEditor.Unnamed");
base.Select();
}

View File

@@ -77,9 +77,8 @@ namespace Barotrauma
}
if (Character.Controlled?.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.Items)
foreach (Item item in Character.Controlled.Inventory.AllItems)
{
if (item == null) { continue; }
if (Character.Controlled.HasEquippedItem(item))
{
item.AddToGUIUpdateList();
@@ -249,6 +248,8 @@ namespace Barotrauma
}
spriteBatch.End();
Level.Loaded?.DrawFront(spriteBatch, cam);
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
graphics.SetRenderTarget(renderTargetWater);
@@ -317,10 +318,8 @@ namespace Barotrauma
{
c.DrawFront(spriteBatch, cam);
}
if (Level.Loaded != null)
{
Level.Loaded.DrawFront(spriteBatch, cam);
}
Level.Loaded?.DrawDebugOverlay(spriteBatch, cam);
if (GameMain.DebugDraw)
{
MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch));
@@ -374,7 +373,10 @@ namespace Barotrauma
{
BlurStrength = Character.Controlled.BlurStrength * 0.005f;
DistortStrength = Character.Controlled.DistortStrength;
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
if (GameMain.Config.EnableRadialDistortion)
{
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
}
chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
}
else
@@ -438,8 +440,8 @@ namespace Barotrauma
if (!PlayerInput.PrimaryMouseButtonHeld())
{
Inventory.draggingSlot = null;
Inventory.draggingItem = null;
Inventory.DraggingSlot = null;
Inventory.DraggingItems.Clear();
}
}
}

View File

@@ -714,8 +714,9 @@ namespace Barotrauma
if (Level.Loaded != null)
{
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: cam.Transform);
Level.Loaded.DrawFront(spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: cam.Transform);
Level.Loaded.DrawDebugOverlay(spriteBatch, cam);
Submarine.Draw(spriteBatch, false);
Submarine.DrawFront(spriteBatch);
Submarine.DrawDamageable(spriteBatch, null);
@@ -817,6 +818,13 @@ namespace Barotrauma
public override void Update(double deltaTime)
{
if (lightingEnabled.Selected)
{
foreach (Item item in Item.ItemList)
{
item?.GetComponent<Items.Components.LightComponent>()?.Update((float)deltaTime, cam);
}
}
GameMain.LightManager?.Update((float)deltaTime);
pointerLightSource.Position = cam.ScreenToWorld(PlayerInput.MousePosition);
@@ -886,16 +894,16 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
string id = element.GetAttributeString("identifier", null) ?? element.Name.ToString();
string id = subElement.GetAttributeString("identifier", null) ?? subElement.Name.ToString();
if (!id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(genParams, element, true);
genParams.Save(subElement);
}
}
else
{
string id = element.GetAttributeString("identifier", null) ?? element.Name.ToString();
if (!id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(genParams, element, true);
genParams.Save(element);
}
break;
}

View File

@@ -679,7 +679,7 @@ namespace Barotrauma
}
#endregion
public void QuickStart(bool fixedSeed = false)
public void QuickStart(bool fixedSeed = false, string sub = null)
{
if (fixedSeed)
{
@@ -688,7 +688,7 @@ namespace Barotrauma
}
SubmarineInfo selectedSub = null;
string subName = GameMain.Config.QuickStartSubmarineName;
string subName = sub ?? GameMain.Config.QuickStartSubmarineName;
if (!string.IsNullOrEmpty(subName))
{
DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
@@ -834,6 +834,39 @@ namespace Barotrauma
return true;
}
private void TryStartServer()
{
if (SubmarineInfo.SavedSubmarines.Any(s => s.CalculatingHash))
{
var waitBox = new GUIMessageBox(TextManager.Get("pleasewait"), TextManager.Get("waitforsubmarinehashcalculations"), new string[] { TextManager.Get("cancel") });
var waitCoroutine = CoroutineManager.StartCoroutine(WaitForSubmarineHashCalculations(waitBox), "WaitForSubmarineHashCalculations");
waitBox.Buttons[0].OnClicked += (btn, userdata) =>
{
CoroutineManager.StopCoroutines(waitCoroutine);
return true;
};
}
else
{
StartServer();
}
}
private IEnumerable<object> WaitForSubmarineHashCalculations(GUIMessageBox messageBox)
{
string originalText = messageBox.Text.Text;
int doneCount = 0;
do
{
doneCount = SubmarineInfo.SavedSubmarines.Count(s => !s.CalculatingHash);
messageBox.Text.Text = originalText + $" ({doneCount}/{SubmarineInfo.SavedSubmarines.Count()})";
yield return CoroutineStatus.Running;
} while (doneCount < SubmarineInfo.SavedSubmarines.Count());
messageBox.Close();
StartServer();
yield return CoroutineStatus.Success;
}
private void StartServer()
{
string name = serverNameBox.Text;
@@ -1095,12 +1128,13 @@ namespace Barotrauma
StartNewGame = StartGame
};
var startButtonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), innerNewGame.RectTransform, Anchor.Center), style: null);
var startButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), innerNewGame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.BottomRight);
campaignSetupUI.StartButton.RectTransform.Parent = startButtonContainer.RectTransform;
campaignSetupUI.StartButton.RectTransform.MinSize = new Point(
(int)(campaignSetupUI.StartButton.TextBlock.TextSize.X * 1.5f),
campaignSetupUI.StartButton.RectTransform.MinSize.Y);
startButtonContainer.RectTransform.MinSize = new Point(0, campaignSetupUI.StartButton.RectTransform.MinSize.Y);
campaignSetupUI.InitialMoneyText.RectTransform.Parent = startButtonContainer.RectTransform;
}
private void CreateHostServerFields()
@@ -1340,7 +1374,7 @@ namespace Barotrauma
new string[] { TextManager.Get("yes"), TextManager.Get("no") });
msgBox.Buttons[0].OnClicked += (_, __) =>
{
StartServer();
TryStartServer();
msgBox.Close();
return true;
};
@@ -1348,7 +1382,7 @@ namespace Barotrauma
}
else
{
StartServer();
TryStartServer();
}
return true;

Some files were not shown because too many files have changed in this diff Show More