(965c31410) v0.10.4.0
This commit is contained in:
@@ -163,7 +163,8 @@ namespace Barotrauma
|
||||
position = Vector2.Zero;
|
||||
|
||||
CreateMatrices();
|
||||
GameMain.Instance.OnResolutionChanged += () => { CreateMatrices(); };
|
||||
// TODO: Needs to unregister if ever destroy cameras.
|
||||
GameMain.Instance.ResolutionChanged += CreateMatrices;
|
||||
|
||||
UpdateTransform(false);
|
||||
}
|
||||
@@ -260,27 +261,30 @@ namespace Barotrauma
|
||||
if (targetPos == Vector2.Zero)
|
||||
{
|
||||
Vector2 moveInput = Vector2.Zero;
|
||||
if (allowMove && GUI.KeyboardDispatcher.Subscriber == null)
|
||||
if (allowMove)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f);
|
||||
moveCam = velocity * moveSpeed * deltaTime * 60.0f;
|
||||
|
||||
if (Screen.Selected == GameMain.GameScreen && FollowSub)
|
||||
{
|
||||
var closestSub = Submarine.FindClosest(WorldViewCenter);
|
||||
if (closestSub != null)
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime);
|
||||
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;
|
||||
}
|
||||
|
||||
velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f);
|
||||
moveCam = velocity * moveSpeed * deltaTime * 60.0f;
|
||||
|
||||
if (Screen.Selected == GameMain.GameScreen && FollowSub)
|
||||
{
|
||||
var closestSub = Submarine.FindClosest(WorldViewCenter);
|
||||
if (closestSub != null)
|
||||
{
|
||||
moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowZoom && GUI.MouseOn == null)
|
||||
@@ -311,7 +315,7 @@ namespace Barotrauma
|
||||
{
|
||||
Freeze = true;
|
||||
}
|
||||
if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen)
|
||||
if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen || ConversationAction.IsDialogOpen)
|
||||
{
|
||||
offset *= 0;
|
||||
Freeze = false;
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Barotrauma
|
||||
{
|
||||
partial class HumanAIController : AIController
|
||||
{
|
||||
public static bool debugai;
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
/*if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
|
||||
@@ -18,6 +20,8 @@ namespace Barotrauma
|
||||
|
||||
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
if (Character == Character.Controlled) { return; }
|
||||
if (!debugai) { return; }
|
||||
Vector2 pos = Character.WorldPosition;
|
||||
pos.Y = -pos.Y;
|
||||
Vector2 textOffset = new Vector2(-40, -160);
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (body.UserData is Limb || body == Collider.FarseerBody)
|
||||
{
|
||||
if (!character.IsRemotePlayer && impact > ImpactTolerance)
|
||||
if (!character.IsRemotelyControlled && impact > ImpactTolerance)
|
||||
{
|
||||
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
|
||||
}
|
||||
@@ -460,21 +460,14 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public float GetDepthOffset()
|
||||
{
|
||||
float maxDepth = 0.0f;
|
||||
float minDepth = 1.0f;
|
||||
float depthOffset = 0.0f;
|
||||
var ladder = character.SelectedConstruction?.GetComponent<Ladder>();
|
||||
|
||||
if (ladder != null)
|
||||
{
|
||||
float maxDepth = 0.0f;
|
||||
float minDepth = 1.0f;
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
var activeSprite = limb.ActiveSprite;
|
||||
if (activeSprite != null)
|
||||
{
|
||||
maxDepth = Math.Max(activeSprite.Depth, maxDepth);
|
||||
minDepth = Math.Min(activeSprite.Depth, minDepth);
|
||||
}
|
||||
}
|
||||
CalculateLimbDepths();
|
||||
if (character.WorldPosition.X < character.SelectedConstruction.WorldPosition.X)
|
||||
{
|
||||
//at the left side of the ladder, needs to be drawn in front of the rungs
|
||||
@@ -486,6 +479,36 @@ namespace Barotrauma
|
||||
depthOffset = Math.Max(ladder.BackgroundSpriteDepth + 0.01f - minDepth, 0.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateLimbDepths();
|
||||
var controller = character.SelectedConstruction?.GetComponent<Controller>();
|
||||
if (controller != null && controller.ControlCharacterPose && controller.User == character)
|
||||
{
|
||||
if (controller.Item.SpriteDepth > maxDepth)
|
||||
{
|
||||
depthOffset = Math.Max(controller.Item.SpriteDepth - 0.0001f - maxDepth, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
depthOffset = Math.Max(controller.Item.SpriteDepth + 0.0001f - minDepth, -minDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateLimbDepths()
|
||||
{
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
var activeSprite = limb.ActiveSprite;
|
||||
if (activeSprite != null)
|
||||
{
|
||||
maxDepth = Math.Max(activeSprite.Depth, maxDepth);
|
||||
minDepth = Math.Min(activeSprite.Depth, minDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return depthOffset;
|
||||
}
|
||||
|
||||
@@ -498,10 +521,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (limb.PullJointEnabled)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorB);
|
||||
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), GUI.Style.Red, true, 0.01f);
|
||||
|
||||
pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
|
||||
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Cyan, true, 0.01f);
|
||||
}
|
||||
|
||||
limb.body.DebugDraw(spriteBatch, inWater ? (currentHull == null ? Color.Blue : Color.Cyan) : Color.White);
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Barotrauma
|
||||
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
protected float hudInfoTimer;
|
||||
protected bool hudInfoVisible;
|
||||
protected float hudInfoTimer = 1.0f;
|
||||
protected bool hudInfoVisible = false;
|
||||
|
||||
private float pressureParticleTimer;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
||||
|
||||
protected float lastRecvPositionUpdateTime;
|
||||
|
||||
private float hudInfoHeight;
|
||||
private float hudInfoHeight = 100.0f;
|
||||
|
||||
private List<CharacterSound> sounds;
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (Lights.LightManager.ViewTarget is Item item && item.Prefab.FocusOnSelected)
|
||||
{
|
||||
cam.OffsetAmount = targetOffsetAmount = item.Prefab.OffsetOnSelected;
|
||||
cam.OffsetAmount = targetOffsetAmount = item.Prefab.OffsetOnSelected * item.OffsetOnSelectedMultiplier;
|
||||
}
|
||||
else if (SelectedConstruction != null && ViewTarget == null &&
|
||||
SelectedConstruction.Components.Any(ic => ic?.GuiFrame != null && ic.ShouldDrawHUD(this)))
|
||||
@@ -549,11 +549,12 @@ namespace Barotrauma
|
||||
public bool ShouldLockHud()
|
||||
{
|
||||
if (this != controlled) { return false; }
|
||||
|
||||
if (GameMain.GameSession?.Campaign != null && GameMain.GameSession.Campaign.ShowCampaignUI) { return true; }
|
||||
var controller = SelectedConstruction?.GetComponent<Controller>();
|
||||
//lock if using a controller, except if we're also using a connection panel in the same item
|
||||
return
|
||||
SelectedConstruction != null &&
|
||||
SelectedConstruction?.GetComponent<Controller>()?.User == this &&
|
||||
controller?.User == this && controller.HideHUD &&
|
||||
SelectedConstruction?.GetComponent<ConnectionPanel>()?.User != this;
|
||||
}
|
||||
|
||||
@@ -661,7 +662,7 @@ namespace Barotrauma
|
||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, bool drawHealth = true)
|
||||
{
|
||||
CharacterHUD.Draw(spriteBatch, this, cam);
|
||||
if (drawHealth) CharacterHealth.DrawHUD(spriteBatch);
|
||||
if (drawHealth && !CharacterHUD.IsCampaignInterfaceOpen) { CharacterHealth.DrawHUD(spriteBatch); }
|
||||
}
|
||||
|
||||
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
@@ -672,8 +673,8 @@ namespace Barotrauma
|
||||
{
|
||||
AnimController.DebugDraw(spriteBatch);
|
||||
}
|
||||
|
||||
if (GUI.DisableHUD) return;
|
||||
|
||||
if (GUI.DisableHUD) { return; }
|
||||
|
||||
if (Controlled != null &&
|
||||
Controlled != this &&
|
||||
@@ -756,19 +757,23 @@ namespace Barotrauma
|
||||
float hoverRange = 300.0f;
|
||||
float fadeOutRange = 200.0f;
|
||||
float cursorDist = Vector2.Distance(WorldPosition, cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f);
|
||||
float hudInfoAlpha =
|
||||
CampaignInteractionType == CampaignMode.InteractionType.None ?
|
||||
MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f) :
|
||||
1.0f;
|
||||
|
||||
if (!GUI.DisableCharacterNames && hudInfoVisible && info != null &&
|
||||
(controlled == null || this != controlled.FocusedCharacter))
|
||||
(controlled == null || this != controlled.FocusedCharacter) && cam.Zoom > 0.4f)
|
||||
{
|
||||
string name = Info.DisplayName;
|
||||
if (controlled == null && name != Info.Name) name += " " + TextManager.Get("Disguised");
|
||||
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
|
||||
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(name) * 0.5f / cam.Zoom;
|
||||
Vector2 nameSize = GUI.Font.MeasureString(name);
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
|
||||
|
||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
|
||||
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
|
||||
namePos *= screenSize / viewportSize;
|
||||
namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
|
||||
namePos *= viewportSize / screenSize;
|
||||
@@ -779,16 +784,30 @@ namespace Barotrauma
|
||||
{
|
||||
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + CampaignInteractionType);
|
||||
if (iconStyle != null)
|
||||
{
|
||||
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
|
||||
Vector2 iconPos = headPos;
|
||||
iconPos.Y = -iconPos.Y;
|
||||
nameColor = iconStyle.Color;
|
||||
var icon = iconStyle.Sprites[GUIComponent.ComponentState.None].First();
|
||||
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
|
||||
icon.Sprite.Draw(spriteBatch, iconPos + new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f);
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos, nameColor * hudInfoAlpha, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.Font.DrawString(spriteBatch, ID.ToString(), namePos - new Vector2(0.0f, 20.0f), Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDead) return;
|
||||
if (IsDead) { return; }
|
||||
|
||||
if (CharacterHealth.DisplayedVitality < MaxVitality * 0.98f && hudInfoVisible)
|
||||
{
|
||||
|
||||
@@ -41,13 +41,21 @@ namespace Barotrauma
|
||||
private static bool shouldRecreateHudTexts = true;
|
||||
private static bool heldDownShiftWhenGotHudTexts;
|
||||
|
||||
public static bool IsCampaignInterfaceOpen =>
|
||||
GameMain.GameSession?.Campaign != null &&
|
||||
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI);
|
||||
|
||||
private static bool ShouldDrawInventory(Character character)
|
||||
{
|
||||
var controller = character.SelectedConstruction?.GetComponent<Controller>();
|
||||
|
||||
return
|
||||
character?.Inventory != null &&
|
||||
character.AllowInput &&
|
||||
!character.LockHands &&
|
||||
character.SelectedConstruction?.GetComponent<Controller>()?.User != character;
|
||||
!character.LockHands &&
|
||||
(controller?.User != character || !controller.HideHUD) &&
|
||||
!IsCampaignInterfaceOpen &&
|
||||
!ConversationAction.FadeScreenToBlack;
|
||||
}
|
||||
|
||||
private static string GetCachedHudText(string textTag, string keyBind)
|
||||
@@ -65,7 +73,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen)
|
||||
{
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
@@ -92,9 +100,17 @@ namespace Barotrauma
|
||||
|
||||
public static void Update(float deltaTime, Character character, Camera cam)
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
if (GUI.DisableHUD)
|
||||
{
|
||||
if (character.Inventory != null && !LockInventory(character))
|
||||
{
|
||||
character.Inventory.UpdateSlotInput();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen)
|
||||
{
|
||||
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null)
|
||||
{
|
||||
@@ -163,7 +179,7 @@ namespace Barotrauma
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine == null || item.Submarine.TeamID != character.TeamID || item.Submarine.Info.IsWreck) { continue; }
|
||||
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.RepairThreshold)) { continue; }
|
||||
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.RepairIconThreshold)) { continue; }
|
||||
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
|
||||
|
||||
Vector2 diff = item.WorldPosition - character.WorldPosition;
|
||||
@@ -211,7 +227,7 @@ namespace Barotrauma
|
||||
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
|
||||
}
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen)
|
||||
{
|
||||
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
|
||||
{
|
||||
@@ -299,6 +315,8 @@ namespace Barotrauma
|
||||
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
}
|
||||
|
||||
if (IsCampaignInterfaceOpen) { return; }
|
||||
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
|
||||
@@ -308,10 +326,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character);
|
||||
if (ic.DrawHudWhenEquipped) { ic.DrawHUD(spriteBatch, character); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool mouseOnPortrait = false;
|
||||
if (character.Stun <= 0.1f && !character.IsDead)
|
||||
{
|
||||
@@ -421,7 +440,7 @@ namespace Barotrauma
|
||||
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += textSize.Y;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
|
||||
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText) && character.FocusedCharacter.AllowCustomInteract)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += textSize.Y;
|
||||
@@ -430,7 +449,7 @@ namespace Barotrauma
|
||||
|
||||
private static bool LockInventory(Character character)
|
||||
{
|
||||
if (character?.Inventory == null || !character.AllowInput || character.LockHands) { return true; }
|
||||
if (character?.Inventory == null || !character.AllowInput || character.LockHands || IsCampaignInterfaceOpen) { return true; }
|
||||
|
||||
return character.ShouldLockHud();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -12,9 +13,11 @@ namespace Barotrauma
|
||||
{
|
||||
private static Sprite infoAreaPortraitBG;
|
||||
|
||||
public bool LastControlled;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.GetDefaultSprite();
|
||||
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
||||
}
|
||||
|
||||
@@ -117,6 +120,7 @@ namespace Barotrauma
|
||||
|
||||
private void DrawInfoFrameCharacterIcon(SpriteBatch sb, Rectangle componentRect)
|
||||
{
|
||||
if (headSprite == null) { return; }
|
||||
Vector2 targetAreaSize = componentRect.Size.ToVector2();
|
||||
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
|
||||
DrawIcon(sb, componentRect.Location.ToVector2() + headSprite.size / 2 * scale, targetAreaSize);
|
||||
@@ -140,6 +144,9 @@ namespace Barotrauma
|
||||
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
|
||||
{
|
||||
if (TeamID == Character.TeamType.FriendlyNPC) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
|
||||
|
||||
if (newLevel - prevLevel > 0.1f)
|
||||
{
|
||||
GUI.AddMessage(
|
||||
|
||||
@@ -75,8 +75,15 @@ namespace Barotrauma
|
||||
states = newInput,
|
||||
intAim = intAngle
|
||||
};
|
||||
if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
|
||||
(!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health)))
|
||||
|
||||
if (FocusedCharacter != null &&
|
||||
FocusedCharacter.CampaignInteractionType != CampaignMode.InteractionType.None &&
|
||||
newMem.states.HasFlag(InputNetFlags.Use))
|
||||
{
|
||||
newMem.interact = FocusedCharacter.ID;
|
||||
}
|
||||
else if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
|
||||
!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health))
|
||||
{
|
||||
newMem.interact = focusedItem.ID;
|
||||
}
|
||||
@@ -278,10 +285,10 @@ namespace Barotrauma
|
||||
break;
|
||||
case ServerNetObject.ENTITY_EVENT:
|
||||
|
||||
int eventType = msg.ReadRangedInteger(0, 4);
|
||||
int eventType = msg.ReadRangedInteger(0, 5);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0:
|
||||
case 0: //NetEntityEvent.Type.InventoryState
|
||||
if (Inventory == null)
|
||||
{
|
||||
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
|
||||
@@ -301,7 +308,7 @@ namespace Barotrauma
|
||||
Inventory.ClientRead(type, msg, sendingTime);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 1: //NetEntityEvent.Type.Control
|
||||
byte ownerID = msg.ReadByte();
|
||||
ResetNetState();
|
||||
if (ownerID == GameMain.Client.ID)
|
||||
@@ -326,10 +333,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 2: //NetEntityEvent.Type.Status
|
||||
ReadStatus(msg);
|
||||
break;
|
||||
case 3:
|
||||
case 3: //NetEntityEvent.Type.UpdateSkills
|
||||
int skillCount = msg.ReadByte();
|
||||
for (int i = 0; i < skillCount; i++)
|
||||
{
|
||||
@@ -338,17 +345,17 @@ namespace Barotrauma
|
||||
info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 4: //NetEntityEvent.Type.ExecuteAttack
|
||||
int attackLimbIndex = msg.ReadByte();
|
||||
UInt16 targetEntityID = msg.ReadUInt16();
|
||||
int targetLimbIndex = msg.ReadByte();
|
||||
|
||||
//255 = entity already removed, no need to do anything
|
||||
if (attackLimbIndex == 255) { break; }
|
||||
if (attackLimbIndex == 255 || Removed) { break; }
|
||||
|
||||
if (attackLimbIndex >= AnimController.Limbs.Length)
|
||||
{
|
||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds ({attackLimbIndex})");
|
||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
|
||||
break;
|
||||
}
|
||||
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
||||
@@ -362,7 +369,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
|
||||
{
|
||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds ({targetLimbIndex})");
|
||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
|
||||
break;
|
||||
}
|
||||
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
||||
@@ -372,6 +379,10 @@ namespace Barotrauma
|
||||
attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
|
||||
}
|
||||
break;
|
||||
case 5: //NetEntityEvent.Type.AssignCampaignInteraction
|
||||
byte campaignInteractionType = msg.ReadByte();
|
||||
(GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
|
||||
break;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
break;
|
||||
@@ -398,7 +409,7 @@ namespace Barotrauma
|
||||
Character character = null;
|
||||
if (noInfo)
|
||||
{
|
||||
character = Create(speciesName, position, seed, null, true);
|
||||
character = Create(speciesName, position, seed, null, false);
|
||||
character.ID = id;
|
||||
bool containsStatusData = inc.ReadBoolean();
|
||||
if (containsStatusData)
|
||||
@@ -416,9 +427,14 @@ namespace Barotrauma
|
||||
|
||||
CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);
|
||||
|
||||
character = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
|
||||
character = Create(speciesName, position, seed, info, ownerId > 0 && GameMain.Client.ID != ownerId, hasAi);
|
||||
character.ID = id;
|
||||
character.TeamID = (TeamType)teamID;
|
||||
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
|
||||
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||
{
|
||||
(GameMain.GameSession.GameMode as CampaignMode)?.AssignNPCMenuInteraction(character, character.CampaignInteractionType);
|
||||
}
|
||||
|
||||
// Check if the character has a current order
|
||||
if (inc.ReadBoolean())
|
||||
|
||||
@@ -525,6 +525,7 @@ namespace Barotrauma
|
||||
},
|
||||
TextManager.Get("GiveInButton"), style: "GUIButtonLarge")
|
||||
{
|
||||
Visible = false,
|
||||
ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer"),
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
@@ -944,6 +945,22 @@ namespace Barotrauma
|
||||
|
||||
suicideButton.Visible = Character == Character.Controlled && !Character.IsDead && Character.IsIncapacitated;
|
||||
|
||||
if (GameMain.GameSession?.Campaign is { } campaign)
|
||||
{
|
||||
RectTransform endRoundButton = campaign?.EndRoundButton.RectTransform;
|
||||
if (endRoundButton != null)
|
||||
{
|
||||
if (suicideButton.Visible)
|
||||
{
|
||||
endRoundButton.ScreenSpaceOffset = new Point(0, suicideButton.Rect.Height);
|
||||
}
|
||||
else if (endRoundButton.ScreenSpaceOffset != Point.Zero)
|
||||
{
|
||||
endRoundButton.ScreenSpaceOffset = Point.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cprButton.Visible =
|
||||
Character == Character.Controlled?.SelectedCharacter
|
||||
&& (Character.IsUnconscious || Character.Stun > 0.0f)
|
||||
@@ -965,23 +982,29 @@ namespace Barotrauma
|
||||
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
if (GUI.DisableHUD) { return; }
|
||||
if (OpenHealthWindow == this)
|
||||
{
|
||||
healthInterfaceFrame.AddToGUIUpdateList();
|
||||
afflictionTooltip?.AddToGUIUpdateList();
|
||||
}
|
||||
else if (Character.Controlled == Character)
|
||||
else if (Character.Controlled == Character && !CharacterHUD.IsCampaignInterfaceOpen)
|
||||
{
|
||||
healthBarHolder.AddToGUIUpdateList();
|
||||
}
|
||||
if (suicideButton.Visible && Character == Character.Controlled) suicideButton.AddToGUIUpdateList();
|
||||
if (cprButton != null && cprButton.Visible) cprButton.AddToGUIUpdateList();
|
||||
if (suicideButton.Visible && Character == Character.Controlled)
|
||||
{
|
||||
suicideButton.AddToGUIUpdateList();
|
||||
}
|
||||
if (cprButton != null && cprButton.Visible)
|
||||
{
|
||||
cprButton.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
if (GUI.DisableHUD) { return; }
|
||||
if (GameMain.GraphicsWidth != screenResolution.X ||
|
||||
GameMain.GraphicsHeight != screenResolution.Y ||
|
||||
Math.Abs(inventoryScale - Inventory.UIScale) > 0.01f ||
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace Barotrauma
|
||||
return frameHolder;
|
||||
}
|
||||
|
||||
|
||||
public class OutfitPreview
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -50,7 +50,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static bool isOpen;
|
||||
public static bool IsOpen => isOpen;
|
||||
public static bool IsOpen
|
||||
{
|
||||
get => isOpen;
|
||||
set => isOpen = value;
|
||||
}
|
||||
|
||||
public static bool Paused = false;
|
||||
|
||||
private static GUITextBlock activeQuestionText;
|
||||
@@ -66,6 +71,8 @@ namespace Barotrauma
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
OpenAL.Alc.SetErrorReasonCallback((string msg) => NewMessage(msg, Color.Orange));
|
||||
|
||||
frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.45f), GUI.Canvas) { MinSize = new Point(400, 300), AbsoluteOffset = new Point(10, 10) },
|
||||
color: new Color(0.4f, 0.4f, 0.4f, 0.8f));
|
||||
|
||||
@@ -263,12 +270,31 @@ namespace Barotrauma
|
||||
|
||||
try
|
||||
{
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
||||
msg.Text, font: GUI.SmallFont, wrap: true)
|
||||
if (msg.IsError)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = msg.Color
|
||||
};
|
||||
var textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform), style: "InnerFrame", color: Color.White)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width - 5, 0), textContainer.RectTransform, Anchor.TopLeft) { AbsoluteOffset = new Point(2, 2) },
|
||||
msg.Text, textAlignment: Alignment.TopLeft, font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = msg.Color
|
||||
};
|
||||
textContainer.RectTransform.NonScaledSize = new Point(textContainer.RectTransform.NonScaledSize.X, textBlock.RectTransform.NonScaledSize.Y + 5);
|
||||
textBlock.SetTextPos();
|
||||
}
|
||||
else
|
||||
{
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
||||
msg.Text, font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = msg.Color
|
||||
};
|
||||
}
|
||||
|
||||
listBox.UpdateScrollBarSize();
|
||||
listBox.BarScroll = 1.0f;
|
||||
}
|
||||
@@ -446,6 +472,11 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.SpriteEditorScreen.Select();
|
||||
}));
|
||||
|
||||
commands.Add(new Command("editevents|eventeditor", "editevents/eventeditor: Switch to the Event Editor to edit scripted events.", (string[] args) =>
|
||||
{
|
||||
GameMain.EventEditorScreen.Select();
|
||||
}));
|
||||
|
||||
commands.Add(new Command("editcharacters|charactereditor", "editcharacters/charactereditor: Switch to the Character Editor to edit/create the ragdolls and animations of characters.", (string[] args) =>
|
||||
{
|
||||
@@ -456,9 +487,11 @@ namespace Barotrauma
|
||||
GameMain.CharacterEditorScreen.Select();
|
||||
}));
|
||||
|
||||
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks debug logging.", (string[] args) =>
|
||||
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks networking debug logging.", (string[] args) =>
|
||||
{
|
||||
SteamManager.NetworkingDebugLog = !SteamManager.NetworkingDebugLog;
|
||||
SteamManager.SetSteamworksNetworkingDebugLog(SteamManager.NetworkingDebugLog);
|
||||
|
||||
}));
|
||||
|
||||
AssignRelayToServer("kick", false);
|
||||
@@ -493,6 +526,7 @@ namespace Barotrauma
|
||||
commands.Add(new Command("traitorlist", "", (string[] args) => { }));
|
||||
AssignRelayToServer("traitorlist", true);
|
||||
AssignRelayToServer("money", true);
|
||||
AssignRelayToServer("setskill", true);
|
||||
|
||||
AssignOnExecute("control", (string[] args) =>
|
||||
{
|
||||
@@ -568,16 +602,46 @@ namespace Barotrauma
|
||||
|
||||
AssignOnExecute("ambientlight", (string[] args) =>
|
||||
{
|
||||
Color color = XMLExtensions.ParseColor(string.Join(",", args));
|
||||
bool add = string.Equals(args.LastOrDefault(), "add");
|
||||
string colorString = string.Join(",", add ? args.SkipLast(1) : args);
|
||||
if (colorString.Equals("restore", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.OriginalAmbientLight != null)
|
||||
{
|
||||
hull.AmbientLight = hull.OriginalAmbientLight.Value;
|
||||
hull.OriginalAmbientLight = null;
|
||||
}
|
||||
}
|
||||
NewMessage("Restored all hull ambient lights", Color.White);
|
||||
return;
|
||||
}
|
||||
|
||||
Color color = XMLExtensions.ParseColor(colorString);
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
Level.Loaded.GenerationParams.AmbientLightColor = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.LightManager.AmbientLight = color;
|
||||
GameMain.LightManager.AmbientLight = add ? GameMain.LightManager.AmbientLight.Add(color) : color;
|
||||
}
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
hull.OriginalAmbientLight ??= hull.AmbientLight;
|
||||
hull.AmbientLight = add ? hull.AmbientLight.Add(color) : color;
|
||||
}
|
||||
|
||||
if (add)
|
||||
{
|
||||
NewMessage($"Set ambient light color to {color}.", Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewMessage($"Increased ambient light by {color}.", Color.White);
|
||||
}
|
||||
NewMessage("Set ambient light color to " + color + ".", Color.White);
|
||||
});
|
||||
AssignRelayToServer("ambientlight", false);
|
||||
|
||||
@@ -849,17 +913,6 @@ namespace Barotrauma
|
||||
TutorialMode.StartTutorial(Tutorials.Tutorial.Tutorials[0]);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("lobby|lobbyscreen", "", (string[] args) =>
|
||||
{
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
ThrowError("This command cannot be used in multiplayer.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameMain.LobbyScreen.Select();
|
||||
}));
|
||||
|
||||
commands.Add(new Command("save|savesub", "save [submarine name]: Save the currently loaded submarine using the specified name.", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) { return; }
|
||||
@@ -1011,9 +1064,39 @@ namespace Barotrauma
|
||||
});
|
||||
AssignRelayToServer("toggleaitargets|aitargets", false);
|
||||
|
||||
AssignOnExecute("debugai", (string[] args) =>
|
||||
{
|
||||
HumanAIController.debugai = !HumanAIController.debugai;
|
||||
if (HumanAIController.debugai)
|
||||
{
|
||||
GameMain.DebugDraw = true;
|
||||
GameMain.LightManager.LightingEnabled = false;
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.DebugDraw = false;
|
||||
GameMain.LightManager.LightingEnabled = true;
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
}
|
||||
NewMessage(HumanAIController.debugai ? "AI debug info visible" : "AI debug info hidden", Color.White);
|
||||
});
|
||||
AssignRelayToServer("debugai", false);
|
||||
|
||||
AssignRelayToServer("water|editwater", false);
|
||||
AssignRelayToServer("fire|editfire", false);
|
||||
|
||||
commands.Add(new Command("togglecampaignteleport", "togglecampaignteleport: Toggle on/off teleportation between campaign locations by double clicking on the campaign map.", (string[] args) =>
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign == null)
|
||||
{
|
||||
ThrowError("No campaign active.");
|
||||
return;
|
||||
}
|
||||
GameMain.GameSession.Map.AllowDebugTeleport = !GameMain.GameSession.Map.AllowDebugTeleport;
|
||||
NewMessage((GameMain.GameSession.Map.AllowDebugTeleport ? "Enabled" : "Disabled") + " teleportation on the campaign map.", Color.White);
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("mute", "mute [name]: Prevent the client from speaking to anyone through the voice chat. Using this command requires a permission from the server host.",
|
||||
null,
|
||||
() =>
|
||||
@@ -1044,7 +1127,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
int? minCost = itemPrefab.GetPrices()?.Min(p => p.BuyPrice);
|
||||
int? minCost = itemPrefab.GetMinPrice();
|
||||
int? fabricationCost = null;
|
||||
int? deconstructProductCost = null;
|
||||
|
||||
@@ -1053,7 +1136,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
int? ingredientPrice = ingredient.ItemPrefab.GetPrices()?.Min(p => p.BuyPrice);
|
||||
int? ingredientPrice = ingredient.ItemPrefab.GetMinPrice();
|
||||
if (ingredientPrice.HasValue)
|
||||
{
|
||||
if (!fabricationCost.HasValue) { fabricationCost = 0; }
|
||||
@@ -1071,7 +1154,7 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
int? deconstructProductPrice = targetItem.GetPrices()?.Min(p => p.BuyPrice);
|
||||
int? deconstructProductPrice = targetItem.GetMinPrice();
|
||||
if (deconstructProductPrice.HasValue)
|
||||
{
|
||||
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
|
||||
@@ -1300,7 +1383,7 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("eventstats", "", (string[] args) =>
|
||||
{
|
||||
var debugLines = ScriptedEventSet.GetDebugStatistics();
|
||||
var debugLines = EventSet.GetDebugStatistics();
|
||||
string filePath = "eventstats.txt";
|
||||
File.WriteAllLines(filePath, debugLines);
|
||||
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
|
||||
@@ -1537,6 +1620,76 @@ namespace Barotrauma
|
||||
File.WriteAllLines(filePath, lines);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("dumpeventtexts", "dumpeventtexts [filepath]: gets the texts from event files and and writes them into a file along with xml tags that can be used in translation files. If the filepath is omitted, the file is written to Content/Texts/EventTexts.txt", (string[] args) =>
|
||||
{
|
||||
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EventTexts.txt";
|
||||
List<string> lines = new List<string>();
|
||||
HashSet<XDocument> docs = new HashSet<XDocument>();
|
||||
HashSet<string> textIds = new HashSet<string>();
|
||||
|
||||
foreach (EventPrefab eventPrefab in EventSet.GetAllEventPrefabs())
|
||||
{
|
||||
if (string.IsNullOrEmpty(eventPrefab.Identifier))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
docs.Add(eventPrefab.ConfigElement.Document);
|
||||
getTextsFromElement(eventPrefab.ConfigElement, lines, eventPrefab.Identifier);
|
||||
}
|
||||
File.WriteAllLines(filePath, lines);
|
||||
|
||||
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
|
||||
|
||||
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
NewLineOnAttributes = false
|
||||
};
|
||||
|
||||
foreach (XDocument doc in docs)
|
||||
{
|
||||
using (var writer = XmlWriter.Create(new System.Uri(doc.BaseUri).LocalPath, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void getTextsFromElement(XElement element, List<string> list, string parentName)
|
||||
{
|
||||
string text = element.GetAttributeString("text", null);
|
||||
string textId = $"EventText.{parentName}";
|
||||
if (!string.IsNullOrEmpty(text) && !text.Contains("EventText.", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
list.Add($"<{textId}>{text}</{textId}>");
|
||||
element.SetAttributeValue("text", textId);
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "conversationaction":
|
||||
while (textIds.Contains(parentName+".c"+i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
parentName += ".c" + i;
|
||||
break;
|
||||
case "option":
|
||||
while (textIds.Contains(parentName.Substring(0, parentName.Length - 3) + ".o" + i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
parentName = parentName.Substring(0, parentName.Length - 3) + ".o" + i;
|
||||
break;
|
||||
}
|
||||
textIds.Add(parentName);
|
||||
getTextsFromElement(subElement, list, parentName);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("itemcomponentdocumentation", "", (string[] args) =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class ConversationAction : EventAction
|
||||
{
|
||||
private GUIMessageBox dialogBox;
|
||||
|
||||
private static ConversationAction lastActiveAction;
|
||||
private static GUIMessageBox lastMessageBox;
|
||||
|
||||
public static bool IsDialogOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
return GUIMessageBox.MessageBoxes.Any(mb =>
|
||||
mb.UserData as string == "ConversationAction" ||
|
||||
(mb.UserData is Pair<string, UInt16> pair && pair.First == "ConversationAction"));
|
||||
}
|
||||
}
|
||||
public static bool FadeScreenToBlack
|
||||
{
|
||||
get { return IsDialogOpen && shouldFadeToBlack; }
|
||||
}
|
||||
|
||||
private static bool shouldFadeToBlack;
|
||||
|
||||
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> _)
|
||||
{
|
||||
return
|
||||
lastActiveAction != null &&
|
||||
lastActiveAction.ParentEvent != ParentEvent &&
|
||||
Timing.TotalTime < lastActiveAction.lastActiveTime + BlockOtherConversationsDuration;
|
||||
}
|
||||
|
||||
partial void ShowDialog(Character speaker, Character targetCharacter)
|
||||
{
|
||||
CreateDialog(Text, speaker, Options.Select(opt => opt.Text), GetEndingOptions(), actionInstance: this, spriteIdentifier: EventSprite, fadeToBlack: FadeToBlack, dialogType: DialogType, continueConversation: ContinueConversation);
|
||||
}
|
||||
|
||||
public static void CreateDialog(string text, Character speaker, IEnumerable<string> options, int[] closingOptions, string eventSprite, UInt16 actionId, bool fadeToBlack, DialogTypes dialogType, bool continueConversation = false)
|
||||
{
|
||||
CreateDialog(text, speaker, options, closingOptions, actionInstance: null, actionId: actionId, spriteIdentifier: eventSprite, fadeToBlack: fadeToBlack, dialogType: dialogType, continueConversation: continueConversation);
|
||||
}
|
||||
|
||||
private static void CreateDialog(string text, Character speaker, IEnumerable<string> options, int[] closingOptions, string spriteIdentifier = null,
|
||||
ConversationAction actionInstance = null, UInt16? actionId = null, bool fadeToBlack = false, DialogTypes dialogType = DialogTypes.Regular, bool continueConversation = false)
|
||||
{
|
||||
Debug.Assert(actionInstance == null || actionId == null);
|
||||
|
||||
shouldFadeToBlack = fadeToBlack;
|
||||
|
||||
if (lastMessageBox != null && !lastMessageBox.Closed && GUIMessageBox.MessageBoxes.Contains(lastMessageBox))
|
||||
{
|
||||
if (actionId != null && lastMessageBox.UserData is Pair<string, ushort> userData)
|
||||
{
|
||||
if (userData.Second == actionId) { return; }
|
||||
lastMessageBox.UserData = new Pair<string, ushort>("ConversationAction", actionId.Value);
|
||||
}
|
||||
|
||||
GUIListBox conversationList = lastMessageBox.FindChild("conversationlist", true) as GUIListBox;
|
||||
Debug.Assert(conversationList != null);
|
||||
|
||||
// gray out the last text block
|
||||
if (conversationList.Content.Children.LastOrDefault() is GUILayoutGroup lastElement)
|
||||
{
|
||||
if (lastElement.FindChild("text", true) is GUITextBlock textLayout)
|
||||
{
|
||||
textLayout.OverrideTextColor(Color.DarkGray * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
List<GUIButton> extraButtons = CreateConversation(conversationList, text, speaker, options, string.IsNullOrWhiteSpace(spriteIdentifier));
|
||||
AssignActionsToButtons(extraButtons, lastMessageBox);
|
||||
RecalculateLastMessage(conversationList, true);
|
||||
|
||||
conversationList.ScrollToEnd(0.5f);
|
||||
lastMessageBox.SetBackgroundIcon(EventSet.GetEventSprite(spriteIdentifier));
|
||||
return;
|
||||
}
|
||||
|
||||
var (relative, min) = GetSizes(dialogType);
|
||||
|
||||
GUIMessageBox messageBox = new GUIMessageBox(string.Empty, string.Empty, new string[0],
|
||||
relativeSize: relative, minSize: min,
|
||||
type: GUIMessageBox.Type.InGame, backgroundIcon: EventSet.GetEventSprite(spriteIdentifier))
|
||||
{
|
||||
UserData = "ConversationAction"
|
||||
};
|
||||
|
||||
lastMessageBox = messageBox;
|
||||
|
||||
messageBox.InnerFrame.ClearChildren();
|
||||
messageBox.AutoClose = false;
|
||||
GUI.Style.Apply(messageBox.InnerFrame, "DialogBox");
|
||||
|
||||
if (actionInstance != null)
|
||||
{
|
||||
lastActiveAction = actionInstance;
|
||||
actionInstance.dialogBox = messageBox;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBox.UserData = new Pair<string, UInt16>("ConversationAction", actionId.Value);
|
||||
}
|
||||
|
||||
int padding = GUI.IntScale(16);
|
||||
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(messageBox.InnerFrame.Rect.Size - new Point(padding * 2), messageBox.InnerFrame.RectTransform, Anchor.Center), style: null)
|
||||
{
|
||||
KeepSpaceForScrollBar = true,
|
||||
HoverCursor = CursorState.Default,
|
||||
UserData = "conversationlist"
|
||||
};
|
||||
|
||||
List<GUIButton> buttons = CreateConversation(listBox, text, speaker, options, string.IsNullOrWhiteSpace(spriteIdentifier));
|
||||
AssignActionsToButtons(buttons, messageBox);
|
||||
RecalculateLastMessage(listBox, false);
|
||||
|
||||
messageBox.InnerFrame.RectTransform.MinSize = new Point(0, Math.Max(listBox.RectTransform.MinSize.Y + padding * 2, (int)(100 * GUI.yScale)));
|
||||
|
||||
var shadow = new GUIFrame(new RectTransform(messageBox.InnerFrame.Rect.Size + new Point(padding * 4), messageBox.InnerFrame.RectTransform, Anchor.Center), style: "OuterGlow")
|
||||
{
|
||||
Color = Color.Black * 0.7f
|
||||
};
|
||||
shadow.SetAsFirstChild();
|
||||
|
||||
void RecalculateLastMessage(GUIListBox conversationList, bool append)
|
||||
{
|
||||
if (conversationList.Content.Children.LastOrDefault() is GUILayoutGroup lastElement)
|
||||
{
|
||||
GUILayoutGroup textLayout = lastElement.GetChild<GUILayoutGroup>();
|
||||
if (lastElement.Rect.Size.Y < textLayout.Rect.Size.Y && !append)
|
||||
{
|
||||
lastElement.RectTransform.MinSize = textLayout.Rect.Size;
|
||||
}
|
||||
if (textLayout != null)
|
||||
{
|
||||
int textHeight = textLayout.Children.Sum(c => c.Rect.Height);
|
||||
textLayout.RectTransform.MaxSize = new Point(lastElement.RectTransform.MaxSize.X, textHeight);
|
||||
textLayout.Recalculate();
|
||||
}
|
||||
int sumHeight = lastElement.Children.Sum(c => c.Rect.Height);
|
||||
lastElement.RectTransform.MaxSize = new Point(lastElement.RectTransform.MaxSize.X, sumHeight);
|
||||
lastElement.Recalculate();
|
||||
conversationList.RecalculateChildren();
|
||||
|
||||
if (!append || textLayout == null) { return; }
|
||||
|
||||
foreach (GUIComponent child in textLayout.Children)
|
||||
{
|
||||
conversationList.UpdateScrollBarSize();
|
||||
float wait = conversationList.BarSize < 1.0f ? 0.5f : 0.0f;
|
||||
|
||||
if (child is GUITextBlock) { child.FadeIn(wait, 0.5f); }
|
||||
|
||||
if (child is GUIButton btn)
|
||||
{
|
||||
btn.FadeIn(wait, 1.0f);
|
||||
btn.TextBlock.FadeIn(wait, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssignActionsToButtons(List<GUIButton> optionButtons, GUIMessageBox target)
|
||||
{
|
||||
if (!options.Any())
|
||||
{
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(Vector2.One, target.InnerFrame.RectTransform, Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
|
||||
{
|
||||
MaxSize = new Point(GUI.IntScale(24)),
|
||||
MinSize = new Point(24),
|
||||
AbsoluteOffset = new Point(GUI.IntScale(48), GUI.IntScale(16))
|
||||
}, style: "GUIButtonVerticalArrow")
|
||||
{
|
||||
UserData = "ContinueButton",
|
||||
IgnoreLayoutGroups = true,
|
||||
Bounce = true,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (actionInstance != null)
|
||||
{
|
||||
actionInstance.selectedOption = 0;
|
||||
}
|
||||
else if (actionId.HasValue)
|
||||
{
|
||||
SendResponse(actionId.Value, 0);
|
||||
}
|
||||
|
||||
if (!continueConversation)
|
||||
{
|
||||
target.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
btn.Frame.FadeOut(0.33f, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
closeButton.Children.ForEach(child => child.SpriteEffects = SpriteEffects.FlipVertically);
|
||||
closeButton.Frame.FadeIn(0.5f, 0.5f);
|
||||
closeButton.SlideIn(0.5f, 0.33f, 16, SlideDirection.Down);
|
||||
}
|
||||
|
||||
for (int i = 0; i < optionButtons.Count; i++)
|
||||
{
|
||||
optionButtons[i].UserData = i;
|
||||
optionButtons[i].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
int selectedOption = (userdata as int?) ?? 0;
|
||||
if (actionInstance != null)
|
||||
{
|
||||
actionInstance.selectedOption = selectedOption;
|
||||
foreach (GUIButton otherButton in optionButtons)
|
||||
{
|
||||
otherButton.CanBeFocused = false;
|
||||
if (otherButton != btn)
|
||||
{
|
||||
otherButton.TextBlock.OverrideTextColor(Color.DarkGray * 0.8f);
|
||||
}
|
||||
}
|
||||
btn.ExternalHighlight = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (actionId.HasValue)
|
||||
{
|
||||
SendResponse(actionId.Value, selectedOption);
|
||||
btn.CanBeFocused = false;
|
||||
btn.ExternalHighlight = true;
|
||||
foreach (GUIButton otherButton in optionButtons)
|
||||
{
|
||||
otherButton.CanBeFocused = false;
|
||||
if (otherButton != btn)
|
||||
{
|
||||
otherButton.TextBlock.OverrideTextColor(Color.DarkGray * 0.8f);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//should not happen
|
||||
return false;
|
||||
};
|
||||
|
||||
if (closingOptions.Contains(i)) { optionButtons[i].OnClicked += target.Close; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<Vector2, Point> GetSizes(DialogTypes dialogTypes)
|
||||
{
|
||||
return dialogTypes switch
|
||||
{
|
||||
DialogTypes.Regular => Tuple.Create(new Vector2(0.3f, 0.2f), new Point(512, 256)),
|
||||
_ => Tuple.Create(new Vector2(0.3f, 0.15f), new Point(512, 128))
|
||||
};
|
||||
}
|
||||
|
||||
private static List<GUIButton> CreateConversation(GUIListBox parentBox, string text, Character speaker, IEnumerable<string> options, bool drawChathead = true)
|
||||
{
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, parentBox.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
CanBeFocused = true,
|
||||
AlwaysOverrideCursor = true
|
||||
};
|
||||
|
||||
string translatedText = TextManager.Get(text, returnNull: true) ?? text;
|
||||
|
||||
if (speaker?.Info != null && drawChathead)
|
||||
{
|
||||
// chathead
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.15f, 0.8f), content.RectTransform), onDraw: (sb, customComponent) =>
|
||||
{
|
||||
speaker.Info.DrawIcon(sb, customComponent.Rect.Center.ToVector2(), customComponent.Rect.Size.ToVector2());
|
||||
});
|
||||
}
|
||||
|
||||
var textContent = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), content.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform), translatedText, wrap: true)
|
||||
{
|
||||
AlwaysOverrideCursor = true,
|
||||
UserData = "text"
|
||||
};
|
||||
|
||||
List<GUIButton> buttons = new List<GUIButton>();
|
||||
if (options.Any())
|
||||
{
|
||||
foreach (string option in options)
|
||||
{
|
||||
var btn = new GUIButton(new RectTransform(new Vector2(0.9f, 0.01f), textContent.RectTransform), TextManager.Get(option, returnNull: true) ?? option, style: "ListBoxElement");
|
||||
btn.TextBlock.TextAlignment = Alignment.CenterLeft;
|
||||
btn.TextColor = btn.HoverTextColor = GUI.Style.Green;
|
||||
btn.TextBlock.Wrap = true;
|
||||
buttons.Add(btn);
|
||||
}
|
||||
}
|
||||
|
||||
content.Recalculate();
|
||||
textContent.Recalculate();
|
||||
textBlock.CalculateHeightFromText();
|
||||
textBlock.RectTransform.MinSize = new Point(0, (int)(textBlock.Rect.Height * 1.2f));
|
||||
foreach (GUIButton btn in buttons)
|
||||
{
|
||||
btn.TextBlock.SetTextPos();
|
||||
btn.TextBlock.CalculateHeightFromText();
|
||||
btn.RectTransform.MinSize = new Point(0, (int)(btn.TextBlock.Rect.Height * 1.2f));
|
||||
}
|
||||
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height + textContent.AbsoluteSpacing) + GUI.IntScale(16));
|
||||
// content.RectTransform.MinSize = new Point(0, textContent.Rect.Height);
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private static void SendResponse(UInt16 actionId, int selectedOption)
|
||||
{
|
||||
IWriteMessage outmsg = new WriteOnlyMessage();
|
||||
outmsg.Write((byte)ClientPacketHeader.EVENTMANAGER_RESPONSE);
|
||||
outmsg.Write(actionId);
|
||||
outmsg.Write((byte)selectedOption);
|
||||
GameMain.Client?.ClientPeer?.Send(outmsg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
// Too broken, left it here if I ever want to come back to it
|
||||
private static List<RichTextData> GetQuoteHighlights(string text, Color color)
|
||||
{
|
||||
char[] quotes = { '“', '”', '\"', '\'', '「', '」'};
|
||||
|
||||
List<RichTextData> textColors = new List<RichTextData> { new RichTextData { StartIndex = 0 } };
|
||||
bool start = true;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
char c = text[i];
|
||||
if (quotes.Contains(c))
|
||||
{
|
||||
textColors.Last().EndIndex = i - 1;
|
||||
textColors.Add(new RichTextData { StartIndex = i, Color = start ? color : (Color?) null });
|
||||
start = !start;
|
||||
}
|
||||
}
|
||||
|
||||
if (textColors.LastOrDefault() is { } last && last.EndIndex == 0)
|
||||
{
|
||||
last.EndIndex = text.Length;
|
||||
}
|
||||
return textColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
#nullable enable
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -11,34 +17,43 @@ namespace Barotrauma
|
||||
private float intensityGraphUpdateInterval;
|
||||
private float lastIntensityUpdate;
|
||||
|
||||
private Event? pinnedEvent;
|
||||
private Vector2 pinnedPosition = new Vector2(256, 128);
|
||||
private bool isDragging;
|
||||
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (ScriptedEvent ev in activeEvents)
|
||||
foreach (Event ev in activeEvents)
|
||||
{
|
||||
Vector2 drawPos = ev.DebugDrawPos;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
var textOffset = new Vector2(-150, 0);
|
||||
ShapeExtensions.DrawCircle(spriteBatch, drawPos, 600, 6, Color.White, thickness: 20);
|
||||
spriteBatch.DrawCircle(drawPos, 600, 6, Color.White, thickness: 20);
|
||||
GUI.DrawString(spriteBatch, drawPos + textOffset, ev.ToString(), Color.White, Color.Black, 0, GUI.LargeFont);
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugDrawHUD(SpriteBatch spriteBatch, int y)
|
||||
{
|
||||
foreach (ScriptedEvent scriptedEvent in activeEvents.Where(ev => !ev.IsFinished && ev is ScriptedEvent).Cast<ScriptedEvent>())
|
||||
{
|
||||
DrawEventTargetTags(spriteBatch, scriptedEvent);
|
||||
}
|
||||
|
||||
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 + 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) &&
|
||||
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
|
||||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.T))
|
||||
{
|
||||
eventCoolDown = 1.0f;
|
||||
@@ -56,7 +71,7 @@ namespace Barotrauma
|
||||
{
|
||||
intensityGraph.Update(currentIntensity);
|
||||
targetIntensityGraph.Update(targetIntensity);
|
||||
lastIntensityUpdate = (float)Timing.TotalTime;
|
||||
lastIntensityUpdate = (float) Timing.TotalTime;
|
||||
}
|
||||
|
||||
Rectangle graphRect = new Rectangle(15, y + 150, 150, 50);
|
||||
@@ -72,17 +87,20 @@ namespace Barotrauma
|
||||
y = graphRect.Bottom + 20;
|
||||
if (eventCoolDown > 0.0f)
|
||||
{
|
||||
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(graphRect.X, y), "Event cooldown active: " + (int) 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);
|
||||
"Intensity too high for new events: " + (int) (currentIntensity * 100) + "%/" + (int) (eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 15;
|
||||
}
|
||||
foreach (ScriptedEventSet eventSet in pendingEventSets)
|
||||
|
||||
foreach (EventSet eventSet in pendingEventSets)
|
||||
{
|
||||
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);
|
||||
y += 12;
|
||||
|
||||
@@ -90,36 +108,421 @@ namespace Barotrauma
|
||||
roundDuration < eventSet.MinMissionTime)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||
" " + (int)(eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int)(distanceTraveled * 100.0f) + " %)",
|
||||
" " + (int) (eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int) (distanceTraveled * 100.0f) + " %)",
|
||||
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
}
|
||||
|
||||
if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||
" intensity between " + ((int)eventSet.MinIntensity) + " and " + ((int)eventSet.MaxIntensity),
|
||||
" intensity between " + ((int) eventSet.MinIntensity) + " and " + ((int) eventSet.MaxIntensity),
|
||||
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
}
|
||||
|
||||
if (roundDuration < eventSet.MinMissionTime)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||
" " + (int)(eventSet.MinMissionTime - roundDuration) + " s",
|
||||
" " + (int) (eventSet.MinMissionTime - roundDuration) + " s",
|
||||
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
}
|
||||
|
||||
y += 15;
|
||||
}
|
||||
|
||||
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
foreach (ScriptedEvent scriptedEvent in activeEvents)
|
||||
y += 15;
|
||||
|
||||
foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
|
||||
{
|
||||
if (scriptedEvent.IsFinished) { continue; }
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X + 5, y), scriptedEvent.ToString(), Color.White * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.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 outlineRect = new Rectangle(rect.Location, rect.Size);
|
||||
outlineRect.Inflate(4, 4);
|
||||
|
||||
if (pinnedEvent == ev) { GUI.DrawRectangle(spriteBatch, outlineRect, Color.White); }
|
||||
|
||||
if (rect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
GUI.MouseCursor = CursorState.Hand;
|
||||
GUI.DrawRectangle(spriteBatch, outlineRect, Color.White);
|
||||
|
||||
if (ev != pinnedEvent)
|
||||
{
|
||||
DrawEvent(spriteBatch, ev, rect);
|
||||
}
|
||||
else if (PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown())
|
||||
{
|
||||
pinnedEvent = null;
|
||||
}
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonHeld() || PlayerInput.PrimaryMouseButtonDown())
|
||||
{
|
||||
pinnedEvent = ev;
|
||||
}
|
||||
}
|
||||
|
||||
y += 18;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPinnedEvent(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (pinnedEvent != null)
|
||||
{
|
||||
Rectangle rect = DrawEvent(spriteBatch, pinnedEvent, null);
|
||||
|
||||
if (rect != Rectangle.Empty)
|
||||
{
|
||||
if (rect.Contains(PlayerInput.MousePosition) && !isDragging)
|
||||
{
|
||||
GUI.MouseCursor = CursorState.Move;
|
||||
if (PlayerInput.PrimaryMouseButtonDown() || PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
isDragging = true;
|
||||
}
|
||||
|
||||
if (PlayerInput.SecondaryMouseButtonClicked() || PlayerInput.SecondaryMouseButtonHeld())
|
||||
{
|
||||
pinnedEvent = null;
|
||||
isDragging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDragging)
|
||||
{
|
||||
GUI.MouseCursor = CursorState.Dragging;
|
||||
pinnedPosition = PlayerInput.MousePosition - (new Vector2(rect.Width / 2.0f, -24));
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
isDragging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawEventTargetTags(SpriteBatch spriteBatch, ScriptedEvent scriptedEvent)
|
||||
{
|
||||
if (Screen.Selected is GameScreen screen)
|
||||
{
|
||||
Camera cam = screen.Cam;
|
||||
Dictionary<Entity, List<string>> tagsDictionary = new Dictionary<Entity, List<string>>();
|
||||
foreach ((string key, List<Entity> value) in scriptedEvent.Targets)
|
||||
{
|
||||
foreach (Entity entity in value)
|
||||
{
|
||||
if (tagsDictionary.ContainsKey(entity))
|
||||
{
|
||||
tagsDictionary[entity].Add(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
tagsDictionary.Add(entity, new List<string> { key });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string identifier = scriptedEvent.Prefab.Identifier;
|
||||
|
||||
foreach ((Entity entity, List<string> tags) in tagsDictionary)
|
||||
{
|
||||
if (entity.Removed) { continue; }
|
||||
|
||||
string text = tags.Aggregate("Tags:\n", (current, tag) => current + $" {tag.ColorizeObject()}\n").TrimEnd('\r', '\n');
|
||||
if (!string.IsNullOrWhiteSpace(identifier)) { text = $"Event: {identifier.ColorizeObject()}\n{text}"; }
|
||||
|
||||
List<RichTextData> richTextData = RichTextData.GetRichTextData(text, out text);
|
||||
|
||||
Vector2 entityPos = cam.WorldToScreen(entity.WorldPosition);
|
||||
Vector2 infoSize = GUI.SmallFont.MeasureString(text);
|
||||
|
||||
Vector2 infoPos = entityPos + new Vector2(128 * cam.Zoom, -(128 * cam.Zoom));
|
||||
infoPos.Y -= infoSize.Y / 2;
|
||||
|
||||
Rectangle infoRect = new Rectangle(infoPos.ToPoint(), infoSize.ToPoint());
|
||||
infoRect.Inflate(4, 4);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.Black * 0.8f, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.White, isFilled: false);
|
||||
|
||||
GUI.DrawStringWithColors(spriteBatch, infoPos, text, Color.White, richTextData, font: GUI.SmallFont);
|
||||
|
||||
GUI.DrawLine(spriteBatch, entityPos, new Vector2(infoRect.Location.X, infoRect.Location.Y + infoRect.Height / 2), Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct DebugLine
|
||||
{
|
||||
public readonly Vector2 Position;
|
||||
public readonly Color Color;
|
||||
|
||||
public DebugLine(Vector2 position, Color color)
|
||||
{
|
||||
Position = position;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private Rectangle DrawEvent(SpriteBatch spriteBatch, Event ev, Rectangle? parentRect = null)
|
||||
{
|
||||
return ev switch
|
||||
{
|
||||
ScriptedEvent scriptedEvent => DrawScriptedEvent(spriteBatch, scriptedEvent, parentRect),
|
||||
ArtifactEvent artifactEvent => DrawArtifactEvent(spriteBatch, artifactEvent, parentRect),
|
||||
MonsterEvent monsterEvent => DrawMonsterEvent(spriteBatch, monsterEvent, parentRect),
|
||||
_ => Rectangle.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private Rectangle DrawScriptedEvent(SpriteBatch spriteBatch, ScriptedEvent scriptedEvent, Rectangle? parentRect = null)
|
||||
{
|
||||
EventAction? currentEvent = !scriptedEvent.IsFinished ? scriptedEvent.Actions[scriptedEvent.CurrentActionIndex] : null;
|
||||
|
||||
List<DebugLine> positions = new List<DebugLine>();
|
||||
|
||||
string text = $"Finished: {scriptedEvent.IsFinished.ColorizeObject()}\n" +
|
||||
$"Action index: {scriptedEvent.CurrentActionIndex.ColorizeObject()}\n" +
|
||||
$"Current action: {currentEvent?.ToDebugString() ?? ToolBox.ColorizeObject(null)}\n";
|
||||
|
||||
text += "All actions:\n";
|
||||
text += FindActions(scriptedEvent).Aggregate(string.Empty, (current, action) => current + $"{new string(' ', action.Item1 * 6)}{action.Item2.ToDebugString()}\n");
|
||||
|
||||
text += "Targets:\n";
|
||||
foreach (var (key, value) in scriptedEvent.Targets)
|
||||
{
|
||||
text += $" {key.ColorizeObject()}: {value.Aggregate(string.Empty, (current, entity) => current + $"{entity.ColorizeObject()} ")}\n";
|
||||
}
|
||||
|
||||
if (scriptedEvent.Targets != null)
|
||||
{
|
||||
foreach ((_, List<Entity> entities) in scriptedEvent.Targets)
|
||||
{
|
||||
if (entities == null || !entities.Any()) { continue; }
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
positions.Add(new DebugLine(entity.WorldPosition, Color.White));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DrawInfoRectangle(spriteBatch, scriptedEvent, text, parentRect, positions);
|
||||
}
|
||||
|
||||
private Rectangle DrawArtifactEvent(SpriteBatch spriteBatch, ArtifactEvent artifactEvent, Rectangle? parentRect = null)
|
||||
{
|
||||
List<DebugLine> positions = new List<DebugLine>();
|
||||
|
||||
string text = $"Finished: {artifactEvent.IsFinished.ColorizeObject()}\n" +
|
||||
$"Item: {artifactEvent.Item.ColorizeObject()}\n" +
|
||||
$"Spawn pending: {artifactEvent.SpawnPending.ColorizeObject()}\n" +
|
||||
$"Spawn position: {artifactEvent.SpawnPos.ColorizeObject()}\n";
|
||||
|
||||
if (artifactEvent.Item != null)
|
||||
{
|
||||
Vector2 pos = artifactEvent.Item.WorldPosition;
|
||||
positions.Add(new DebugLine(pos, Color.White));
|
||||
}
|
||||
|
||||
return DrawInfoRectangle(spriteBatch, artifactEvent, text, parentRect, positions);
|
||||
}
|
||||
|
||||
private Rectangle DrawMonsterEvent(SpriteBatch spriteBatch, MonsterEvent monsterEvent, Rectangle? parentRect = null)
|
||||
{
|
||||
List<DebugLine> positions = new List<DebugLine>();
|
||||
|
||||
string text = $"Finished: {monsterEvent.IsFinished.ColorizeObject()}\n" +
|
||||
$"Amount: {monsterEvent.MinAmount.ColorizeObject()} - {monsterEvent.MaxAmount.ColorizeObject()}\n" +
|
||||
$"Spawn pending: {monsterEvent.SpawnPending.ColorizeObject()}\n" +
|
||||
$"Spawn position: {monsterEvent.SpawnPos.ColorizeObject()}\n";
|
||||
|
||||
if (monsterEvent.SpawnPos != null && Submarine.MainSub != null)
|
||||
{
|
||||
Vector2 pos = monsterEvent.SpawnPos.Value;
|
||||
text += $"Distance from submarine: {Vector2.Distance(pos, Submarine.MainSub.WorldPosition).ColorizeObject()}\n";
|
||||
positions.Add(new DebugLine(pos, Color.White));
|
||||
}
|
||||
|
||||
if (monsterEvent.Monsters != null)
|
||||
{
|
||||
text += !monsterEvent.Monsters.Any() ? $"Monsters: {"None".ColorizeObject()}" : "Monsters:\n";
|
||||
|
||||
foreach (Character monster in monsterEvent.Monsters)
|
||||
{
|
||||
text += $" {monster.ColorizeObject()} -> (Dead: {monster.IsDead.ColorizeObject()}, Health: {monster.HealthPercentage.ColorizeObject()}%, AIState: {(monster.AIController?.State).ColorizeObject()})\n";
|
||||
positions.Add(new DebugLine(monster.WorldPosition, Color.Red));
|
||||
}
|
||||
}
|
||||
|
||||
return DrawInfoRectangle(spriteBatch, monsterEvent, text, parentRect, positions);
|
||||
}
|
||||
|
||||
private Rectangle DrawInfoRectangle(SpriteBatch spriteBatch, Event @event, string text, Rectangle? parentRect = null, List<DebugLine>? drawPoints = null)
|
||||
{
|
||||
text = text.TrimEnd('\r', '\n');
|
||||
|
||||
string identifier = @event.Prefab.Identifier;
|
||||
if (!string.IsNullOrWhiteSpace(identifier))
|
||||
{
|
||||
text = $"Identifier: {identifier.ColorizeObject()}\n{text}";
|
||||
}
|
||||
|
||||
List<RichTextData> richTextData = RichTextData.GetRichTextData(text, out text);
|
||||
|
||||
Vector2 size = GUI.SmallFont.MeasureString(text);
|
||||
Vector2 pos = pinnedPosition;
|
||||
Rectangle infoRect;
|
||||
Rectangle? infoBarRect = null;
|
||||
|
||||
if (parentRect != null)
|
||||
{
|
||||
Rectangle rect = parentRect.Value;
|
||||
pos = new Vector2(350, GameMain.GraphicsHeight / 2.0f - size.Y / 2);
|
||||
infoRect = new Rectangle(pos.ToPoint(), size.ToPoint());
|
||||
infoRect.Inflate(8, 8);
|
||||
|
||||
GUI.DrawLine(spriteBatch, new Vector2(rect.Right, rect.Y + rect.Height / 2), new Vector2(infoRect.X, infoRect.Y + infoRect.Height / 2), Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoRect = new Rectangle(pos.ToPoint(), size.ToPoint());
|
||||
infoRect.Inflate(8, 8);
|
||||
|
||||
Rectangle barRect = new Rectangle(infoRect.Left, infoRect.Top - 32, infoRect.Width, 32);
|
||||
const string titleHeader = "Pinned event";
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, barRect, Color.DarkGray * 0.8f, isFilled: true);
|
||||
GUI.DrawString(spriteBatch, barRect.Location.ToVector2() + barRect.Size.ToVector2() / 2 - GUI.SubHeadingFont.MeasureString(titleHeader) / 2, titleHeader, Color.White);
|
||||
GUI.DrawRectangle(spriteBatch, barRect, Color.White);
|
||||
infoBarRect = barRect;
|
||||
}
|
||||
|
||||
if (drawPoints != null && drawPoints.Any() && Screen.Selected?.Cam != null)
|
||||
{
|
||||
foreach (DebugLine line in drawPoints)
|
||||
{
|
||||
if (line.Position != Vector2.Zero)
|
||||
{
|
||||
float xPos = infoRect.Right;
|
||||
|
||||
if (parentRect == null && pinnedPosition.X + infoRect.Width / 2.0f > GameMain.GraphicsWidth / 2.0f)
|
||||
{
|
||||
xPos = infoRect.Left;
|
||||
}
|
||||
|
||||
GUI.DrawLine(spriteBatch, new Vector2(xPos, infoRect.Top + infoRect.Height / 2), Screen.Selected.Cam.WorldToScreen(line.Position), line.Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.Black * 0.8f, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.White);
|
||||
|
||||
GUI.DrawStringWithColors(spriteBatch, pos, text, Color.White, richTextData, null, 0, GUI.SmallFont);
|
||||
richTextData.Clear();
|
||||
return infoBarRect ?? infoRect;
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
NetworkEventType eventType = (NetworkEventType)msg.ReadByte();
|
||||
switch (eventType)
|
||||
{
|
||||
case NetworkEventType.STATUSEFFECT:
|
||||
string eventIdentifier = msg.ReadString();
|
||||
UInt16 actionIndex = msg.ReadUInt16();
|
||||
UInt16 targetCount = msg.ReadUInt16();
|
||||
List<Entity> targets = new List<Entity>();
|
||||
for (int i = 0; i < targetCount; i++)
|
||||
{
|
||||
UInt16 targetID = msg.ReadUInt16();
|
||||
Entity target = Entity.FindEntityByID(targetID);
|
||||
if (target != null) { targets.Add(target); }
|
||||
}
|
||||
|
||||
var eventPrefab = EventSet.GetEventPrefab(eventIdentifier);
|
||||
if (eventPrefab == null) { return; }
|
||||
int j = 0;
|
||||
foreach (XElement element in eventPrefab.ConfigElement.Descendants())
|
||||
{
|
||||
if (j != actionIndex)
|
||||
{
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("statuseffect", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
StatusEffect effect = StatusEffect.Load(subElement, $"EventManager.ClientRead ({eventIdentifier})");
|
||||
foreach (Entity target in targets)
|
||||
{
|
||||
effect.Apply(effect.type, 1.0f, target, target as ISerializableEntity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetworkEventType.CONVERSATION:
|
||||
UInt16 identifier = msg.ReadUInt16();
|
||||
string eventSprite = msg.ReadString();
|
||||
byte dialogType = msg.ReadByte();
|
||||
bool continueConversation = msg.ReadBoolean();
|
||||
UInt16 speakerId = msg.ReadUInt16();
|
||||
string text = msg.ReadString();
|
||||
bool fadeToBlack = msg.ReadBoolean();
|
||||
byte optionCount = msg.ReadByte();
|
||||
List<string> options = new List<string>();
|
||||
for (int i = 0; i < optionCount; i++)
|
||||
{
|
||||
options.Add(msg.ReadString());
|
||||
}
|
||||
|
||||
byte endCount = msg.ReadByte();
|
||||
int[] endings = new int[endCount];
|
||||
for (int i = 0; i < endCount; i++)
|
||||
{
|
||||
endings[i] = msg.ReadByte();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(text) && optionCount == 0)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.ForEachMod(mb =>
|
||||
{
|
||||
if (mb.UserData is Pair<string, UInt16> pair && pair.First == "ConversationAction" && pair.Second == identifier)
|
||||
{
|
||||
(mb as GUIMessageBox)?.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ConversationAction.CreateDialog(text, Entity.FindEntityByID(speakerId) as Character, options, endings, eventSprite, identifier, fadeToBlack, (ConversationAction.DialogTypes)dialogType, continueConversation);
|
||||
}
|
||||
if (Entity.FindEntityByID(speakerId) is Character speaker)
|
||||
{
|
||||
speaker.CampaignInteractionType = CampaignMode.InteractionType.None;
|
||||
speaker.SetCustomInteract(null, null);
|
||||
}
|
||||
break;
|
||||
case NetworkEventType.MISSION:
|
||||
string missionIdentifier = msg.ReadString();
|
||||
|
||||
MissionPrefab? prefab = MissionPrefab.List.Find(mp => mp.Identifier.Equals(missionIdentifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (prefab != null)
|
||||
{
|
||||
new GUIMessageBox(string.Empty, TextManager.GetWithVariable("missionunlocked", "[missionname]", prefab.Name),
|
||||
new string[0], type: GUIMessageBox.Type.InGame, icon: prefab.Icon, relativeSize: new Vector2(0.3f, 0.15f), minSize: new Point(512, 128))
|
||||
{
|
||||
IconColor = prefab.IconColor
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -13,10 +14,20 @@ namespace Barotrauma
|
||||
string header = messageIndex < Headers.Count ? Headers[messageIndex] : "";
|
||||
string message = messageIndex < Messages.Count ? Messages[messageIndex] : "";
|
||||
|
||||
CoroutineManager.StartCoroutine(ShowMessageBoxAfterRoundSummary(header, message));
|
||||
}
|
||||
|
||||
private IEnumerable<object> ShowMessageBoxAfterRoundSummary(string header, string message)
|
||||
{
|
||||
while (GUIMessageBox.VisibleBox?.UserData is RoundSummary)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
}
|
||||
new GUIMessageBox(header, message, buttons: new string[0], type: GUIMessageBox.Type.InGame, icon: Prefab.Icon)
|
||||
{
|
||||
IconColor = Prefab.IconColor
|
||||
};
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage msg)
|
||||
|
||||
@@ -492,7 +492,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 MeasureString(string text)
|
||||
public Vector2 MeasureString(string text, bool removeExtraSpacing = false)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
@@ -501,7 +501,16 @@ namespace Barotrauma
|
||||
|
||||
float currentLineX = 0.0f;
|
||||
Vector2 retVal = Vector2.Zero;
|
||||
retVal.Y = baseHeight * 1.8f;
|
||||
|
||||
if (!removeExtraSpacing)
|
||||
{
|
||||
retVal.Y = baseHeight * 1.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal.Y = baseHeight;
|
||||
}
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (text[i] == '\n')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -144,6 +145,15 @@ namespace Barotrauma
|
||||
GetSize(element);
|
||||
}
|
||||
|
||||
public Sprite GetDefaultSprite()
|
||||
{
|
||||
return GetSprite(GUIComponent.ComponentState.None);
|
||||
}
|
||||
public Sprite GetSprite(GUIComponent.ComponentState state)
|
||||
{
|
||||
return Sprites.ContainsKey(state) ? Sprites[state]?.First()?.Sprite : null;
|
||||
}
|
||||
|
||||
public void GetSize(XElement element)
|
||||
{
|
||||
Point size = new Point(0, 0);
|
||||
|
||||
729
Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs
Normal file
729
Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs
Normal file
@@ -0,0 +1,729 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CrewManagement
|
||||
{
|
||||
private CampaignMode campaign => campaignUI.Campaign;
|
||||
private readonly CampaignUI campaignUI;
|
||||
private readonly GUIComponent parentComponent;
|
||||
|
||||
private GUIListBox hireableList, pendingList, crewList;
|
||||
private GUIFrame characterPreviewFrame;
|
||||
private GUIDropDown sortingDropDown;
|
||||
private GUITextBlock totalBlock;
|
||||
private GUIButton validateHiresButton;
|
||||
private GUIButton clearAllButton;
|
||||
|
||||
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
|
||||
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign();
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
|
||||
private enum SortingMethod
|
||||
{
|
||||
AlphabeticalAsc,
|
||||
JobAsc,
|
||||
PriceAsc,
|
||||
PriceDesc,
|
||||
SkillAsc,
|
||||
SkillDesc
|
||||
}
|
||||
|
||||
public CrewManagement(CampaignUI campaignUI, GUIComponent parentComponent)
|
||||
{
|
||||
this.campaignUI = campaignUI;
|
||||
this.parentComponent = parentComponent;
|
||||
|
||||
CreateUI();
|
||||
UpdateLocationView(campaignUI.Campaign.Map.CurrentLocation, true);
|
||||
|
||||
campaignUI.Campaign.Map.OnLocationChanged += (prevLocation, newLocation) => UpdateLocationView(newLocation, true, prevLocation);
|
||||
}
|
||||
|
||||
public void RefreshPermissions()
|
||||
{
|
||||
RefreshCrewFrames(hireableList);
|
||||
RefreshCrewFrames(crewList);
|
||||
RefreshCrewFrames(pendingList);
|
||||
if (clearAllButton != null) { clearAllButton.Enabled = HasPermission; }
|
||||
}
|
||||
|
||||
private void RefreshCrewFrames(GUIListBox listBox)
|
||||
{
|
||||
if (listBox == null) { return; }
|
||||
listBox.CanBeFocused = HasPermission;
|
||||
foreach (GUIComponent child in listBox.Content.Children)
|
||||
{
|
||||
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
|
||||
{
|
||||
buyButton.Enabled = HasPermission;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUI()
|
||||
{
|
||||
if (parentComponent.FindChild(c => c.UserData as string == "glow") is GUIComponent glowChild)
|
||||
{
|
||||
parentComponent.RemoveChild(glowChild);
|
||||
}
|
||||
if (parentComponent.FindChild(c => c.UserData as string == "container") is GUIComponent containerChild)
|
||||
{
|
||||
parentComponent.RemoveChild(containerChild);
|
||||
}
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), parentComponent.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow", color: Color.Black * 0.7f)
|
||||
{
|
||||
UserData = "glow"
|
||||
};
|
||||
new GUIFrame(new RectTransform(new Vector2(0.95f), parentComponent.RectTransform, anchor: Anchor.Center),
|
||||
style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = "container"
|
||||
};
|
||||
|
||||
var availableMainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).RectTransform)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
})
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
// Header ------------------------------------------------
|
||||
var headerGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), availableMainGroup.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
var imageWidth = (float)headerGroup.Rect.Height / headerGroup.Rect.Width;
|
||||
new GUIImage(new RectTransform(new Vector2(imageWidth, 1.0f), headerGroup.RectTransform), "CrewManagementHeaderIcon");
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - imageWidth, 1.0f), headerGroup.RectTransform), TextManager.Get("campaigncrew.header"), font: GUI.LargeFont)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
ForceUpperCase = true
|
||||
};
|
||||
|
||||
var hireablesGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), availableMainGroup.RectTransform)).RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.015f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var sortGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), hireablesGroup.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sortGroup.RectTransform), text: TextManager.Get("campaignstore.sortby"));
|
||||
sortingDropDown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1.0f), sortGroup.RectTransform), elementCount: 5)
|
||||
{
|
||||
OnSelected = (child, userData) =>
|
||||
{
|
||||
SortCharacters(hireableList, (SortingMethod)userData);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var tag = "sortingmethod.";
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.JobAsc), userData: SortingMethod.JobAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.SkillAsc), userData: SortingMethod.SkillAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.SkillDesc), userData: SortingMethod.SkillDesc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.PriceAsc), userData: SortingMethod.PriceAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.PriceDesc), userData: SortingMethod.PriceDesc);
|
||||
|
||||
hireableList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.96f),
|
||||
hireablesGroup.RectTransform,
|
||||
anchor: Anchor.Center))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
var pendingAndCrewMainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).RectTransform, anchor: Anchor.TopRight)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
})
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), pendingAndCrewMainGroup.RectTransform), childAnchor: Anchor.TopRight)
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
TextManager.Get("campaignstore.balance"), font: GUI.Font, textAlignment: Alignment.BottomRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
ForceUpperCase = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => FormatCurrency(campaign.Money)
|
||||
};
|
||||
|
||||
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
}).RectTransform));
|
||||
|
||||
float height = 0.05f;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaigncrew.pending"), font: GUI.SubHeadingFont);
|
||||
pendingList = new GUIListBox(new RectTransform(new Vector2(1.0f, 8 * height), pendingAndCrewGroup.RectTransform))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaignmenucrew"), font: GUI.SubHeadingFont);
|
||||
crewList = new GUIListBox(new RectTransform(new Vector2(1.0f, (8)* height), pendingAndCrewGroup.RectTransform))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
var group = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), group.RectTransform), TextManager.Get("campaignstore.total"));
|
||||
totalBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), group.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
TextScale = 1.1f
|
||||
};
|
||||
group = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.TopRight)
|
||||
{
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
validateHiresButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaigncrew.validate"))
|
||||
{
|
||||
ForceUpperCase = true,
|
||||
OnClicked = (b, o) => ValidatePendingHires(true)
|
||||
};
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ForceUpperCase = true,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemoveAllPendingHires()
|
||||
};
|
||||
|
||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
private void UpdateLocationView(Location location, bool removePending, Location prevLocation = null)
|
||||
{
|
||||
if (prevLocation != null && prevLocation == location && GameMain.NetworkMember != null) { return; }
|
||||
|
||||
if (characterPreviewFrame != null)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
UpdateHireables(location);
|
||||
if (pendingList != null)
|
||||
{
|
||||
if (removePending)
|
||||
{
|
||||
PendingHires?.Clear();
|
||||
pendingList.Content.ClearChildren();
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingHires?.ForEach(ci => AddPendingHire(ci));
|
||||
}
|
||||
SetTotalHireCost();
|
||||
}
|
||||
UpdateCrew();
|
||||
}
|
||||
|
||||
private void UpdateHireables(Location location)
|
||||
{
|
||||
if (hireableList != null)
|
||||
{
|
||||
hireableList.Content.Children.ToList().ForEach(c => hireableList.RemoveChild(c));
|
||||
var hireableCharacters = location.GetHireableCharacters();
|
||||
if (hireableCharacters.None())
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), hireableList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (CharacterInfo c in hireableCharacters)
|
||||
{
|
||||
if (c == null) { continue; }
|
||||
CreateCharacterFrame(c, hireableList);
|
||||
}
|
||||
}
|
||||
sortingDropDown.SelectItem(SortingMethod.JobAsc);
|
||||
hireableList.UpdateScrollBarSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHireables(Location location, List<CharacterInfo> availableHires)
|
||||
{
|
||||
HireManager hireManager = location.HireManager;
|
||||
if (hireManager == null) { return; }
|
||||
int hireVal = hireManager.AvailableCharacters.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
|
||||
int newVal = availableHires.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
|
||||
if (hireVal != newVal)
|
||||
{
|
||||
location.HireManager.AvailableCharacters = availableHires;
|
||||
UpdateHireables(location);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCrew()
|
||||
{
|
||||
crewList.Content.Children.ToList().ForEach(c => crewList.Content.RemoveChild(c));
|
||||
foreach (CharacterInfo c in GameMain.GameSession.CrewManager.GetCharacterInfos())
|
||||
{
|
||||
if (c == null || !((c.Character?.IsBot ?? true) || campaign is SinglePlayerCampaign)) { continue; }
|
||||
CreateCharacterFrame(c, crewList);
|
||||
}
|
||||
SortCharacters(crewList, SortingMethod.JobAsc);
|
||||
crewList.UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
private void SortCharacters(GUIListBox list, SortingMethod sortingMethod)
|
||||
{
|
||||
if (sortingMethod == SortingMethod.AlphabeticalAsc)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Name.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Name));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.JobAsc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
String.Compare((x.GUIComponent.UserData as Tuple<CharacterInfo, float>)?.Item1.Job.Name, (y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Job.Name, StringComparison.Ordinal));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Salary.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Salary));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.SkillAsc || sortingMethod == SortingMethod.SkillDesc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item2.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item2));
|
||||
if (sortingMethod == SortingMethod.SkillDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCharacterFrame(CharacterInfo characterInfo, GUIListBox listBox)
|
||||
{
|
||||
Skill skill = null;
|
||||
Color? jobColor = null;
|
||||
if (characterInfo.Job != null)
|
||||
{
|
||||
skill = characterInfo.Job?.PrimarySkill ?? characterInfo.Job.Skills.OrderByDescending(s => s.Level).FirstOrDefault();
|
||||
jobColor = characterInfo.Job.Prefab.UIColor;
|
||||
}
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, 55), parent: listBox.Content.RectTransform), "ListBoxElement")
|
||||
{
|
||||
UserData = new Tuple<CharacterInfo, float>(characterInfo, skill != null ? skill.Level : 0.0f)
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), frame.RectTransform, anchor: Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
float portraitWidth = (0.8f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
new GUICustomComponent(new RectTransform(new Vector2(portraitWidth, 0.8f), mainGroup.RectTransform),
|
||||
onDraw: (sb, component) => characterInfo.DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()))
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUILayoutGroup nameAndJobGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f - portraitWidth, 0.8f), mainGroup.RectTransform));
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform),
|
||||
characterInfo.Name, textColor: jobColor, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text, nameBlock.Font, nameBlock.Rect.Width);
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform),
|
||||
characterInfo.Job.Name, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
jobBlock.Text = ToolBox.LimitString(jobBlock.Text, jobBlock.Font, jobBlock.Rect.Width);
|
||||
|
||||
float width = 0.6f / 3;
|
||||
if (characterInfo.Job != null)
|
||||
{
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(width, 0.6f), mainGroup.RectTransform), isHorizontal: true);
|
||||
float iconWidth = (float)skillGroup.Rect.Height / skillGroup.Rect.Width;
|
||||
GUIImage skillIcon = new GUIImage(new RectTransform(new Vector2(iconWidth, 1.0f), skillGroup.RectTransform), skill.Icon)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
if (jobColor.HasValue) { skillIcon.Color = jobColor.Value; }
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 1.0f), skillGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (listBox != crewList)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform), FormatCurrency(characterInfo.Salary), textAlignment: Alignment.Center)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (listBox == hireableList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
else if (listBox == pendingList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementRemoveButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemovePendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
else if (listBox == crewList && campaign != null)
|
||||
{
|
||||
var currentCrew = GameMain.GameSession.CrewManager.GetCharacterInfos();
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementFireButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
//can't fire if there's only one character in the crew
|
||||
Enabled = currentCrew.Contains(characterInfo) && currentCrew.Count() > 1 && HasPermission,
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
var confirmDialog = new GUIMessageBox(
|
||||
TextManager.Get("FireWarningHeader"),
|
||||
TextManager.GetWithVariable("FireWarningText", "[charactername]", ((CharacterInfo)obj).Name),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
confirmDialog.Buttons[0].UserData = (CharacterInfo)obj;
|
||||
confirmDialog.Buttons[0].OnClicked = FireCharacter;
|
||||
confirmDialog.Buttons[0].OnClicked += confirmDialog.Close;
|
||||
confirmDialog.Buttons[1].OnClicked = confirmDialog.Close;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCharacterPreviewFrame(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
{
|
||||
Pivot pivot = listBox == hireableList ? Pivot.TopLeft : Pivot.TopRight;
|
||||
Point absoluteOffset = new Point(
|
||||
pivot == Pivot.TopLeft ? listBox.Parent.Parent.Rect.Right + 5 : listBox.Parent.Parent.Rect.Left - 5,
|
||||
characterFrame.Rect.Top);
|
||||
int frameSize = (int)(GUI.Scale * 300);
|
||||
if (GameMain.GraphicsHeight - (absoluteOffset.Y + frameSize) < 0)
|
||||
{
|
||||
pivot = listBox == hireableList ? Pivot.BottomLeft : Pivot.BottomRight;
|
||||
absoluteOffset.Y = characterFrame.Rect.Bottom;
|
||||
}
|
||||
characterPreviewFrame = new GUIFrame(new RectTransform(new Point(frameSize), parent: campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Parent.RectTransform, pivot: pivot)
|
||||
{
|
||||
AbsoluteOffset = absoluteOffset
|
||||
}, style: "InnerFrame")
|
||||
{
|
||||
UserData = characterInfo
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), characterPreviewFrame.RectTransform, anchor: Anchor.Center))
|
||||
{
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
// Character info
|
||||
GUILayoutGroup infoGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.475f), mainGroup.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup infoLabelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
GUILayoutGroup infoValueGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.6f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
float blockHeight = 1.0f / 4;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("name"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), characterInfo.Name);
|
||||
if (characterInfo.HasGenders)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("gender"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get(characterInfo.Gender.ToString()));
|
||||
}
|
||||
if (characterInfo.Job is Job job)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("tabmenu.job"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), job.Name);
|
||||
}
|
||||
if (characterInfo.PersonalityTrait is NPCPersonalityTrait trait)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("PersonalityTrait"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get("personalitytrait." + trait.Name.Replace(" ", "")));
|
||||
}
|
||||
infoLabelGroup.Recalculate();
|
||||
infoValueGroup.Recalculate();
|
||||
|
||||
new GUIImage(new RectTransform(new Vector2(1.0f, 0.05f), mainGroup.RectTransform), "HorizontalLine");
|
||||
|
||||
// Skills
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.475f), mainGroup.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup skillNameGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), skillGroup.RectTransform));
|
||||
GUILayoutGroup skillLevelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), skillGroup.RectTransform));
|
||||
List<Skill> characterSkills = characterInfo.Job.Skills;
|
||||
blockHeight = 1.0f / characterSkills.Count;
|
||||
foreach (Skill skill in characterSkills)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), skillNameGroup.RectTransform), TextManager.Get("SkillName." + skill.Identifier));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), skillLevelGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.Right);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SelectCharacter(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterPreviewFrame != null && characterPreviewFrame.UserData != characterInfo)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
|
||||
if (listBox == null || characterFrame == null || characterInfo == null) { return false; }
|
||||
|
||||
if (characterPreviewFrame == null)
|
||||
{
|
||||
CreateCharacterPreviewFrame(listBox, characterFrame, characterInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool AddPendingHire(CharacterInfo characterInfo, bool createNetworkMessage = true)
|
||||
{
|
||||
hireableList.Content.RemoveChild(hireableList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == characterInfo));
|
||||
hireableList.UpdateScrollBarSize();
|
||||
if (!PendingHires.Contains(characterInfo)) { PendingHires.Add(characterInfo); }
|
||||
CreateCharacterFrame(characterInfo, pendingList);
|
||||
SortCharacters(pendingList, SortingMethod.JobAsc);
|
||||
pendingList.UpdateScrollBarSize();
|
||||
SetTotalHireCost();
|
||||
if (createNetworkMessage) { SendCrewState(true); }
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RemovePendingHire(CharacterInfo characterInfo, bool setTotalHireCost = true, bool createNetworkMessage = true)
|
||||
{
|
||||
if (PendingHires.Contains(characterInfo)) { PendingHires.Remove(characterInfo); }
|
||||
pendingList.Content.RemoveChild(pendingList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == characterInfo));
|
||||
pendingList.UpdateScrollBarSize();
|
||||
CreateCharacterFrame(characterInfo, hireableList);
|
||||
SortCharacters(hireableList, (SortingMethod)sortingDropDown.SelectedItemData);
|
||||
hireableList.UpdateScrollBarSize();
|
||||
if (setTotalHireCost) { SetTotalHireCost(); }
|
||||
if (createNetworkMessage) { SendCrewState(true); }
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RemoveAllPendingHires(bool createNetworkMessage = true)
|
||||
{
|
||||
pendingList.Content.Children.ToList().ForEach(c => RemovePendingHire((c.UserData as Tuple<CharacterInfo, float>).Item1, setTotalHireCost: false, createNetworkMessage));
|
||||
SetTotalHireCost();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetTotalHireCost()
|
||||
{
|
||||
if (pendingList == null || totalBlock == null || validateHiresButton == null) { return; }
|
||||
int total = 0;
|
||||
pendingList.Content.Children.ForEach(c => total += (c.UserData as Tuple<CharacterInfo, float>).Item1.Salary);
|
||||
totalBlock.Text = FormatCurrency(total);
|
||||
bool enoughMoney = campaign != null ? total <= campaign.Money : true;
|
||||
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
|
||||
validateHiresButton.Enabled = enoughMoney && pendingList.Content.RectTransform.Children.Any();
|
||||
}
|
||||
|
||||
public bool ValidatePendingHires(bool createNetworkEvent = false)
|
||||
{
|
||||
List<CharacterInfo> hires = new List<CharacterInfo>();
|
||||
int total = 0;
|
||||
foreach (GUIComponent c in pendingList.Content.Children.ToList())
|
||||
{
|
||||
if (c.UserData is Tuple<CharacterInfo, float> info)
|
||||
{
|
||||
hires.Add(info.Item1);
|
||||
total += info.Item1.Salary;
|
||||
}
|
||||
}
|
||||
|
||||
if (hires.None() || total > campaign.Money) { return false; }
|
||||
|
||||
bool atLeastOneHired = false;
|
||||
foreach (CharacterInfo ci in hires)
|
||||
{
|
||||
if (campaign.TryHireCharacter(campaign.Map.CurrentLocation, ci))
|
||||
{
|
||||
atLeastOneHired = true;
|
||||
PendingHires.Remove(ci);
|
||||
pendingList.Content.RemoveChild(pendingList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == ci));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOneHired)
|
||||
{
|
||||
UpdateLocationView(campaign.Map.CurrentLocation, true);
|
||||
SelectCharacter(null, null, null);
|
||||
var dialog = new GUIMessageBox(
|
||||
TextManager.Get("newcrewmembers"),
|
||||
TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.Name),
|
||||
new string[] { TextManager.Get("Ok") });
|
||||
dialog.Buttons[0].OnClicked += dialog.Close;
|
||||
}
|
||||
|
||||
if (createNetworkEvent)
|
||||
{
|
||||
SendCrewState(true, validateHires: true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool FireCharacter(GUIButton button, object selection)
|
||||
{
|
||||
if (!(selection is CharacterInfo characterInfo)) { return false; }
|
||||
|
||||
campaign.CrewManager.FireCharacter(characterInfo);
|
||||
SelectCharacter(null, null, null);
|
||||
UpdateCrew();
|
||||
|
||||
SendCrewState(false, firedCharacter: characterInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||
{
|
||||
CreateUI();
|
||||
UpdateLocationView(campaign.Map.CurrentLocation, false);
|
||||
}
|
||||
|
||||
if ((GUI.MouseOn?.UserData as Tuple<CharacterInfo, float>)?.Item1 is CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterPreviewFrame == null || characterInfo != characterPreviewFrame.UserData)
|
||||
{
|
||||
GUIComponent component = GUI.MouseOn;
|
||||
GUIListBox listBox = null;
|
||||
do
|
||||
{
|
||||
if (component.Parent is GUIListBox)
|
||||
{
|
||||
listBox = component.Parent as GUIListBox;
|
||||
break;
|
||||
}
|
||||
else if (component.Parent != null)
|
||||
{
|
||||
component = component.Parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (listBox == null);
|
||||
|
||||
if (listBox != null)
|
||||
{
|
||||
SelectCharacter(listBox, GUI.MouseOn as GUIFrame, characterInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Reposition the current preview panel if necessary
|
||||
// Could happen if we scroll a list while hovering?
|
||||
}
|
||||
}
|
||||
else if (characterPreviewFrame != null)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPendingHires(List<int> characterInfos, Location location)
|
||||
{
|
||||
List<CharacterInfo> oldHires = PendingHires.ToList();
|
||||
foreach (CharacterInfo pendingHire in oldHires)
|
||||
{
|
||||
RemovePendingHire(pendingHire, createNetworkMessage: false);
|
||||
}
|
||||
PendingHires.Clear();
|
||||
foreach (int identifier in characterInfos)
|
||||
{
|
||||
CharacterInfo match = location.HireManager.AvailableCharacters.Find(info => info.GetIdentifier() == identifier);
|
||||
if (match != null)
|
||||
{
|
||||
PendingHires.Add(match);
|
||||
AddPendingHire(match, createNetworkMessage: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Received a hire that doesn't exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notify the server of crew changes
|
||||
/// </summary>
|
||||
/// <param name="updatePending">When set to true will tell the server to update the pending hires</param>
|
||||
/// <param name="firedCharacter">When not null tell the server to fire this character</param>
|
||||
/// <param name="validateHires">When set to true will tell the server to validate pending hires</param>
|
||||
public void SendCrewState(bool updatePending, CharacterInfo firedCharacter = null, bool validateHires = false)
|
||||
{
|
||||
if (campaign is MultiPlayerCampaign)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.CREW);
|
||||
|
||||
msg.Write(updatePending);
|
||||
if (updatePending)
|
||||
{
|
||||
msg.Write((ushort)PendingHires.Count);
|
||||
foreach (CharacterInfo pendingHire in PendingHires)
|
||||
{
|
||||
msg.Write(pendingHire.GetIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write(validateHires);
|
||||
|
||||
msg.Write(firedCharacter != null);
|
||||
if (firedCharacter != null)
|
||||
{
|
||||
msg.Write(firedCharacter.GetIdentifier());
|
||||
}
|
||||
|
||||
GameMain.Client.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
|
||||
private string FormatCurrency(int currency) => TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", currency));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -145,6 +146,11 @@ namespace Barotrauma
|
||||
textBlock.ToolTip = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Pulse { get; set; }
|
||||
private float pulseTimer;
|
||||
private float pulseExpand;
|
||||
private bool flashed;
|
||||
|
||||
public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
@@ -196,7 +202,14 @@ namespace Barotrauma
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
//do nothing
|
||||
if (Pulse && pulseTimer > 1.0f)
|
||||
{
|
||||
Rectangle expandRect = Rect;
|
||||
float expand = (pulseExpand * 20.0f) * GUI.Scale;
|
||||
expandRect.Inflate(expand, expand);
|
||||
|
||||
GUI.Style.ButtonPulse.Draw(spriteBatch, expandRect, ToolBox.GradientLerp(pulseExpand, Color.White, Color.White, Color.Transparent));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
@@ -244,13 +257,41 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
State = Selected ? ComponentState.Selected : ComponentState.None;
|
||||
if (!ExternalHighlight)
|
||||
{
|
||||
State = Selected ? ComponentState.Selected : ComponentState.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
State = ComponentState.Hover;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
child.State = State;
|
||||
}
|
||||
|
||||
if (Pulse)
|
||||
{
|
||||
pulseTimer += deltaTime;
|
||||
if (pulseTimer > 1.0f)
|
||||
{
|
||||
if (!flashed)
|
||||
{
|
||||
flashed = true;
|
||||
Frame.Flash(Color.White * 0.2f, 0.8f, true);
|
||||
}
|
||||
|
||||
pulseExpand += deltaTime;
|
||||
if (pulseExpand > 1.0f)
|
||||
{
|
||||
pulseTimer = 0.0f;
|
||||
pulseExpand = 0.0f;
|
||||
flashed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
_instance = new GUICanvas();
|
||||
if (GameMain.Instance != null)
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged += RecalculateSize;
|
||||
GameMain.Instance.ResolutionChanged += RecalculateSize;
|
||||
}
|
||||
_instance.ItemComponentHolder = new GUIFrame(new RectTransform(Vector2.One, _instance, Anchor.Center)).RectTransform;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,16 @@ using System.Net;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public enum SlideDirection { Up, Down, Left, Right }
|
||||
|
||||
public abstract class GUIComponent
|
||||
{
|
||||
#region Hierarchy
|
||||
public GUIComponent Parent => RectTransform.Parent?.GUIComponent;
|
||||
|
||||
public CursorState HoverCursor = CursorState.Default;
|
||||
|
||||
public bool AlwaysOverrideCursor = false;
|
||||
|
||||
public delegate bool SecondaryButtonDownHandler(GUIComponent component, object userData);
|
||||
public SecondaryButtonDownHandler OnSecondaryClicked;
|
||||
@@ -75,7 +79,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void RemoveChild(GUIComponent child)
|
||||
{
|
||||
if (child == null) return;
|
||||
if (child == null) { return; }
|
||||
child.RectTransform.Parent = null;
|
||||
}
|
||||
|
||||
@@ -139,6 +143,11 @@ namespace Barotrauma
|
||||
public bool AutoUpdate { get; set; } = true;
|
||||
public bool AutoDraw { get; set; } = true;
|
||||
public int UpdateOrder { get; set; }
|
||||
|
||||
public bool Bounce { get; set; }
|
||||
private float bounceTimer;
|
||||
private float bounceJump;
|
||||
private bool bounceDown;
|
||||
|
||||
public Action<GUIComponent> OnAddedToGUIUpdateList;
|
||||
|
||||
@@ -158,6 +167,8 @@ namespace Barotrauma
|
||||
protected Color disabledColor;
|
||||
protected Color pressedColor;
|
||||
|
||||
public bool GlowOnSelect { get; set; }
|
||||
|
||||
private CoroutineHandle pulsateCoroutine;
|
||||
|
||||
protected Color flashColor;
|
||||
@@ -326,6 +337,11 @@ namespace Barotrauma
|
||||
{
|
||||
get { return RectTransform.CountChildren; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently only used for the fade effect in GUIListBox, should be set to the same value as Color but only assigned once
|
||||
/// </summary>
|
||||
public Color DefaultColor { get; set; }
|
||||
|
||||
public virtual Color Color
|
||||
{
|
||||
@@ -462,6 +478,36 @@ namespace Barotrauma
|
||||
OnSecondaryClicked?.Invoke(this, userData);
|
||||
}
|
||||
}
|
||||
|
||||
if (Bounce)
|
||||
{
|
||||
if (bounceTimer > 3.0f || bounceDown)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = new Point(RectTransform.ScreenSpaceOffset.X, (int) -(bounceJump * 10f));
|
||||
if (!bounceDown)
|
||||
{
|
||||
bounceJump += deltaTime * 4;
|
||||
if (bounceJump > 0.5f)
|
||||
{
|
||||
bounceDown = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bounceJump -= deltaTime * 4;
|
||||
if (bounceJump <= 0.0f)
|
||||
{
|
||||
bounceJump = 0.0f;
|
||||
bounceTimer = 0.0f;
|
||||
bounceDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bounceTimer += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (flashTimer > 0.0f)
|
||||
{
|
||||
@@ -526,12 +572,14 @@ namespace Barotrauma
|
||||
protected virtual Color GetColor(ComponentState state)
|
||||
{
|
||||
if (!Enabled) { return DisabledColor; }
|
||||
if (ExternalHighlight) { return HoverColor; }
|
||||
|
||||
return state switch
|
||||
{
|
||||
ComponentState.Hover => HoverColor,
|
||||
ComponentState.HoverSelected => HoverColor,
|
||||
ComponentState.Pressed => PressedColor,
|
||||
ComponentState.Selected => SelectedColor,
|
||||
ComponentState.Selected when !GlowOnSelect => SelectedColor,
|
||||
_ => Color,
|
||||
};
|
||||
}
|
||||
@@ -619,6 +667,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GlowOnSelect && State == ComponentState.Selected)
|
||||
{
|
||||
GUI.UIGlow.Draw(spriteBatch, Rect, SelectedColor);
|
||||
}
|
||||
|
||||
if (flashTimer > 0.0f)
|
||||
{
|
||||
//the number of flashes depends on the duration, 1 flash per 1 full second
|
||||
@@ -690,6 +743,7 @@ namespace Barotrauma
|
||||
protected virtual void SetAlpha(float a)
|
||||
{
|
||||
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
|
||||
hoverColor = new Color(hoverColor.R / 255.0f, hoverColor.G / 255.0f, hoverColor.B / 255.0f, a);;
|
||||
}
|
||||
|
||||
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectInflate = null)
|
||||
@@ -707,10 +761,77 @@ namespace Barotrauma
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(0.0f, duration, removeAfter));
|
||||
}
|
||||
|
||||
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter)
|
||||
public void FadeIn(float wait, float duration)
|
||||
{
|
||||
SetAlpha(0.0f);
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(1.0f, duration, false, wait));
|
||||
}
|
||||
|
||||
public void SlideIn(float wait, float duration, int amount, SlideDirection direction)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = direction switch
|
||||
{
|
||||
SlideDirection.Up => new Point(0, amount),
|
||||
SlideDirection.Down => new Point(0, -amount),
|
||||
SlideDirection.Left => new Point(amount, 0),
|
||||
SlideDirection.Right => new Point(-amount, 0),
|
||||
_ => RectTransform.ScreenSpaceOffset
|
||||
};
|
||||
CoroutineManager.StartCoroutine(SlideToPosition(duration, wait, Vector2.Zero));
|
||||
}
|
||||
|
||||
public void SlideOut(float duration, int amount, SlideDirection direction)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = Point.Zero;
|
||||
|
||||
Vector2 targetPos = direction switch
|
||||
{
|
||||
SlideDirection.Up => new Vector2(0, amount),
|
||||
SlideDirection.Down => new Vector2(0, -amount),
|
||||
SlideDirection.Left => new Vector2(amount, 0),
|
||||
SlideDirection.Right => new Vector2(-amount, 0),
|
||||
_ => Vector2.Zero
|
||||
};
|
||||
|
||||
CoroutineManager.StartCoroutine(SlideToPosition(duration, 0.0f, targetPos));
|
||||
}
|
||||
|
||||
private IEnumerable<object> SlideToPosition(float duration, float wait, Vector2 target)
|
||||
{
|
||||
float t = 0.0f;
|
||||
float startA = color.A;
|
||||
var (startX, startY) = RectTransform.ScreenSpaceOffset.ToVector2();
|
||||
var (endX, endY) = target;
|
||||
while (t < wait)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
t = 0.0f;
|
||||
|
||||
while (t < duration)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
RectTransform.ScreenSpaceOffset = new Point((int)MathHelper.Lerp(startX, endX, t / duration), (int)MathHelper.Lerp(startY, endY, t / duration));
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
RectTransform.ScreenSpaceOffset = new Point(0, 0);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
|
||||
{
|
||||
State = ComponentState.None;
|
||||
float t = 0.0f;
|
||||
float startA = color.A / 255.0f;
|
||||
|
||||
while (t < wait)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
t = 0.0f;
|
||||
|
||||
while (t < duration)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Barotrauma
|
||||
{
|
||||
public class GUIFrame : GUIComponent
|
||||
{
|
||||
public int OutlineThickness { get; set; }
|
||||
|
||||
public GUIFrame(RectTransform rectT, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
Enabled = true;
|
||||
@@ -26,7 +28,7 @@ namespace Barotrauma
|
||||
|
||||
if (OutlineColor != Color.Transparent)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false);
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false, thickness: OutlineThickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,32 @@ namespace Barotrauma
|
||||
{
|
||||
return crop;
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
public void SetCrop(bool state, bool center = true)
|
||||
{
|
||||
crop = state;
|
||||
if (crop && sprite != null)
|
||||
{
|
||||
crop = value;
|
||||
if (crop)
|
||||
{
|
||||
sourceRect.Width = Math.Min(sprite.SourceRect.Width, Rect.Width);
|
||||
sourceRect.Height = Math.Min(sprite.SourceRect.Height, Rect.Height);
|
||||
sourceRect.Width = Math.Min(sprite.SourceRect.Width, (int)(Rect.Width / Scale));
|
||||
sourceRect.Height = Math.Min(sprite.SourceRect.Height, (int)(Rect.Height / Scale));
|
||||
|
||||
if (center)
|
||||
{
|
||||
sourceRect.X = (sprite.SourceRect.Width - sourceRect.Width) / 2;
|
||||
sourceRect.Y = (sprite.SourceRect.Height - sourceRect.Height) / 2;
|
||||
}
|
||||
|
||||
origin = sourceRect.Size.ToVector2() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
origin = sprite == null ? Vector2.Zero : sprite.size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 origin;
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get;
|
||||
@@ -72,7 +87,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (sprite == value) return;
|
||||
sprite = value;
|
||||
sourceRect = sprite.SourceRect;
|
||||
sourceRect = value == null ? Rectangle.Empty : value.SourceRect;
|
||||
origin = value == null ? Vector2.Zero : value.size / 2;
|
||||
if (scaleToFit) RecalculateScale();
|
||||
}
|
||||
}
|
||||
@@ -134,7 +150,8 @@ namespace Barotrauma
|
||||
{
|
||||
loadingTextures = true;
|
||||
loading = true;
|
||||
TaskPool.Add(LoadTextureAsync(), (Task) =>
|
||||
TaskPool.Add("LoadTextureAsync",
|
||||
LoadTextureAsync(), (Task) =>
|
||||
{
|
||||
loading = false;
|
||||
lazyLoaded = true;
|
||||
@@ -178,7 +195,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (sprite?.Texture != null)
|
||||
{
|
||||
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, sprite.size / 2,
|
||||
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, origin,
|
||||
Scale, SpriteEffects, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Barotrauma
|
||||
(RectTransform.Children.Count(c => !c.GUIComponent.IgnoreLayoutGroups) - 1) *
|
||||
(absoluteSpacing + relativeSpacing * thisSize);
|
||||
|
||||
stretchFactor = totalSize <= 0.0f || minSize >= thisSize ?
|
||||
stretchFactor = totalSize <= 0.0f || minSize >= thisSize || totalSize == minSize ?
|
||||
1.0f :
|
||||
(thisSize - minSize) / (totalSize - minSize);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
||||
public GUIScrollBar ScrollBar { get; private set; }
|
||||
|
||||
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
|
||||
|
||||
private int totalSize;
|
||||
private bool childrenNeedsRecalculation;
|
||||
private bool scrollBarNeedsRecalculation;
|
||||
@@ -59,6 +59,37 @@ namespace Barotrauma
|
||||
|
||||
private bool useGridLayout;
|
||||
|
||||
private float targetScroll;
|
||||
|
||||
private GUIComponent pendingScroll;
|
||||
|
||||
public bool AllowMouseWheelScroll { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list smoothly
|
||||
/// </summary>
|
||||
public bool SmoothScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to only allow scrolling from one element to the next when smooth scrolling is enabled
|
||||
/// </summary>
|
||||
public bool ClampScrollToElements { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to true elements at the bottom of the list are gradually faded
|
||||
/// </summary>
|
||||
public bool FadeElements { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds enough extra padding to the bottom so the end of the scroll will only contain the last element
|
||||
/// </summary>
|
||||
public bool PadBottom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to true always selects the topmost item on the list
|
||||
/// </summary>
|
||||
public bool SelectTop { get; set; }
|
||||
|
||||
public bool UseGridLayout
|
||||
{
|
||||
get { return useGridLayout; }
|
||||
@@ -189,10 +220,13 @@ namespace Barotrauma
|
||||
private Point draggedReferenceOffset;
|
||||
|
||||
public GUIComponent DraggedElement => draggedElement;
|
||||
|
||||
private bool scheduledScroll = false;
|
||||
|
||||
/// <param name="isScrollBarOnDefaultSide">For horizontal listbox, default side is on the bottom. For vertical, it's on the right.</param>
|
||||
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true, bool useMouseDownToSelect = false) : base(style, rectT)
|
||||
{
|
||||
HoverCursor = CursorState.Hand;
|
||||
CanBeFocused = true;
|
||||
selected = new List<GUIComponent>();
|
||||
this.useMouseDownToSelect = useMouseDownToSelect;
|
||||
@@ -363,6 +397,49 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list to the specific element, currently only works when smooth scrolling and PadBottom are enabled.
|
||||
/// </summary>
|
||||
/// <param name="component"></param>
|
||||
public void ScrollToElement(GUIComponent component)
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.Click);
|
||||
List<GUIComponent> children = Content.Children.ToList();
|
||||
int index = children.IndexOf(component);
|
||||
if (index < 0) { return; }
|
||||
|
||||
targetScroll = MathHelper.Clamp(MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, (children.Count - 0.9f), index)), ScrollBar.MinValue, ScrollBar.MaxValue);
|
||||
}
|
||||
|
||||
public void ScrollToEnd(float duration)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(ScrollCoroutine());
|
||||
|
||||
IEnumerable<object> ScrollCoroutine()
|
||||
{
|
||||
if (BarSize >= 1.0f)
|
||||
{
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
float t = 0.0f;
|
||||
float startScroll = BarScroll * BarSize;
|
||||
float distanceToTravel = ScrollBar.MaxValue - startScroll;
|
||||
float progress = startScroll;
|
||||
float speed = distanceToTravel / duration;
|
||||
|
||||
while (t < duration && !MathUtils.NearlyEqual(ScrollBar.MaxValue, progress))
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
progress += speed * CoroutineManager.DeltaTime;
|
||||
BarScroll = progress;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateChildrenRect()
|
||||
{
|
||||
@@ -404,6 +481,32 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectTop)
|
||||
{
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
child.CanBeFocused = !selected.Contains(child);
|
||||
if (!child.CanBeFocused)
|
||||
{
|
||||
child.State = ComponentState.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectTop && Content.Children.Any() && pendingScroll == null)
|
||||
{
|
||||
GUIComponent component = Content.Children.FirstOrDefault(c => (c.Rect.Y - Content.Rect.Y) / (float)c.Rect.Height > -0.1f);
|
||||
|
||||
if (component != null && !selected.Contains(component))
|
||||
{
|
||||
int index = Content.Children.ToList().IndexOf(component);
|
||||
if (index >= 0)
|
||||
{
|
||||
Select(index, false, false, takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Content.CountChildren; i++)
|
||||
{
|
||||
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
|
||||
@@ -418,7 +521,16 @@ namespace Barotrauma
|
||||
|
||||
if (mouseDown)
|
||||
{
|
||||
Select(i, autoScroll: false);
|
||||
if (SelectTop)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
Select(i, autoScroll: false, takeKeyBoardFocus: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Select(i, autoScroll: false, takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (CanDragElements && PlayerInput.LeftButtonDown() && GUI.MouseOn == child)
|
||||
@@ -538,10 +650,93 @@ namespace Barotrauma
|
||||
{
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && PlayerInput.ScrollWheelSpeed != 0)
|
||||
|
||||
|
||||
if (FadeElements)
|
||||
{
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
foreach (var (component, _) in childVisible)
|
||||
{
|
||||
float lerp = 0;
|
||||
float y = component.Rect.Y;
|
||||
float contentY = Content.Rect.Y;
|
||||
float height = component.Rect.Height;
|
||||
if (y < Content.Rect.Y)
|
||||
{
|
||||
float distance = (contentY - y) / height;
|
||||
lerp = distance;
|
||||
}
|
||||
|
||||
float centerY = Content.Rect.Y + Content.Rect.Height / 2.0f;
|
||||
if (y > centerY)
|
||||
{
|
||||
float distance = (y - centerY) / (centerY - height);
|
||||
lerp = distance;
|
||||
}
|
||||
|
||||
component.Color = component.HoverColor = ToolBox.GradientLerp(lerp, component.DefaultColor, Color.Transparent);
|
||||
component.DisabledColor = ToolBox.GradientLerp(lerp, component.Style.DisabledColor, Color.Transparent);
|
||||
component.HoverColor = ToolBox.GradientLerp(lerp, component.Style.HoverColor, Color.Transparent);
|
||||
|
||||
foreach (var child in component.GetAllChildren())
|
||||
{
|
||||
Color gradient = ToolBox.GradientLerp(lerp, child.DefaultColor, Color.Transparent);
|
||||
child.Color = child.HoverColor = gradient;
|
||||
if (child is GUITextBlock block)
|
||||
{
|
||||
block.TextColor = block.HoverTextColor = gradient;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SmoothScroll)
|
||||
{
|
||||
if (targetScroll > -1)
|
||||
{
|
||||
float distance = Math.Abs(targetScroll - BarScroll);
|
||||
float speed = Math.Max(distance * BarSize, 0.1f);
|
||||
BarScroll = (1.0f - speed) * BarScroll + speed * targetScroll;
|
||||
if (MathUtils.NearlyEqual(BarScroll, targetScroll) || GUIScrollBar.DraggingBar != null)
|
||||
{
|
||||
targetScroll = -1;
|
||||
pendingScroll = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && AllowMouseWheelScroll && PlayerInput.ScrollWheelSpeed != 0)
|
||||
{
|
||||
float speed = PlayerInput.ScrollWheelSpeed / 500.0f * BarSize;
|
||||
if (SmoothScroll)
|
||||
{
|
||||
if (ClampScrollToElements)
|
||||
{
|
||||
bool scrollDown = Math.Clamp(PlayerInput.ScrollWheelSpeed, 0, 1) > 0;
|
||||
|
||||
if (scrollDown)
|
||||
{
|
||||
SelectPrevious(takeKeyBoardFocus: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectNext(takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingScroll = null;
|
||||
if (targetScroll < 0) { targetScroll = BarScroll; }
|
||||
targetScroll -= speed;
|
||||
targetScroll = Math.Clamp(targetScroll, ScrollBar.MinValue, ScrollBar.MaxValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
|
||||
if (AutoHideScrollBar)
|
||||
{
|
||||
@@ -553,35 +748,47 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectNext(bool force = false, bool autoScroll = true)
|
||||
public void SelectNext(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
int index = SelectedIndex + 1;
|
||||
while (index < Content.CountChildren)
|
||||
{
|
||||
if (Content.GetChild(index).Visible)
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, autoScroll);
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectPrevious(bool force = false, bool autoScroll = true)
|
||||
public void SelectPrevious(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
int index = SelectedIndex - 1;
|
||||
while (index >= 0)
|
||||
{
|
||||
if (Content.GetChild(index).Visible)
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, autoScroll);
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
public void Select(int childIndex, bool force = false, bool autoScroll = true)
|
||||
public void Select(int childIndex, bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
|
||||
|
||||
@@ -646,7 +853,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// If one of the children is the subscriber, we don't want to register, because it will unregister the child.
|
||||
if (RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
if (takeKeyBoardFocus && RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
{
|
||||
Selected = true;
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
@@ -712,6 +919,14 @@ namespace Barotrauma
|
||||
totalSize += (ScrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
|
||||
}
|
||||
totalSize += Content.CountChildren * Spacing;
|
||||
if (PadBottom)
|
||||
{
|
||||
GUIComponent last = Content.Children.LastOrDefault();
|
||||
if (last != null)
|
||||
{
|
||||
totalSize += Rect.Height - last.Rect.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float minScrollBarSize = 20.0f;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
||||
|
||||
public GUIMessage(string text, Color color, float lifeTime, ScalableFont font = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false);
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
this.lifeTime = lifeTime;
|
||||
Timer = lifeTime;
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
||||
|
||||
public GUIMessage(string text, Color color, Vector2 worldPosition, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false);
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
WorldSpace = true;
|
||||
pos = worldPosition;
|
||||
Timer = lifeTime;
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Barotrauma
|
||||
public GUITextBlock Header { get; private set; }
|
||||
public GUITextBlock Text { get; private set; }
|
||||
public string Tag { get; private set; }
|
||||
public bool Closed { get; private set; }
|
||||
|
||||
public GUIImage Icon
|
||||
{
|
||||
@@ -47,9 +48,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool alwaysVisible;
|
||||
public GUIImage BackgroundIcon { get; private set; }
|
||||
private GUIImage newBackgroundIcon;
|
||||
|
||||
public bool AutoClose;
|
||||
|
||||
private readonly bool alwaysVisible;
|
||||
|
||||
private float openState;
|
||||
private float iconState;
|
||||
private bool iconSwitching;
|
||||
private bool closing;
|
||||
|
||||
private Type type;
|
||||
@@ -62,7 +70,7 @@ namespace Barotrauma
|
||||
this.Buttons[0].OnClicked = Close;
|
||||
}
|
||||
|
||||
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, Type type = Type.Default, string tag = "", Sprite icon = null)
|
||||
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, Type type = Type.Default, string tag = "", Sprite icon = null, string iconStyle = "", Sprite backgroundIcon = null)
|
||||
: base(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: GUI.Style.GetComponentStyle("GUIMessageBox." + type) != null ? "GUIMessageBox." + type : "GUIMessageBox")
|
||||
{
|
||||
int width = (int)(DefaultWidth * (type == Type.Default ? 1.0f : 1.5f)), height = 0;
|
||||
@@ -80,6 +88,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (backgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon = new GUIImage(new RectTransform(backgroundIcon.size.ToPoint(), RectTransform), backgroundIcon)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Color = Color.Transparent
|
||||
};
|
||||
}
|
||||
|
||||
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, type == Type.InGame ? Anchor.TopCenter : Anchor.Center) { IsFixedSize = false }, style: null);
|
||||
GUI.Style.Apply(InnerFrame, "", this);
|
||||
this.type = type;
|
||||
@@ -145,6 +162,7 @@ namespace Barotrauma
|
||||
InnerFrame.RectTransform.AbsoluteOffset = new Point(0, GameMain.GraphicsHeight);
|
||||
alwaysVisible = true;
|
||||
CanBeFocused = false;
|
||||
AutoClose = true;
|
||||
GUI.Style.Apply(InnerFrame, "", this);
|
||||
|
||||
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), InnerFrame.RectTransform, Anchor.Center),
|
||||
@@ -157,6 +175,10 @@ namespace Barotrauma
|
||||
{
|
||||
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), icon, scaleToFit: true);
|
||||
}
|
||||
else if (iconStyle != string.Empty)
|
||||
{
|
||||
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), iconStyle, scaleToFit: true);
|
||||
}
|
||||
|
||||
Content = new GUILayoutGroup(new RectTransform(new Vector2(icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
|
||||
|
||||
@@ -182,6 +204,10 @@ namespace Barotrauma
|
||||
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
|
||||
new Point(Text.Rect.Width, Text.Rect.Height);
|
||||
Text.RectTransform.IsFixedSize = true;
|
||||
if (string.IsNullOrWhiteSpace(headerText))
|
||||
{
|
||||
Content.ChildAnchor = Anchor.Center;
|
||||
}
|
||||
}
|
||||
|
||||
if (height == 0)
|
||||
@@ -226,6 +252,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBackgroundIcon(Sprite icon)
|
||||
{
|
||||
if (icon == null) { return; }
|
||||
GUIImage newIcon = new GUIImage(new RectTransform(icon.size.ToPoint(), RectTransform), icon)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Color = Color.Transparent
|
||||
};
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
RemoveChild(newBackgroundIcon);
|
||||
newBackgroundIcon = null;
|
||||
}
|
||||
newBackgroundIcon = newIcon;
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (type == Type.InGame)
|
||||
@@ -246,10 +289,19 @@ namespace Barotrauma
|
||||
|
||||
if (!closing)
|
||||
{
|
||||
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (BackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - BackgroundIcon.Rect.Size.Y / 2);
|
||||
if (!MathUtils.NearlyEqual(openState, 1.0f))
|
||||
{
|
||||
BackgroundIcon.Color = ToolBox.GradientLerp(openState, Color.Transparent, Color.White);
|
||||
}
|
||||
}
|
||||
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
|
||||
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn))
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn) && AutoClose)
|
||||
{
|
||||
inGameCloseTimer += deltaTime;
|
||||
}
|
||||
@@ -262,13 +314,55 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
openState += deltaTime * 2.0f;
|
||||
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
}
|
||||
if (openState >= 2.0f)
|
||||
{
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
}
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
if (!iconSwitching)
|
||||
{
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
if (BackgroundIcon.Color.A == 0)
|
||||
{
|
||||
BackgroundIcon = null;
|
||||
iconSwitching = true;
|
||||
RemoveChild(BackgroundIcon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iconSwitching = true;
|
||||
}
|
||||
iconState = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newBackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
|
||||
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
|
||||
if (newBackgroundIcon.Color.A == 255)
|
||||
{
|
||||
BackgroundIcon = newBackgroundIcon;
|
||||
BackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon = null;
|
||||
iconSwitching = false;
|
||||
}
|
||||
|
||||
iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +378,8 @@ namespace Barotrauma
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
|
||||
Closed = true;
|
||||
}
|
||||
|
||||
public bool Close(GUIButton button, object obj)
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma
|
||||
private float pressedDelay = 0.5f;
|
||||
private bool IsPressedTimerRunning { get { return pressedTimer > 0; } }
|
||||
|
||||
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null) : base(style, rectT)
|
||||
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null, bool hidePlusMinusButtons = false) : base(style, rectT)
|
||||
{
|
||||
LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
if (inputType != NumberType.Int)
|
||||
if (inputType != NumberType.Int || hidePlusMinusButtons)
|
||||
{
|
||||
HidePlusMinusButtons();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Barotrauma
|
||||
(int)(Rect.Width - style.Padding.X + style.Padding.Z),
|
||||
(int)(Rect.Height - style.Padding.Y + style.Padding.W));
|
||||
frame.Visible = showFrame;
|
||||
slider.Visible = true;
|
||||
slider.Visible = BarSize > 0.0f;
|
||||
|
||||
if (showFrame)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace Barotrauma
|
||||
public UISprite UIGlow { get; private set; }
|
||||
public UISprite UIGlowCircular { get; private set; }
|
||||
|
||||
public UISprite ButtonPulse { get; private set; }
|
||||
|
||||
public SpriteSheet FocusIndicator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -206,6 +208,9 @@ namespace Barotrauma
|
||||
case "uiglowcircular":
|
||||
UIGlowCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "endroundbuttonpulse":
|
||||
ButtonPulse = new UISprite(subElement);
|
||||
break;
|
||||
case "focusindicator":
|
||||
FocusIndicator = new SpriteSheet(subElement);
|
||||
break;
|
||||
@@ -255,7 +260,8 @@ namespace Barotrauma
|
||||
DebugConsole.NewMessage("Global font not defined in the current UI style file. The global font is used to render western symbols when using Chinese/Japanese/Korean localization. Using default font instead...", Color.Orange);
|
||||
}
|
||||
|
||||
GameMain.Instance.OnResolutionChanged += () => { RescaleElements(); };
|
||||
// TODO: Needs to unregister if we ever remove GUIStyles.
|
||||
GameMain.Instance.ResolutionChanged += RescaleElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -271,6 +271,8 @@ namespace Barotrauma
|
||||
public OnClickDelegate OnClick;
|
||||
}
|
||||
public List<ClickableArea> ClickableAreas { get; private set; } = new List<ClickableArea>();
|
||||
|
||||
public bool Shadow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is the new constructor.
|
||||
@@ -320,10 +322,10 @@ namespace Barotrauma
|
||||
hasColorHighlight = richTextData != null;
|
||||
}
|
||||
|
||||
public void CalculateHeightFromText(int padding = 0)
|
||||
public void CalculateHeightFromText(int padding = 0, bool removeExtraSpacing = false)
|
||||
{
|
||||
if (wrappedText == null) { return; }
|
||||
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText).Y + padding));
|
||||
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText, removeExtraSpacing).Y + padding));
|
||||
}
|
||||
|
||||
public override void ApplyStyle(GUIComponentStyle componentStyle)
|
||||
@@ -443,8 +445,8 @@ namespace Barotrauma
|
||||
|
||||
protected override void SetAlpha(float a)
|
||||
{
|
||||
base.SetAlpha(a);
|
||||
textColor = new Color(textColor.R, textColor.G, textColor.B, a);
|
||||
// base.SetAlpha(a);
|
||||
textColor = new Color(TextColor.R / 255.0f, TextColor.G / 255.0f, TextColor.B / 255.0f, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -626,12 +628,17 @@ namespace Barotrauma
|
||||
|
||||
if (!hasColorHighlight)
|
||||
{
|
||||
Font.DrawString(spriteBatch,
|
||||
Censor ? censoredText : (Wrap ? wrappedText : text),
|
||||
pos,
|
||||
currentTextColor * (currentTextColor.A / 255.0f),
|
||||
0.0f, origin, TextScale,
|
||||
SpriteEffects.None, textDepth);
|
||||
string textToShow = Censor ? censoredText : (Wrap ? wrappedText : text);
|
||||
Color colorToShow = currentTextColor * (currentTextColor.A / 255.0f);
|
||||
|
||||
if (Shadow)
|
||||
{
|
||||
Vector2 shadowOffset = new Vector2(GUI.IntScale(2));
|
||||
Font.DrawString(spriteBatch, textToShow, pos + shadowOffset, Color.Black, 0.0f, origin, TextScale, SpriteEffects.None, textDepth);
|
||||
}
|
||||
|
||||
Font.DrawString(spriteBatch, textToShow, pos, colorToShow, 0.0f, origin, TextScale, SpriteEffects.None, textDepth);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -134,6 +134,10 @@ namespace Barotrauma
|
||||
{
|
||||
textBlock.OverflowClip = value != null;
|
||||
maxTextLength = value;
|
||||
if (Text.Length > MaxTextLength)
|
||||
{
|
||||
SetText(textBlock.Text.Substring(0, (int)maxTextLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,6 +364,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
|
||||
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex));
|
||||
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin;
|
||||
|
||||
@@ -75,6 +75,11 @@ namespace Barotrauma
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static Rectangle VotingArea
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static int Padding
|
||||
{
|
||||
get; private set;
|
||||
@@ -84,7 +89,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.Instance != null)
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged += CreateAreas;
|
||||
GameMain.Instance.ResolutionChanged += CreateAreas;
|
||||
GameMain.Config.OnHUDScaleChanged += CreateAreas;
|
||||
CreateAreas();
|
||||
CharacterInfo.Init();
|
||||
@@ -144,6 +149,13 @@ namespace Barotrauma
|
||||
int healthWindowY = GameMain.GraphicsHeight / 2 - healthWindowHeight / 2;
|
||||
|
||||
HealthWindowAreaLeft = new Rectangle(healthWindowX, healthWindowY, healthWindowWidth, healthWindowHeight);
|
||||
|
||||
int votingAreaWidth = (int)(400 * GUI.Scale);
|
||||
int votingAreaX = GameMain.GraphicsWidth - Padding - votingAreaWidth;
|
||||
int votingAreaY = Padding + ButtonAreaTop.Height;
|
||||
|
||||
// Height is based on text content
|
||||
VotingArea = new Rectangle(votingAreaX, votingAreaY, votingAreaWidth, 0);
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch)
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Barotrauma
|
||||
float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0);
|
||||
float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f;
|
||||
noiseSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight),
|
||||
startOffset: new Point(Rand.Range(0, noiseSprite.SourceRect.Width), Rand.Range(0, noiseSprite.SourceRect.Height)),
|
||||
startOffset: new Vector2(Rand.Range(0.0f, noiseSprite.SourceRect.Width), Rand.Range(0.0f, noiseSprite.SourceRect.Height)),
|
||||
color: Color.White * noiseStrength * 0.1f,
|
||||
textureScale: Vector2.One * noiseScale);
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
if (LoadState == 100.0f)
|
||||
{
|
||||
#if DEBUG
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled && GameMain.FirstLoad)
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled && GameMain.FirstLoad)
|
||||
{
|
||||
loadText = "QUICKSTARTING ...";
|
||||
}
|
||||
|
||||
1089
Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs
Normal file
1089
Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,683 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SubmarineSelection
|
||||
{
|
||||
private const int submarinesPerPage = 4;
|
||||
private int currentPage = 1;
|
||||
private int pageCount;
|
||||
private bool transferService, purchaseService, initialized;
|
||||
private int deliveryFee;
|
||||
private string deliveryLocationName;
|
||||
|
||||
public GUIFrame GuiFrame;
|
||||
private GUIFrame pageIndicatorHolder;
|
||||
private GUICustomComponent selectedSubmarineIndicator;
|
||||
private GUILayoutGroup submarineHorizontalGroup, submarineControlsGroup;
|
||||
private GUIButton browseLeftButton, browseRightButton, confirmButton, confirmButtonAlt;
|
||||
private GUIListBox specsFrame;
|
||||
private GUIImage[] pageIndicators;
|
||||
private GUITextBlock descriptionTextBlock;
|
||||
private int selectionIndicatorThickness;
|
||||
private GUIImage listBackground;
|
||||
|
||||
private List<SubmarineInfo> subsToShow;
|
||||
private SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
||||
private SubmarineInfo selectedSubmarine = null;
|
||||
private string purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyShorthandText, currencyLongText;
|
||||
private RectTransform parent;
|
||||
private Action closeAction;
|
||||
private Sprite pageIndicator;
|
||||
|
||||
public static readonly string[] DeliveryTextVariables = new string[] { "[submarinename1]", "[location1]", "[location2]", "[submarinename2]", "[amount]", "[currencyname]" };
|
||||
public static readonly string[] SwitchTextVariables = new string[] { "[submarinename1]", "[submarinename2]" };
|
||||
public static readonly string[] PurchaseAndSwitchTextVariables = new string[] { "[submarinename1]", "[amount]", "[currencyname]", "[submarinename2]" };
|
||||
public static readonly string[] PurchaseTextVariables = new string[] { "[submarinename]", "[amount]", "[currencyname]" };
|
||||
|
||||
private static readonly string[] notEnoughCreditsDeliveryTextVariables = new string[] { "[currencyname]", "[submarinename]", "[location1]", "[location2]" };
|
||||
private static readonly string[] notEnoughCreditsPurchaseTextVariables = new string[] { "[currencyname]", "[submarinename]" };
|
||||
private string[] messageBoxOptions;
|
||||
|
||||
public const int DeliveryFeePerDistanceTravelled = 1000;
|
||||
public static bool ContentRefreshRequired = false;
|
||||
|
||||
private static readonly Color indicatorColor = new Color(112, 149, 129);
|
||||
private Point createdForResolution;
|
||||
|
||||
private struct SubmarineDisplayContent
|
||||
{
|
||||
public GUIFrame background;
|
||||
public GUIImage submarineImage;
|
||||
public SubmarineInfo displayedSubmarine;
|
||||
public GUITextBlock submarineName;
|
||||
public GUITextBlock submarineClass;
|
||||
public GUITextBlock submarineFee;
|
||||
public GUIButton selectSubmarineButton;
|
||||
public GUITextBlock middleTextBlock;
|
||||
}
|
||||
|
||||
public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent)
|
||||
{
|
||||
if (GameMain.GameSession.Campaign == null) return;
|
||||
|
||||
transferService = transfer;
|
||||
purchaseService = !transfer;
|
||||
this.parent = parent;
|
||||
this.closeAction = closeAction;
|
||||
|
||||
subsToShow = new List<SubmarineInfo>();
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
messageBoxOptions = new string[2] { TextManager.Get("Yes"), TextManager.Get("Cancel") };
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBoxOptions = new string[2] { TextManager.Get("Yes") + " " + TextManager.Get("initiatevoting"), TextManager.Get("Cancel") };
|
||||
}
|
||||
|
||||
if (Submarine.MainSub?.Info == null) return;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
initialized = true;
|
||||
if (transferService)
|
||||
{
|
||||
deliveryFee = CalculateDeliveryFee();
|
||||
currentSubText = TextManager.Get("currentsub");
|
||||
deliveryFeeText = TextManager.Get("deliveryfee");
|
||||
deliveryText = TextManager.Get("requestdeliverybutton");
|
||||
switchText = TextManager.Get("switchtosubmarinebutton");
|
||||
}
|
||||
else
|
||||
{
|
||||
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
|
||||
purchaseOnlyText = TextManager.Get("purchase");
|
||||
priceText = TextManager.Get("price");
|
||||
}
|
||||
|
||||
currencyShorthandText = TextManager.Get("currencyformat");
|
||||
currencyLongText = TextManager.Get("credit").ToLower();
|
||||
|
||||
UpdateSubmarines();
|
||||
missingPreviewText = TextManager.Get("SubPreviewImageNotFound");
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
private int CalculateDeliveryFee()
|
||||
{
|
||||
int distanceToOutpost = GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
deliveryLocationName = endLocation.Name;
|
||||
return DeliveryFeePerDistanceTravelled * distanceToOutpost;
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
{
|
||||
createdForResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
|
||||
GUILayoutGroup content;
|
||||
GuiFrame = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.7f), parent, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.02f) });
|
||||
selectionIndicatorThickness = HUDLayoutSettings.Padding / 2;
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center), color: Color.Black * 0.9f)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
content = new GUILayoutGroup(new RectTransform(new Point(background.Rect.Width - HUDLayoutSettings.Padding * 4, background.Rect.Height - HUDLayoutSettings.Padding * 4), background.RectTransform, Anchor.Center)) { AbsoluteSpacing = (int)(HUDLayoutSettings.Padding * 1.5f) };
|
||||
GUITextBlock header = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), content.RectTransform), transferService ? TextManager.Get("switchsubmarineheader") : TextManager.GetWithVariable("outpostshipyard", "[location]", GameMain.GameSession.Map.CurrentLocation.Name), font: GUI.LargeFont);
|
||||
header.CalculateHeightFromText(0, true);
|
||||
GUITextBlock credits = new GUITextBlock(new RectTransform(Vector2.One, header.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = CampaignUI.GetMoney
|
||||
};
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), content.RectTransform), style: "HorizontalLine");
|
||||
|
||||
GUILayoutGroup submarineContentGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.4f), content.RectTransform)) { AbsoluteSpacing = HUDLayoutSettings.Padding, Stretch = true };
|
||||
submarineHorizontalGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), submarineContentGroup.RectTransform)) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding, Stretch = true };
|
||||
|
||||
submarineControlsGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), submarineContentGroup.RectTransform), true, Anchor.TopCenter);
|
||||
|
||||
GUILayoutGroup infoFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.4f), content.RectTransform)) { IsHorizontal = true, Stretch = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform), style: null, new Color(8, 13, 19)) { IgnoreLayoutGroups = true };
|
||||
listBackground = new GUIImage(new RectTransform(new Vector2(0.59f, 1f), infoFrame.RectTransform, Anchor.CenterRight), style: null, true)
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
new GUIListBox(new RectTransform(Vector2.One, infoFrame.RectTransform)) { IgnoreLayoutGroups = true, CanBeFocused = false };
|
||||
specsFrame = new GUIListBox(new RectTransform(new Vector2(0.39f, 1f), infoFrame.RectTransform), style: null) { Spacing = GUI.IntScale(5), Padding = new Vector4(HUDLayoutSettings.Padding / 2f, HUDLayoutSettings.Padding, 0, 0) };
|
||||
new GUIFrame(new RectTransform(new Vector2(0.02f, 0.8f), infoFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.1f) }, style: "VerticalLine");
|
||||
GUIListBox descriptionFrame = new GUIListBox(new RectTransform(new Vector2(0.59f, 1f), infoFrame.RectTransform), style: null) { Padding = new Vector4(HUDLayoutSettings.Padding / 2f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding / 2f) };
|
||||
descriptionTextBlock = new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionFrame.Content.RectTransform), string.Empty, font: GUI.Font, wrap: true) { CanBeFocused = false };
|
||||
|
||||
GUILayoutGroup buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.075f), content.RectTransform), childAnchor: Anchor.CenterRight) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
|
||||
if (closeAction != null)
|
||||
{
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), TextManager.Get("Close"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
closeAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (purchaseService) confirmButtonAlt = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseOnlyText, style: "GUIButtonFreeScale");
|
||||
confirmButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseService ? purchaseAndSwitchText : deliveryFee > 0 ? deliveryText : switchText, style: "GUIButtonFreeScale");
|
||||
SetConfirmButtonState(false);
|
||||
|
||||
pageIndicatorHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.5f), submarineControlsGroup.RectTransform), style: null);
|
||||
pageIndicator = GUI.Style.GetComponentStyle("GUIPageIndicator").GetDefaultSprite();
|
||||
UpdatePaging();
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
SubmarineDisplayContent submarineDisplayElement = new SubmarineDisplayContent();
|
||||
submarineDisplayElement.background = new GUIFrame(new RectTransform(new Vector2(1f / submarinesPerPage, 1f), submarineHorizontalGroup.RectTransform), style: null, new Color(8, 13, 19));
|
||||
submarineDisplayElement.submarineImage = new GUIImage(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), null, true);
|
||||
submarineDisplayElement.middleTextBlock = new GUITextBlock(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), string.Empty, textAlignment: Alignment.Center);
|
||||
submarineDisplayElement.submarineName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
submarineDisplayElement.submarineClass = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding + (int)GUI.Font.MeasureString(submarineDisplayElement.submarineName.Text).Y) }, string.Empty, textAlignment: Alignment.Center);
|
||||
submarineDisplayElement.submarineFee = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
submarineDisplayElement.selectSubmarineButton = new GUIButton(new RectTransform(Vector2.One, submarineDisplayElement.background.RectTransform), style: null);
|
||||
submarineDisplays[i] = submarineDisplayElement;
|
||||
}
|
||||
|
||||
selectedSubmarineIndicator = new GUICustomComponent(new RectTransform(Point.Zero, submarineHorizontalGroup.RectTransform), onDraw: (sb, component) => DrawSubmarineIndicator(sb, component.Rect)) { IgnoreLayoutGroups = true, CanBeFocused = false };
|
||||
}
|
||||
|
||||
private void UpdatePaging()
|
||||
{
|
||||
if (pageIndicatorHolder == null) return;
|
||||
pageIndicatorHolder.ClearChildren();
|
||||
if (currentPage > pageCount) currentPage = pageCount;
|
||||
if (pageCount < 2) return;
|
||||
|
||||
browseLeftButton = new GUIButton(new RectTransform(new Vector2(1.15f, 1.15f), pageIndicatorHolder.RectTransform, Anchor.CenterLeft, Pivot.CenterRight) { AbsoluteOffset = new Point(-HUDLayoutSettings.Padding * 3, 0) }, string.Empty, style: "GUIButtonToggleLeft")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
ChangePage(-1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Point indicatorSize = new Point(GUI.IntScale(pageIndicator.SourceRect.Width * 1.5f), GUI.IntScale(pageIndicator.SourceRect.Height * 1.5f));
|
||||
pageIndicatorHolder.RectTransform.NonScaledSize = new Point(pageCount * indicatorSize.X + HUDLayoutSettings.Padding * (pageCount - 1), pageIndicatorHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
int xPos = 0;
|
||||
int yPos = pageIndicatorHolder.Rect.Height / 2 - indicatorSize.Y / 2;
|
||||
|
||||
pageIndicators = new GUIImage[pageCount];
|
||||
for (int i = 0; i < pageCount; i++)
|
||||
{
|
||||
pageIndicators[i] = new GUIImage(new RectTransform(indicatorSize, pageIndicatorHolder.RectTransform) { AbsoluteOffset = new Point(xPos, yPos) }, pageIndicator, null, true);
|
||||
xPos += indicatorSize.X + HUDLayoutSettings.Padding;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pageIndicators.Length; i++)
|
||||
{
|
||||
pageIndicators[i].Color = i == currentPage - 1 ? Color.White : Color.Gray;
|
||||
}
|
||||
|
||||
browseRightButton = new GUIButton(new RectTransform(new Vector2(1.15f, 1.15f), pageIndicatorHolder.RectTransform, Anchor.CenterRight, Pivot.CenterLeft) { AbsoluteOffset = new Point(-HUDLayoutSettings.Padding * 3, 0) }, string.Empty, style: "GUIButtonToggleRight")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
ChangePage(1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
browseLeftButton.Enabled = currentPage > 1;
|
||||
browseRightButton.Enabled = currentPage < pageCount;
|
||||
}
|
||||
|
||||
private void DrawSubmarineIndicator(SpriteBatch spriteBatch, Rectangle area)
|
||||
{
|
||||
if (area == Rectangle.Empty) return;
|
||||
GUI.DrawRectangle(spriteBatch, area, indicatorColor, thickness: selectionIndicatorThickness);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (ContentRefreshRequired)
|
||||
{
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
|
||||
// Input
|
||||
if (PlayerInput.KeyHit(Keys.Left))
|
||||
{
|
||||
SelectSubmarine(subsToShow.IndexOf(selectedSubmarine), -1);
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.Right))
|
||||
{
|
||||
SelectSubmarine(subsToShow.IndexOf(selectedSubmarine), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSubmarineDisplay(bool updateSubs)
|
||||
{
|
||||
if (!initialized) Initialize();
|
||||
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateGUI();
|
||||
if (updateSubs) UpdateSubmarines();
|
||||
|
||||
if (pageIndicators != null)
|
||||
{
|
||||
for (int i = 0; i < pageIndicators.Length; i++)
|
||||
{
|
||||
pageIndicators[i].Color = i == currentPage - 1 ? Color.White : Color.Gray;
|
||||
}
|
||||
}
|
||||
|
||||
int submarineIndex = (currentPage - 1) * submarinesPerPage;
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
SubmarineInfo subToDisplay = GetSubToDisplay(submarineIndex);
|
||||
if (subToDisplay == null)
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = null;
|
||||
submarineDisplays[i].submarineName.Text = string.Empty;
|
||||
submarineDisplays[i].submarineFee.Text = string.Empty;
|
||||
submarineDisplays[i].submarineClass.Text = string.Empty;
|
||||
submarineDisplays[i].selectSubmarineButton.Enabled = false;
|
||||
submarineDisplays[i].selectSubmarineButton.OnClicked = null;
|
||||
submarineDisplays[i].displayedSubmarine = null;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].displayedSubmarine = subToDisplay;
|
||||
Sprite previewImage = GetPreviewImage(subToDisplay);
|
||||
|
||||
if (previewImage != null)
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = previewImage;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = null;
|
||||
submarineDisplays[i].middleTextBlock.Text = missingPreviewText;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = true;
|
||||
}
|
||||
|
||||
submarineDisplays[i].selectSubmarineButton.Enabled = true;
|
||||
|
||||
int index = i;
|
||||
submarineDisplays[i].selectSubmarineButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[index].background.Rect);
|
||||
return true;
|
||||
};
|
||||
|
||||
submarineDisplays[i].submarineName.Text = subToDisplay.DisplayName;
|
||||
submarineDisplays[i].submarineClass.Text = $"{TextManager.GetWithVariable("submarineclass.classsuffixformat", "[type]", TextManager.Get($"submarineclass.{subToDisplay.SubmarineClass}"))}";
|
||||
|
||||
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
|
||||
{
|
||||
string amountString = currencyShorthandText.Replace("[credits]", subToDisplay.Price.ToString());
|
||||
submarineDisplays[i].submarineFee.Text = priceText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subToDisplay.Name != CurrentOrPendingSubmarine().Name)
|
||||
{
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
string amountString = currencyShorthandText.Replace("[credits]", deliveryFee.ToString());
|
||||
submarineDisplays[i].submarineFee.Text = deliveryFeeText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineFee.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineFee.Text = currentSubText;
|
||||
}
|
||||
}
|
||||
|
||||
if (transferService && subToDisplay.Name == CurrentOrPendingSubmarine().Name && updateSubs)
|
||||
{
|
||||
if (selectedSubmarine == null)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(SelectOwnSubmarineWithDelay(subToDisplay, submarineDisplays[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[i].background.Rect);
|
||||
}
|
||||
}
|
||||
else if (!transferService && selectedSubmarine == null || !transferService && GameMain.GameSession.IsSubmarineOwned(selectedSubmarine) || subToDisplay == selectedSubmarine)
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[i].background.Rect);
|
||||
}
|
||||
}
|
||||
|
||||
submarineIndex++;
|
||||
}
|
||||
|
||||
if (subsToShow.Count == 0)
|
||||
{
|
||||
SelectSubmarine(null, Rectangle.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSubmarines()
|
||||
{
|
||||
subsToShow.Clear();
|
||||
if (transferService)
|
||||
{
|
||||
subsToShow.AddRange(GameMain.GameSession.OwnedSubmarines);
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
string currentSubName = CurrentOrPendingSubmarine().Name;
|
||||
int currentIndex = subsToShow.FindIndex(s => s.Name == currentSubName);
|
||||
if (currentIndex != -1)
|
||||
{
|
||||
currentPage = (int)Math.Ceiling((currentIndex + 1) / (float)submarinesPerPage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
subsToShow.AddRange(SubmarineInfo.SavedSubmarines.Where(s => s.IsCampaignCompatible && !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
subsToShow.AddRange(GameMain.NetLobbyScreen.CampaignSubmarines.Where(s => !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
}
|
||||
|
||||
if (transferService) SetConfirmButtonState(selectedSubmarine != null && selectedSubmarine.Name != CurrentOrPendingSubmarine().Name);
|
||||
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
pageCount = Math.Max(1, (int)Math.Ceiling(subsToShow.Count / (float)submarinesPerPage));
|
||||
UpdatePaging();
|
||||
ContentRefreshRequired = false;
|
||||
}
|
||||
|
||||
private SubmarineInfo GetSubToDisplay(int index)
|
||||
{
|
||||
if (subsToShow.Count <= index || index < 0) return null;
|
||||
return subsToShow[index];
|
||||
}
|
||||
|
||||
private Sprite GetPreviewImage(SubmarineInfo info)
|
||||
{
|
||||
Sprite preview = info.PreviewImage;
|
||||
|
||||
if (preview == null)
|
||||
{
|
||||
SubmarineInfo potentialMatch;
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
potentialMatch = GameMain.NetLobbyScreen.CampaignSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
|
||||
preview = potentialMatch?.PreviewImage;
|
||||
|
||||
// Try from savedsubmarines with name comparison as a backup
|
||||
if (preview == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == info.Name);
|
||||
preview = potentialMatch?.PreviewImage;
|
||||
}
|
||||
}
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
// Initial submarine selection needs a slight wait to allow the layoutgroups to place content properly
|
||||
private IEnumerable<object> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
|
||||
{
|
||||
yield return new WaitForSeconds(0.05f);
|
||||
SelectSubmarine(info, display.background.Rect);
|
||||
}
|
||||
|
||||
// Selection based on key input
|
||||
private void SelectSubmarine(int index, int direction)
|
||||
{
|
||||
SubmarineInfo nextSub = GetSubToDisplay(index + direction);
|
||||
if (nextSub == null) return;
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
if (submarineDisplays[i].displayedSubmarine == nextSub)
|
||||
{
|
||||
SelectSubmarine(nextSub, submarineDisplays[i].background.Rect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChangePage(direction);
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
if (submarineDisplays[i].displayedSubmarine == nextSub)
|
||||
{
|
||||
SelectSubmarine(nextSub, submarineDisplays[i].background.Rect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectSubmarine(SubmarineInfo info, Rectangle backgroundRect)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (selectedSubmarine == info) return;
|
||||
#endif
|
||||
specsFrame.Content.ClearChildren();
|
||||
selectedSubmarine = info;
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
bool owned = GameMain.GameSession.IsSubmarineOwned(info);
|
||||
|
||||
if (owned)
|
||||
{
|
||||
confirmButton.Text = deliveryFee > 0 ? deliveryText : switchText;
|
||||
confirmButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowTransferPrompt();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
confirmButton.Text = purchaseAndSwitchText;
|
||||
confirmButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowBuyPrompt(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
confirmButtonAlt.Text = purchaseOnlyText;
|
||||
confirmButtonAlt.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowBuyPrompt(true);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
SetConfirmButtonState(selectedSubmarine.Name != CurrentOrPendingSubmarine().Name);
|
||||
|
||||
selectedSubmarineIndicator.RectTransform.NonScaledSize = backgroundRect.Size;
|
||||
selectedSubmarineIndicator.RectTransform.AbsoluteOffset = new Point(backgroundRect.Left - submarineHorizontalGroup.Rect.Left, 0);
|
||||
|
||||
Sprite previewImage = GetPreviewImage(info);
|
||||
listBackground.Sprite = previewImage;
|
||||
listBackground.SetCrop(true);
|
||||
|
||||
ScalableFont font = GUI.Font;
|
||||
info.CreateSpecsWindow(specsFrame, font);
|
||||
descriptionTextBlock.Text = info.Description;
|
||||
descriptionTextBlock.CalculateHeightFromText();
|
||||
}
|
||||
else
|
||||
{
|
||||
listBackground.Sprite = null;
|
||||
listBackground.SetCrop(false);
|
||||
descriptionTextBlock.Text = string.Empty;
|
||||
selectedSubmarineIndicator.RectTransform.NonScaledSize = Point.Zero;
|
||||
SetConfirmButtonState(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConfirmButtonState(bool state)
|
||||
{
|
||||
if (confirmButtonAlt != null)
|
||||
{
|
||||
confirmButtonAlt.Enabled = state;
|
||||
}
|
||||
|
||||
if (confirmButton != null)
|
||||
{
|
||||
confirmButton.Enabled = state;
|
||||
}
|
||||
}
|
||||
|
||||
public static SubmarineInfo CurrentOrPendingSubmarine()
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign?.PendingSubmarineSwitch == null)
|
||||
{
|
||||
return Submarine.MainSub.Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GameMain.GameSession.Campaign.PendingSubmarineSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangePage(int pageChangeDirection)
|
||||
{
|
||||
SelectSubmarine(null, Rectangle.Empty);
|
||||
if (pageChangeDirection < 0 && currentPage > 1) currentPage--;
|
||||
if (pageChangeDirection > 0 && currentPage < pageCount) currentPage++;
|
||||
browseLeftButton.Enabled = currentPage > 1;
|
||||
browseRightButton.Enabled = currentPage < pageCount;
|
||||
|
||||
RefreshSubmarineDisplay(false);
|
||||
}
|
||||
|
||||
private void ShowTransferPrompt()
|
||||
{
|
||||
if (GameMain.GameSession.Campaign.Money < deliveryFee && deliveryFee > 0)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("notenoughmoneyfordeliverytext", notEnoughCreditsDeliveryTextVariables,
|
||||
new string[] { currencyLongText, selectedSubmarine.DisplayName, deliveryLocationName, GameMain.GameSession.Map.CurrentLocation.Name }));
|
||||
return;
|
||||
}
|
||||
|
||||
GUIMessageBox msgBox;
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("deliveryrequesttext", DeliveryTextVariables,
|
||||
new string[6] { selectedSubmarine.DisplayName, deliveryLocationName, GameMain.GameSession.Map.CurrentLocation.Name, CurrentOrPendingSubmarine().DisplayName, deliveryFee.ToString(), currencyLongText }), messageBoxOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("switchsubmarineheader"), TextManager.GetWithVariables("switchsubmarinetext", SwitchTextVariables,
|
||||
new string[2] { CurrentOrPendingSubmarine().DisplayName, selectedSubmarine.DisplayName }), messageBoxOptions);
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.SwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
|
||||
private void ShowBuyPrompt(bool purchaseOnly)
|
||||
{
|
||||
if (GameMain.GameSession.Campaign.Money < selectedSubmarine.Price)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext", notEnoughCreditsPurchaseTextVariables,
|
||||
new string[2] { currencyLongText, selectedSubmarine.DisplayName }));
|
||||
return;
|
||||
}
|
||||
|
||||
GUIMessageBox msgBox;
|
||||
|
||||
if (!purchaseOnly)
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), TextManager.GetWithVariables("purchaseandswitchsubmarinetext", PurchaseAndSwitchTextVariables,
|
||||
new string[4] { selectedSubmarine.DisplayName, selectedSubmarine.Price.ToString(), currencyLongText, CurrentOrPendingSubmarine().DisplayName }), messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseAndSwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("purchasesubmarinetext", PurchaseTextVariables,
|
||||
new string[3] { selectedSubmarine.DisplayName, selectedSubmarine.Price.ToString(), currencyLongText }), messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -13,7 +14,7 @@ namespace Barotrauma
|
||||
|
||||
private static bool initialized = false;
|
||||
|
||||
private static UISprite spectateIcon, deadIcon, disconnectedIcon;
|
||||
private static UISprite spectateIcon, disconnectedIcon;
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
private enum InfoFrameTab { Crew, Mission, MyCharacter, Traitor };
|
||||
@@ -31,7 +32,7 @@ namespace Barotrauma
|
||||
private List<Character.TeamType> teamIDs;
|
||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||
|
||||
private static Color ownCharacterBGColor = Color.Gold * 0.7f;
|
||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||
|
||||
private class LinkedGUI
|
||||
{
|
||||
@@ -115,10 +116,9 @@ namespace Barotrauma
|
||||
public void Initialize()
|
||||
{
|
||||
spectateIcon = GUI.Style.GetComponentStyle("SpectateIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
deadIcon = GUI.Style.GetComponentStyle("DeadIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
disconnectedIcon = GUI.Style.GetComponentStyle("DisconnectedIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
ownerIcon = GUI.Style.GetComponentStyle("OwnerIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
moderatorIcon = GUI.Style.GetComponentStyle("ModeratorIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
ownerIcon = GUI.Style.GetComponentStyle("OwnerIcon").GetDefaultSprite();
|
||||
moderatorIcon = GUI.Style.GetComponentStyle("ModeratorIcon").GetDefaultSprite();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace Barotrauma
|
||||
teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
|
||||
|
||||
// Show own team first when there's more than one team
|
||||
if (teamIDs.Count > 1 && GameMain.Client.Character != null)
|
||||
if (teamIDs.Count > 1 && GameMain.Client?.Character != null)
|
||||
{
|
||||
Character.TeamType ownTeam = GameMain.Client.Character.TeamID;
|
||||
teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
|
||||
@@ -408,7 +408,7 @@ namespace Barotrauma
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = character,
|
||||
Color = (Character.Controlled == character) ? ownCharacterBGColor : Color.Transparent
|
||||
Color = (Character.Controlled == character) ? OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
@@ -486,7 +486,7 @@ namespace Barotrauma
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = character,
|
||||
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? ownCharacterBGColor : Color.Transparent
|
||||
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
frame.OnSecondaryClicked += (component, data) =>
|
||||
@@ -631,7 +631,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.NetworkMember == null || client == null || !client.HasPermissions) return null;
|
||||
|
||||
if (!client.AllowKicking) // Owner cannot be kicked
|
||||
if (client.IsOwner) // Owner cannot be kicked
|
||||
{
|
||||
return ownerIcon;
|
||||
}
|
||||
@@ -649,7 +649,10 @@ namespace Barotrauma
|
||||
}
|
||||
else if (client.Character != null && client.Character.IsDead)
|
||||
{
|
||||
client.Character.Info.DrawJobIcon(spriteBatch, area);
|
||||
if (client.Character.Info != null)
|
||||
{
|
||||
client.Character.Info.DrawJobIcon(spriteBatch, area);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -780,7 +783,7 @@ namespace Barotrauma
|
||||
|
||||
public static void StorePlayerConnectionChangeMessage(ChatMessage message)
|
||||
{
|
||||
if (!GameMain.GameSession?.GameMode?.IsRunning ?? true) { return; }
|
||||
if (!GameMain.GameSession?.IsRunning ?? true) { return; }
|
||||
|
||||
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
|
||||
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
|
||||
@@ -847,15 +850,15 @@ namespace Barotrauma
|
||||
infoFrame.ClearChildren();
|
||||
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = (int)(0.0245f * missionFrame.Rect.Height);
|
||||
Location endLocation = GameMain.GameSession.EndLocation;
|
||||
Sprite portrait = endLocation.Type.GetPortrait(endLocation.PortraitId);
|
||||
Location location = GameMain.GameSession.EndLocation != null ? GameMain.GameSession.EndLocation : GameMain.GameSession.StartLocation;
|
||||
Sprite portrait = location.Type.GetPortrait(location.PortraitId);
|
||||
bool hasPortrait = portrait != null && portrait.SourceRect.Width > 0 && portrait.SourceRect.Height > 0;
|
||||
int contentWidth = hasPortrait ? (int)(missionFrame.Rect.Width * 0.951f) : missionFrame.Rect.Width - padding * 2;
|
||||
|
||||
Vector2 locationNameSize = GUI.LargeFont.MeasureString(endLocation.Name);
|
||||
Vector2 locationTypeSize = GUI.SubHeadingFont.MeasureString(endLocation.Name);
|
||||
GUITextBlock locationNameText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationNameSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, endLocation.Name, font: GUI.LargeFont);
|
||||
GUITextBlock locationTypeText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationTypeSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationNameText.Rect.Height + padding) }, endLocation.Type.Name, font: GUI.SubHeadingFont);
|
||||
Vector2 locationNameSize = GUI.LargeFont.MeasureString(location.Name);
|
||||
Vector2 locationTypeSize = GUI.SubHeadingFont.MeasureString(location.Name);
|
||||
GUITextBlock locationNameText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationNameSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, location.Name, font: GUI.LargeFont);
|
||||
GUITextBlock locationTypeText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationTypeSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationNameText.Rect.Height + padding) }, location.Type.Name, font: GUI.SubHeadingFont);
|
||||
|
||||
int locationInfoYOffset = locationNameText.Rect.Height + locationTypeText.Rect.Height + padding * 2;
|
||||
|
||||
@@ -881,7 +884,8 @@ namespace Barotrauma
|
||||
|
||||
string missionNameString = ToolBox.WrapText(mission.Name, missionTextGroup.Rect.Width, GUI.LargeFont);
|
||||
string missionDescriptionString = ToolBox.WrapText(mission.Description, missionTextGroup.Rect.Width, GUI.Font);
|
||||
string missionRewardString = ToolBox.WrapText(TextManager.GetWithVariable("MissionReward", "[reward]", mission.Reward.ToString()), missionTextGroup.Rect.Width, GUI.Font);
|
||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", mission.Reward));
|
||||
string missionRewardString = ToolBox.WrapText(TextManager.GetWithVariable("MissionReward", "[reward]", rewardText), missionTextGroup.Rect.Width, GUI.Font);
|
||||
|
||||
Vector2 missionNameSize = GUI.LargeFont.MeasureString(missionNameString);
|
||||
Vector2 missionDescriptionSize = GUI.Font.MeasureString(missionDescriptionString);
|
||||
@@ -890,13 +894,15 @@ namespace Barotrauma
|
||||
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)(missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y));
|
||||
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
float iconAspectRatio = mission.Prefab.Icon.SourceRect.Width / mission.Prefab.Icon.SourceRect.Height;
|
||||
int iconWidth = (int)(0.225f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);
|
||||
|
||||
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true) { Color = mission.Prefab.IconColor };
|
||||
if (mission.Prefab.Icon != null)
|
||||
{
|
||||
float iconAspectRatio = mission.Prefab.Icon.SourceRect.Width / mission.Prefab.Icon.SourceRect.Height;
|
||||
int iconWidth = (int)(0.225f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);
|
||||
|
||||
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true) { Color = mission.Prefab.IconColor };
|
||||
}
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionNameString, font: GUI.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionRewardString);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionDescriptionString);
|
||||
|
||||
@@ -36,6 +36,12 @@ namespace Barotrauma
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool MaintainBorderAspectRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How much the borders of a sliced sprite are allowed to scale
|
||||
@@ -52,6 +58,7 @@ namespace Barotrauma
|
||||
{
|
||||
Sprite = new Sprite(element);
|
||||
MaintainAspectRatio = element.GetAttributeBool("maintainaspectratio", false);
|
||||
MaintainBorderAspectRatio = element.GetAttributeBool("maintainborderaspectratio", false);
|
||||
Tile = element.GetAttributeBool("tile", true);
|
||||
CrossFadeIn = element.GetAttributeBool("crossfadein", CrossFadeIn);
|
||||
CrossFadeOut = element.GetAttributeBool("crossfadeout", CrossFadeOut);
|
||||
@@ -120,13 +127,16 @@ namespace Barotrauma
|
||||
{
|
||||
Vector2 pos = new Vector2(rect.X, rect.Y);
|
||||
|
||||
float scale = GetSliceBorderScale(rect.Size);
|
||||
float scale = MaintainBorderAspectRatio ? 1.0f : GetSliceBorderScale(rect.Size);
|
||||
float aspectScale = MaintainBorderAspectRatio ? Math.Min((float)rect.Width / Sprite.SourceRect.Width, (float)rect.Height / Sprite.SourceRect.Height) : 1.0f;
|
||||
|
||||
int centerHeight = rect.Height - (int)((Slices[0].Height + Slices[6].Height) * scale);
|
||||
int centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale);
|
||||
int centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale * aspectScale);
|
||||
|
||||
for (int x = 0; x < 3; x++)
|
||||
{
|
||||
int width = (int)(x == 1 ? centerWidth : Slices[x].Width * scale);
|
||||
|
||||
int width = (int)(x == 1 ? centerWidth : Slices[x].Width * scale * aspectScale);
|
||||
if (width <= 0) { continue; }
|
||||
for (int y = 0; y < 3; y++)
|
||||
{
|
||||
@@ -147,7 +157,7 @@ namespace Barotrauma
|
||||
else if (Tile)
|
||||
{
|
||||
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), null, color);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
1142
Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs
Normal file
1142
Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs
Normal file
File diff suppressed because it is too large
Load Diff
235
Barotrauma/BarotraumaClient/ClientSource/GUI/VotingInterface.cs
Normal file
235
Barotrauma/BarotraumaClient/ClientSource/GUI/VotingInterface.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class VotingInterface
|
||||
{
|
||||
public bool VoteRunning = false;
|
||||
|
||||
private GUIFrame frame;
|
||||
private GUITextBlock votingTextBlock, votedTextBlock, voteCounter;
|
||||
private GUIProgressBar votingTimer;
|
||||
private GUIButton yesVoteButton, noVoteButton;
|
||||
private Action onVoteEnd;
|
||||
|
||||
private int yesVotes, noVotes, maxVotes;
|
||||
private Func<int> getYesVotes, getNoVotes, getMaxVotes;
|
||||
private bool votePassed;
|
||||
|
||||
private string votingOnText;
|
||||
private List<RichTextData> votingOnTextData;
|
||||
private float votingTime = 100f;
|
||||
private float timer;
|
||||
private VoteType currentVoteType;
|
||||
private Color submarineColor => GUI.Style.Orange;
|
||||
private Point createdForResolution;
|
||||
|
||||
public VotingInterface(Client starter, SubmarineInfo info, VoteType type, float votingTime)
|
||||
{
|
||||
if (starter == null || info == null) return;
|
||||
SetSubmarineVotingText(starter, info, type);
|
||||
this.votingTime = votingTime;
|
||||
getYesVotes = SubmarineYesVotes;
|
||||
getNoVotes = SubmarineNoVotes;
|
||||
getMaxVotes = SubmarineMaxVotes;
|
||||
onVoteEnd = () => SendSubmarineVoteEndMessage(info, type);
|
||||
|
||||
Initialize(starter, type);
|
||||
}
|
||||
|
||||
private void Initialize(Client starter, VoteType type)
|
||||
{
|
||||
currentVoteType = type;
|
||||
CreateVotingGUI();
|
||||
if (starter.ID == GameMain.Client.ID) SetGUIToVotedState(2);
|
||||
VoteRunning = true;
|
||||
}
|
||||
|
||||
private void CreateVotingGUI()
|
||||
{
|
||||
createdForResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
|
||||
if (frame != null) frame.Parent.RemoveChild(frame);
|
||||
frame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.VotingArea, GameMain.Client.InGameHUD.RectTransform), style: "");
|
||||
|
||||
int padding = HUDLayoutSettings.Padding * 2;
|
||||
int spacing = HUDLayoutSettings.Padding;
|
||||
int yOffset = padding;
|
||||
int paddedWidth = frame.Rect.Width - padding * 2;
|
||||
|
||||
votingTextBlock = new GUITextBlock(new RectTransform(new Point(paddedWidth, 0), frame.RectTransform), votingOnTextData, votingOnText, wrap: true);
|
||||
votingTextBlock.RectTransform.NonScaledSize = votingTextBlock.RectTransform.MinSize = votingTextBlock.RectTransform.MaxSize = new Point(votingTextBlock.Rect.Width, votingTextBlock.Rect.Height);
|
||||
votingTextBlock.RectTransform.IsFixedSize = true;
|
||||
votingTextBlock.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
|
||||
yOffset += votingTextBlock.Rect.Height + spacing;
|
||||
|
||||
voteCounter = new GUITextBlock(new RectTransform(new Point(paddedWidth, 0), frame.RectTransform), "(0/0)", GUI.Style.Green, textAlignment: Alignment.Center);
|
||||
voteCounter.RectTransform.NonScaledSize = voteCounter.RectTransform.MinSize = voteCounter.RectTransform.MaxSize = new Point(voteCounter.Rect.Width, voteCounter.Rect.Height);
|
||||
voteCounter.RectTransform.IsFixedSize = true;
|
||||
voteCounter.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
|
||||
yOffset += voteCounter.Rect.Height + spacing;
|
||||
|
||||
votingTimer = new GUIProgressBar(new RectTransform(new Point(paddedWidth, Math.Max(spacing, 8)), frame.RectTransform) { AbsoluteOffset = new Point(padding, yOffset) }, HUDLayoutSettings.Padding);
|
||||
votingTimer.RectTransform.IsFixedSize = true;
|
||||
yOffset += votingTimer.Rect.Height + spacing;
|
||||
|
||||
int buttonWidth = (int)(paddedWidth * 0.3f);
|
||||
yesVoteButton = new GUIButton(new RectTransform(new Point(buttonWidth, 0), frame.RectTransform) { AbsoluteOffset = new Point((int)(frame.Rect.Width / 2f - buttonWidth - spacing), yOffset) }, TextManager.Get("yes"))
|
||||
{
|
||||
OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
SetGUIToVotedState(2);
|
||||
GameMain.Client.Vote(currentVoteType, 2);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
noVoteButton = new GUIButton(new RectTransform(new Point(buttonWidth, 0), frame.RectTransform) { AbsoluteOffset = new Point(yesVoteButton.RectTransform.AbsoluteOffset.X + yesVoteButton.Rect.Width + padding, yOffset) }, TextManager.Get("no"))
|
||||
{
|
||||
OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
SetGUIToVotedState(1);
|
||||
GameMain.Client.Vote(currentVoteType, 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
votedTextBlock = new GUITextBlock(new RectTransform(new Point(paddedWidth, yesVoteButton.Rect.Height), frame.RectTransform), string.Empty, textAlignment: Alignment.Center);
|
||||
votedTextBlock.RectTransform.IsFixedSize = true;
|
||||
votedTextBlock.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
votedTextBlock.Visible = false;
|
||||
|
||||
yOffset += yesVoteButton.Rect.Height;
|
||||
|
||||
frame.RectTransform.NonScaledSize = new Point(frame.Rect.Width, yOffset + padding);
|
||||
}
|
||||
|
||||
private void SetGUIToVotedState(int vote)
|
||||
{
|
||||
yesVoteButton.Visible = noVoteButton.Visible = false;
|
||||
votedTextBlock.Text = TextManager.Get(vote == 2 ? "yesvoted" : "novoted");
|
||||
votedTextBlock.Visible = true;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (!VoteRunning) return;
|
||||
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateVotingGUI();
|
||||
yesVotes = getYesVotes();
|
||||
noVotes = getNoVotes();
|
||||
maxVotes = getMaxVotes();
|
||||
voteCounter.Text = $"({yesVotes + noVotes}/{maxVotes})";
|
||||
timer += deltaTime;
|
||||
votingTimer.BarSize = timer / votingTime;
|
||||
}
|
||||
|
||||
|
||||
public void EndVote(bool passed, int yesVoteFinal, int noVoteFinal)
|
||||
{
|
||||
VoteRunning = false;
|
||||
votePassed = passed;
|
||||
yesVotes = yesVoteFinal;
|
||||
noVotes = noVoteFinal;
|
||||
onVoteEnd?.Invoke();
|
||||
}
|
||||
|
||||
#region Submarine Voting
|
||||
private void SetSubmarineVotingText(Client starter, SubmarineInfo info, VoteType type)
|
||||
{
|
||||
string name = starter.Name;
|
||||
JobPrefab prefab = starter?.Character?.Info?.Job?.Prefab;
|
||||
Color nameColor = prefab != null ? prefab.UIColor : Color.White;
|
||||
string characterRichString = $"‖color:{nameColor.R},{nameColor.G},{nameColor.B}‖{name}‖color:end‖";
|
||||
string submarineRichString = $"‖color:{submarineColor.R},{submarineColor.G},{submarineColor.B}‖{info.DisplayName}‖color:end‖";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
votingOnText = TextManager.GetWithVariables("submarinepurchaseandswitchvote", new string[] { "[playername]", "[submarinename]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, info.Price.ToString(), TextManager.Get("credit").ToLower() });
|
||||
break;
|
||||
case VoteType.PurchaseSub:
|
||||
votingOnText = TextManager.GetWithVariables("submarinepurchasevote", new string[] { "[playername]", "[submarinename]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, info.Price.ToString(), TextManager.Get("credit").ToLower() });
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
int deliveryFee = SubmarineSelection.DeliveryFeePerDistanceTravelled * GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
votingOnText = TextManager.GetWithVariables("submarineswitchfeevote", new string[] { "[playername]", "[submarinename]", "[locationname]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, endLocation.Name, deliveryFee.ToString(), TextManager.Get("credit").ToLower() });
|
||||
}
|
||||
else
|
||||
{
|
||||
votingOnText = TextManager.GetWithVariables("submarineswitchnofeevote", new string[] { "[playername]", "[submarinename]" }, new string[] { characterRichString, submarineRichString });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
votingOnTextData = RichTextData.GetRichTextData(votingOnText, out votingOnText);
|
||||
}
|
||||
|
||||
private int SubmarineYesVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteYesCount;
|
||||
}
|
||||
|
||||
private int SubmarineNoVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteNoCount;
|
||||
}
|
||||
|
||||
private int SubmarineMaxVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteMax;
|
||||
}
|
||||
|
||||
private void SendSubmarineVoteEndMessage(SubmarineInfo info, VoteType type)
|
||||
{
|
||||
GameMain.NetworkMember.AddChatMessage(GetSubmarineVoteResultMessage(info, type, yesVotes.ToString(), noVotes.ToString(), votePassed), ChatMessageType.Server);
|
||||
}
|
||||
|
||||
public static string GetSubmarineVoteResultMessage(SubmarineInfo info, VoteType type, string yesVoteString, string noVoteString, bool votePassed)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchaseandswitchvotepassed" : "submarinepurchaseandswitchvotefailed", new string[] { "[submarinename]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, info.Price.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
break;
|
||||
case VoteType.PurchaseSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchasevotepassed" : "submarinepurchasevotefailed", new string[] { "[submarinename]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, info.Price.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
int deliveryFee = SubmarineSelection.DeliveryFeePerDistanceTravelled * GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarineswitchfeevotepassed" : "submarineswitchfeevotefailed", new string[] { "[submarinename]", "[locationname]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, endLocation.Name, deliveryFee.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarineswitchnofeevotepassed" : "submarineswitchnofeevotefailed", new string[] { "[submarinename]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, yesVoteString, noVoteString });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (frame != null)
|
||||
{
|
||||
frame.Parent.RemoveChild(frame);
|
||||
frame = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ using System.Threading;
|
||||
using Barotrauma.Tutorials;
|
||||
using Barotrauma.Media;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -35,7 +36,6 @@ namespace Barotrauma
|
||||
|
||||
public static GameScreen GameScreen;
|
||||
public static MainMenuScreen MainMenuScreen;
|
||||
public static LobbyScreen LobbyScreen;
|
||||
|
||||
public static NetLobbyScreen NetLobbyScreen;
|
||||
public static ServerListScreen ServerListScreen;
|
||||
@@ -45,8 +45,11 @@ namespace Barotrauma
|
||||
public static ParticleEditorScreen ParticleEditorScreen;
|
||||
public static LevelEditorScreen LevelEditorScreen;
|
||||
public static SpriteEditorScreen SpriteEditorScreen;
|
||||
public static EventEditorScreen EventEditorScreen;
|
||||
public static CharacterEditor.CharacterEditorScreen CharacterEditorScreen;
|
||||
|
||||
public static CampaignEndScreen CampaignEndScreen;
|
||||
|
||||
public static Lights.LightManager LightManager;
|
||||
|
||||
public static Sounds.SoundManager SoundManager;
|
||||
@@ -79,6 +82,10 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
if (gameSession == value) { return; }
|
||||
if (value == null && Screen.Selected == GameScreen && gameSession.GameMode is CampaignMode)
|
||||
{
|
||||
DebugConsole.AddWarning("GameSession set to null while in the game screen\n" + Environment.StackTrace);
|
||||
}
|
||||
if (gameSession?.GameMode != null && gameSession.GameMode != value?.GameMode)
|
||||
{
|
||||
gameSession.GameMode.Remove();
|
||||
@@ -100,7 +107,7 @@ namespace Barotrauma
|
||||
private CoroutineHandle loadingCoroutine;
|
||||
private bool hasLoaded;
|
||||
|
||||
private GameTime fixedTime;
|
||||
private readonly GameTime fixedTime;
|
||||
|
||||
public string ConnectName;
|
||||
public string ConnectEndpoint;
|
||||
@@ -110,7 +117,7 @@ namespace Barotrauma
|
||||
|
||||
private Viewport defaultViewport;
|
||||
|
||||
public event Action OnResolutionChanged;
|
||||
public event Action ResolutionChanged;
|
||||
|
||||
private bool exiting;
|
||||
|
||||
@@ -190,7 +197,6 @@ namespace Barotrauma
|
||||
public GameMain(string[] args)
|
||||
{
|
||||
Content.RootDirectory = "Content";
|
||||
|
||||
#if DEBUG && WINDOWS
|
||||
GraphicsAdapter.UseDebugLayers = true;
|
||||
#endif
|
||||
@@ -273,7 +279,7 @@ namespace Barotrauma
|
||||
|
||||
defaultViewport = GraphicsDevice.Viewport;
|
||||
|
||||
OnResolutionChanged?.Invoke();
|
||||
ResolutionChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetWindowMode(WindowMode windowMode)
|
||||
@@ -455,9 +461,10 @@ namespace Barotrauma
|
||||
{
|
||||
bool waitingForWorkshopUpdates = true;
|
||||
bool result = false;
|
||||
TaskPool.Add(SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
|
||||
TaskPool.Add("AutoUpdateWorkshopItemsAsync",
|
||||
SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
|
||||
{
|
||||
result = task.Result;
|
||||
result = ((Task<bool>)task).Result;
|
||||
waitingForWorkshopUpdates = false;
|
||||
});
|
||||
|
||||
@@ -521,6 +528,10 @@ namespace Barotrauma
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
TaskPool.Add("InitRelayNetworkAccess", SteamManager.InitRelayNetworkAccess(), (t) => { });
|
||||
|
||||
FactionPrefab.LoadFactions();
|
||||
NPCSet.LoadSets();
|
||||
CharacterPrefab.LoadAll();
|
||||
MissionPrefab.Init();
|
||||
TraitorMissionPrefab.Init();
|
||||
@@ -528,8 +539,9 @@ namespace Barotrauma
|
||||
Tutorials.Tutorial.Init();
|
||||
MapGenerationParams.Init();
|
||||
LevelGenerationParams.LoadPresets();
|
||||
OutpostGenerationParams.LoadPresets();
|
||||
WreckAIConfig.LoadAll();
|
||||
ScriptedEventSet.LoadPrefabs();
|
||||
EventSet.LoadPrefabs();
|
||||
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
|
||||
Order.Init();
|
||||
@@ -544,6 +556,10 @@ namespace Barotrauma
|
||||
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||
TitleScreen.LoadState = 55.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
UpgradePrefab.LoadAll(GetFilesOfType(ContentType.UpgradeModules));
|
||||
TitleScreen.LoadState = 56.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
|
||||
CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses));
|
||||
@@ -567,7 +583,6 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
MainMenuScreen = new MainMenuScreen(this);
|
||||
LobbyScreen = new LobbyScreen();
|
||||
ServerListScreen = new ServerListScreen();
|
||||
|
||||
TitleScreen.LoadState = 70.0f;
|
||||
@@ -594,7 +609,9 @@ namespace Barotrauma
|
||||
|
||||
LevelEditorScreen = new LevelEditorScreen();
|
||||
SpriteEditorScreen = new SpriteEditorScreen();
|
||||
EventEditorScreen = new EventEditorScreen();
|
||||
CharacterEditorScreen = new CharacterEditor.CharacterEditorScreen();
|
||||
CampaignEndScreen = new CampaignEndScreen();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -633,7 +650,7 @@ namespace Barotrauma
|
||||
foreach (ContentPackage contentPackage in Config.SelectedContentPackages)
|
||||
{
|
||||
var exePaths = contentPackage.GetFilesOfType(ContentType.Executable);
|
||||
if (exePaths.Any() && AppDomain.CurrentDomain.FriendlyName != exePaths.First())
|
||||
if (exePaths.Any() && AppDomain.CurrentDomain.FriendlyName != Path.GetFileNameWithoutExtension(exePaths.First()))
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("IncorrectExe",
|
||||
new string[2] { "[selectedpackage]", "[exename]" }, new string[2] { contentPackage.Name, exePaths.First() }),
|
||||
@@ -763,7 +780,7 @@ namespace Barotrauma
|
||||
//reset accumulator if loading
|
||||
// -> less choppy loading screens because the screen is rendered after each update
|
||||
// -> no pause caused by leftover time in the accumulator when starting a new shift
|
||||
GameMain.ResetFrameTime();
|
||||
ResetFrameTime();
|
||||
|
||||
if (!TitleScreen.PlayingSplashScreen)
|
||||
{
|
||||
@@ -777,11 +794,33 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && Config.AutomaticQuickStartEnabled && FirstLoad)
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift))
|
||||
{
|
||||
loadingScreenOpen = false;
|
||||
FirstLoad = false;
|
||||
MainMenuScreen.QuickStart();
|
||||
|
||||
if (Config.AutomaticQuickStartEnabled)
|
||||
{
|
||||
MainMenuScreen.QuickStart();
|
||||
}
|
||||
else if (Config.AutomaticCampaignLoadEnabled)
|
||||
{
|
||||
IEnumerable<string> saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Singleplayer);
|
||||
|
||||
if (saveFiles.Count() > 0)
|
||||
{
|
||||
saveFiles = saveFiles.OrderBy(file => File.GetLastWriteTime(file));
|
||||
try
|
||||
{
|
||||
SaveUtil.LoadGame(saveFiles.Last());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading save \"" + saveFiles.Last() + "\" failed", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -845,6 +884,12 @@ namespace Barotrauma
|
||||
{
|
||||
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
|
||||
}
|
||||
else if (GUIMessageBox.VisibleBox?.UserData is RoundSummary roundSummary &&
|
||||
roundSummary.ContinueButton != null &&
|
||||
roundSummary.ContinueButton.Visible)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
||||
}
|
||||
else if (Tutorial.Initialized && Tutorial.ContentRunning)
|
||||
{
|
||||
(GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI();
|
||||
@@ -868,7 +913,7 @@ namespace Barotrauma
|
||||
GUI.TogglePauseMenu();
|
||||
}
|
||||
|
||||
bool itemHudActive()
|
||||
static bool itemHudActive()
|
||||
{
|
||||
if (Character.Controlled?.SelectedConstruction == null) { return false; }
|
||||
return
|
||||
@@ -878,7 +923,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (GameMain.NetworkMember == null)
|
||||
if (NetworkMember == null)
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.P) && !(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
|
||||
{
|
||||
@@ -890,6 +935,10 @@ namespace Barotrauma
|
||||
GUI.ClearUpdateList();
|
||||
Paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning || DebugConsole.Paused) &&
|
||||
(NetworkMember == null || !NetworkMember.GameStarted);
|
||||
if (GameSession?.GameMode != null && GameSession.GameMode.Paused)
|
||||
{
|
||||
Paused = true;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
if (NetworkMember == null && !WindowActive && !Paused && true && Screen.Selected != MainMenuScreen && Config.PauseOnFocusLost)
|
||||
@@ -921,7 +970,7 @@ namespace Barotrauma
|
||||
{
|
||||
(GameSession.GameMode as TutorialMode).Update((float)Timing.Step);
|
||||
}
|
||||
else if (DebugConsole.Paused)
|
||||
else
|
||||
{
|
||||
if (Screen.Selected.Cam == null)
|
||||
{
|
||||
@@ -929,7 +978,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Screen.Selected.Cam.MoveCamera((float)Timing.Step);
|
||||
Screen.Selected.Cam.MoveCamera((float)Timing.Step, allowMove: DebugConsole.Paused, allowZoom: DebugConsole.Paused);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1027,41 +1076,53 @@ namespace Barotrauma
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void QuitToMainMenu(bool save)
|
||||
{
|
||||
if (save)
|
||||
{
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
if (GameSession.Submarine != null && !GameSession.Submarine.Removed)
|
||||
{
|
||||
GameSession.SubmarineInfo = new SubmarineInfo(GameSession.Submarine);
|
||||
}
|
||||
|
||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign campaign && Level.IsLoadedOutpost && campaign.Map?.CurrentLocation != null && campaign.CargoManager != null)
|
||||
{
|
||||
campaign.Map.CurrentLocation.AddToStock(campaign.CargoManager.SoldItems);
|
||||
campaign.CargoManager.ClearSoldItemsProjSpecific();
|
||||
campaign.Map.CurrentLocation.RemoveFromStock(campaign.CargoManager.PurchasedItems);
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameSession.SavePath);
|
||||
}
|
||||
|
||||
if (GameMain.Client != null)
|
||||
if (Client != null)
|
||||
{
|
||||
GameMain.Client.Disconnect();
|
||||
GameMain.Client = null;
|
||||
Client.Disconnect();
|
||||
Client = null;
|
||||
}
|
||||
|
||||
CoroutineManager.StopCoroutines("EndCinematic");
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
if (GameSession != null)
|
||||
{
|
||||
if (Tutorial.Initialized)
|
||||
{
|
||||
((TutorialMode)GameMain.GameSession.GameMode).Tutorial?.Stop();
|
||||
((TutorialMode)GameSession.GameMode).Tutorial?.Stop();
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
Mission mission = GameMain.GameSession.Mission;
|
||||
Mission mission = GameSession.Mission;
|
||||
GameAnalyticsManager.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave"));
|
||||
GameAnalyticsManager.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed")));
|
||||
}
|
||||
GameMain.GameSession = null;
|
||||
}
|
||||
GUIMessageBox.CloseAll();
|
||||
GameMain.MainMenuScreen.Select();
|
||||
MainMenuScreen.Select();
|
||||
GameSession = null;
|
||||
}
|
||||
|
||||
public void ShowCampaignDisclaimer(Action onContinue = null)
|
||||
@@ -1071,12 +1132,7 @@ namespace Barotrauma
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
var roadMap = new GUIMessageBox(TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("CampaignRoadMapText"),
|
||||
new string[] { TextManager.Get("Back"), TextManager.Get("OK") });
|
||||
roadMap.Buttons[0].OnClicked += roadMap.Close;
|
||||
roadMap.Buttons[0].OnClicked += (_, __) => { ShowCampaignDisclaimer(onContinue); return true; };
|
||||
roadMap.Buttons[1].OnClicked += roadMap.Close;
|
||||
roadMap.Buttons[1].OnClicked += (_, __) => { onContinue?.Invoke(); return true; };
|
||||
ShowOpenUrlInWebBrowserPrompt("https://trello.com/b/hBXI8ltN/barotrauma-roadmap-known-issues");
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
@@ -1094,9 +1150,9 @@ namespace Barotrauma
|
||||
linkHolder.RectTransform.MaxSize = new Point(int.MaxValue, linkHolder.Rect.Height);
|
||||
List<Pair<string, string>> links = new List<Pair<string, string>>()
|
||||
{
|
||||
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")),
|
||||
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)
|
||||
{
|
||||
@@ -1124,8 +1180,10 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("bugreportbutton"), "");
|
||||
msgBox.UserData = "bugreporter";
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("bugreportbutton"), "")
|
||||
{
|
||||
UserData = "bugreporter"
|
||||
};
|
||||
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), msgBox.Content.RectTransform)) { Stretch = true, RelativeSpacing = 0.025f };
|
||||
linkHolder.RectTransform.MaxSize = new Point(int.MaxValue, linkHolder.Rect.Height);
|
||||
|
||||
@@ -1189,7 +1247,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while cleaning unnecessary save files", e);
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics){ GameAnalytics.OnQuit(); }
|
||||
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
|
||||
if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); }
|
||||
|
||||
base.OnExiting(sender, args);
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class CargoManager
|
||||
{
|
||||
private class SoldEntity
|
||||
{
|
||||
public enum SellStatus
|
||||
{
|
||||
Confirmed,
|
||||
Unconfirmed,
|
||||
Local
|
||||
}
|
||||
|
||||
public Item Item { get; }
|
||||
public SellStatus Status { get; set; }
|
||||
|
||||
private SoldEntity(Item item, SellStatus status)
|
||||
{
|
||||
Item = item;
|
||||
Status = status;
|
||||
}
|
||||
|
||||
public static SoldEntity CreateInSinglePlayer(Item item) => new SoldEntity(item, SellStatus.Confirmed);
|
||||
public static SoldEntity CreateInMultiPlayer(Item item) => new SoldEntity(item, SellStatus.Local);
|
||||
}
|
||||
|
||||
private List<SoldEntity> SoldEntities { get; } = new List<SoldEntity>();
|
||||
|
||||
public List<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 multiplier (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.IsFullCondition && soldEntities.None(se => se.Item == i));
|
||||
|
||||
// Prevent selling things like battery cells from headsets and oxygen tanks from diving masks
|
||||
var slots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.OuterClothes, InvSlotType.Headset };
|
||||
foreach (InvSlotType slot in slots)
|
||||
{
|
||||
var index = character.Inventory.FindLimbSlot(slot);
|
||||
if (character.Inventory.Items[index] is Item item && item.ContainedItems != null)
|
||||
{
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
if (containedItem != null)
|
||||
{
|
||||
sellables.Remove(containedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sellables;
|
||||
}
|
||||
|
||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInBuyCrate.Clear();
|
||||
ItemsInBuyCrate.AddRange(items);
|
||||
OnItemsInBuyCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetSoldItems(List<SoldItem> items)
|
||||
{
|
||||
SoldItems.Clear();
|
||||
SoldItems.AddRange(items);
|
||||
|
||||
foreach (SoldEntity se in SoldEntities)
|
||||
{
|
||||
if (se.Status == SoldEntity.SellStatus.Confirmed) { continue; }
|
||||
if (SoldItems.Any(si => si.ID == se.Item.ID && si.ItemPrefab == se.Item.Prefab && (GameMain.Client == null || GameMain.Client.ID == si.SellerID)))
|
||||
{
|
||||
se.Status = SoldEntity.SellStatus.Confirmed;
|
||||
}
|
||||
else
|
||||
{
|
||||
se.Status = SoldEntity.SellStatus.Unconfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ModifyItemQuantityInSellCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
||||
{
|
||||
PurchasedItem itemToSell = ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
if (itemToSell != null)
|
||||
{
|
||||
itemToSell.Quantity += changeInQuantity;
|
||||
if (itemToSell.Quantity < 1)
|
||||
{
|
||||
ItemsInSellCrate.Remove(itemToSell);
|
||||
}
|
||||
}
|
||||
else if (changeInQuantity > 0)
|
||||
{
|
||||
itemToSell = new PurchasedItem(itemPrefab, changeInQuantity);
|
||||
ItemsInSellCrate.Add(itemToSell);
|
||||
}
|
||||
OnItemsInSellCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SellItems(List<PurchasedItem> itemsToSell)
|
||||
{
|
||||
var itemsInInventory = GetSellableItems(Character.Controlled);
|
||||
var canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
||||
var sellerId = GameMain.Client?.ID ?? 0;
|
||||
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
{
|
||||
var itemValue = GetSellValueAtCurrentLocation(item.ItemPrefab, quantity: item.Quantity);
|
||||
|
||||
// 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)
|
||||
{
|
||||
foreach (Item i in matchingItems)
|
||||
{
|
||||
SoldItems.Add(new SoldItem(i.Prefab, i.ID, canAddToRemoveQueue, sellerId));
|
||||
SoldEntities.Add(campaign.IsSinglePlayer ? SoldEntity.CreateInSinglePlayer(i) : SoldEntity.CreateInMultiPlayer(i));
|
||||
if (canAddToRemoveQueue) { Entity.Spawner.AddToRemoveQueue(i); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < item.Quantity; i++)
|
||||
{
|
||||
var matchingItem = matchingItems[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); }
|
||||
}
|
||||
}
|
||||
|
||||
// Exchange money
|
||||
campaign.Map.CurrentLocation.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
|
||||
// Remove from the sell crate
|
||||
if (ItemsInSellCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } itemToSell)
|
||||
{
|
||||
itemToSell.Quantity -= item.Quantity;
|
||||
if (itemToSell.Quantity < 1)
|
||||
{
|
||||
ItemsInSellCrate.Remove(itemToSell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ClearSoldItemsProjSpecific()
|
||||
{
|
||||
SoldItems.Clear();
|
||||
SoldEntities.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,6 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
const float CharacterWaitOnSwitch = 10.0f;
|
||||
|
||||
private readonly List<CharacterInfo> characterInfos = new List<CharacterInfo>();
|
||||
private readonly List<Character> characters = new List<Character>();
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
#region UI
|
||||
@@ -30,6 +27,7 @@ namespace Barotrauma
|
||||
public GUIComponent ReportButtonFrame { get; set; }
|
||||
|
||||
private GUIFrame guiFrame;
|
||||
private GUIComponent crewAreaWithButtons;
|
||||
private GUIFrame crewArea;
|
||||
private GUIListBox crewList;
|
||||
private GUIButton commandButton, toggleCrewButton;
|
||||
@@ -72,19 +70,7 @@ namespace Barotrauma
|
||||
public CrewManager(XElement element, bool isSinglePlayer)
|
||||
: this(isSinglePlayer)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("character", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
var characterInfo = new CharacterInfo(subElement);
|
||||
characterInfos.Add(characterInfo);
|
||||
foreach (XElement invElement in subElement.Elements())
|
||||
{
|
||||
if (!invElement.Name.ToString().Equals("inventory", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
characterInfo.InventoryData = invElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AddCharacterElements(element);
|
||||
}
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
@@ -96,7 +82,7 @@ namespace Barotrauma
|
||||
|
||||
#region Crew Area
|
||||
|
||||
var crewAreaWithButtons = new GUIFrame(
|
||||
crewAreaWithButtons = new GUIFrame(
|
||||
HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.CrewArea, guiFrame.RectTransform),
|
||||
style: null,
|
||||
color: Color.Transparent)
|
||||
@@ -326,43 +312,6 @@ namespace Barotrauma
|
||||
return characterInfos;
|
||||
}
|
||||
|
||||
public void AddCharacter(Character character)
|
||||
{
|
||||
if (character.Removed)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to add a removed character to CrewManager!\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
if (character.IsDead)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to add a dead character to CrewManager!\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!characters.Contains(character))
|
||||
{
|
||||
characters.Add(character);
|
||||
}
|
||||
if (!characterInfos.Contains(character.Info))
|
||||
{
|
||||
characterInfos.Add(character.Info);
|
||||
}
|
||||
|
||||
AddCharacterToCrewList(character);
|
||||
DisplayCharacterOrder(character, character.CurrentOrder, character.CurrentOrderOption);
|
||||
}
|
||||
|
||||
public void AddCharacterInfo(CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterInfos.Contains(characterInfo))
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
characterInfos.Add(characterInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the character from the crew (and crew menus).
|
||||
/// </summary>
|
||||
@@ -379,15 +328,6 @@ namespace Barotrauma
|
||||
if (removeInfo) { characterInfos.Remove(character.Info); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove info of a selected character. The character will not be visible in any menus or the round summary.
|
||||
/// </summary>
|
||||
/// <param name="characterInfo"></param>
|
||||
public void RemoveCharacterInfo(CharacterInfo characterInfo)
|
||||
{
|
||||
characterInfos.Remove(characterInfo);
|
||||
}
|
||||
|
||||
private void AddCharacterToCrewList(Character character)
|
||||
{
|
||||
if (character == null) { return; }
|
||||
@@ -516,7 +456,7 @@ namespace Barotrauma
|
||||
};
|
||||
new GUIImage(
|
||||
new RectTransform(Vector2.One, soundIcons.RectTransform),
|
||||
GUI.Style.GetComponentStyle("GUISoundIcon").Sprites[GUIComponent.ComponentState.None].FirstOrDefault().Sprite,
|
||||
GUI.Style.GetComponentStyle("GUISoundIcon").GetDefaultSprite(),
|
||||
scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
@@ -630,6 +570,22 @@ namespace Barotrauma
|
||||
ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender));
|
||||
}
|
||||
|
||||
public void AddSinglePlayerChatMessage(ChatMessage message)
|
||||
{
|
||||
if (!IsSinglePlayer)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(message.Text)) { return; }
|
||||
|
||||
if (message.Sender != null)
|
||||
{
|
||||
GameMain.GameSession.CrewManager.SetCharacterSpeaking(message.Sender);
|
||||
}
|
||||
ChatBox.AddMessage(message);
|
||||
}
|
||||
|
||||
private WifiComponent GetHeadset(Character character, bool requireEquipped)
|
||||
{
|
||||
if (character?.Inventory == null) return null;
|
||||
@@ -861,27 +817,6 @@ namespace Barotrauma
|
||||
return characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
|
||||
}
|
||||
|
||||
private struct OrderInfo
|
||||
{
|
||||
public string ComponentIdentifier { get; set; }
|
||||
public Order Order { get; private set; }
|
||||
public string OrderOption { get; private set; }
|
||||
|
||||
public OrderInfo(Order order, string orderOption)
|
||||
{
|
||||
ComponentIdentifier = "currentorder";
|
||||
Order = order;
|
||||
OrderOption = orderOption;
|
||||
}
|
||||
|
||||
public OrderInfo(OrderInfo orderInfo)
|
||||
{
|
||||
ComponentIdentifier = "previousorder";
|
||||
Order = orderInfo.Order;
|
||||
OrderOption = orderInfo.OrderOption;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Updating and drawing the UI
|
||||
@@ -1123,6 +1058,7 @@ namespace Barotrauma
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
if (CoroutineManager.IsCoroutineRunning("LevelTransition") || CoroutineManager.IsCoroutineRunning("SubmarineTransition")) { return; }
|
||||
|
||||
commandFrame?.AddToGUIUpdateList();
|
||||
|
||||
@@ -1145,6 +1081,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
crewAreaWithButtons.Visible = !(GameMain.GameSession?.GameMode is CampaignMode campaign) || (!campaign.ForceMapUI && !campaign.ShowCampaignUI);
|
||||
|
||||
guiFrame.AddToGUIUpdateList();
|
||||
contextMenu?.AddToGUIUpdateList(false, 1);
|
||||
subContextMenu?.AddToGUIUpdateList(false, 1);
|
||||
@@ -1170,6 +1108,7 @@ namespace Barotrauma
|
||||
|
||||
private void SelectCharacter(Character character)
|
||||
{
|
||||
if (ConversationAction.IsDialogOpen) { return; }
|
||||
if (!AllowCharacterSwitch) { return; }
|
||||
//make the previously selected character wait in place for some time
|
||||
//(so they don't immediately start idling and walking away from their station)
|
||||
@@ -1256,7 +1195,7 @@ namespace Barotrauma
|
||||
WasCommandInterfaceDisabledThisUpdate = false;
|
||||
|
||||
if (PlayerInput.KeyDown(InputType.Command) && (GUI.KeyboardDispatcher.Subscriber == null || GUI.KeyboardDispatcher.Subscriber == crewList) &&
|
||||
commandFrame == null && !clicklessSelectionActive && CanIssueOrders)
|
||||
commandFrame == null && !clicklessSelectionActive && CanIssueOrders && !(GameMain.GameSession?.Campaign?.ShowCampaignUI ?? false))
|
||||
{
|
||||
if (PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift))
|
||||
{
|
||||
@@ -1574,32 +1513,32 @@ namespace Barotrauma
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
return Character.Controlled == null || Character.Controlled.Info != null && Character.Controlled.SpeechImpediment < 100.0f;
|
||||
#else
|
||||
return Character.Controlled?.Info != null && Character.Controlled.SpeechImpediment < 100.0f;
|
||||
if (Character.Controlled == null) { return true; }
|
||||
#endif
|
||||
return Character.Controlled?.Info != null && Character.Controlled.SpeechImpediment < 100.0f;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanSomeoneHearCharacter()
|
||||
{
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
return Character.Controlled != null && characters.Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled));
|
||||
if (Character.Controlled == null) { return true; }
|
||||
#endif
|
||||
return Character.Controlled != null && characters.Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled));
|
||||
}
|
||||
|
||||
private Entity FindEntityContext()
|
||||
{
|
||||
if (Character.Controlled?.FocusedCharacter != null)
|
||||
if (Character.Controlled?.FocusedCharacter is Character focusedCharacter && !focusedCharacter.IsDead &&
|
||||
HumanAIController.IsFriendly(Character.Controlled, focusedCharacter) && Character.Controlled.TeamID == focusedCharacter.TeamID)
|
||||
{
|
||||
if (Character.Controlled?.FocusedItem != null)
|
||||
{
|
||||
Vector2 mousePos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (Vector2.Distance(mousePos, Character.Controlled.FocusedCharacter.WorldPosition) < Vector2.Distance(mousePos, Character.Controlled.FocusedItem.WorldPosition))
|
||||
if (Vector2.Distance(mousePos, focusedCharacter.WorldPosition) < Vector2.Distance(mousePos, Character.Controlled.FocusedItem.WorldPosition))
|
||||
{
|
||||
return Character.Controlled.FocusedCharacter;
|
||||
return focusedCharacter;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1608,7 +1547,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
return Character.Controlled.FocusedCharacter;
|
||||
return focusedCharacter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1677,24 +1616,22 @@ namespace Barotrauma
|
||||
"CommandNodeContainer",
|
||||
scaleToFit: true)
|
||||
{
|
||||
Color = characterContext.Info.Job.Prefab.UIColor * nodeColorMultiplier,
|
||||
HoverColor = characterContext.Info.Job.Prefab.UIColor,
|
||||
Color = characterContext.Info?.Job?.Prefab != null ? characterContext.Info.Job.Prefab.UIColor * nodeColorMultiplier : Color.White,
|
||||
HoverColor = characterContext.Info?.Job?.Prefab != null ? characterContext.Info.Job.Prefab.UIColor : Color.White,
|
||||
UserData = "colorsource"
|
||||
};
|
||||
// Character icon
|
||||
new GUICustomComponent(
|
||||
var characterIcon = new GUICustomComponent(
|
||||
new RectTransform(Vector2.One, startNode.RectTransform, anchor: Anchor.Center),
|
||||
(spriteBatch, _) =>
|
||||
{
|
||||
if (!(entityContext is Character character)) { return; }
|
||||
if (!(entityContext is Character character) || character?.Info == null) { return; }
|
||||
var node = startNode;
|
||||
character.Info.DrawJobIcon(spriteBatch,
|
||||
new Rectangle((int)(node.Rect.X + node.Rect.Width * 0.5f), (int)(node.Rect.Y + node.Rect.Height * 0.1f), (int)(node.Rect.Width * 0.6f), (int)(node.Rect.Height * 0.8f)));
|
||||
character.Info.DrawIcon(spriteBatch, new Vector2(node.Rect.X + node.Rect.Width * 0.35f, node.Center.Y), node.Rect.Size.ToVector2() * 0.7f);
|
||||
})
|
||||
{
|
||||
ToolTip = characterContext.Info.DisplayName + " (" + characterContext.Info.Job.Name + ")"
|
||||
};
|
||||
});
|
||||
SetCharacterTooltip(characterIcon, entityContext as Character);
|
||||
}
|
||||
SetCenterNode(startNode);
|
||||
|
||||
@@ -1934,7 +1871,7 @@ namespace Barotrauma
|
||||
c.HoverColor = c.Color;
|
||||
c.PressedColor = c.Color;
|
||||
c.SelectedColor = c.Color;
|
||||
c.ToolTip = characterContext != null ? characterContext.Info.DisplayName + " (" + characterContext.Info.Job.Name + ")" : null;
|
||||
SetCharacterTooltip(c, characterContext);
|
||||
}
|
||||
node.OnClicked = null;
|
||||
centerNode = node;
|
||||
@@ -2040,7 +1977,7 @@ namespace Barotrauma
|
||||
var reactorOutput = -reactor.CurrPowerConsumption;
|
||||
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
|
||||
// ---> Create shortcut node for "Operate Reactor" order's "Power Up" option
|
||||
if ((Character.Controlled == null || Character.Controlled.Info.Job.Prefab != JobPrefab.Get("engineer")) &&
|
||||
if ((Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
||||
reactorOutput < float.Epsilon && characters.None(c => c.SelectedConstruction == reactor.Item))
|
||||
{
|
||||
var order = new Order(Order.GetPrefab("operatereactor"), reactor.Item, reactor, Character.Controlled);
|
||||
@@ -2053,7 +1990,7 @@ namespace Barotrauma
|
||||
// TODO: Reconsider the conditions as bot captain can have the nav term selected without operating it
|
||||
// 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 < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info.Job.Prefab != JobPrefab.Get("captain")) &&
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (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) &&
|
||||
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
|
||||
{
|
||||
@@ -2063,7 +2000,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not a security officer AND invaders are reported
|
||||
// --> Create shorcut node for Fight Intruders order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info.Job.Prefab != JobPrefab.Get("securityofficer")) &&
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("securityofficer")) &&
|
||||
(Order.GetPrefab("reportintruders") is Order reportIntruders && ActiveOrders.Any(o => o.First.Prefab == reportIntruders)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2072,7 +2009,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not a mechanic AND a breach has been reported
|
||||
// --> Create shorcut node for Fix Leaks order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info.Job.Prefab != JobPrefab.Get("mechanic")) &&
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("mechanic")) &&
|
||||
(Order.GetPrefab("reportbreach") is Order reportBreach && ActiveOrders.Any(o => o.First.Prefab == reportBreach)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2081,7 +2018,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not an engineer AND broken devices have been reported
|
||||
// --> Create shortcut node for Repair Damaged Systems order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info.Job.Prefab != JobPrefab.Get("engineer")) &&
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
||||
(Order.GetPrefab("reportbrokendevices") is Order reportBrokenDevices && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2741,11 +2678,11 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
bool canHear = true;
|
||||
#else
|
||||
bool canHear = character.CanHearCharacter(Character.Controlled);
|
||||
#if DEBUG
|
||||
if (Character.Controlled == null) { canHear = true; }
|
||||
#endif
|
||||
|
||||
if (!canHear)
|
||||
{
|
||||
node.CanBeFocused = orderIcon.CanBeFocused = false;
|
||||
@@ -2904,18 +2841,29 @@ namespace Barotrauma
|
||||
return sub;
|
||||
}
|
||||
|
||||
private void SetCharacterTooltip(GUIComponent component, Character character)
|
||||
{
|
||||
if (component == null) { return; }
|
||||
var tooltip = character?.Info != null ? characterContext.Info.DisplayName : null;
|
||||
if (string.IsNullOrWhiteSpace(tooltip)) { component.ToolTip = tooltip; return; }
|
||||
if (character.Info?.Job != null && !string.IsNullOrWhiteSpace(characterContext.Info.Job.Name)) { tooltip += " (" + characterContext.Info.Job.Name + ")"; }
|
||||
component.ToolTip = tooltip;
|
||||
}
|
||||
|
||||
#region Crew Member Assignment Logic
|
||||
|
||||
private Character GetCharacterForQuickAssignment(Order order)
|
||||
{
|
||||
var controllingCharacter = Character.Controlled != null;
|
||||
#if !DEBUG
|
||||
if (Character.Controlled == null) { return null; }
|
||||
if (!controllingCharacter) { return null; }
|
||||
#endif
|
||||
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemOperatedByAnother(null, order.TargetItemComponent, out Character operatingCharacter))
|
||||
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemOperatedByAnother(null, order.TargetItemComponent, out Character operatingCharacter) &&
|
||||
(!controllingCharacter || operatingCharacter.CanHearCharacter(Character.Controlled)))
|
||||
{
|
||||
return operatingCharacter;
|
||||
}
|
||||
return GetCharactersSortedForOrder(order, false).FirstOrDefault() ?? Character.Controlled;
|
||||
return GetCharactersSortedForOrder(order, false).FirstOrDefault(c => !controllingCharacter || c.CanHearCharacter(Character.Controlled)) ?? Character.Controlled;
|
||||
}
|
||||
|
||||
private List<Character> GetCharactersForManualAssignment(Order order)
|
||||
@@ -2934,11 +2882,17 @@ namespace Barotrauma
|
||||
private IEnumerable<Character> GetCharactersSortedForOrder(Order order, bool includeSelf)
|
||||
{
|
||||
return characters.FindAll(c => Character.Controlled == null || ((includeSelf || c != Character.Controlled) && c.TeamID == Character.Controlled.TeamID))
|
||||
// 1. Prioritize those who are already ordered to operate the item target of the new 'operate' order
|
||||
.OrderByDescending(c => c.CurrentOrder != null && order.Category == OrderCategory.Operate && c.CurrentOrder.Identifier == order.Identifier && c.CurrentOrder.TargetEntity == order.TargetEntity)
|
||||
// 2. Prioritize those who are currently dismissed
|
||||
.ThenByDescending(c => c.CurrentOrder == null || c.CurrentOrder.Identifier == dismissedOrderPrefab.Identifier)
|
||||
// 3. Prioritize those who are not currently assigned with the same type of order (for example, when giving a 'Fix Leak' order, prioritize those who have a different order)
|
||||
.ThenBy(c => c.CurrentOrder != null && c.CurrentOrder.Identifier == order.Identifier && c.CurrentOrder.TargetEntity == order.TargetEntity)
|
||||
// 4. Prioritize those with the appropriate job for the order
|
||||
.ThenByDescending(c => order.HasAppropriateJob(c))
|
||||
// 5. Prioritize those with the lowest "weight" of the current order
|
||||
.ThenBy(c => c.CurrentOrder?.Weight)
|
||||
// 6. Prioritize those with the best skill for the order
|
||||
.ThenByDescending(c => c.GetSkillLevel(order.AppropriateSkill));
|
||||
}
|
||||
|
||||
@@ -3013,40 +2967,7 @@ namespace Barotrauma
|
||||
public void InitSinglePlayerRound()
|
||||
{
|
||||
crewList.ClearChildren();
|
||||
characters.Clear();
|
||||
|
||||
WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub);
|
||||
|
||||
for (int i = 0; i < waypoints.Length; i++)
|
||||
{
|
||||
Character character;
|
||||
character = Character.Create(characterInfos[i], waypoints[i].WorldPosition, characterInfos[i].Name);
|
||||
|
||||
if (character.Info != null)
|
||||
{
|
||||
if (!character.Info.StartItemsGiven && character.Info.InventoryData != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error when initializing a single player round: character \"{character.Name}\" has not been given their initial items but has saved inventory data. Using the saved inventory data instead of giving the character new items.");
|
||||
}
|
||||
if (character.Info.InventoryData != null)
|
||||
{
|
||||
character.Info.SpawnInventoryItems(character.Inventory, character.Info.InventoryData);
|
||||
}
|
||||
else if (!character.Info.StartItemsGiven)
|
||||
{
|
||||
character.GiveJobItems(waypoints[i]);
|
||||
}
|
||||
character.Info.StartItemsGiven = true;
|
||||
}
|
||||
|
||||
AddCharacter(character);
|
||||
if (i == 0)
|
||||
{
|
||||
Character.Controlled = character;
|
||||
}
|
||||
}
|
||||
|
||||
conversationTimer = Rand.Range(5.0f, 10.0f);
|
||||
InitRound();
|
||||
}
|
||||
|
||||
public void EndRound()
|
||||
@@ -3072,10 +2993,9 @@ namespace Barotrauma
|
||||
foreach (CharacterInfo ci in characterInfos)
|
||||
{
|
||||
var infoElement = ci.Save(element);
|
||||
if (ci.InventoryData != null)
|
||||
{
|
||||
infoElement.Add(ci.InventoryData);
|
||||
}
|
||||
if (ci.InventoryData != null) { infoElement.Add(ci.InventoryData); }
|
||||
if (ci.HealthData != null) { infoElement.Add(ci.HealthData); }
|
||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||
}
|
||||
parentElement.Add(element);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,65 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract partial class CampaignMode : GameMode
|
||||
{
|
||||
protected bool crewDead;
|
||||
|
||||
protected Color overlayColor;
|
||||
protected string overlayText, overlayTextBottom;
|
||||
protected Color overlayTextColor;
|
||||
protected Sprite overlaySprite;
|
||||
|
||||
protected GUIButton endRoundButton;
|
||||
|
||||
public GUIButton EndRoundButton => endRoundButton;
|
||||
|
||||
protected GUIFrame campaignUIContainer;
|
||||
public CampaignUI CampaignUI;
|
||||
|
||||
public bool ForceMapUI
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
}
|
||||
|
||||
private bool showCampaignUI;
|
||||
private bool wasChatBoxOpen;
|
||||
public bool ShowCampaignUI
|
||||
{
|
||||
get { return showCampaignUI; }
|
||||
set
|
||||
{
|
||||
if (value == showCampaignUI) { return; }
|
||||
var chatBox = CrewManager?.ChatBox ?? GameMain.Client?.ChatBox;
|
||||
if (value)
|
||||
{
|
||||
if (chatBox != null)
|
||||
{
|
||||
wasChatBoxOpen = chatBox.ToggleOpen;
|
||||
chatBox.ToggleOpen = false;
|
||||
}
|
||||
}
|
||||
else if (chatBox != null)
|
||||
{
|
||||
chatBox.ToggleOpen = wasChatBoxOpen;
|
||||
}
|
||||
showCampaignUI = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
if (Mission == null) return;
|
||||
@@ -15,5 +70,216 @@ namespace Barotrauma
|
||||
UserData = "missionstartmessage"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There is a server-side implementation of the method in <see cref="MultiPlayerCampaign"/>
|
||||
/// </summary>
|
||||
public bool AllowedToEndRound()
|
||||
{
|
||||
//allow ending the round if the client has permissions, is the owner, the only client in the server
|
||||
//or if no-one has management permissions
|
||||
if (GameMain.Client == null) { return true; }
|
||||
return
|
||||
GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
|
||||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
GameMain.Client.ConnectedClients.Count == 1 ||
|
||||
GameMain.Client.IsServerOwner ||
|
||||
GameMain.Client.ConnectedClients.None(c =>
|
||||
c.InGame && (c.IsOwner || c.HasPermission(ClientPermissions.ManageRound) || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There is a server-side implementation of the method in <see cref="MultiPlayerCampaign"/>
|
||||
/// </summary>
|
||||
public bool AllowedToManageCampaign()
|
||||
{
|
||||
//allow ending the round if the client has permissions, is the owner, the only client in the server,
|
||||
//or if no-one has management permissions
|
||||
if (GameMain.Client == null) { return true; }
|
||||
return
|
||||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
GameMain.Client.ConnectedClients.Count == 1 ||
|
||||
GameMain.Client.IsServerOwner ||
|
||||
GameMain.Client.ConnectedClients.None(c =>
|
||||
c.InGame && (c.IsOwner || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (overlayColor.A > 0)
|
||||
{
|
||||
if (overlaySprite != null)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * (overlayColor.A / 255.0f), isFilled: true);
|
||||
float scale = Math.Max(GameMain.GraphicsWidth / overlaySprite.size.X, GameMain.GraphicsHeight / overlaySprite.size.Y);
|
||||
overlaySprite.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2, overlayColor, overlaySprite.size / 2, scale: scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), overlayColor, isFilled: true);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(overlayText) && overlayTextColor.A > 0)
|
||||
{
|
||||
var backgroundSprite = GUI.Style.GetComponentStyle("CommandBackground").GetDefaultSprite();
|
||||
Vector2 centerPos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2;
|
||||
backgroundSprite.Draw(spriteBatch,
|
||||
centerPos,
|
||||
Color.White * (overlayTextColor.A / 255.0f),
|
||||
origin: backgroundSprite.size / 2,
|
||||
rotate: 0.0f,
|
||||
scale: new Vector2(1.5f, 0.7f) * (GameMain.GraphicsWidth / 3 / backgroundSprite.size.X));
|
||||
|
||||
string wrappedText = ToolBox.WrapText(overlayText, GameMain.GraphicsWidth / 3, GUI.Font);
|
||||
Vector2 textSize = GUI.Font.MeasureString(wrappedText);
|
||||
Vector2 textPos = centerPos - textSize / 2;
|
||||
GUI.DrawString(spriteBatch, textPos + Vector2.One, wrappedText, Color.Black * (overlayTextColor.A / 255.0f));
|
||||
GUI.DrawString(spriteBatch, textPos, wrappedText, overlayTextColor);
|
||||
|
||||
if (!string.IsNullOrEmpty(overlayTextBottom))
|
||||
{
|
||||
Vector2 bottomTextPos = centerPos + new Vector2(0.0f, textSize.Y + 30 * GUI.Scale) - GUI.Font.MeasureString(overlayTextBottom) / 2;
|
||||
GUI.DrawString(spriteBatch, bottomTextPos + Vector2.One, overlayTextBottom, Color.Black * (overlayTextColor.A / 255.0f));
|
||||
GUI.DrawString(spriteBatch, bottomTextPos, overlayTextBottom, overlayTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.DisableHUD || GUI.DisableUpperHUD || ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"))
|
||||
{
|
||||
endRoundButton.Visible = false;
|
||||
return;
|
||||
}
|
||||
if (Submarine.MainSub == null) { return; }
|
||||
|
||||
endRoundButton.Visible = false;
|
||||
var availableTransition = GetAvailableTransition(out _, out Submarine leavingSub);
|
||||
string buttonText = "";
|
||||
switch (availableTransition)
|
||||
{
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
case TransitionType.ProgressToNextEmptyLocation:
|
||||
if (Level.Loaded.EndOutpost == null || !Level.Loaded.EndOutpost.DockedTo.Contains(leavingSub))
|
||||
{
|
||||
buttonText = TextManager.GetWithVariable("EnterLocation", "[locationname]", Level.Loaded.EndLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
break;
|
||||
case TransitionType.LeaveLocation:
|
||||
// not sure why this can happen at an outpost but it apparently can in multiplayer
|
||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
break;
|
||||
case TransitionType.ReturnToPreviousLocation:
|
||||
case TransitionType.ReturnToPreviousEmptyLocation:
|
||||
if (Level.Loaded.StartOutpost == null || !Level.Loaded.StartOutpost.DockedTo.Contains(leavingSub))
|
||||
{
|
||||
buttonText = TextManager.GetWithVariable("EnterLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
|
||||
break;
|
||||
case TransitionType.None:
|
||||
default:
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
||||
(Character.Controlled?.Submarine?.Info.Type == SubmarineType.Player || (Character.Controlled?.CurrentHull?.OutpostModuleTags?.Contains("airlock") ?? false)))
|
||||
{
|
||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
else
|
||||
{
|
||||
endRoundButton.Visible = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (endRoundButton.Visible)
|
||||
{
|
||||
endRoundButton.Text = ToolBox.LimitString(buttonText, endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
||||
if (endRoundButton.Text != buttonText)
|
||||
{
|
||||
endRoundButton.ToolTip = buttonText;
|
||||
}
|
||||
endRoundButton.Enabled = AllowedToEndRound();
|
||||
}
|
||||
|
||||
endRoundButton.DrawManually(spriteBatch);
|
||||
}
|
||||
|
||||
public Task SelectSummaryScreen(RoundSummary roundSummary, LevelData newLevel, bool mirror, Action action)
|
||||
{
|
||||
var roundSummaryScreen = RoundSummaryScreen.Select(overlaySprite, roundSummary);
|
||||
|
||||
GUI.ClearCursorWait();
|
||||
|
||||
var loadTask = Task.Run(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
Rand.ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
GameMain.GameSession.StartRound(newLevel, mirrorLevel: mirror);
|
||||
Rand.ThreadId = 0;
|
||||
});
|
||||
TaskPool.Add("AsyncCampaignStartRound", loadTask, (t) =>
|
||||
{
|
||||
overlayColor = Color.Transparent;
|
||||
action?.Invoke();
|
||||
});
|
||||
|
||||
return loadTask;
|
||||
}
|
||||
|
||||
partial void NPCInteractProjSpecific(Character npc, Character interactor)
|
||||
{
|
||||
if (npc == null || interactor == null) { return; }
|
||||
|
||||
switch (npc.CampaignInteractionType)
|
||||
{
|
||||
case InteractionType.None:
|
||||
case InteractionType.Talk:
|
||||
return;
|
||||
case InteractionType.Upgrade when !UpgradeManager.CanUpgradeSub():
|
||||
UpgradeManager.CreateUpgradeErrorMessage(TextManager.Get("Dialog.CantUpgrade"), IsSinglePlayer, npc);
|
||||
return;
|
||||
case InteractionType.Crew when GameMain.NetworkMember != null:
|
||||
CampaignUI.CrewManagement.SendCrewState(false);
|
||||
goto default;
|
||||
default:
|
||||
ShowCampaignUI = true;
|
||||
CampaignUI.SelectTab(npc.CampaignInteractionType);
|
||||
CampaignUI.UpgradeStore?.RefreshAll();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
if (ShowCampaignUI || ForceMapUI)
|
||||
{
|
||||
campaignUIContainer?.AddToGUIUpdateList();
|
||||
if (CampaignUI?.UpgradeStore?.HoveredItem != null)
|
||||
{
|
||||
if (CampaignUI.SelectedTab != InteractionType.Upgrade) { return; }
|
||||
CampaignUI?.UpgradeStore?.ItemInfoFrame.AddToGUIUpdateList(order: 1);
|
||||
}
|
||||
}
|
||||
base.AddToGUIUpdateList();
|
||||
CrewManager.AddToGUIUpdateList();
|
||||
endRoundButton.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData is RoundSummary);
|
||||
}
|
||||
|
||||
if (ShowCampaignUI || ForceMapUI)
|
||||
{
|
||||
CampaignUI?.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal partial class CampaignMetadata
|
||||
{
|
||||
private const int MaxDrawnElements = 12;
|
||||
|
||||
public void DebugDraw(SpriteBatch spriteBatch, Vector2 pos, int debugDrawMetadataOffset, string[] ignoredMetadataInfo)
|
||||
{
|
||||
var campaignData = data;
|
||||
foreach (string ignored in ignoredMetadataInfo)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(ignored))
|
||||
{
|
||||
campaignData = campaignData.Where(pair => !pair.Key.StartsWith(ignored)).ToDictionary(i => i.Key, i => i.Value);
|
||||
}
|
||||
}
|
||||
|
||||
int offset = 0;;
|
||||
if (campaignData.Count > 0)
|
||||
{
|
||||
offset = debugDrawMetadataOffset % campaignData.Count;
|
||||
if (offset < 0) { offset += campaignData.Count; }
|
||||
}
|
||||
|
||||
var text = "Campaign metadata:\n";
|
||||
|
||||
int max = 0;
|
||||
for (int i = offset; i < campaignData.Count + offset; i++)
|
||||
{
|
||||
int index = i;
|
||||
if (index >= campaignData.Count) { index -= campaignData.Count; }
|
||||
|
||||
var (key, value) = campaignData.ElementAt(index);
|
||||
|
||||
if (max < MaxDrawnElements)
|
||||
{
|
||||
text += $"{key.ColorizeObject()}: {value.ColorizeObject()}\n";
|
||||
max++;
|
||||
}
|
||||
else
|
||||
{
|
||||
text += "Use arrow keys to scroll";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
text = text.TrimEnd('\n');
|
||||
|
||||
List<RichTextData> richTextDatas = RichTextData.GetRichTextData(text, out text) ?? new List<RichTextData>();
|
||||
|
||||
Vector2 size = GUI.SmallFont.MeasureString(text);
|
||||
Vector2 infoPos = new Vector2(GameMain.GraphicsWidth - size.X - 16, pos.Y + 8);
|
||||
Rectangle infoRect = new Rectangle(infoPos.ToPoint(), size.ToPoint());
|
||||
infoRect.Inflate(8, 8);
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.Black * 0.8f, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, infoRect, Color.White * 0.8f);
|
||||
|
||||
if (richTextDatas.Any())
|
||||
{
|
||||
GUI.DrawStringWithColors(spriteBatch, infoPos, text, Color.White, richTextDatas, font: GUI.SmallFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawString(spriteBatch, infoPos, text, Color.White, font: GUI.SmallFont);
|
||||
}
|
||||
|
||||
float y = infoRect.Bottom + 16;
|
||||
if (Campaign.Factions != null)
|
||||
{
|
||||
const string factionHeader = "Reputations";
|
||||
Vector2 factionHeaderSize = GUI.SubHeadingFont.MeasureString(factionHeader);
|
||||
Vector2 factionPos = new Vector2(GameMain.GraphicsWidth - (264 / 2) - factionHeaderSize.X / 2, y);
|
||||
|
||||
GUI.DrawString(spriteBatch, factionPos, factionHeader, Color.White, font: GUI.SubHeadingFont);
|
||||
y += factionHeaderSize.Y + 8;
|
||||
|
||||
foreach (Faction faction in Campaign.Factions)
|
||||
{
|
||||
string name = faction.Prefab.Name;
|
||||
Vector2 nameSize = GUI.SmallFont.MeasureString(name);
|
||||
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 264, y), name, Color.White, font: GUI.SmallFont);
|
||||
y += nameSize.Y + 5;
|
||||
|
||||
Color color = ToolBox.GradientLerp(faction.Reputation.NormalizedValue, Color.Red, Color.Yellow, Color.LightGreen);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(GameMain.GraphicsWidth - 264, (int) y, (int)(faction.Reputation.NormalizedValue * 255), 10), color, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(GameMain.GraphicsWidth - 264, (int) y, 256, 10), Color.White);
|
||||
y += 15;
|
||||
}
|
||||
}
|
||||
|
||||
Location location = Campaign.Map?.CurrentLocation;
|
||||
if (location?.Reputation != null)
|
||||
{
|
||||
string name = Campaign.Map?.CurrentLocation.Name;
|
||||
Vector2 nameSize = GUI.SmallFont.MeasureString(name);
|
||||
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 264, y), name, Color.White, font: GUI.SmallFont);
|
||||
y += nameSize.Y + 5;
|
||||
|
||||
float normalizedReputation = MathUtils.InverseLerp(location.Reputation.MinReputation, location.Reputation.MaxReputation, location.Reputation.Value);
|
||||
Color color = ToolBox.GradientLerp(normalizedReputation, Color.Red, Color.Yellow, Color.LightGreen);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(GameMain.GraphicsWidth - 264, (int) y, (int)(normalizedReputation * 255), 10), color, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(GameMain.GraphicsWidth - 264, (int) y, 256, 10), Color.White);
|
||||
}
|
||||
|
||||
richTextDatas.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -11,14 +13,30 @@ namespace Barotrauma
|
||||
{
|
||||
public bool SuppressStateSending = false;
|
||||
|
||||
private UInt16 startWatchmanID, endWatchmanID;
|
||||
private UInt16 pendingSaveID = 1;
|
||||
public UInt16 PendingSaveID
|
||||
{
|
||||
get
|
||||
{
|
||||
return pendingSaveID;
|
||||
}
|
||||
set
|
||||
{
|
||||
pendingSaveID = value;
|
||||
//pending save ID 0 means "no save received yet"
|
||||
//save IDs are always above 0, so we should never be waiting for 0
|
||||
if (pendingSaveID == 0) { pendingSaveID++; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void StartCampaignSetup(IEnumerable<string> saveFiles)
|
||||
{
|
||||
var parent = GameMain.NetLobbyScreen.CampaignSetupFrame;
|
||||
parent.ClearChildren();
|
||||
parent.Visible = true;
|
||||
GameMain.NetLobbyScreen.HighlightMode(2);
|
||||
GameMain.NetLobbyScreen.HighlightMode(
|
||||
GameMain.NetLobbyScreen.ModeList.Content.GetChildIndex(GameMain.NetLobbyScreen.ModeList.Content.GetChildByUserData(GameModePreset.MultiPlayerCampaign)));
|
||||
|
||||
var layout = new GUILayoutGroup(new RectTransform(Vector2.One, parent.RectTransform, Anchor.Center))
|
||||
{
|
||||
@@ -38,7 +56,7 @@ namespace Barotrauma
|
||||
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||
|
||||
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
|
||||
TextManager.Get("NewCampaign"), style: "GUITabButton")
|
||||
@@ -68,94 +86,488 @@ namespace Barotrauma
|
||||
loadCampaignContainer.Visible = false;
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(newCampaignButton.TextBlock, loadCampaignButton.TextBlock);
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI.StartNewGame = GameMain.Client.SetupNewCampaign;
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI.LoadGame = GameMain.Client.SetupLoadCampaign;
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUICanvas.Instance),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterRight)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
campaignSetupUI.StartNewGame = GameMain.Client.SetupNewCampaign;
|
||||
campaignSetupUI.LoadGame = GameMain.Client.SetupLoadCampaign;
|
||||
int buttonHeight = (int)(GUI.Scale * 40);
|
||||
int buttonWidth = GUI.IntScale(200);
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
{
|
||||
Pulse = true,
|
||||
TextBlock =
|
||||
{
|
||||
Shadow = true,
|
||||
AutoScaleHorizontal = true
|
||||
},
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
var availableTransition = GetAvailableTransition(out _, out _);
|
||||
if (Character.Controlled != null &&
|
||||
availableTransition == TransitionType.ReturnToPreviousLocation &&
|
||||
Character.Controlled?.Submarine == Level.Loaded?.StartOutpost)
|
||||
{
|
||||
GameMain.Client.RequestStartRound();
|
||||
}
|
||||
else if (Character.Controlled != null &&
|
||||
availableTransition == TransitionType.ProgressToNextLocation &&
|
||||
Character.Controlled?.Submarine == Level.Loaded?.EndOutpost)
|
||||
{
|
||||
GameMain.Client.RequestStartRound();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowCampaignUI = true;
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
CampaignUI.SelectTab(InteractionType.Map);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
buttonContainer.Recalculate();
|
||||
}
|
||||
|
||||
private void InitCampaignUI()
|
||||
{
|
||||
campaignUIContainer = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: "InnerGlow", color: Color.Black);
|
||||
CampaignUI = new CampaignUI(this, campaignUIContainer)
|
||||
{
|
||||
StartRound = () =>
|
||||
{
|
||||
GameMain.Client.RequestStartRound();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
CoroutineManager.StartCoroutine(DoInitialCameraTransition(), "MultiplayerCampaign.DoInitialCameraTransition");
|
||||
}
|
||||
|
||||
protected override void LoadInitialLevel()
|
||||
{
|
||||
//clients should never call this
|
||||
throw new InvalidOperationException("");
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<object> DoInitialCameraTransition()
|
||||
{
|
||||
while (GameMain.Instance.LoadingScreenOpen)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
if (GameMain.Client.LateCampaignJoin)
|
||||
{
|
||||
GameMain.Client.LateCampaignJoin = false;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
Character prevControlled = Character.Controlled;
|
||||
if (prevControlled?.AIController != null)
|
||||
{
|
||||
prevControlled.AIController.Enabled = false;
|
||||
}
|
||||
GUI.DisableHUD = true;
|
||||
if (IsFirstRound)
|
||||
{
|
||||
Character.Controlled = null;
|
||||
|
||||
if (prevControlled != null)
|
||||
{
|
||||
prevControlled.ClearInputs();
|
||||
}
|
||||
|
||||
overlayColor = Color.LightGray;
|
||||
overlaySprite = Map.CurrentLocation.Type.GetPortrait(Map.CurrentLocation.PortraitId);
|
||||
overlayTextColor = Color.Transparent;
|
||||
overlayText = TextManager.GetWithVariables("campaignstart",
|
||||
new string[] { "xxxx", "yyyy" },
|
||||
new string[] { Map.CurrentLocation.Name, TextManager.Get("submarineclass." + Submarine.MainSub.Info.SubmarineClass) });
|
||||
float fadeInDuration = 1.0f;
|
||||
float textDuration = 10.0f;
|
||||
float timer = 0.0f;
|
||||
while (timer < textDuration)
|
||||
{
|
||||
// Try to grab the controlled here to prevent inputs, assigned late on multiplayer
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
prevControlled = Character.Controlled;
|
||||
Character.Controlled = null;
|
||||
prevControlled.ClearInputs();
|
||||
}
|
||||
overlayTextColor = Color.Lerp(Color.Transparent, Color.White, (timer - 1.0f) / fadeInDuration);
|
||||
timer = Math.Min(timer + CoroutineManager.DeltaTime, textDuration);
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
var transition = new CameraTransition(prevControlled, GameMain.GameScreen.Cam,
|
||||
null, null,
|
||||
fadeOut: false,
|
||||
duration: 5,
|
||||
startZoom: 1.5f, endZoom: 1.0f)
|
||||
{
|
||||
AllowInterrupt = true,
|
||||
RemoveControlFromCharacter = false
|
||||
};
|
||||
fadeInDuration = 1.0f;
|
||||
timer = 0.0f;
|
||||
overlayTextColor = Color.Transparent;
|
||||
overlayText = "";
|
||||
while (timer < fadeInDuration)
|
||||
{
|
||||
overlayColor = Color.Lerp(Color.LightGray, Color.Transparent, timer / fadeInDuration);
|
||||
timer += CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
overlayColor = Color.Transparent;
|
||||
while (transition.Running)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
if (prevControlled != null)
|
||||
{
|
||||
Character.Controlled = prevControlled;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var transition = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam,
|
||||
null, null,
|
||||
fadeOut: false,
|
||||
duration: 5,
|
||||
startZoom: 0.5f, endZoom: 1.0f)
|
||||
{
|
||||
AllowInterrupt = true,
|
||||
RemoveControlFromCharacter = true
|
||||
};
|
||||
while (transition.Running)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
}
|
||||
|
||||
if (prevControlled != null)
|
||||
{
|
||||
prevControlled.SelectedConstruction = null;
|
||||
if (prevControlled.AIController != null)
|
||||
{
|
||||
prevControlled.AIController.Enabled = true;
|
||||
}
|
||||
}
|
||||
GUI.DisableHUD = false;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
|
||||
{
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private IEnumerable<object> DoLevelTransition()
|
||||
{
|
||||
SoundPlayer.OverrideMusicType = CrewManager.GetCharacters().Any(c => !c.IsDead) ? "endround" : "crewdead";
|
||||
SoundPlayer.OverrideMusicDuration = 18.0f;
|
||||
|
||||
Level prevLevel = Level.Loaded;
|
||||
|
||||
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
||||
crewDead = false;
|
||||
|
||||
var continueButton = GameMain.GameSession.RoundSummary?.ContinueButton;
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.Visible = false;
|
||||
}
|
||||
|
||||
Character.Controlled = null;
|
||||
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
GameMain.Client.EndCinematic?.Stop();
|
||||
var endTransition = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null,
|
||||
Alignment.Center,
|
||||
fadeOut: false,
|
||||
duration: EndTransitionDuration);
|
||||
GameMain.Client.EndCinematic = endTransition;
|
||||
|
||||
Location portraitLocation = Map?.SelectedLocation ?? Map?.CurrentLocation ?? Level.Loaded?.StartLocation;
|
||||
if (portraitLocation != null)
|
||||
{
|
||||
overlaySprite = portraitLocation.Type.GetPortrait(portraitLocation.PortraitId);
|
||||
}
|
||||
float fadeOutDuration = endTransition.Duration;
|
||||
float t = 0.0f;
|
||||
while (t < fadeOutDuration || endTransition.Running)
|
||||
{
|
||||
t += CoroutineManager.UnscaledDeltaTime;
|
||||
overlayColor = Color.Lerp(Color.Transparent, Color.White, t / fadeOutDuration);
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
overlayColor = Color.White;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
//wait for the new level to be loaded
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
|
||||
while (Level.Loaded == prevLevel || Level.Loaded == null)
|
||||
{
|
||||
if (DateTime.Now > timeOut || Screen.Selected != GameMain.GameScreen) { break; }
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
endTransition.Stop();
|
||||
overlayColor = Color.Transparent;
|
||||
|
||||
if (DateTime.Now > timeOut) { GameMain.NetLobbyScreen.Select(); }
|
||||
if (!(Screen.Selected is RoundSummaryScreen))
|
||||
{
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (CoroutineManager.IsCoroutineRunning("LevelTransition") || Level.Loaded == null) { return; }
|
||||
|
||||
if (ShowCampaignUI || ForceMapUI)
|
||||
{
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
Character.DisableControls = true;
|
||||
}
|
||||
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (startWatchmanID > 0 && startWatchman == null)
|
||||
if (PlayerInput.RightButtonClicked() ||
|
||||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
startWatchman = Entity.FindEntityByID(startWatchmanID) as Character;
|
||||
if (startWatchman != null) { InitializeWatchman(startWatchman); }
|
||||
ShowCampaignUI = false;
|
||||
if (GUIMessageBox.VisibleBox?.UserData is RoundSummary roundSummary &&
|
||||
roundSummary.ContinueButton != null &&
|
||||
roundSummary.ContinueButton.Visible)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
||||
}
|
||||
}
|
||||
if (endWatchmanID > 0 && endWatchman == null)
|
||||
|
||||
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
|
||||
{
|
||||
endWatchman = Entity.FindEntityByID(endWatchmanID) as Character;
|
||||
if (endWatchman != null) { InitializeWatchman(endWatchman); }
|
||||
endRoundButton.UpdateManually(deltaTime);
|
||||
if (CoroutineManager.IsCoroutineRunning("LevelTransition") || ForceMapUI) { return; }
|
||||
}
|
||||
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
if (wasDocked)
|
||||
{
|
||||
var connectedSubs = Submarine.MainSub.GetConnectedSubs();
|
||||
bool isDocked = Level.Loaded.StartOutpost != null && connectedSubs.Contains(Level.Loaded.StartOutpost);
|
||||
if (!isDocked)
|
||||
{
|
||||
//undocked from outpost, need to choose a destination
|
||||
ForceMapUI = true;
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
CampaignUI.SelectTab(InteractionType.Map);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//wasn't initially docked (sub doesn't have a docking port?)
|
||||
// -> choose a destination when the sub is far enough from the start outpost
|
||||
if (!Submarine.MainSub.AtStartPosition)
|
||||
{
|
||||
ForceMapUI = true;
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
CampaignUI.SelectTab(InteractionType.Map);
|
||||
}
|
||||
}
|
||||
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WatchmanInteract(Character watchman, Character interactor)
|
||||
public override void End(TransitionType transitionType = TransitionType.None)
|
||||
{
|
||||
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
|
||||
(watchman.Submarine == Level.Loaded.EndOutpost && !Submarine.MainSub.AtEndPosition))
|
||||
base.End(transitionType);
|
||||
ForceMapUI = ShowCampaignUI = false;
|
||||
UpgradeManager.CanUpgrade = true;
|
||||
|
||||
// remove all event dialogue boxes
|
||||
GUIMessageBox.MessageBoxes.ForEachMod(mb =>
|
||||
{
|
||||
return;
|
||||
if (mb is GUIMessageBox msgBox)
|
||||
{
|
||||
if (mb.UserData is Pair<string, ushort> pair && pair.First.Equals("conversationaction", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
msgBox.Close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (transitionType == TransitionType.End)
|
||||
{
|
||||
EndCampaign();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsFirstRound = false;
|
||||
CoroutineManager.StartCoroutine(DoLevelTransition(), "LevelTransition");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void EndCampaignProjSpecific()
|
||||
{
|
||||
if (GUIMessageBox.VisibleBox?.UserData is RoundSummary roundSummary)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
||||
}
|
||||
CoroutineManager.StartCoroutine(DoEndCampaignCameraTransition(), "DoEndCampaignCameraTransition");
|
||||
GameMain.CampaignEndScreen.OnFinished = () =>
|
||||
{
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
if (GameMain.NetLobbyScreen.ContinueCampaignButton != null) { GameMain.NetLobbyScreen.ContinueCampaignButton.Enabled = false; }
|
||||
if (GameMain.NetLobbyScreen.QuitCampaignButton != null) { GameMain.NetLobbyScreen.QuitCampaignButton.Enabled = false; }
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<object> DoEndCampaignCameraTransition()
|
||||
{
|
||||
Character controlled = Character.Controlled;
|
||||
if (controlled != null)
|
||||
{
|
||||
controlled.AIController.Enabled = false;
|
||||
}
|
||||
|
||||
if (GUIMessageBox.MessageBoxes.Any(mbox => mbox.UserData as string == "watchmanprompt"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
GUI.DisableHUD = true;
|
||||
ISpatialEntity endObject = Level.Loaded.LevelObjectManager.GetAllObjects().FirstOrDefault(obj => obj.Prefab.SpawnPos == LevelObjectPrefab.SpawnPosType.LevelEnd);
|
||||
var transition = new CameraTransition(endObject ?? Submarine.MainSub, GameMain.GameScreen.Cam,
|
||||
null, Alignment.Center,
|
||||
fadeOut: true,
|
||||
duration: 10,
|
||||
startZoom: null, endZoom: 0.2f);
|
||||
|
||||
if (GameMain.Client != null && interactor == Character.Controlled)
|
||||
while (transition.Running)
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.GetWithVariable("CampaignEnterOutpostPrompt", "[locationname]",
|
||||
Submarine.MainSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
|
||||
{
|
||||
UserData = "watchmanprompt"
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.Client.RequestRoundEnd();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
GameMain.CampaignEndScreen.Select();
|
||||
GUI.DisableHUD = false;
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
|
||||
|
||||
msg.Write(map.CurrentLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.CurrentLocationIndex);
|
||||
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
||||
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
|
||||
msg.Write(PurchasedHullRepairs);
|
||||
msg.Write(PurchasedItemRepairs);
|
||||
msg.Write(PurchasedLostShuttles);
|
||||
|
||||
msg.Write((UInt16)CargoManager.ItemsInBuyCrate.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.SoldItems.Count);
|
||||
foreach (SoldItem si in CargoManager.SoldItems)
|
||||
{
|
||||
msg.Write(si.ItemPrefab.Identifier);
|
||||
msg.Write((UInt16)si.ID);
|
||||
msg.Write(si.Removed);
|
||||
msg.Write(si.SellerID);
|
||||
}
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PurchasedUpgrades.Count);
|
||||
foreach (var (prefab, category, level) in UpgradeManager.PurchasedUpgrades)
|
||||
{
|
||||
msg.Write(prefab.Identifier);
|
||||
msg.Write(category.Identifier);
|
||||
msg.Write((byte)level);
|
||||
}
|
||||
}
|
||||
|
||||
//static because we may need to instantiate the campaign if it hasn't been done yet
|
||||
public static void ClientRead(IReadMessage msg)
|
||||
{
|
||||
byte campaignID = msg.ReadByte();
|
||||
UInt16 updateID = msg.ReadUInt16();
|
||||
UInt16 saveID = msg.ReadUInt16();
|
||||
string mapSeed = msg.ReadString();
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
byte selectedMissionIndex = msg.ReadByte();
|
||||
bool isFirstRound = msg.ReadBoolean();
|
||||
byte campaignID = msg.ReadByte();
|
||||
UInt16 updateID = msg.ReadUInt16();
|
||||
UInt16 saveID = msg.ReadUInt16();
|
||||
string mapSeed = msg.ReadString();
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
byte selectedMissionIndex = msg.ReadByte();
|
||||
float? reputation = null;
|
||||
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
|
||||
|
||||
Dictionary<string, float> factionReps = new Dictionary<string, float>();
|
||||
byte factionsCount = msg.ReadByte();
|
||||
for (int i = 0; i < factionsCount; i++)
|
||||
{
|
||||
factionReps.Add(msg.ReadString(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
UInt16 startWatchmanID = msg.ReadUInt16();
|
||||
UInt16 endWatchmanID = msg.ReadUInt16();
|
||||
bool forceMapUI = msg.ReadBoolean();
|
||||
|
||||
int money = msg.ReadInt32();
|
||||
bool purchasedHullRepairs = msg.ReadBoolean();
|
||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||
bool purchasedHullRepairs = msg.ReadBoolean();
|
||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||
|
||||
byte missionCount = msg.ReadByte();
|
||||
List<Pair<string, byte>> availableMissions = new List<Pair<string, byte>>();
|
||||
for (int i = 0; i < missionCount; i++)
|
||||
{
|
||||
string missionIdentifier = msg.ReadString();
|
||||
byte connectionIndex = msg.ReadByte();
|
||||
availableMissions.Add(new Pair<string, byte>(missionIdentifier, connectionIndex));
|
||||
}
|
||||
|
||||
UInt16? storeBalance = null;
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
storeBalance = msg.ReadUInt16();
|
||||
}
|
||||
|
||||
UInt16 buyCrateItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> buyCrateItems = new List<PurchasedItem>();
|
||||
for (int i = 0; i < buyCrateItemCount; i++)
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
|
||||
@@ -166,65 +578,129 @@ namespace Barotrauma
|
||||
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 soldItemCount = msg.ReadUInt16();
|
||||
List<SoldItem> soldItems = new List<SoldItem>();
|
||||
for (int i = 0; i < soldItemCount; i++)
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool removed = msg.ReadBoolean();
|
||||
byte sellerId = msg.ReadByte();
|
||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
|
||||
}
|
||||
|
||||
ushort pendingUpgradeCount = msg.ReadUInt16();
|
||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||
for (int i = 0; i < pendingUpgradeCount; i++)
|
||||
{
|
||||
string upgradeIdentifier = msg.ReadString();
|
||||
UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier);
|
||||
string categoryIdentifier = msg.ReadString();
|
||||
UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier);
|
||||
int upgradeLevel = msg.ReadByte();
|
||||
if (prefab == null || category == null) { continue; }
|
||||
pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||
}
|
||||
|
||||
bool hasCharacterData = msg.ReadBoolean();
|
||||
CharacterInfo myCharacterInfo = null;
|
||||
if (hasCharacterData)
|
||||
{
|
||||
myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
|
||||
}
|
||||
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
if (campaign == null || campaignID != campaign.CampaignID)
|
||||
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID)
|
||||
{
|
||||
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);
|
||||
|
||||
GameMain.GameSession = new GameSession(null, savePath,
|
||||
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
|
||||
|
||||
campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, mapSeed);
|
||||
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
|
||||
campaign.CampaignID = campaignID;
|
||||
campaign.GenerateMap(mapSeed);
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
|
||||
|
||||
//server has a newer save file
|
||||
if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID))
|
||||
{
|
||||
/*//stop any active campaign save transfers, they're outdated now
|
||||
List<FileReceiver.FileTransferIn> saveTransfers =
|
||||
GameMain.Client.FileReceiver.ActiveTransfers.FindAll(t => t.FileType == FileTransferType.CampaignSave);
|
||||
|
||||
foreach (var transfer in saveTransfers)
|
||||
{
|
||||
GameMain.Client.FileReceiver.StopTransfer(transfer);
|
||||
}
|
||||
|
||||
GameMain.Client.RequestFile(FileTransferType.CampaignSave, null, null);*/
|
||||
campaign.PendingSaveID = saveID;
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID))
|
||||
{
|
||||
campaign.SuppressStateSending = true;
|
||||
campaign.IsFirstRound = isFirstRound;
|
||||
|
||||
//we need to have the latest save file to display location/mission/store
|
||||
if (campaign.LastSaveID == saveID)
|
||||
{
|
||||
campaign.ForceMapUI = forceMapUI;
|
||||
|
||||
UpgradeStore.WaitForServerUpdate = false;
|
||||
|
||||
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
||||
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
campaign.Map.SelectMission(selectedMissionIndex);
|
||||
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
|
||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||
campaign.CargoManager.SetSoldItems(soldItems);
|
||||
if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; }
|
||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||
|
||||
foreach (var (identifier, rep) in factionReps)
|
||||
{
|
||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (faction?.Reputation != null)
|
||||
{
|
||||
faction.Reputation.Value = rep;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\".");
|
||||
}
|
||||
}
|
||||
|
||||
if (reputation.HasValue)
|
||||
{
|
||||
campaign.Map.CurrentLocation.Reputation.Value = reputation.Value;
|
||||
campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
|
||||
}
|
||||
|
||||
foreach (var availableMission in availableMissions)
|
||||
{
|
||||
MissionPrefab missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier == availableMission.First);
|
||||
if (missionPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error when receiving campaign data from the server: mission prefab \"{availableMission.First}\" not found.");
|
||||
continue;
|
||||
}
|
||||
if (availableMission.Second < 0 || availableMission.Second >= campaign.Map.CurrentLocation.Connections.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error when receiving campaign data from the server: connection index for mission \"{availableMission.First}\" out of range (index: {availableMission.Second}, current location: {campaign.Map.CurrentLocation.Name}, connections: {campaign.Map.CurrentLocation.Connections.Count}).");
|
||||
continue;
|
||||
}
|
||||
LocationConnection connection = campaign.Map.CurrentLocation.Connections[availableMission.Second];
|
||||
campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection);
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
|
||||
campaign.startWatchmanID = startWatchmanID;
|
||||
campaign.endWatchmanID = endWatchmanID;
|
||||
bool shouldRefresh = campaign.Money != money ||
|
||||
campaign.PurchasedHullRepairs != purchasedHullRepairs ||
|
||||
campaign.PurchasedItemRepairs != purchasedItemRepairs ||
|
||||
campaign.PurchasedLostShuttles != purchasedLostShuttles;
|
||||
|
||||
campaign.Money = money;
|
||||
campaign.PurchasedHullRepairs = purchasedHullRepairs;
|
||||
campaign.PurchasedItemRepairs = purchasedItemRepairs;
|
||||
campaign.PurchasedLostShuttles = purchasedLostShuttles;
|
||||
|
||||
if (shouldRefresh)
|
||||
{
|
||||
campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
|
||||
}
|
||||
|
||||
if (myCharacterInfo != null)
|
||||
{
|
||||
GameMain.Client.CharacterInfo = myCharacterInfo;
|
||||
@@ -240,9 +716,68 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientReadCrew(IReadMessage msg)
|
||||
{
|
||||
ushort availableHireLength = msg.ReadUInt16();
|
||||
List<CharacterInfo> availableHires = new List<CharacterInfo>();
|
||||
for (int i = 0; i < availableHireLength; i++)
|
||||
{
|
||||
CharacterInfo hire = CharacterInfo.ClientRead("human", msg);
|
||||
hire.Salary = msg.ReadInt32();
|
||||
availableHires.Add(hire);
|
||||
}
|
||||
|
||||
ushort pendingHireLength = msg.ReadUInt16();
|
||||
List<int> pendingHires = new List<int>();
|
||||
for (int i = 0; i < pendingHireLength; i++)
|
||||
{
|
||||
pendingHires.Add(msg.ReadInt32());
|
||||
}
|
||||
|
||||
bool validateHires = msg.ReadBoolean();
|
||||
|
||||
bool fireCharacter = msg.ReadBoolean();
|
||||
|
||||
int firedIdentifier = -1;
|
||||
if (fireCharacter) { firedIdentifier = msg.ReadInt32(); }
|
||||
|
||||
if (fireCharacter)
|
||||
{
|
||||
CharacterInfo firedCharacter = CrewManager.CharacterInfos.FirstOrDefault(info => info.GetIdentifier() == firedIdentifier);
|
||||
// this one might and is allowed to be null since the character is already fired on the original sender's game
|
||||
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
|
||||
}
|
||||
|
||||
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null)
|
||||
{
|
||||
CampaignUI?.CrewManagement?.SetHireables(map.CurrentLocation, availableHires);
|
||||
if (validateHires) { CampaignUI?.CrewManagement.ValidatePendingHires(); }
|
||||
CampaignUI?.CrewManagement?.SetPendingHires(pendingHires, map?.CurrentLocation);
|
||||
if (fireCharacter) { CampaignUI?.CrewManagement.UpdateCrew(); }
|
||||
}
|
||||
}
|
||||
|
||||
public override void Save(XElement element)
|
||||
{
|
||||
//do nothing, the clients get the save files from the server
|
||||
}
|
||||
|
||||
public void LoadState(string filePath)
|
||||
{
|
||||
DebugConsole.Log($"Loading save file for an existing game session ({filePath})");
|
||||
SaveUtil.DecompressToDirectory(filePath, SaveUtil.TempPath, null);
|
||||
|
||||
string gamesessionDocPath = Path.Combine(SaveUtil.TempPath, "gamesession.xml");
|
||||
XDocument doc = XMLExtensions.TryLoadXml(gamesessionDocPath);
|
||||
if (doc == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to load the state of a multiplayer campaign. Could not open the file \"{gamesessionDocPath}\".");
|
||||
return;
|
||||
}
|
||||
Load(doc.Root.Element("MultiPlayerCampaign"));
|
||||
SubmarineInfo selectedSub;
|
||||
GameMain.GameSession.OwnedSubmarines = SaveUtil.LoadOwnedSubmarines(doc, out selectedSub);
|
||||
GameMain.GameSession.SubmarineInfo = selectedSub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,80 +0,0 @@
|
||||
using Barotrauma.Tutorials;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SubTestMode : GameMode
|
||||
{
|
||||
public SubTestMode(GameModePreset preset, object param)
|
||||
: base(preset, param)
|
||||
{
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||
{
|
||||
for (int i = 0; i < jobPrefab.InitialCount; i++)
|
||||
{
|
||||
var variant = Rand.Range(0, jobPrefab.Variants);
|
||||
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
isRunning = true;
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
|
||||
Submarine.MainSub.SetPosition(Vector2.Zero);
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!isRunning|| GUI.DisableHUD || GUI.DisableUpperHUD) return;
|
||||
|
||||
if (Submarine.MainSub == null) return;
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
if (!isRunning) return;
|
||||
|
||||
base.AddToGUIUpdateList();
|
||||
CrewManager.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isRunning) { return; }
|
||||
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
public override void End(string endMessage = "")
|
||||
{
|
||||
isRunning = false;
|
||||
|
||||
GameMain.GameSession.EndRound("");
|
||||
|
||||
CrewManager.EndRound();
|
||||
|
||||
Submarine.Unload();
|
||||
|
||||
GameMain.SubEditorScreen.Select();
|
||||
}
|
||||
|
||||
private bool EndRound(Submarine leavingSub)
|
||||
{
|
||||
isRunning = false;
|
||||
|
||||
End("");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class TestGameMode : GameMode
|
||||
{
|
||||
public Action OnRoundEnd;
|
||||
|
||||
public TestGameMode(GameModePreset preset) : base(preset)
|
||||
{
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||
{
|
||||
for (int i = 0; i < jobPrefab.InitialCount; i++)
|
||||
{
|
||||
var variant = Rand.Range(0, jobPrefab.Variants);
|
||||
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
}
|
||||
|
||||
public override void End(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
{
|
||||
OnRoundEnd?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,7 +614,7 @@ namespace Barotrauma.Tutorials
|
||||
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
|
||||
var cinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f);
|
||||
var cinematic = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, Alignment.CenterLeft, Alignment.CenterRight, duration: 5.0f);
|
||||
|
||||
while (cinematic.Running)
|
||||
{
|
||||
|
||||
@@ -101,6 +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.GiveJobItems(null);
|
||||
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
@@ -123,14 +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.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.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.GiveJobItems();
|
||||
|
||||
captain_mechanic.CanSpeak = captain_security.CanSpeak = captain_engineer.CanSpeak = false;
|
||||
|
||||
@@ -80,6 +80,7 @@ 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.GiveJobItems(null);
|
||||
patient1.CanSpeak = false;
|
||||
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 45.0f) }, stun: 0, playSound: false);
|
||||
@@ -87,22 +88,26 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("assistant"));
|
||||
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
|
||||
patient2.TeamID = Character.TeamType.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.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.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.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient3);
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!engineer_brokenJunctionBox.IsFullCondition); // Wait until repaired
|
||||
} while (engineer_brokenJunctionBox.Condition < repairableJunctionBoxComponent.RepairThreshold); // Wait until repaired
|
||||
SetHighlight(engineer_brokenJunctionBox, false);
|
||||
RemoveCompletedObjective(segments[2]);
|
||||
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, true);
|
||||
@@ -408,15 +408,20 @@ namespace Barotrauma.Tutorials
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(4); // Repair junction box
|
||||
while (ContentRunning) yield return null;
|
||||
SetHighlight(engineer_submarineJunctionBox_1, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_2, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_3, true);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_1, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_2, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_3, engineer_repairIcon, engineer_repairIconColor);
|
||||
SetHighlight(engineer_submarineJunctionBox_1, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_2, true);
|
||||
SetHighlight(engineer_submarineJunctionBox_3, true);
|
||||
|
||||
Repairable repairableJunctionBoxComponent1 = engineer_submarineJunctionBox_1.GetComponent<Repairable>();
|
||||
Repairable repairableJunctionBoxComponent2 = engineer_submarineJunctionBox_2.GetComponent<Repairable>();
|
||||
Repairable repairableJunctionBoxComponent3 = engineer_submarineJunctionBox_3.GetComponent<Repairable>();
|
||||
|
||||
// Remove highlights when each individual machine is repaired
|
||||
do { CheckJunctionBoxHighlights(); yield return null; } while (!engineer_submarineJunctionBox_1.IsFullCondition || !engineer_submarineJunctionBox_2.IsFullCondition || !engineer_submarineJunctionBox_3.IsFullCondition);
|
||||
CheckJunctionBoxHighlights();
|
||||
do { CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3); yield return null; } while (engineer_submarineJunctionBox_1.Condition < repairableJunctionBoxComponent1.RepairThreshold || engineer_submarineJunctionBox_2.Condition < repairableJunctionBoxComponent2.RepairThreshold || engineer_submarineJunctionBox_3.Condition < repairableJunctionBoxComponent3.RepairThreshold);
|
||||
CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3);
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
@@ -557,19 +562,19 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckJunctionBoxHighlights()
|
||||
private void CheckJunctionBoxHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
|
||||
{
|
||||
if (engineer_submarineJunctionBox_1.IsFullCondition && engineer_submarineJunctionBox_1.ExternalHighlight)
|
||||
if (engineer_submarineJunctionBox_1.Condition > comp1.RepairThreshold && engineer_submarineJunctionBox_1.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_1, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_1);
|
||||
}
|
||||
if (engineer_submarineJunctionBox_2.IsFullCondition && engineer_submarineJunctionBox_2.ExternalHighlight)
|
||||
if (engineer_submarineJunctionBox_2.Condition > comp2.RepairThreshold && engineer_submarineJunctionBox_2.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_2, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_2);
|
||||
}
|
||||
if (engineer_submarineJunctionBox_3.IsFullCondition && engineer_submarineJunctionBox_3.ExternalHighlight)
|
||||
if (engineer_submarineJunctionBox_3.Condition > comp3.RepairThreshold && engineer_submarineJunctionBox_3.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(engineer_submarineJunctionBox_3, false);
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_3);
|
||||
|
||||
@@ -385,7 +385,8 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotOxygenTank && mechanic.Inventory.FindItemByIdentifier("oxygentank") != null)
|
||||
if (!gotOxygenTank && (mechanic.Inventory.FindItemByIdentifier("oxygentank") != null ||
|
||||
mechanic_deconstructor.InputContainer.Inventory.FindItemByIdentifier("oxygentank") != null))
|
||||
{
|
||||
gotOxygenTank = true;
|
||||
}
|
||||
@@ -551,7 +552,7 @@ namespace Barotrauma.Tutorials
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
if (!mechanic_brokenPump.Item.IsFullCondition)
|
||||
if (mechanic_brokenPump.Item.Condition < repairablePumpComponent.RepairThreshold)
|
||||
{
|
||||
if (!mechanic.HasEquippedItem("wrench"))
|
||||
{
|
||||
@@ -575,7 +576,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!mechanic_brokenPump.Item.IsFullCondition || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
|
||||
} while (mechanic_brokenPump.Item.Condition < repairablePumpComponent.RepairThreshold || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
|
||||
RemoveCompletedObjective(segments[9]);
|
||||
SetHighlight(mechanic_brokenPump.Item, false);
|
||||
do { yield return null; } while (mechanic_brokenhull_2.WaterPercentage > waterVolumeBeforeOpening);
|
||||
@@ -592,9 +593,14 @@ namespace Barotrauma.Tutorials
|
||||
SetHighlight(mechanic_ballastPump_1.Item, true);
|
||||
SetHighlight(mechanic_ballastPump_2.Item, true);
|
||||
SetHighlight(mechanic_submarineEngine.Item, true);
|
||||
|
||||
Repairable repairablePumpComponent1 = mechanic_ballastPump_1.Item.GetComponent<Repairable>();
|
||||
Repairable repairablePumpComponent2 = mechanic_ballastPump_2.Item.GetComponent<Repairable>();
|
||||
Repairable repairableEngineComponent = mechanic_submarineEngine.Item.GetComponent<Repairable>();
|
||||
|
||||
// Remove highlights when each individual machine is repaired
|
||||
do { CheckHighlights(); yield return null; } while (!mechanic_ballastPump_1.Item.IsFullCondition || !mechanic_ballastPump_2.Item.IsFullCondition || !mechanic_submarineEngine.Item.IsFullCondition);
|
||||
CheckHighlights();
|
||||
do { CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent); yield return null; } while (mechanic_ballastPump_1.Item.Condition < repairablePumpComponent1.RepairThreshold || mechanic_ballastPump_2.Item.Condition < repairablePumpComponent2.RepairThreshold || mechanic_submarineEngine.Item.Condition < repairableEngineComponent.RepairThreshold);
|
||||
CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent);
|
||||
RemoveCompletedObjective(segments[10]);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
@@ -617,19 +623,19 @@ namespace Barotrauma.Tutorials
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CheckHighlights()
|
||||
private void CheckHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
|
||||
{
|
||||
if (mechanic_ballastPump_1.Item.IsFullCondition && mechanic_ballastPump_1.Item.ExternalHighlight)
|
||||
if (mechanic_ballastPump_1.Item.Condition > comp1.RepairThreshold && mechanic_ballastPump_1.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_ballastPump_1.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_1.Item);
|
||||
}
|
||||
if (mechanic_ballastPump_2.Item.IsFullCondition && mechanic_ballastPump_2.Item.ExternalHighlight)
|
||||
if (mechanic_ballastPump_2.Item.Condition > comp2.RepairThreshold && mechanic_ballastPump_2.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_ballastPump_2.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_2.Item);
|
||||
}
|
||||
if (mechanic_submarineEngine.Item.IsFullCondition && mechanic_submarineEngine.Item.ExternalHighlight)
|
||||
if (mechanic_submarineEngine.Item.Condition > comp3.RepairThreshold && mechanic_submarineEngine.Item.ExternalHighlight)
|
||||
{
|
||||
SetHighlight(mechanic_submarineEngine.Item, false);
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_submarineEngine.Item);
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace Barotrauma.Tutorials
|
||||
do
|
||||
{
|
||||
float distance = Vector2.Distance(officer_coilgunPeriscope.WorldPosition, officer_hammerhead.WorldPosition);
|
||||
if (distance > originalDistance * 1.5f)
|
||||
if (distance > originalDistance * 1.5f || officer_hammerhead.WorldPosition.Y > officer_coilgunPeriscope.WorldPosition.Y)
|
||||
{
|
||||
// Don't let the Hammerhead go too far.
|
||||
officer_hammerhead.TeleportTo(officer_hammerheadSpawnPos + new Vector2(0, -1000));
|
||||
|
||||
@@ -58,30 +58,31 @@ namespace Barotrauma.Tutorials
|
||||
{
|
||||
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
|
||||
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Name == levelParams);
|
||||
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Identifier.Equals(levelParams, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
GameMain.GameSession = new GameSession(subInfo, "",
|
||||
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
|
||||
GameMain.GameSession = new GameSession(subInfo, GameModePreset.Tutorial, missionPrefab: null);
|
||||
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
|
||||
|
||||
if (generationParams != null)
|
||||
{
|
||||
Biome biome = LevelGenerationParams.GetBiomes().Find(b => generationParams.AllowedBiomes.Contains(b));
|
||||
Biome biome =
|
||||
LevelGenerationParams.GetBiomes().FirstOrDefault(b => generationParams.AllowedBiomes.Contains(b)) ??
|
||||
LevelGenerationParams.GetBiomes().First();
|
||||
|
||||
if (startOutpostPath != string.Empty)
|
||||
if (!string.IsNullOrEmpty(startOutpostPath))
|
||||
{
|
||||
startOutpost = new SubmarineInfo(startOutpostPath);
|
||||
}
|
||||
|
||||
if (endOutpostPath != string.Empty)
|
||||
if (!string.IsNullOrEmpty(endOutpostPath))
|
||||
{
|
||||
endOutpost = new SubmarineInfo(endOutpostPath);
|
||||
}
|
||||
|
||||
Level tutorialLevel = new Level(levelSeed, 0, 0, generationParams, biome, startOutpost, endOutpost);
|
||||
GameMain.GameSession.StartRound(tutorialLevel);
|
||||
LevelData tutorialLevel = new LevelData(levelSeed, 0, 0, generationParams, biome);
|
||||
GameMain.GameSession.StartRound(tutorialLevel, startOutpost: startOutpost, endOutpost: endOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -100,6 +101,13 @@ namespace Barotrauma.Tutorials
|
||||
base.Start();
|
||||
|
||||
Submarine.MainSub.GodMode = true;
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
{
|
||||
if (wall.Submarine != null && wall.Submarine.Info.IsOutpost)
|
||||
{
|
||||
wall.Indestructible = true;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterInfo charInfo = configElement.Element("Character") == null ?
|
||||
new CharacterInfo(CharacterPrefab.HumanSpeciesName, "", JobPrefab.Get("engineer")) :
|
||||
@@ -114,6 +122,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
|
||||
character = Character.Create(charInfo, wayPoint.WorldPosition, "", false, false);
|
||||
character.TeamID = Character.TeamType.Team1;
|
||||
Character.Controlled = character;
|
||||
character.GiveJobItems(null);
|
||||
|
||||
@@ -126,19 +135,14 @@ namespace Barotrauma.Tutorials
|
||||
idCard.AddTag("com");
|
||||
idCard.AddTag("eng");
|
||||
|
||||
List<Entity> entities = Entity.GetEntityList();
|
||||
|
||||
for (int i = 0; i < entities.Count; i++)
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (entities[i] is Item)
|
||||
Door door = item.GetComponent<Door>();
|
||||
if (door != null)
|
||||
{
|
||||
Door door = (entities[i] as Item).GetComponent<Door>();
|
||||
if (door != null)
|
||||
{
|
||||
door.CanBeWelded = false;
|
||||
}
|
||||
door.CanBeWelded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tutorialCoroutine = CoroutineManager.StartCoroutine(UpdateState());
|
||||
}
|
||||
@@ -284,7 +288,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
yield return new WaitForSeconds(waitBeforeFade);
|
||||
|
||||
var endCinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, fadeOutTime);
|
||||
var endCinematic = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null, Alignment.Center, duration: fadeOutTime);
|
||||
currentTutorialCompleted = Completed = true;
|
||||
while (endCinematic.Running) yield return null;
|
||||
Stop();
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Barotrauma.Tutorials
|
||||
protected enum TutorialContentTypes { None = 0, Video = 1, ManualVideo = 2, TextOnly = 3 };
|
||||
protected string playableContentPath;
|
||||
protected Point screenResolution;
|
||||
protected WindowMode windowMode;
|
||||
protected float prevUIScale;
|
||||
|
||||
private GUIFrame holderFrame, objectiveFrame;
|
||||
@@ -207,7 +208,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
{
|
||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
|
||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale || GameMain.Config.WindowMode != windowMode)
|
||||
{
|
||||
CreateObjectiveFrame();
|
||||
}
|
||||
@@ -340,6 +341,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
|
||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
windowMode = GameMain.Config.WindowMode;
|
||||
prevUIScale = GUI.Scale;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Barotrauma
|
||||
tutorial.Initialize();
|
||||
}
|
||||
|
||||
public TutorialMode(GameModePreset preset, object param)
|
||||
: base(preset, param)
|
||||
public TutorialMode(GameModePreset preset)
|
||||
: base(preset)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace Barotrauma
|
||||
base.Start();
|
||||
GameMain.GameSession.CrewManager = new CrewManager(true);
|
||||
Tutorial.Start();
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
//don't consider the items to belong in the outpost to prevent the stealing icon from showing
|
||||
item.SpawnedInOutpost = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class GameSession
|
||||
{
|
||||
public RoundSummary RoundSummary { get; private set; }
|
||||
public RoundSummary RoundSummary
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static bool IsTabMenuOpen => GameMain.GameSession?.tabMenu != null;
|
||||
public static TabMenu TabMenuInstance => GameMain.GameSession?.tabMenu;
|
||||
|
||||
|
||||
private TabMenu tabMenu;
|
||||
|
||||
public bool ToggleTabMenu()
|
||||
@@ -46,30 +51,20 @@ namespace Barotrauma
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
if (GUI.DisableHUD) { return; }
|
||||
|
||||
if (GameMode.IsRunning)
|
||||
if (tabMenu == null)
|
||||
{
|
||||
if (tabMenu == null)
|
||||
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
|
||||
{
|
||||
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
|
||||
{
|
||||
ToggleTabMenu();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tabMenu.Update();
|
||||
|
||||
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
|
||||
{
|
||||
ToggleTabMenu();
|
||||
}
|
||||
ToggleTabMenu();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tabMenu != null)
|
||||
tabMenu.Update();
|
||||
|
||||
if (PlayerInput.KeyHit(InputType.InfoTab) && GUI.KeyboardDispatcher.Subscriber is GUITextBox == false)
|
||||
{
|
||||
ToggleTabMenu();
|
||||
}
|
||||
@@ -97,7 +92,6 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
GameMode?.Draw(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,185 +1,654 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class RoundSummary
|
||||
{
|
||||
private Location startLocation, endLocation;
|
||||
private const float jobColumnWidthPercentage = 0.11f;
|
||||
private const float characterColumnWidthPercentage = 0.44f;
|
||||
private const float statusColumnWidthPercentage = 0.45f;
|
||||
|
||||
private GameSession gameSession;
|
||||
private int jobColumnWidth, characterColumnWidth, statusColumnWidth;
|
||||
|
||||
private Mission selectedMission;
|
||||
|
||||
public RoundSummary(GameSession gameSession)
|
||||
private readonly SubmarineInfo sub;
|
||||
private readonly Mission selectedMission;
|
||||
private readonly Location startLocation, endLocation;
|
||||
|
||||
private readonly GameMode gameMode;
|
||||
|
||||
private readonly float initialLocationReputation;
|
||||
private readonly Dictionary<Faction, float> initialFactionReputations = new Dictionary<Faction, float>();
|
||||
|
||||
public GUILayoutGroup ButtonArea { get; private set; }
|
||||
|
||||
public GUIButton ContinueButton { get; private set; }
|
||||
|
||||
public GUIComponent Frame { get; private set; }
|
||||
|
||||
|
||||
|
||||
public RoundSummary(SubmarineInfo sub, GameMode gameMode, Mission selectedMission, Location startLocation, Location endLocation)
|
||||
{
|
||||
this.gameSession = gameSession;
|
||||
|
||||
startLocation = gameSession.StartLocation;
|
||||
endLocation = gameSession.EndLocation;
|
||||
|
||||
selectedMission = gameSession.Mission;
|
||||
this.sub = sub;
|
||||
this.gameMode = gameMode;
|
||||
this.selectedMission = selectedMission;
|
||||
this.startLocation = startLocation;
|
||||
this.endLocation = endLocation;
|
||||
initialLocationReputation = startLocation?.Reputation?.Value ?? 0.0f;
|
||||
if (gameMode is CampaignMode campaignMode)
|
||||
{
|
||||
foreach (Faction faction in campaignMode.Factions)
|
||||
{
|
||||
initialFactionReputations.Add(faction, faction.Reputation.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GUIFrame CreateSummaryFrame(string endMessage)
|
||||
public GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, List<TraitorMissionResult> traitorResults, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
{
|
||||
bool singleplayer = GameMain.NetworkMember == null;
|
||||
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated);
|
||||
bool progress = Submarine.MainSub.AtEndPosition;
|
||||
bool gameOver =
|
||||
gameSession.GameMode.IsSinglePlayer ?
|
||||
gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated) :
|
||||
gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated || c.IsBot);
|
||||
|
||||
if (!singleplayer)
|
||||
{
|
||||
SoundPlayer.OverrideMusicType = gameOver ? "crewdead" : "endround";
|
||||
SoundPlayer.OverrideMusicDuration = 18.0f;
|
||||
}
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: "GUIBackgroundBlocker");
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(Vector2.One, background.RectTransform, Anchor.Center), style: null)
|
||||
GUIFrame background = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: "GUIBackgroundBlocker")
|
||||
{
|
||||
UserData = "roundsummary"
|
||||
UserData = this
|
||||
};
|
||||
|
||||
int width = 760, height = 500;
|
||||
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.5f), frame.RectTransform, Anchor.Center, minSize: new Point(width, height)));
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center))
|
||||
List<GUIComponent> rightPanels = new List<GUIComponent>();
|
||||
|
||||
int minWidth = 400, minHeight = 350;
|
||||
int padding = GUI.IntScale(25.0f);
|
||||
|
||||
//crew panel -------------------------------------------------------------------------------
|
||||
|
||||
GUIFrame crewFrame = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.55f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
|
||||
GUIFrame crewFrameInner = new GUIFrame(new RectTransform(new Point(crewFrame.Rect.Width - padding * 2, crewFrame.Rect.Height - padding * 2), crewFrame.RectTransform, Anchor.Center), style: "InnerFrame");
|
||||
|
||||
var crewContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), crewFrameInner.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.03f
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUIListBox infoTextBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), paddedFrame.RectTransform))
|
||||
var crewHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), crewContent.RectTransform),
|
||||
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));
|
||||
|
||||
//another crew frame for the 2nd team in combat missions
|
||||
if (gameSession.Mission is CombatMission)
|
||||
{
|
||||
Spacing = (int)(5 * GUI.Scale)
|
||||
};
|
||||
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), infoTextBox.Content.RectTransform), style: null);
|
||||
|
||||
string summaryText = TextManager.GetWithVariables(gameOver ? "RoundSummaryGameOver" :
|
||||
(progress ? "RoundSummaryProgress" : "RoundSummaryReturn"), new string[2] { "[sub]", "[location]" },
|
||||
new string[2] { Submarine.MainSub.Info.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
|
||||
|
||||
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
summaryText, wrap: true);
|
||||
|
||||
GUIComponent endText = null;
|
||||
if (!string.IsNullOrWhiteSpace(endMessage))
|
||||
{
|
||||
endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
TextManager.GetServerMessage(endMessage), wrap: true);
|
||||
crewHeader.Text = CombatMission.GetTeamName(Character.TeamType.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");
|
||||
var crewContent2 = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), crewFrameInner2.RectTransform, Anchor.Center))
|
||||
{
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
//don't show the mission info if the mission was not completed and there's no localized "mission failed" text available
|
||||
if (GameMain.GameSession.Mission != null)
|
||||
//header -------------------------------------------------------------------------------
|
||||
|
||||
string headerText = GetHeaderText(gameOver, transitionType);
|
||||
GUITextBlock headerTextBlock = null;
|
||||
if (!string.IsNullOrEmpty(headerText))
|
||||
{
|
||||
string message = GameMain.GameSession.Mission.Completed ? GameMain.GameSession.Mission.SuccessMessage : GameMain.GameSession.Mission.FailureMessage;
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
//spacing
|
||||
var spacingTransform = new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform);
|
||||
|
||||
new GUIFrame(spacingTransform, style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("Mission"), GameMain.GameSession.Mission.Name),
|
||||
font: GUI.LargeFont);
|
||||
|
||||
var missionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
message, wrap: true);
|
||||
|
||||
if (GameMain.GameSession.Mission.Completed && singleplayer)
|
||||
{
|
||||
var missionReward = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
TextManager.GetWithVariable("MissionReward", "[reward]", GameMain.GameSession.Mission.Reward.ToString()));
|
||||
}
|
||||
}
|
||||
headerTextBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), crewFrame.RectTransform, Anchor.TopLeft, Pivot.BottomLeft),
|
||||
headerText, textAlignment: Alignment.BottomLeft, font: GUI.LargeFont, wrap: true);
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||
TextManager.Get("RoundSummaryCrewStatus"), font: GUI.LargeFont);
|
||||
|
||||
GUIListBox characterListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), paddedFrame.RectTransform, minSize: new Point(0, 75)), isHorizontal: true);
|
||||
|
||||
foreach (CharacterInfo characterInfo in gameSession.CrewManager.GetCharacterInfos())
|
||||
//traitor panel -------------------------------------------------------------------------------
|
||||
|
||||
if (traitorResults != null && traitorResults.Any())
|
||||
{
|
||||
if (GameMain.GameSession.Mission is CombatMission &&
|
||||
characterInfo.TeamID != GameMain.GameSession.WinningTeam)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
GUIFrame traitorframe = new GUIFrame(new RectTransform(crewFrame.RectTransform.RelativeSize, background.RectTransform, Anchor.TopCenter, minSize: crewFrame.RectTransform.MinSize));
|
||||
rightPanels.Add(traitorframe);
|
||||
GUIFrame traitorframeInner = new GUIFrame(new RectTransform(new Point(traitorframe.Rect.Width - padding * 2, traitorframe.Rect.Height - padding * 2), traitorframe.RectTransform, Anchor.Center), style: "InnerFrame");
|
||||
|
||||
var characterFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), characterListBox.Content.RectTransform, minSize: new Point(170, 0)))
|
||||
var traitorContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), traitorframeInner.RectTransform, Anchor.Center))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
characterInfo.CreateCharacterFrame(characterFrame,
|
||||
characterInfo.Job != null ? (characterInfo.Name + '\n' + "(" + characterInfo.Job.Name + ")") : characterInfo.Name, null);
|
||||
var traitorHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorContent.RectTransform),
|
||||
TextManager.Get("traitors"), font: GUI.SubHeadingFont);
|
||||
traitorHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(traitorHeader.Rect.Height * 2.0f));
|
||||
|
||||
string statusText = TextManager.Get("StatusOK");
|
||||
Color statusColor = Color.DarkGreen;
|
||||
GUIListBox listBox = CreateCrewList(traitorContent, traitorResults.SelectMany(tr => tr.Characters.Select(c => c.Info)));
|
||||
|
||||
Character character = characterInfo.Character;
|
||||
if (character == null || character.IsDead)
|
||||
foreach (var traitorResult in traitorResults)
|
||||
{
|
||||
if (characterInfo.CauseOfDeath == null)
|
||||
var traitorMission = TraitorMissionPrefab.List.Find(t => t.Identifier == traitorResult.MissionIdentifier);
|
||||
if (traitorMission == null) { continue; }
|
||||
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(25)), listBox.Content.RectTransform), style: null);
|
||||
|
||||
var traitorResultHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), listBox.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
{
|
||||
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||
RelativeSpacing = 0.05f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUIImage(new RectTransform(new Point(traitorResultHorizontal.Rect.Height), traitorResultHorizontal.RectTransform), traitorMission.Icon, scaleToFit: true)
|
||||
{
|
||||
Color = traitorMission.IconColor
|
||||
};
|
||||
|
||||
string traitorMessage = TextManager.GetServerMessage(traitorResult.EndMessage);
|
||||
if (!string.IsNullOrEmpty(traitorMessage))
|
||||
{
|
||||
var textContent = new GUILayoutGroup(new RectTransform(Vector2.One, traitorResultHorizontal.RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.025f
|
||||
};
|
||||
|
||||
var traitorStatusText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
|
||||
TextManager.Get(traitorResult.Success ? "missioncompleted" : "missionfailed"),
|
||||
textColor: traitorResult.Success ? GUI.Style.Green : GUI.Style.Red, font: GUI.SubHeadingFont);
|
||||
|
||||
var traitorMissionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
|
||||
traitorMessage, font: GUI.SmallFont, wrap: true);
|
||||
|
||||
traitorResultHorizontal.Recalculate();
|
||||
|
||||
traitorStatusText.CalculateHeightFromText();
|
||||
traitorMissionInfo.CalculateHeightFromText();
|
||||
traitorStatusText.RectTransform.MinSize = new Point(0, traitorStatusText.Rect.Height);
|
||||
traitorMissionInfo.RectTransform.MinSize = new Point(0, traitorMissionInfo.Rect.Height);
|
||||
textContent.RectTransform.MaxSize = new Point(int.MaxValue, (int)((traitorStatusText.Rect.Height + traitorMissionInfo.Rect.Height) * 1.2f));
|
||||
traitorResultHorizontal.RectTransform.MinSize = new Point(0, traitorStatusText.RectTransform.MinSize.Y + traitorMissionInfo.RectTransform.MinSize.Y);
|
||||
}
|
||||
else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
|
||||
}
|
||||
}
|
||||
|
||||
//reputation panel -------------------------------------------------------------------------------
|
||||
|
||||
if (gameMode is CampaignMode campaignMode)
|
||||
{
|
||||
GUIFrame reputationframe = new GUIFrame(new RectTransform(crewFrame.RectTransform.RelativeSize, background.RectTransform, Anchor.TopCenter, minSize: crewFrame.RectTransform.MinSize));
|
||||
rightPanels.Add(reputationframe);
|
||||
GUIFrame reputationframeInner = new GUIFrame(new RectTransform(new Point(reputationframe.Rect.Width - padding * 2, reputationframe.Rect.Height - padding * 2), reputationframe.RectTransform, Anchor.Center), style: "InnerFrame");
|
||||
|
||||
var reputationContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), reputationframeInner.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var reputationHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), reputationContent.RectTransform),
|
||||
TextManager.Get("reputation"), textAlignment: Alignment.TopLeft, font: GUI.SubHeadingFont);
|
||||
reputationHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(reputationHeader.Rect.Height * 2.0f));
|
||||
|
||||
GUIListBox reputationList = new GUIListBox(new RectTransform(Vector2.One, reputationContent.RectTransform))
|
||||
{
|
||||
Padding = new Vector4(2, 5, 0, 0)
|
||||
};
|
||||
reputationList.ContentBackground.Color = Color.Transparent;
|
||||
|
||||
if (startLocation.Type.HasOutpost && startLocation.Reputation != null)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("LocationReputationIcon");
|
||||
CreateReputationElement(
|
||||
reputationList.Content,
|
||||
startLocation.Name,
|
||||
startLocation.Reputation.Value, startLocation.Reputation.NormalizedValue, initialLocationReputation,
|
||||
startLocation.Type.Name, "",
|
||||
iconStyle?.GetDefaultSprite(), startLocation.Type.GetPortrait(0), iconStyle?.Color ?? Color.White);
|
||||
}
|
||||
|
||||
foreach (Faction faction in campaignMode.Factions)
|
||||
{
|
||||
float initialReputation = faction.Reputation.Value;
|
||||
if (initialFactionReputations.ContainsKey(faction))
|
||||
{
|
||||
string errorMsg = "Character \"" + character.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||
initialReputation = initialFactionReputations[faction];
|
||||
}
|
||||
else
|
||||
{
|
||||
statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ?
|
||||
characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
|
||||
TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
|
||||
DebugConsole.AddWarning($"Could not determine reputation change for faction \"{faction.Prefab.Name}\" (faction was not present at the start of the round).");
|
||||
}
|
||||
CreateReputationElement(
|
||||
reputationList.Content,
|
||||
faction.Prefab.Name,
|
||||
faction.Reputation.Value, faction.Reputation.NormalizedValue, initialReputation,
|
||||
faction.Prefab.ShortDescription, faction.Prefab.Description,
|
||||
faction.Prefab.Icon, faction.Prefab.BackgroundPortrait, faction.Prefab.IconColor);
|
||||
}
|
||||
|
||||
float otherElementHeight = 0.0f;
|
||||
float maxDescriptionHeight = 0.0f;
|
||||
foreach (GUIComponent child in reputationList.Content.Children)
|
||||
{
|
||||
var descriptionElement = child.FindChild("description", recursive: true) as GUITextBlock;
|
||||
maxDescriptionHeight = Math.Max(maxDescriptionHeight, descriptionElement.TextSize.Y * 1.1f);
|
||||
otherElementHeight = Math.Max(otherElementHeight, descriptionElement.Parent.Rect.Height - descriptionElement.TextSize.Y);
|
||||
}
|
||||
foreach (GUIComponent child in reputationList.Content.Children)
|
||||
{
|
||||
var descriptionElement = child.FindChild("description", recursive: true) as GUITextBlock;
|
||||
descriptionElement.RectTransform.MaxSize = new Point(int.MaxValue, (int)(maxDescriptionHeight));
|
||||
child.RectTransform.MaxSize = new Point(int.MaxValue, (int)((maxDescriptionHeight + otherElementHeight) * 1.2f));
|
||||
(descriptionElement?.Parent as GUILayoutGroup).Recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
//mission panel -------------------------------------------------------------------------------
|
||||
|
||||
GUIFrame missionframe = new GUIFrame(new RectTransform(new Vector2(0.39f, 0.22f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight / 4)));
|
||||
GUIFrame missionframeInner = new GUIFrame(new RectTransform(new Point(missionframe.Rect.Width - padding * 2, missionframe.Rect.Height - padding * 2), missionframe.RectTransform, Anchor.Center), style: "InnerFrame");
|
||||
|
||||
var missionContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), missionframeInner.RectTransform, Anchor.Center))
|
||||
{
|
||||
RelativeSpacing = 0.05f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(endMessage))
|
||||
{
|
||||
var endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionContent.RectTransform),
|
||||
TextManager.GetServerMessage(endMessage), wrap: true);
|
||||
endText.RectTransform.MinSize = new Point(0, endText.Rect.Height);
|
||||
var line = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), missionContent.RectTransform), style: "HorizontalLine");
|
||||
line.RectTransform.NonScaledSize = new Point(line.Rect.Width, GUI.IntScale(5.0f));
|
||||
}
|
||||
|
||||
var missionContentHorizontal = new GUILayoutGroup(new RectTransform(Vector2.One, missionContent.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.025f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
Mission displayedMission = selectedMission ?? startLocation.SelectedMission;
|
||||
string missionMessage = "";
|
||||
GUIImage missionIcon;
|
||||
if (displayedMission != null)
|
||||
{
|
||||
missionMessage =
|
||||
displayedMission == selectedMission ?
|
||||
displayedMission.Completed ? displayedMission.SuccessMessage : displayedMission.FailureMessage :
|
||||
displayedMission.Description;
|
||||
missionIcon = new GUIImage(new RectTransform(new Point(missionContentHorizontal.Rect.Height), missionContentHorizontal.RectTransform), displayedMission.Prefab.Icon, scaleToFit: true)
|
||||
{
|
||||
Color = displayedMission.Prefab.IconColor
|
||||
};
|
||||
if (displayedMission == selectedMission)
|
||||
{
|
||||
new GUIImage(new RectTransform(Vector2.One, missionIcon.RectTransform), displayedMission.Completed ? "MissionCompletedIcon" : "MissionFailedIcon", scaleToFit: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
missionIcon = new GUIImage(new RectTransform(new Point(missionContentHorizontal.Rect.Height), missionContentHorizontal.RectTransform), style: "NoMissionIcon", scaleToFit: true);
|
||||
}
|
||||
var missionTextContent = new GUILayoutGroup(new RectTransform(Vector2.One, missionContentHorizontal.RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
missionContentHorizontal.Recalculate();
|
||||
missionContent.Recalculate();
|
||||
missionIcon.RectTransform.MinSize = new Point(0, missionContentHorizontal.Rect.Height);
|
||||
missionTextContent.RectTransform.MaxSize = new Point(int.MaxValue, missionIcon.Rect.Width);
|
||||
|
||||
GUITextBlock missionDescription = null;
|
||||
if (displayedMission == null)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
||||
TextManager.Get("nomission"), font: GUI.LargeFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("Mission"), displayedMission.Name), font: GUI.SubHeadingFont);
|
||||
missionDescription = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
||||
missionMessage, wrap: true);
|
||||
if (displayedMission == selectedMission && displayedMission.Completed)
|
||||
{
|
||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", displayedMission.Reward));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
||||
TextManager.GetWithVariable("MissionReward", "[reward]", rewardText));
|
||||
}
|
||||
}
|
||||
|
||||
ButtonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), missionContent.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomRight)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
RelativeSpacing = 0.025f
|
||||
};
|
||||
|
||||
ContinueButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), ButtonArea.RectTransform), TextManager.Get("Close"));
|
||||
ButtonArea.RectTransform.NonScaledSize = new Point(ButtonArea.Rect.Width, ContinueButton.Rect.Height);
|
||||
ButtonArea.RectTransform.IsFixedSize = true;
|
||||
|
||||
missionContent.Recalculate();
|
||||
//description overlapping with the buttons -> switch to small font
|
||||
if (missionDescription != null && missionDescription.Rect.Y + missionDescription.TextSize.Y > ButtonArea.Rect.Y)
|
||||
{
|
||||
missionDescription.Font = GUI.Style.SmallFont;
|
||||
//still overlapping -> shorten the text
|
||||
if (missionDescription.Rect.Y + missionDescription.TextSize.Y > ButtonArea.Rect.Y && missionDescription.WrappedText.Contains('\n'))
|
||||
{
|
||||
missionDescription.ToolTip = missionDescription.Text;
|
||||
missionDescription.Text = missionDescription.WrappedText.Split('\n').First() + "...";
|
||||
}
|
||||
}
|
||||
|
||||
// set layout -------------------------------------------------------------------
|
||||
|
||||
int panelSpacing = GUI.IntScale(20);
|
||||
int totalHeight = crewFrame.Rect.Height + panelSpacing + missionframe.Rect.Height;
|
||||
int totalWidth = crewFrame.Rect.Width;
|
||||
|
||||
crewFrame.RectTransform.AbsoluteOffset = new Point(0, (GameMain.GraphicsHeight - totalHeight) / 2);
|
||||
missionframe.RectTransform.AbsoluteOffset = new Point(0, crewFrame.Rect.Bottom + panelSpacing);
|
||||
|
||||
if (rightPanels.Any())
|
||||
{
|
||||
totalWidth = crewFrame.Rect.Width * 2 + panelSpacing;
|
||||
if (headerTextBlock != null)
|
||||
{
|
||||
headerTextBlock.RectTransform.MinSize = new Point(totalWidth, 0);
|
||||
}
|
||||
crewFrame.RectTransform.AbsoluteOffset = new Point(-(crewFrame.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
|
||||
foreach (var rightPanel in rightPanels)
|
||||
{
|
||||
rightPanel.RectTransform.AbsoluteOffset = new Point((rightPanel.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gameSession.GameMode is CampaignMode))
|
||||
{
|
||||
var shadow = new GUIFrame(new RectTransform(new Point((int)(totalWidth * 1.2f), GameMain.GraphicsHeight * 2), background.RectTransform, Anchor.Center), style: "OuterGlow")
|
||||
{
|
||||
Color = Color.Black
|
||||
};
|
||||
shadow.RectTransform.SetAsFirstChild();
|
||||
}
|
||||
|
||||
Frame = background;
|
||||
return background;
|
||||
}
|
||||
|
||||
private string GetHeaderText(bool gameOver, CampaignMode.TransitionType transitionType)
|
||||
{
|
||||
string locationName = Submarine.MainSub.AtEndPosition ? endLocation?.Name : startLocation?.Name;
|
||||
|
||||
string textTag;
|
||||
if (gameOver)
|
||||
{
|
||||
textTag = "RoundSummaryGameOver";
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (transitionType)
|
||||
{
|
||||
case CampaignMode.TransitionType.LeaveLocation:
|
||||
locationName = startLocation?.Name;
|
||||
textTag = "RoundSummaryLeaving";
|
||||
break;
|
||||
case CampaignMode.TransitionType.ProgressToNextLocation:
|
||||
case CampaignMode.TransitionType.ProgressToNextEmptyLocation:
|
||||
locationName = endLocation?.Name;
|
||||
textTag = "RoundSummaryProgress";
|
||||
break;
|
||||
case CampaignMode.TransitionType.ReturnToPreviousLocation:
|
||||
case CampaignMode.TransitionType.ReturnToPreviousEmptyLocation:
|
||||
locationName = startLocation?.Name;
|
||||
textTag = "RoundSummaryReturn";
|
||||
break;
|
||||
default:
|
||||
textTag = Submarine.MainSub.AtEndPosition ? "RoundSummaryProgress" : "RoundSummaryReturn";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (textTag == null) { return ""; }
|
||||
|
||||
if (locationName == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error while creating round summary: could not determine destination location. Start location: {startLocation?.Name ?? "null"}, end location: {endLocation?.Name ?? "null"}");
|
||||
locationName = "[UNKNOWN]";
|
||||
}
|
||||
|
||||
string subName = string.Empty;
|
||||
SubmarineInfo currentOrPending = SubmarineSelection.CurrentOrPendingSubmarine();
|
||||
if (currentOrPending != null)
|
||||
{
|
||||
subName = currentOrPending.DisplayName;
|
||||
}
|
||||
|
||||
return TextManager.GetWithVariables(textTag, new string[2] { "[sub]", "[location]" }, new string[2] { subName, locationName });
|
||||
}
|
||||
|
||||
private GUIListBox CreateCrewList(GUIComponent parent, IEnumerable<CharacterInfo> characterInfos)
|
||||
{
|
||||
var headerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.0f), parent.RectTransform, Anchor.TopCenter, minSize: new Point(0, (int)(30 * GUI.Scale))) { }, isHorizontal: true)
|
||||
{
|
||||
AbsoluteSpacing = 2
|
||||
};
|
||||
GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton statusButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("label.statuslabel"), style: "GUIButtonSmallFreeScale");
|
||||
|
||||
float sizeMultiplier = 1.0f;
|
||||
//sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
|
||||
|
||||
jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
characterButton.RectTransform.RelativeSize = new Vector2(characterColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
statusButton.RectTransform.RelativeSize = new Vector2(statusColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
|
||||
jobButton.TextBlock.Font = characterButton.TextBlock.Font = statusButton.TextBlock.Font = GUI.HotkeyFont;
|
||||
jobButton.CanBeFocused = characterButton.CanBeFocused = statusButton.CanBeFocused = false;
|
||||
jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase = statusButton.ForceUpperCase = true;
|
||||
|
||||
jobColumnWidth = jobButton.Rect.Width;
|
||||
characterColumnWidth = characterButton.Rect.Width;
|
||||
statusColumnWidth = statusButton.Rect.Width;
|
||||
|
||||
GUIListBox crewList = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform))
|
||||
{
|
||||
Padding = new Vector4(2, 5, 0, 0),
|
||||
AutoHideScrollBar = false
|
||||
};
|
||||
crewList.ContentBackground.Color = Color.Transparent;
|
||||
|
||||
headerFrame.RectTransform.RelativeSize -= new Vector2(crewList.ScrollBar.RectTransform.RelativeSize.X, 0.0f);
|
||||
|
||||
foreach (CharacterInfo characterInfo in characterInfos)
|
||||
{
|
||||
if (characterInfo == null) { continue; }
|
||||
CreateCharacterElement(characterInfo, crewList);
|
||||
}
|
||||
|
||||
return crewList;
|
||||
}
|
||||
|
||||
private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox)
|
||||
{
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = characterInfo,
|
||||
Color = (Character.Controlled?.Info == characterInfo) ? TabMenu.OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AbsoluteSpacing = 2,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => characterInfo.DrawJobIcon(sb, component.Rect))
|
||||
{
|
||||
ToolTip = characterInfo.Job.Name ?? "",
|
||||
HoverColor = Color.White,
|
||||
SelectedColor = Color.White
|
||||
};
|
||||
|
||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(characterInfo.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor);
|
||||
|
||||
string statusText = TextManager.Get("StatusOK");
|
||||
Color statusColor = GUI.Style.Green;
|
||||
|
||||
Character character = characterInfo.Character;
|
||||
if (character == null || character.IsDead)
|
||||
{
|
||||
if (characterInfo.IsNewHire)
|
||||
{
|
||||
statusText = TextManager.Get("CampaignCrew.NewHire");
|
||||
statusColor = GUI.Style.Blue;
|
||||
}
|
||||
else if (characterInfo.CauseOfDeath == null)
|
||||
{
|
||||
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||
statusColor = Color.DarkRed;
|
||||
}
|
||||
else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
|
||||
{
|
||||
string errorMsg = "Character \"" + characterInfo.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||
statusColor = GUI.Style.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (character.IsUnconscious)
|
||||
{
|
||||
statusText = TextManager.Get("Unconscious");
|
||||
statusColor = Color.DarkOrange;
|
||||
}
|
||||
else if (character.Vitality / character.MaxVitality < 0.8f)
|
||||
{
|
||||
statusText = TextManager.Get("Injured");
|
||||
statusColor = Color.DarkOrange;
|
||||
}
|
||||
statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ?
|
||||
characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
|
||||
TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
|
||||
statusColor = Color.DarkRed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (character.IsUnconscious)
|
||||
{
|
||||
statusText = TextManager.Get("Unconscious");
|
||||
statusColor = Color.DarkOrange;
|
||||
}
|
||||
else if (character.Vitality / character.MaxVitality < 0.8f)
|
||||
{
|
||||
statusText = TextManager.Get("Injured");
|
||||
statusColor = Color.DarkOrange;
|
||||
}
|
||||
|
||||
var textHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), characterFrame.RectTransform, Anchor.BottomCenter), style: "InnerGlow", color: statusColor);
|
||||
new GUITextBlock(new RectTransform(Vector2.One, textHolder.RectTransform, Anchor.Center),
|
||||
statusText, Color.White,
|
||||
textAlignment: Alignment.Center,
|
||||
wrap: true, font: GUI.SmallFont, style: null);
|
||||
}
|
||||
|
||||
new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.BottomRight)
|
||||
GUITextBlock statusBlock = new GUITextBlock(new RectTransform(new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(statusText, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: statusColor);
|
||||
}
|
||||
|
||||
private void CreateReputationElement(GUIComponent parent,
|
||||
string name, float reputation, float normalizedReputation, float initialReputation,
|
||||
string shortDescription, string fullDescription, Sprite icon, Sprite backgroundPortrait, Color iconColor)
|
||||
{
|
||||
var factionFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), parent.RectTransform), style: null);
|
||||
|
||||
if (backgroundPortrait != null)
|
||||
{
|
||||
RelativeSpacing = 0.05f,
|
||||
UserData = "buttonarea"
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, factionFrame.RectTransform), onDraw: (sb, customComponent) =>
|
||||
{
|
||||
backgroundPortrait.Draw(sb, customComponent.Rect.Center.ToVector2(), customComponent.Color, backgroundPortrait.size / 2, scale: customComponent.Rect.Width / backgroundPortrait.size.X);
|
||||
})
|
||||
{
|
||||
HideElementsOutsideFrame = true,
|
||||
IgnoreLayoutGroups = true,
|
||||
Color = iconColor * 0.2f
|
||||
};
|
||||
}
|
||||
|
||||
var factionInfoHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), factionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.02f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
foreach (GUIComponent child in infoTextBox.Content.Children)
|
||||
var factionTextContent = new GUILayoutGroup(new RectTransform(Vector2.One, factionInfoHorizontal.RectTransform))
|
||||
{
|
||||
child.CanBeFocused = false;
|
||||
if (child is GUITextBlock textBlock)
|
||||
{
|
||||
textBlock.CalculateHeightFromText();
|
||||
}
|
||||
RelativeSpacing = 0.05f,
|
||||
Stretch = true
|
||||
};
|
||||
var factionIcon = new GUIImage(new RectTransform(new Point((int)(factionInfoHorizontal.Rect.Height * 0.7f)), factionInfoHorizontal.RectTransform, scaleBasis: ScaleBasis.Smallest), icon, scaleToFit: true)
|
||||
{
|
||||
Color = iconColor
|
||||
};
|
||||
factionInfoHorizontal.Recalculate();
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), factionTextContent.RectTransform),
|
||||
name, font: GUI.SubHeadingFont)
|
||||
{
|
||||
Padding = Vector4.Zero
|
||||
};
|
||||
var factionDescription = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.6f), factionTextContent.RectTransform),
|
||||
shortDescription, font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
UserData = "description",
|
||||
Padding = Vector4.Zero
|
||||
};
|
||||
if (shortDescription != fullDescription && !string.IsNullOrEmpty(fullDescription))
|
||||
{
|
||||
factionDescription.ToolTip = fullDescription;
|
||||
}
|
||||
|
||||
return frame;
|
||||
var sliderHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), factionTextContent.RectTransform),
|
||||
childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.05f,
|
||||
Stretch = true
|
||||
};
|
||||
sliderHolder.RectTransform.MaxSize = new Point(int.MaxValue, GUI.IntScale(25.0f));
|
||||
factionTextContent.Recalculate();
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.8f, 1.0f), sliderHolder.RectTransform), onDraw: (sb, customComponent) =>
|
||||
{
|
||||
GUI.DrawRectangle(sb, customComponent.Rect, GUI.Style.ColorInventoryBackground, isFilled: true);
|
||||
if (normalizedReputation < 0.5f)
|
||||
{
|
||||
int barWidth = (int)((0.5f - normalizedReputation) * customComponent.Rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(customComponent.Rect.Center.X - barWidth, customComponent.Rect.Y, barWidth, customComponent.Rect.Height), GUI.Style.Red, isFilled: true);
|
||||
}
|
||||
else if (normalizedReputation > 0.5f)
|
||||
{
|
||||
int barWidth = (int)((normalizedReputation - 0.5f) * customComponent.Rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(customComponent.Rect.Center.X, customComponent.Rect.Y, barWidth, customComponent.Rect.Height), GUI.Style.Green, isFilled: true);
|
||||
}
|
||||
GUI.DrawLine(sb, new Vector2(customComponent.Rect.Center.X, customComponent.Rect.Y - 2), new Vector2(customComponent.Rect.Center.X, customComponent.Rect.Bottom + 2), factionDescription.TextColor, width: 1);
|
||||
});
|
||||
|
||||
string reputationText = ((int)Math.Round(reputation)).ToString();
|
||||
int reputationChange = (int)Math.Round( reputation - initialReputation);
|
||||
if (Math.Abs(reputationChange) > 0)
|
||||
{
|
||||
string changeText = $"{(reputationChange > 0 ? "+" : "") + reputationChange}";
|
||||
string colorStr = XMLExtensions.ColorToString(reputationChange > 0 ? GUI.Style.Green : GUI.Style.Red);
|
||||
var rtData = RichTextData.GetRichTextData($"{reputationText} (‖color:{colorStr}‖{changeText}‖color:end‖)", out string sanitizedText);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), sliderHolder.RectTransform),
|
||||
rtData, sanitizedText,
|
||||
textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), sliderHolder.RectTransform),
|
||||
reputationText,
|
||||
textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class UpgradeManager
|
||||
{
|
||||
partial void UpgradeNPCSpeak(string text, bool isSinglePlayer, Character? character)
|
||||
{
|
||||
if (Level.Loaded?.StartOutpost?.Info?.OutpostNPCs == null) { return; }
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
Speak(character);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Character npc in Level.Loaded.StartOutpost.Info.OutpostNPCs.SelectMany(kpv => kpv.Value))
|
||||
{
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.Upgrade)
|
||||
{
|
||||
Speak(npc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Speak(Character npc)
|
||||
{
|
||||
ChatMessage message = ChatMessage.Create(npc.Name, text, ChatMessageType.Default, npc);
|
||||
if (!isSinglePlayer)
|
||||
{
|
||||
GameMain.Client?.AddChatMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server has notified us that upgrades were reset.
|
||||
/// </summary>
|
||||
/// <param name="inc"></param>
|
||||
/// <see cref="UpgradeManager.SendUpgradeResetMessage"/>
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
bool shouldReset = inc.ReadBoolean();
|
||||
int money = inc.ReadInt32();
|
||||
// uint length = inc.ReadUInt32();
|
||||
//
|
||||
// for (int i = 0; i < length; i++)
|
||||
// {
|
||||
// string key = inc.ReadString();
|
||||
// byte value = inc.ReadByte();
|
||||
// Metadata.SetValue(key, value);
|
||||
// }
|
||||
|
||||
Campaign.Money = money;
|
||||
|
||||
if (shouldReset)
|
||||
{
|
||||
ResetUpgrades();
|
||||
}
|
||||
|
||||
// spentMoney is local, so this message box should only appear for those who have spent money on upgrades
|
||||
if (spentMoney > 0)
|
||||
{
|
||||
GUIMessageBox msgBox = new GUIMessageBox(TextManager.Get("UpgradeRefundTitle"), TextManager.Get("UpgradeRefundBody"), new [] { TextManager.Get("Ok") });
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
}
|
||||
|
||||
spentMoney = 0;
|
||||
PendingUpgrades.Clear();
|
||||
PurchasedUpgrades.Clear();
|
||||
CanUpgrade = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -761,6 +761,44 @@ namespace Barotrauma
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
#if (!OSX)
|
||||
AudioDeviceNames = Alc.GetStringList((IntPtr)null, Alc.AllDevicesSpecifier);
|
||||
if (string.IsNullOrEmpty(AudioOutputDevice))
|
||||
{
|
||||
AudioOutputDevice = Alc.GetString((IntPtr)null, Alc.DefaultDeviceSpecifier);
|
||||
if (AudioDeviceNames.Any() && !AudioDeviceNames.Any(n => n.Equals(AudioOutputDevice, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
AudioOutputDevice = AudioDeviceNames[0];
|
||||
}
|
||||
}
|
||||
|
||||
var outputDeviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), audioContent.RectTransform), TrimAudioDeviceName(AudioOutputDevice), AudioDeviceNames.Count);
|
||||
if (AudioDeviceNames?.Count > 0)
|
||||
{
|
||||
foreach (string name in AudioDeviceNames)
|
||||
{
|
||||
outputDeviceList.AddItem(TrimAudioDeviceName(name), name);
|
||||
}
|
||||
outputDeviceList.OnSelected = (GUIComponent selected, object obj) =>
|
||||
{
|
||||
string name = obj as string;
|
||||
if (!GameMain.SoundManager.Disconnected && AudioOutputDevice == name) { return true; }
|
||||
|
||||
AudioOutputDevice = name;
|
||||
GameMain.SoundManager.InitializeAlcDevice(AudioOutputDevice);
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
outputDeviceList.AddItem(TextManager.Get("AudioNoDevices") ?? "N/A", null);
|
||||
outputDeviceList.ButtonTextColor = GUI.Style.Red;
|
||||
outputDeviceList.ButtonEnabled = false;
|
||||
outputDeviceList.Select(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(textBlockScale, audioContent.RectTransform), TextManager.Get("SoundVolume"), font: GUI.SubHeadingFont);
|
||||
GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(textBlockScale, audioContent.RectTransform),
|
||||
style: "GUISlider", barSize: 0.05f)
|
||||
@@ -893,7 +931,7 @@ namespace Barotrauma
|
||||
deviceList.OnSelected = (GUIComponent selected, object obj) =>
|
||||
{
|
||||
string name = obj as string;
|
||||
if (VoiceCaptureDevice == name) { return true; }
|
||||
if (!(VoipCapture.Instance?.Disconnected ?? true) && VoiceCaptureDevice == name) { return true; }
|
||||
|
||||
VoipCapture.ChangeCaptureDevice(name);
|
||||
return true;
|
||||
@@ -1179,12 +1217,16 @@ namespace Barotrauma
|
||||
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 };
|
||||
inputNameBlocks.Add(inputName);
|
||||
string keyText = KeyBindText((InputType)i);
|
||||
var keyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), inputContainer.RectTransform),
|
||||
text: KeyBindText((InputType)i), font: GUI.SmallFont, style: "GUITextBoxNoIcon")
|
||||
text: keyText, font: GUI.SmallFont, style: "GUITextBoxNoIcon")
|
||||
{
|
||||
UserData = i
|
||||
};
|
||||
keyBox.Text = ToolBox.LimitString(keyBox.Text, keyBox.Font, (int)(keyBox.Rect.Width - keyBox.Padding.X - keyBox.Padding.Z));
|
||||
keyBox.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
keyBox.Text = ToolBox.LimitString(keyText, keyBox.Font, (int)(keyBox.Rect.Width - keyBox.Padding.X - keyBox.Padding.Z));
|
||||
};
|
||||
keyBox.OnSelected += KeyBoxSelected;
|
||||
keyBox.SelectedColor = Color.Gold * 0.3f;
|
||||
}
|
||||
@@ -1337,6 +1379,16 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
var automaticCampaignLoadTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Automatic campaign load enabled", style: "GUITickBox");
|
||||
automaticCampaignLoadTickBox.Selected = AutomaticCampaignLoadEnabled;
|
||||
automaticCampaignLoadTickBox.ToolTip = "Will the game automatically load the latest campaign save when the game is launched";
|
||||
automaticCampaignLoadTickBox.OnSelected = (tickBox) =>
|
||||
{
|
||||
AutomaticCampaignLoadEnabled = tickBox.Selected;
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
var showSplashScreenTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Splash screen enabled", style: "GUITickBox");
|
||||
showSplashScreenTickBox.Selected = EnableSplashScreen;
|
||||
showSplashScreenTickBox.ToolTip = "Are the splash screens shown when the game is launched";
|
||||
@@ -1520,8 +1572,7 @@ namespace Barotrauma
|
||||
{
|
||||
return GameMain.Client == null &&
|
||||
(ContentPackage.IngameModSwap ||
|
||||
(Screen.Selected != GameMain.GameScreen &&
|
||||
Screen.Selected != GameMain.LobbyScreen) &&
|
||||
Screen.Selected != GameMain.GameScreen &&
|
||||
Screen.Selected != GameMain.SubEditorScreen) &&
|
||||
(!core ||
|
||||
(Screen.Selected != GameMain.CharacterEditorScreen &&
|
||||
|
||||
@@ -35,6 +35,26 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
|
||||
public static Dictionary<InvSlotType, Sprite> LimbSlotIcons
|
||||
{
|
||||
get
|
||||
{
|
||||
if (limbSlotIcons == null)
|
||||
{
|
||||
limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
|
||||
int margin = 2;
|
||||
limbSlotIcons.Add(InvSlotType.Headset, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(384 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.InnerClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(512 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.Card, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(640 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
|
||||
limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
}
|
||||
return limbSlotIcons;
|
||||
}
|
||||
}
|
||||
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
|
||||
@@ -88,7 +108,7 @@ namespace Barotrauma
|
||||
|
||||
indicatorGroup = new GUILayoutGroup(new RectTransform(Point.Zero, hideButton.RectTransform)) { IsHorizontal = false };
|
||||
indicatorGroup.ChildAnchor = Anchor.TopCenter;
|
||||
indicatorSpriteSize = GUI.Style.GetComponentStyle("EquipmentIndicatorDivingSuit").Sprites[GUIComponent.ComponentState.None][0].Sprite.size;
|
||||
indicatorSpriteSize = GUI.Style.GetComponentStyle("EquipmentIndicatorDivingSuit").GetDefaultSprite().size;
|
||||
|
||||
indicators[0] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorDivingSuit");
|
||||
indicators[1] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorID");
|
||||
@@ -115,20 +135,6 @@ namespace Barotrauma
|
||||
|
||||
hidePersonalSlots = false;
|
||||
|
||||
if (limbSlotIcons == null)
|
||||
{
|
||||
limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
|
||||
|
||||
int margin = 2;
|
||||
limbSlotIcons.Add(InvSlotType.Headset, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(384 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.InnerClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(512 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.Card, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(640 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
|
||||
limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
}
|
||||
SlotPositions = new Vector2[SlotTypes.Length];
|
||||
CurrentLayout = Layout.Default;
|
||||
SetSlotPositions(layout);
|
||||
@@ -522,14 +528,7 @@ namespace Barotrauma
|
||||
if (hoverOnInventory) { HideTimer = 0.5f; }
|
||||
if (HideTimer > 0.0f) { HideTimer -= deltaTime; }
|
||||
|
||||
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))
|
||||
{
|
||||
QuickUseItem(Items[i], true, false, true);
|
||||
}
|
||||
}
|
||||
UpdateSlotInput();
|
||||
|
||||
//force personal slots open if an item is running out of battery/fuel/oxygen/etc
|
||||
if (hidePersonalSlots)
|
||||
@@ -685,6 +684,18 @@ namespace Barotrauma
|
||||
doubleClickedItem = null;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
QuickUseItem(Items[i], true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleButtonEquipStates(Item item, InventorySlot slot, float deltaTime)
|
||||
{
|
||||
slot.EquipButtonState = slot.EquipButtonRect.Contains(PlayerInput.MousePosition) ?
|
||||
@@ -1084,9 +1095,9 @@ namespace Barotrauma
|
||||
!Items[i].AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||
{
|
||||
//draw limb icons on empty slots
|
||||
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
|
||||
if (LimbSlotIcons.ContainsKey(SlotTypes[i]))
|
||||
{
|
||||
var icon = limbSlotIcons[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);
|
||||
}
|
||||
continue;
|
||||
@@ -1096,12 +1107,12 @@ namespace Barotrauma
|
||||
//draw hand icons if the item is equipped in a hand slot
|
||||
if (IsInLimbSlot(Items[i], InvSlotType.LeftHand))
|
||||
{
|
||||
var icon = limbSlotIcons[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);
|
||||
}
|
||||
if (IsInLimbSlot(Items[i], InvSlotType.RightHand))
|
||||
{
|
||||
var icon = limbSlotIcons[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);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void UpdateConvexHulls()
|
||||
{
|
||||
if (item.Removed) { return; }
|
||||
|
||||
doorRect = new Rectangle(
|
||||
item.Rect.Center.X - (int)(doorSprite.size.X / 2 * item.Scale),
|
||||
item.Rect.Y - item.Rect.Height / 2 + (int)(doorSprite.size.Y / 2.0f * item.Scale),
|
||||
@@ -92,8 +94,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (convexHull == null) return;
|
||||
|
||||
if (convexHull == null) { return; }
|
||||
|
||||
if (rect.Height == 0 || rect.Width == 0)
|
||||
{
|
||||
@@ -128,7 +130,7 @@ namespace Barotrauma.Items.Components
|
||||
if (brokenSprite == null)
|
||||
{
|
||||
//broken doors turn black if no broken sprite has been configured
|
||||
color *= (item.Condition / item.Prefab.Health);
|
||||
color *= (item.Condition / item.MaxCondition);
|
||||
color.A = 255;
|
||||
}
|
||||
|
||||
@@ -162,10 +164,10 @@ namespace Barotrauma.Items.Components
|
||||
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||
}
|
||||
|
||||
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
||||
if (brokenSprite != null && item.Health < item.MaxCondition)
|
||||
{
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.Prefab.Health) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.Prefab.Health : 1.0f;
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
|
||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
|
||||
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
|
||||
@@ -188,10 +190,10 @@ namespace Barotrauma.Items.Components
|
||||
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
|
||||
}
|
||||
|
||||
if (brokenSprite != null && item.Health < item.Prefab.Health)
|
||||
if (brokenSprite != null && item.Health < item.MaxCondition)
|
||||
{
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.Prefab.Health, 1.0f) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.Prefab.Health : 1.0f;
|
||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition, 1.0f) : Vector2.One;
|
||||
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
|
||||
spriteBatch.Draw(brokenSprite.Texture, pos,
|
||||
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
|
||||
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
crosshairSprite?.Remove();
|
||||
crosshairSprite = null;
|
||||
crosshairPointerSprite?.Remove();
|
||||
|
||||
@@ -186,7 +186,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool shouldMuffleLooping;
|
||||
private float lastMuffleCheckTime;
|
||||
private ItemSound loopingSound;
|
||||
@@ -295,8 +294,6 @@ namespace Barotrauma.Items.Components
|
||||
PlaySound(matchingSounds[index], item.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void PlaySound(ItemSound itemSound, Vector2 position)
|
||||
{
|
||||
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > itemSound.Range * itemSound.Range)
|
||||
@@ -387,7 +384,6 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public ItemComponent GetLinkUIToComponent()
|
||||
{
|
||||
if (string.IsNullOrEmpty(LinkUIToComponent))
|
||||
@@ -431,13 +427,8 @@ namespace Barotrauma.Items.Components
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - GUIFrame defined as rect, use RectTransform instead.");
|
||||
break;
|
||||
}
|
||||
|
||||
Color? color = null;
|
||||
if (subElement.Attribute("color") != null) color = subElement.GetAttributeColor("color", Color.White);
|
||||
string style = subElement.Attribute("style") == null ?
|
||||
null : subElement.GetAttributeString("style", "");
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas.ItemComponentHolder, Anchor.Center), style, color);
|
||||
DefaultLayout = GUILayoutSettings.Load(subElement);
|
||||
GuiFrameSource = subElement;
|
||||
ReloadGuiFrame();
|
||||
break;
|
||||
case "alternativelayout":
|
||||
AlternativeLayout = GUILayoutSettings.Load(subElement);
|
||||
@@ -501,6 +492,42 @@ namespace Barotrauma.Items.Components
|
||||
return true; //element processed
|
||||
}
|
||||
|
||||
private XElement GuiFrameSource;
|
||||
|
||||
protected void ReleaseGuiFrame()
|
||||
{
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
GuiFrame.RectTransform.Parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void ReloadGuiFrame()
|
||||
{
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
ReleaseGuiFrame();
|
||||
}
|
||||
Color? color = null;
|
||||
if (GuiFrameSource.Attribute("color") != null)
|
||||
{
|
||||
color = GuiFrameSource.GetAttributeColor("color", Color.White);
|
||||
}
|
||||
string style = GuiFrameSource.Attribute("style") == null ? null : GuiFrameSource.GetAttributeString("style", "");
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas.ItemComponentHolder, Anchor.Center), style, color);
|
||||
DefaultLayout = GUILayoutSettings.Load(GuiFrameSource);
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
GuiFrame.RectTransform.ParentChanged += OnGUIParentChanged;
|
||||
}
|
||||
GameMain.Instance.ResolutionChanged += OnResolutionChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overload this method and implement. The method is automatically called when the resolution changes.
|
||||
/// </summary>
|
||||
protected virtual void CreateGUI() { }
|
||||
|
||||
//Starts a coroutine that will read the correct state of the component from the NetBuffer when correctionTimer reaches zero.
|
||||
protected void StartDelayedCorrection(ServerNetObject type, IReadMessage buffer, float sendingTime, bool waitForMidRoundSync = false)
|
||||
{
|
||||
@@ -530,5 +557,29 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launches when the parent of the GuiFrame is changed.
|
||||
/// </summary>
|
||||
protected void OnGUIParentChanged(RectTransform newParent)
|
||||
{
|
||||
if (newParent == null)
|
||||
{
|
||||
// Make sure to unregister. It doesn't matter if we haven't ever registered to the event.
|
||||
GameMain.Instance.ResolutionChanged -= OnResolutionChangedPrivate;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnResolutionChanged() { }
|
||||
|
||||
private void OnResolutionChangedPrivate()
|
||||
{
|
||||
if (RecreateGUIOnResolutionChange)
|
||||
{
|
||||
ReloadGuiFrame();
|
||||
CreateGUI();
|
||||
}
|
||||
OnResolutionChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private GUICustomComponent guiCustomComponent;
|
||||
|
||||
private Point prevResolution;
|
||||
|
||||
public Sprite InventoryTopSprite
|
||||
{
|
||||
get { return inventoryTopSprite; }
|
||||
@@ -115,16 +113,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
GuiFrame.RectTransform.ParentChanged += OnGUIParentChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if a GUIFrame has been defined, draw the inventory inside it
|
||||
CreateGUI();
|
||||
prevResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var content = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
||||
style: null)
|
||||
@@ -167,16 +165,6 @@ namespace Barotrauma.Items.Components
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
|
||||
|
||||
if ((prevResolution.X > 0 && prevResolution.Y > 0) &&
|
||||
(prevResolution.X != GameMain.GraphicsWidth || prevResolution.Y != GameMain.GraphicsHeight))
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
|
||||
prevResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
DrawContainedItems(spriteBatch, itemDepth);
|
||||
}
|
||||
|
||||
@@ -238,7 +226,7 @@ namespace Barotrauma.Items.Components
|
||||
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
|
||||
|
||||
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth;
|
||||
containedSpriteDepth = itemDepth + (containedSpriteDepth - item.SpriteDepth) / 10000.0f;
|
||||
containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
|
||||
|
||||
containedItem.Sprite.Draw(
|
||||
spriteBatch,
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float[] charWidths;
|
||||
|
||||
[Serialize("0,0,0,0", true, description: "The amount of padding around the text in pixels (left,top,right,bottom). ")]
|
||||
[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; }
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return text; }
|
||||
set
|
||||
{
|
||||
if (value == text || item.Rect.Width < 5) return;
|
||||
if (value == text || item.Rect.Width < 5) { return; }
|
||||
|
||||
if (TextBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return textColor; }
|
||||
set
|
||||
{
|
||||
if (textBlock != null) textBlock.TextColor = value;
|
||||
if (textBlock != null) { textBlock.TextColor = value; }
|
||||
textColor = value;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return textBlock == null ? 1.0f : textBlock.TextScale; }
|
||||
set
|
||||
{
|
||||
if (textBlock != null) textBlock.TextScale = MathHelper.Clamp(value, 0.1f, 10.0f);
|
||||
if (textBlock != null) { textBlock.TextScale = MathHelper.Clamp(value, 0.1f, 10.0f); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Barotrauma.Items.Components
|
||||
if (textBlock == null)
|
||||
{
|
||||
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
|
||||
textColor: textColor, font: GUI.UnscaledSmallFont, textAlignment: Alignment.Center, wrap: true, style: null)
|
||||
textColor: textColor, font: GUI.UnscaledSmallFont, textAlignment: scrollable ? Alignment.CenterLeft : Alignment.Center, wrap: true, style: null)
|
||||
{
|
||||
TextDepth = item.SpriteDepth - 0.00001f,
|
||||
RoundToNearestPixel = false,
|
||||
|
||||
@@ -27,8 +27,9 @@ namespace Barotrauma.Items.Components
|
||||
if (backgroundSprite == null) { return; }
|
||||
|
||||
backgroundSprite.DrawTiled(spriteBatch,
|
||||
new Vector2(item.DrawPosition.X - item.Rect.Width / 2, -(item.DrawPosition.Y + item.Rect.Height / 2)) - backgroundSprite.Origin,
|
||||
new Vector2(backgroundSprite.size.X, item.Rect.Height), color: item.Color,
|
||||
new Vector2(item.DrawPosition.X - item.Rect.Width / 2 * item.Scale, -(item.DrawPosition.Y + item.Rect.Height / 2)) - backgroundSprite.Origin * item.Scale,
|
||||
new Vector2(backgroundSprite.size.X * item.Scale, item.Rect.Height), color: item.Color,
|
||||
textureScale: Vector2.One * item.Scale,
|
||||
depth: BackgroundSpriteDepth);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -74,6 +75,21 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void CreateEditingHUD(SerializableEntityEditor editor)
|
||||
{
|
||||
base.CreateEditingHUD(editor);
|
||||
|
||||
foreach (LimbPos limbPos in limbPositions)
|
||||
{
|
||||
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(limbPos);
|
||||
|
||||
PropertyDescriptor limbPosProperty = properties.Find("Position", false);
|
||||
editor.CreateVector2Field(limbPos, new SerializableProperty(limbPosProperty), limbPos.Position, limbPos.LimbType.ToString(), "");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
State = msg.ReadBoolean();
|
||||
|
||||
@@ -23,17 +23,15 @@ namespace Barotrauma.Items.Components
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
CreateGUI();
|
||||
GameMain.Instance.OnResolutionChanged += RecreateGUI;
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
base.OnResolutionChanged();
|
||||
OnItemLoadedProjSpecific();
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.90f, 0.80f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
@@ -170,10 +168,5 @@ namespace Barotrauma.Items.Components
|
||||
SetActive(msg.ReadBoolean());
|
||||
progressTimer = msg.ReadSingle();
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged -= RecreateGUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,15 @@ namespace Barotrauma.Items.Components
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
CreateGUI();
|
||||
GameMain.Instance.OnResolutionChanged += RecreateGUI;
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
base.OnResolutionChanged();
|
||||
OnItemLoadedProjSpecific();
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter);
|
||||
|
||||
@@ -242,8 +240,8 @@ namespace Barotrauma.Items.Components
|
||||
var item1 = c1.GUIComponent.UserData as FabricationRecipe;
|
||||
var item2 = c2.GUIComponent.UserData as FabricationRecipe;
|
||||
|
||||
bool hasSkills1 = DegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
|
||||
bool hasSkills2 = DegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
|
||||
bool hasSkills1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
|
||||
bool hasSkills2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
|
||||
|
||||
if (hasSkills1 != hasSkills2)
|
||||
{
|
||||
@@ -267,7 +265,7 @@ namespace Barotrauma.Items.Components
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
};
|
||||
var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && DegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f);
|
||||
var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && FabricationDegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f);
|
||||
if (firstinSufficient != null)
|
||||
{
|
||||
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
||||
@@ -476,7 +474,7 @@ namespace Barotrauma.Items.Components
|
||||
List<Skill> inadequateSkills = new List<Skill>();
|
||||
if (user != null)
|
||||
{
|
||||
inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => user.GetSkillLevel(skill.Identifier) < skill.Level);
|
||||
inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => user.GetSkillLevel(skill.Identifier) < Math.Round(skill.Level * SkillRequirementMultiplier));
|
||||
}
|
||||
|
||||
if (selectedItem.RequiredSkills.Any())
|
||||
@@ -489,13 +487,13 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
foreach (Skill skill in selectedItem.RequiredSkills)
|
||||
{
|
||||
text += TextManager.Get("SkillName." + skill.Identifier) + " " + TextManager.Get("Lvl").ToLower() + " " + skill.Level;
|
||||
text += TextManager.Get("SkillName." + skill.Identifier) + " " + TextManager.Get("Lvl").ToLower() + " " + Math.Round(skill.Level * SkillRequirementMultiplier);
|
||||
if (skill != selectedItem.RequiredSkills.Last()) { text += "\n"; }
|
||||
}
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform), text, font: GUI.SmallFont);
|
||||
}
|
||||
|
||||
float degreeOfSuccess = user == null ? 0.0f : DegreeOfSuccess(user, selectedItem.RequiredSkills);
|
||||
float degreeOfSuccess = user == null ? 0.0f : FabricationDegreeOfSuccess(user, selectedItem.RequiredSkills);
|
||||
if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; }
|
||||
|
||||
float requiredTime = user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user);
|
||||
@@ -621,10 +619,5 @@ namespace Barotrauma.Items.Components
|
||||
StartFabricating(fabricationRecipes[itemIndex], user);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged -= RecreateGUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,17 @@ namespace Barotrauma.Items.Components
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
noPowerTip = TextManager.Get("SteeringNoPowerTip");
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
base.OnResolutionChanged();
|
||||
CreateHUD();
|
||||
}
|
||||
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.05f, 0.0f);
|
||||
GuiFrame.CanBeFocused = true;
|
||||
new GUICustomComponent(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
||||
@@ -53,7 +63,11 @@ namespace Barotrauma.Items.Components
|
||||
hullAirQualityText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "") { Wrap = true };
|
||||
hullWaterText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "") { Wrap = true };
|
||||
|
||||
hullInfoFrame.Children.ForEach(c => { c.CanBeFocused = false; c.Children.ForEach(c2 => c2.CanBeFocused = false); });
|
||||
hullInfoFrame.Children.ForEach(c =>
|
||||
{
|
||||
c.CanBeFocused = false;
|
||||
c.Children.ForEach(c2 => c2.CanBeFocused = false);
|
||||
});
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
@@ -72,7 +86,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
submarineContainer.ClearChildren();
|
||||
|
||||
if (item.Submarine == null) return;
|
||||
if (item.Submarine == null) { return; }
|
||||
|
||||
item.Submarine.CreateMiniMap(submarineContainer);
|
||||
displayedSubs.Clear();
|
||||
@@ -125,10 +139,8 @@ namespace Barotrauma.Items.Components
|
||||
GUI.Style.Orange * (float)Math.Abs(Math.Sin(Timing.TotalTime)), Color.Black * 0.8f, font: GUI.SubHeadingFont);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!submarineContainer.Children.Any()) { return; }
|
||||
|
||||
foreach (GUIComponent child in submarineContainer.Children.First().Children)
|
||||
foreach (GUIComponent child in submarineContainer.Children.FirstOrDefault()?.Children)
|
||||
{
|
||||
if (child.UserData is Hull hull)
|
||||
{
|
||||
@@ -177,9 +189,19 @@ namespace Barotrauma.Items.Components
|
||||
HashSet<Submarine> subs = new HashSet<Submarine>();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine == null) continue;
|
||||
if (hull.Submarine == null) { continue; }
|
||||
var hullFrame = submarineContainer.Children.FirstOrDefault()?.FindChild(hull);
|
||||
if (hullFrame == null) continue;
|
||||
if (hullFrame == null) { continue; }
|
||||
|
||||
hullFrame.Visible = true;
|
||||
if (!submarineContainer.Rect.Contains(hullFrame.Rect))
|
||||
{
|
||||
if (hull.Submarine.Info.Type != SubmarineType.Player)
|
||||
{
|
||||
hullFrame.Visible = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
hullDatas.TryGetValue(hull, out HullData hullData);
|
||||
if (hullData == null)
|
||||
@@ -294,7 +316,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (Submarine sub in subs)
|
||||
{
|
||||
if (sub.HullVertices == null) { continue; }
|
||||
if (sub.HullVertices == null || sub.Info.IsOutpost) { continue; }
|
||||
|
||||
Rectangle worldBorders = sub.GetDockedBorders();
|
||||
worldBorders.Location += sub.WorldPosition.ToPoint();
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class OutpostTerminal : ItemComponent
|
||||
{
|
||||
private SubmarineSelection selectionUI;
|
||||
|
||||
public override bool Select(Character character)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectionUI == null)
|
||||
{
|
||||
selectionUI = new SubmarineSelection(true, null, GUICanvas.Instance.ItemComponentHolder);
|
||||
}
|
||||
|
||||
GuiFrame = selectionUI.GuiFrame;
|
||||
selectionUI.RefreshSubmarineDisplay(true);
|
||||
IsActive = true;
|
||||
return base.Select(character);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (Character.Controlled?.SelectedConstruction != item)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
base.Update(deltaTime, cam);
|
||||
|
||||
if (selectionUI != null)
|
||||
{
|
||||
selectionUI.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,16 +157,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
CreateGUI();
|
||||
GameMain.Instance.OnResolutionChanged += RecreateGUI;
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
base.OnResolutionChanged();
|
||||
UpdateGUIElements();
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
bool isConnectedToSteering = item.GetComponent<Steering>() != null;
|
||||
Vector2 size = isConnectedToSteering ? controlBoxSize : new Vector2(controlBoxSize.X * 2.0f, controlBoxSize.Y);
|
||||
@@ -667,23 +666,27 @@ namespace Barotrauma.Items.Components
|
||||
signalWarningText.Visible = false;
|
||||
}
|
||||
|
||||
if (GameMain.GameSession == null) { return; }
|
||||
if (GameMain.GameSession == null || Level.Loaded == null) { return; }
|
||||
|
||||
if (Level.Loaded == null) { return; }
|
||||
if (Level.Loaded.StartLocation != null)
|
||||
{
|
||||
DrawMarker(spriteBatch,
|
||||
Level.Loaded.StartLocation.Name,
|
||||
"outpost",
|
||||
Level.Loaded.StartLocation.Name,
|
||||
Level.Loaded.StartPosition, transducerCenter,
|
||||
displayScale, center, DisplayRadius);
|
||||
}
|
||||
|
||||
DrawMarker(spriteBatch,
|
||||
GameMain.GameSession.StartLocation.Name,
|
||||
"outpost",
|
||||
GameMain.GameSession.StartLocation.Name,
|
||||
Level.Loaded.StartPosition, transducerCenter,
|
||||
displayScale, center, DisplayRadius);
|
||||
|
||||
DrawMarker(spriteBatch,
|
||||
GameMain.GameSession.EndLocation.Name,
|
||||
"outpost",
|
||||
GameMain.GameSession.EndLocation.Name,
|
||||
Level.Loaded.EndPosition, transducerCenter,
|
||||
displayScale, center, DisplayRadius);
|
||||
if (Level.Loaded.EndLocation != null && Level.Loaded.Type == LevelData.LevelType.LocationConnection)
|
||||
{
|
||||
DrawMarker(spriteBatch,
|
||||
Level.Loaded.EndLocation.Name,
|
||||
"outpost",
|
||||
Level.Loaded.EndLocation.Name,
|
||||
Level.Loaded.EndPosition, transducerCenter,
|
||||
displayScale, center, DisplayRadius);
|
||||
}
|
||||
|
||||
foreach (AITarget aiTarget in AITarget.List)
|
||||
{
|
||||
@@ -1444,8 +1447,6 @@ namespace Barotrauma.Items.Components
|
||||
sprite.Remove();
|
||||
}
|
||||
targetIcons.Clear();
|
||||
|
||||
GameMain.Instance.OnResolutionChanged -= RecreateGUI;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool? swapDestinationOrder;
|
||||
|
||||
private GUIMessageBox enterOutpostPrompt;
|
||||
|
||||
private bool levelStartSelected;
|
||||
public bool LevelStartSelected
|
||||
{
|
||||
@@ -105,10 +107,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
CreateGUI();
|
||||
GameMain.Instance.OnResolutionChanged += RecreateGUI;
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
controlContainer = new GUIFrame(new RectTransform(new Vector2(Sonar.controlBoxSize.X, 1 - Sonar.controlBoxSize.Y * 2), GuiFrame.RectTransform, Anchor.CenterLeft), "ItemUI");
|
||||
var paddedControlContainer = new GUIFrame(new RectTransform(controlContainer.Rect.Size - GUIStyle.ItemFrameMargin, controlContainer.RectTransform, Anchor.Center)
|
||||
@@ -220,11 +221,12 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
|
||||
levelEndTickBox = new GUITickBox(new RectTransform(new Vector2(1, 0.333f), paddedAutoPilotControls.RectTransform, Anchor.BottomCenter),
|
||||
GameMain.GameSession?.EndLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, textLimit),
|
||||
(GameMain.GameSession?.EndLocation == null || Level.IsLoadedOutpost) ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, textLimit),
|
||||
font: GUI.SmallFont, style: "GUIRadioButton")
|
||||
{
|
||||
Enabled = autoPilot,
|
||||
Selected = levelEndSelected,
|
||||
Visible = GameMain.GameSession?.EndLocation != null,
|
||||
OnSelected = tickBox =>
|
||||
{
|
||||
if (levelEndSelected != tickBox.Selected)
|
||||
@@ -321,7 +323,7 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
break;
|
||||
}
|
||||
new GUITextBlock(new RectTransform(Vector2.One, left.RectTransform), leftText, font: GUI.SubHeadingFont, wrap: true, textAlignment: Alignment.CenterRight);
|
||||
new GUITextBlock(new RectTransform(Vector2.One, left.RectTransform), leftText, font: GUI.SubHeadingFont, wrap: leftText.Contains(' '), textAlignment: Alignment.CenterRight);
|
||||
new GUITextBlock(new RectTransform(Vector2.One, center.RectTransform), centerText, font: GUI.Font, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
||||
var digitalFrame = new GUIFrame(new RectTransform(Vector2.One, right.RectTransform), style: "DigitalFrameDark");
|
||||
new GUITextBlock(new RectTransform(Vector2.One * 0.85f, digitalFrame.RectTransform, Anchor.Center), "12345", GUI.Style.TextColorDark, GUI.DigitalFont, Alignment.CenterRight)
|
||||
@@ -347,18 +349,47 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
|
||||
if (GameMain.GameSession?.Campaign != null)
|
||||
{
|
||||
item.SendSignal(0, "1", "toggle_docking", sender: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
dockingNetworkMessagePending = true;
|
||||
item.CreateClientEvent(this);
|
||||
if (Level.IsLoadedOutpost &&
|
||||
DockingSources.Any(d => d.Docked && (d.DockingTarget?.Item.Submarine?.Info?.IsOutpost ?? false)))
|
||||
{
|
||||
GameMain.GameSession.Campaign.CampaignUI.SelectTab(CampaignMode.InteractionType.Map);
|
||||
GameMain.GameSession.Campaign.ShowCampaignUI = true;
|
||||
return false;
|
||||
}
|
||||
else if (!Level.IsLoadedOutpost && DockingModeEnabled && ActiveDockingSource != null &&
|
||||
!ActiveDockingSource.Docked && (DockingTarget?.Item?.Submarine?.Info.IsOutpost ?? false))
|
||||
{
|
||||
enterOutpostPrompt = new GUIMessageBox("", TextManager.GetWithVariable("campaignenteroutpostprompt", "[locationname]", DockingTarget.Item.Submarine.Info.Name), new string[] { TextManager.Get("yes"), TextManager.Get("no") });
|
||||
enterOutpostPrompt.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
SendDockingSignal();
|
||||
enterOutpostPrompt.Close();
|
||||
return true;
|
||||
};
|
||||
enterOutpostPrompt.Buttons[1].OnClicked += enterOutpostPrompt.Close;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SendDockingSignal();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
void SendDockingSignal()
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
item.SendSignal(0, "1", "toggle_docking", sender: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
dockingNetworkMessagePending = true;
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
}
|
||||
dockingButton.Font = GUI.SubHeadingFont;
|
||||
dockingButton.TextBlock.RectTransform.MaxSize = new Point((int)(dockingButton.Rect.Width * 0.7f), int.MaxValue);
|
||||
dockingButton.TextBlock.AutoScaleHorizontal = true;
|
||||
@@ -413,10 +444,9 @@ namespace Barotrauma.Items.Components
|
||||
GameMain.GameSession?.EndLocation == null ? "End" : GameMain.GameSession.EndLocation.Name);
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
base.OnResolutionChanged();
|
||||
UpdateGUIElements();
|
||||
}
|
||||
|
||||
@@ -600,6 +630,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
dockingContainer.Visible = DockingModeEnabled;
|
||||
statusContainer.Visible = !DockingModeEnabled;
|
||||
if (!DockingModeEnabled)
|
||||
{
|
||||
enterOutpostPrompt?.Close();
|
||||
}
|
||||
|
||||
if (DockingModeEnabled && ActiveDockingSource != null)
|
||||
{
|
||||
@@ -613,6 +647,10 @@ namespace Barotrauma.Items.Components
|
||||
dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enterOutpostPrompt?.Close();
|
||||
}
|
||||
}
|
||||
else if (DockingSources.Any(d => d.Docked))
|
||||
{
|
||||
@@ -663,7 +701,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen)
|
||||
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen &&
|
||||
(!GameMain.GameSession?.Campaign?.ShowCampaignUI ?? true) && !GUIMessageBox.MessageBoxes.Any())
|
||||
{
|
||||
Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2();
|
||||
inputPos.Y = -inputPos.Y;
|
||||
@@ -800,8 +839,7 @@ namespace Barotrauma.Items.Components
|
||||
maintainPosIndicator?.Remove();
|
||||
maintainPosOriginIndicator?.Remove();
|
||||
steeringIndicator?.Remove();
|
||||
|
||||
GameMain.Instance.OnResolutionChanged -= RecreateGUI;
|
||||
enterOutpostPrompt?.Close();
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -111,27 +111,28 @@ namespace Barotrauma.Items.Components
|
||||
if (item.FlippedX && item.Prefab.CanSpriteFlipX) { indicatorPos.X = -indicatorPos.X - indicatorSize.X * item.Scale; }
|
||||
if (item.FlippedY && item.Prefab.CanSpriteFlipY) { indicatorPos.Y = -indicatorPos.Y - indicatorSize.Y * item.Scale; }
|
||||
|
||||
if (charge > 0)
|
||||
if (charge > 0 && capacity > 0)
|
||||
{
|
||||
Color indicatorColor = ToolBox.GradientLerp(charge / capacity, Color.Red, Color.Orange, Color.Green);
|
||||
float chargeRatio = MathHelper.Clamp(charge / capacity, 0.0f, 1.0f);
|
||||
Color indicatorColor = ToolBox.GradientLerp(chargeRatio, Color.Red, Color.Orange, Color.Green);
|
||||
if (!isHorizontal)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y + ((indicatorSize.Y * item.Scale) * (1.0f - charge / capacity))) + indicatorPos,
|
||||
new Vector2(indicatorSize.X * item.Scale, (indicatorSize.Y * item.Scale) * (charge / capacity)), indicatorColor, true,
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y + ((indicatorSize.Y * item.Scale) * (1.0f - chargeRatio))) + indicatorPos,
|
||||
new Vector2(indicatorSize.X * item.Scale, (indicatorSize.Y * item.Scale) * chargeRatio), indicatorColor, true,
|
||||
depth: item.SpriteDepth - 0.00001f);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y) + indicatorPos,
|
||||
new Vector2((indicatorSize.X * item.Scale) * (charge / capacity), indicatorSize.Y * item.Scale), indicatorColor, true,
|
||||
new Vector2((indicatorSize.X * item.Scale) * chargeRatio, indicatorSize.Y * item.Scale), indicatorColor, true,
|
||||
depth: item.SpriteDepth - 0.00001f);
|
||||
}
|
||||
}
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y) + indicatorPos,
|
||||
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.00001f);
|
||||
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.000015f);
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData)
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma.Items.Components
|
||||
var progressBar = user.UpdateHUDProgressBar(
|
||||
targetStructure.ID * 1000 + sectionIndex, //unique "identifier" for each wall section
|
||||
progressBarPos,
|
||||
1.0f - targetStructure.SectionDamage(sectionIndex) / targetStructure.Health,
|
||||
MathUtils.InverseLerp(targetStructure.Prefab.MinHealth, targetStructure.Health, targetStructure.Health - targetStructure.SectionDamage(sectionIndex)),
|
||||
GUI.Style.Red, GUI.Style.Green);
|
||||
|
||||
if (progressBar != null) progressBar.Size = new Vector2(60.0f, 20.0f);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -49,6 +50,42 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
CreateGUI();
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "emitter":
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
float minCondition = subElement.GetAttributeFloat("mincondition", 0.0f);
|
||||
float maxCondition = subElement.GetAttributeFloat("maxcondition", 100.0f);
|
||||
|
||||
if (maxCondition < minCondition)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid damage particle configuration in the Repairable component of " + item.Name + ". MaxCondition needs to be larger than MinCondition.");
|
||||
float temp = maxCondition;
|
||||
maxCondition = minCondition;
|
||||
minCondition = temp;
|
||||
}
|
||||
particleEmitterConditionRanges.Add(new Vector2(minCondition, maxCondition));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
{
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.75f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
@@ -56,7 +93,7 @@ namespace Barotrauma.Items.Components
|
||||
RelativeSpacing = 0.05f,
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||
header, textAlignment: Alignment.TopCenter, font: GUI.LargeFont);
|
||||
|
||||
@@ -68,7 +105,7 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
{
|
||||
var skillText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + requiredSkills[i].Identifier), ((int) requiredSkills[i].Level).ToString()),
|
||||
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + requiredSkills[i].Identifier), ((int) Math.Round(requiredSkills[i].Level * SkillRequirementMultiplier)).ToString()),
|
||||
font: GUI.SmallFont)
|
||||
{
|
||||
UserData = requiredSkills[i]
|
||||
@@ -111,43 +148,27 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "emitter":
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
float minCondition = subElement.GetAttributeFloat("mincondition", 0.0f);
|
||||
float maxCondition = subElement.GetAttributeFloat("maxcondition", 100.0f);
|
||||
|
||||
if (maxCondition < minCondition)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid damage particle configuration in the Repairable component of " + item.Name + ". MaxCondition needs to be larger than MinCondition.");
|
||||
float temp = maxCondition;
|
||||
maxCondition = minCondition;
|
||||
minCondition = temp;
|
||||
}
|
||||
particleEmitterConditionRanges.Add(new Vector2(minCondition, maxCondition));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (Character.Controlled == null || (Character.Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
|
||||
if (FakeBrokenTimer > 0.0f)
|
||||
{
|
||||
FakeBrokenTimer = 0.0f;
|
||||
item.FakeBroken = true;
|
||||
if (Character.Controlled == null || (Character.Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
|
||||
{
|
||||
FakeBrokenTimer = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
FakeBrokenTimer -= deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FakeBrokenTimer -= deltaTime;
|
||||
item.FakeBroken = false;
|
||||
}
|
||||
|
||||
item.FakeBroken = FakeBrokenTimer > 0.0f;
|
||||
|
||||
if (!GameMain.IsMultiplayer)
|
||||
{
|
||||
@@ -211,7 +232,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!(c.UserData is Skill skill)) continue;
|
||||
|
||||
GUITextBlock textBlock = (GUITextBlock)c;
|
||||
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
|
||||
if (character.GetSkillLevel(skill.Identifier) < (skill.Level * SkillRequirementMultiplier))
|
||||
{
|
||||
textBlock.TextColor = GUI.Style.Red;
|
||||
}
|
||||
@@ -247,6 +268,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma.Items.Components
|
||||
flashColor * (float)Math.Sin(FlashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), scale: connectorSpriteScale);
|
||||
}
|
||||
|
||||
if (Wires.Any(w => w != null && w != DraggingConnected))
|
||||
if (Wires.Any(w => w != null && w != DraggingConnected && !w.Hidden))
|
||||
{
|
||||
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
||||
screwSprites[screwIndex].Draw(spriteBatch, position, scale: connectorSpriteScale);
|
||||
|
||||
@@ -18,17 +18,9 @@ namespace Barotrauma.Items.Components
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
CreateGUI();
|
||||
GameMain.Instance.OnResolutionChanged += RecreateGUI;
|
||||
}
|
||||
|
||||
private void RecreateGUI()
|
||||
{
|
||||
GuiFrame.ClearChildren();
|
||||
CreateGUI();
|
||||
UpdateLabelsProjSpecific();
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
uiElements.Clear();
|
||||
var visibleElements = customInterfaceElementList.Where(ciElement => !string.IsNullOrEmpty(ciElement.Label));
|
||||
@@ -309,10 +301,5 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged -= RecreateGUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
if (IsActive && item.ParentInventory?.Owner is Character user && user == Character.Controlled)// && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
|
||||
{
|
||||
if (user.CanInteract)
|
||||
if (user.CanInteract && currLength < MaxLength)
|
||||
{
|
||||
Vector2 gridPos = Character.Controlled.Position;
|
||||
Vector2 roundedGridPos = new Vector2(
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Barotrauma.Items.Components
|
||||
Entity targetEntity = Entity.FindEntityByID(dockingTargetID);
|
||||
if (targetEntity == null || !(targetEntity is Item))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + targetEntity?.ToString() ?? "null" + ")");
|
||||
DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + (targetEntity?.ToString() ?? "null") + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,11 @@ namespace Barotrauma
|
||||
item.Name :
|
||||
item.Name + '\n' + description;
|
||||
}
|
||||
|
||||
if (item.SpawnedInOutpost)
|
||||
{
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Red);
|
||||
toolTip = $"‖color:{colorStr}‖{toolTip}‖color:end‖";
|
||||
}
|
||||
return toolTip;
|
||||
}
|
||||
}
|
||||
@@ -1127,6 +1131,8 @@ namespace Barotrauma
|
||||
public static void DrawFront(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) { return; }
|
||||
if (GameMain.GameSession?.Campaign != null &&
|
||||
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI)) { return; }
|
||||
|
||||
subInventorySlotsToDraw.Clear();
|
||||
subInventorySlotsToDraw.AddRange(highlightedSubInventorySlots);
|
||||
@@ -1377,6 +1383,17 @@ namespace Barotrauma
|
||||
sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black * 0.6f, rotate: rotation, scale: scale);
|
||||
}
|
||||
sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
|
||||
|
||||
if (item.SpawnedInOutpost && CharacterInventory.LimbSlotIcons.ContainsKey(InvSlotType.LeftHand))
|
||||
{
|
||||
var stealIcon = CharacterInventory.LimbSlotIcons[InvSlotType.LeftHand];
|
||||
Vector2 iconSize = new Vector2(25 * GUI.Scale);
|
||||
stealIcon.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + iconSize.X * 0.2f, rect.Bottom - iconSize.Y * 1.2f),
|
||||
color: GUI.Style.Red,
|
||||
scale: iconSize.X / stealIcon.size.X);
|
||||
}
|
||||
}
|
||||
|
||||
if (inventory != null &&
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Barotrauma
|
||||
float fadeInBrokenSpriteAlpha = 0.0f;
|
||||
float displayCondition = FakeBroken ? 0.0f : condition;
|
||||
Vector2 drawOffset = Vector2.Zero;
|
||||
if (displayCondition < Prefab.Health)
|
||||
if (displayCondition < MaxCondition)
|
||||
{
|
||||
for (int i = 0; i < Prefab.BrokenSprites.Count; i++)
|
||||
{
|
||||
@@ -299,22 +299,23 @@ namespace Barotrauma
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
||||
new Vector2(rect.Width, rect.Height), color: color,
|
||||
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
||||
size, color: color,
|
||||
textureScale: Vector2.One * Scale,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, SpriteRotation, Scale, activeSprite.effects, depth);
|
||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, SpriteRotation, Scale, activeSprite.effects, depth - 0.000001f);
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, SpriteRotation + rotation, Scale, activeSprite.effects, depth);
|
||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, SpriteRotation + rotation, Scale, activeSprite.effects, depth - 0.000001f);
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
SpriteRotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
SpriteRotation + rotation + rot, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||
}
|
||||
}
|
||||
@@ -328,7 +329,7 @@ namespace Barotrauma
|
||||
if (holdable.Picker.SelectedItems[0] == this)
|
||||
{
|
||||
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightHand);
|
||||
if (holdLimb != null)
|
||||
if (holdLimb?.ActiveSprite != null)
|
||||
{
|
||||
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() + depthStep * 2;
|
||||
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
|
||||
@@ -340,7 +341,7 @@ namespace Barotrauma
|
||||
else if (holdable.Picker.SelectedItems[1] == this)
|
||||
{
|
||||
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftHand);
|
||||
if (holdLimb != null)
|
||||
if (holdLimb?.ActiveSprite != null)
|
||||
{
|
||||
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() - depthStep * 2;
|
||||
foreach (WearableSprite wearableSprite in holdLimb.WearingItems)
|
||||
@@ -368,6 +369,23 @@ namespace Barotrauma
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var upgrade in Upgrades)
|
||||
{
|
||||
var upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
|
||||
foreach (var decorativeSprite in upgradeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
var (xOff, yOff) = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + xOff, -(DrawPosition.Y + yOff)), color,
|
||||
rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
activeSprite.effects = oldEffects;
|
||||
if (fadeInBrokenSprite != null && fadeInBrokenSprite.Sprite != activeSprite)
|
||||
@@ -437,6 +455,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDecorativeSprite(SpriteBatch spriteBatch, DecorativeSprite decorativeSprite, Color color, float depth)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { return; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * 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(DrawPosition.X + transformedOffset.X, -(DrawPosition.Y + transformedOffset.Y)), color,
|
||||
-body.Rotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
|
||||
partial void OnCollisionProjSpecific(float impact)
|
||||
{
|
||||
if (impact > 1.0f &&
|
||||
@@ -451,6 +484,22 @@ namespace Barotrauma
|
||||
public void UpdateSpriteStates(float deltaTime)
|
||||
{
|
||||
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
|
||||
|
||||
foreach (var upgrade in Upgrades)
|
||||
{
|
||||
var upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
|
||||
foreach (var decorativeSprite in upgradeSprites)
|
||||
{
|
||||
var spriteState = spriteAnimState[decorativeSprite];
|
||||
spriteState.IsActive = true;
|
||||
foreach (var _ in decorativeSprite.IsActiveConditionals.Where(conditional => !ConditionalMatches(conditional)))
|
||||
{
|
||||
spriteState.IsActive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
@@ -541,12 +590,14 @@ namespace Barotrauma
|
||||
linkText.TextColor = GUI.Style.Orange;
|
||||
itemsText.TextColor = GUI.Style.Orange;
|
||||
}
|
||||
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, heightScaled)), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f,
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||
@@ -588,6 +639,22 @@ namespace Barotrauma
|
||||
buttonContainer.RectTransform.IsFixedSize = true;
|
||||
itemEditor.AddCustomContent(buttonContainer, itemEditor.ContentCount);
|
||||
GUITextBlock.AutoScaleAndNormalize(buttonContainer.Children.Select(b => ((GUIButton)b).TextBlock));
|
||||
|
||||
if (Submarine.MainSub?.Info?.Type == SubmarineType.OutpostModule)
|
||||
{
|
||||
GUITickBox tickBox = new GUITickBox(new RectTransform(new Point(listBox.Content.Rect.Width, 10)), TextManager.Get("sp.structure.removeiflinkedoutpostdoorinuse.name"))
|
||||
{
|
||||
Font = GUI.SmallFont,
|
||||
Selected = RemoveIfLinkedOutpostDoorInUse,
|
||||
ToolTip = TextManager.Get("sp.structure.removeiflinkedoutpostdoorinuse.description"),
|
||||
OnSelected = (tickBox) =>
|
||||
{
|
||||
RemoveIfLinkedOutpostDoorInUse = tickBox.Selected;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
itemEditor.AddCustomContent(tickBox, 1);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ItemComponent ic in components)
|
||||
@@ -667,6 +734,39 @@ namespace Barotrauma
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
private List<DecorativeSprite> GetUpgradeSprites(Upgrade upgrade)
|
||||
{
|
||||
var upgradeSprites = upgrade.Prefab.DecorativeSprites;
|
||||
|
||||
if (Prefab.UpgradeOverrideSprites.ContainsKey(upgrade.Prefab.Identifier))
|
||||
{
|
||||
upgradeSprites = Prefab.UpgradeOverrideSprites[upgrade.Prefab.Identifier];
|
||||
}
|
||||
|
||||
return upgradeSprites;
|
||||
}
|
||||
|
||||
public override bool AddUpgrade(Upgrade upgrade, bool createNetworkEvent = false)
|
||||
{
|
||||
if (upgrade.Prefab.IsWallUpgrade) { return false; }
|
||||
bool result = base.AddUpgrade(upgrade, createNetworkEvent);
|
||||
if (result && !upgrade.Disposed)
|
||||
{
|
||||
List<DecorativeSprite> upgradeSprites = GetUpgradeSprites(upgrade);
|
||||
|
||||
if (upgradeSprites.Any())
|
||||
{
|
||||
foreach (DecorativeSprite decorativeSprite in upgradeSprites)
|
||||
{
|
||||
decorativeSprite.Sprite.EnsureLazyLoaded();
|
||||
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
|
||||
}
|
||||
UpdateSpriteStates(0.0f);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void CreateTagPicker(GUITextBox textBox, IEnumerable<string> availableTags)
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel") }, new Vector2(0.2f, 0.5f), new Point(300, 400));
|
||||
@@ -756,6 +856,10 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<Rectangle> debugInitialHudPositions = new List<Rectangle>();
|
||||
|
||||
private readonly List<ItemComponent> prevActiveHUDs = new List<ItemComponent>();
|
||||
private readonly List<ItemComponent> activeComponents = new List<ItemComponent>();
|
||||
private readonly List<ItemComponent> maxPriorityHUDs = new List<ItemComponent>();
|
||||
|
||||
public void UpdateHUD(Camera cam, Character character, float deltaTime)
|
||||
{
|
||||
bool editingHUDCreated = false;
|
||||
@@ -774,8 +878,11 @@ namespace Barotrauma
|
||||
editingHUDRefreshTimer -= deltaTime;
|
||||
}
|
||||
|
||||
List<ItemComponent> prevActiveHUDs = new List<ItemComponent>(activeHUDs);
|
||||
List<ItemComponent> activeComponents = new List<ItemComponent>(components);
|
||||
prevActiveHUDs.Clear();
|
||||
prevActiveHUDs.AddRange(activeHUDs);
|
||||
activeComponents.Clear();
|
||||
activeComponents.AddRange(components);
|
||||
|
||||
foreach (MapEntity entity in linkedTo)
|
||||
{
|
||||
if (prefab.IsLinkAllowed(entity.prefab) && entity is Item i)
|
||||
@@ -788,12 +895,11 @@ namespace Barotrauma
|
||||
activeHUDs.Clear();
|
||||
//the HUD of the component with the highest priority will be drawn
|
||||
//if all components have a priority of 0, all of them are drawn
|
||||
List<ItemComponent> maxPriorityHUDs = new List<ItemComponent>();
|
||||
maxPriorityHUDs.Clear();
|
||||
bool DrawHud(ItemComponent ic) => ic.ShouldDrawHUD(character) && (ic.CanBeSelected && ic.HasRequiredItems(character, addMessage: false) || (character.HasEquippedItem(this) && ic.DrawHudWhenEquipped));
|
||||
foreach (ItemComponent ic in activeComponents)
|
||||
{
|
||||
if (ic.HudPriority > 0 && ic.ShouldDrawHUD(character) &&
|
||||
(ic.CanBeSelected || (character.HasEquippedItem(this) && ic.DrawHudWhenEquipped)) &&
|
||||
(maxPriorityHUDs.Count == 0 || ic.HudPriority >= maxPriorityHUDs[0].HudPriority))
|
||||
if (ic.HudPriority > 0 && DrawHud(ic) && (maxPriorityHUDs.Count == 0 || ic.HudPriority >= maxPriorityHUDs[0].HudPriority))
|
||||
{
|
||||
if (maxPriorityHUDs.Count > 0 && ic.HudPriority > maxPriorityHUDs[0].HudPriority) { maxPriorityHUDs.Clear(); }
|
||||
maxPriorityHUDs.Add(ic);
|
||||
@@ -808,8 +914,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ItemComponent ic in activeComponents)
|
||||
{
|
||||
if (ic.ShouldDrawHUD(character) &&
|
||||
(ic.CanBeSelected || (character.HasEquippedItem(this) && ic.DrawHudWhenEquipped)))
|
||||
if (DrawHud(ic))
|
||||
{
|
||||
activeHUDs.Add(ic);
|
||||
}
|
||||
@@ -914,11 +1019,11 @@ namespace Barotrauma
|
||||
color = Color.Cyan;
|
||||
}
|
||||
}
|
||||
texts.Add(new ColoredText(ic.DisplayMsg, color, false));
|
||||
texts.Add(new ColoredText(ic.DisplayMsg, color, false, false));
|
||||
}
|
||||
if ((PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift)) && CrewManager.DoesItemHaveContextualOrders(this))
|
||||
{
|
||||
texts.Add(new ColoredText(TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders")), Color.Cyan, false));
|
||||
texts.Add(new ColoredText(TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders")), Color.Cyan, false, false));
|
||||
}
|
||||
return texts;
|
||||
}
|
||||
@@ -1048,6 +1153,29 @@ namespace Barotrauma
|
||||
ReadPropertyChange(msg, false);
|
||||
editingHUDRefreshPending = true;
|
||||
break;
|
||||
case NetEntityEvent.Type.Upgrade:
|
||||
{
|
||||
string identifier = msg.ReadString();
|
||||
byte level = msg.ReadByte();
|
||||
if (UpgradePrefab.Find(identifier) is { } upgradePrefab)
|
||||
{
|
||||
Upgrade upgrade = new Upgrade(this, upgradePrefab, level);
|
||||
|
||||
byte targetCount = msg.ReadByte();
|
||||
for (int i = 0; i < targetCount; i++)
|
||||
{
|
||||
byte propertyCount = msg.ReadByte();
|
||||
for (int j = 0; j < propertyCount; j++)
|
||||
{
|
||||
float value = msg.ReadSingle();
|
||||
upgrade.TargetComponents.ElementAt(i).Value[j].SetOriginalValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
AddUpgrade(upgrade, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetEntityEvent.Type.Invalid:
|
||||
break;
|
||||
}
|
||||
@@ -1220,7 +1348,7 @@ namespace Barotrauma
|
||||
ushort itemId = msg.ReadUInt16();
|
||||
ushort inventoryId = msg.ReadUInt16();
|
||||
|
||||
DebugConsole.Log("Received entity spawn message for item " + itemName + ".");
|
||||
DebugConsole.Log($"Received entity spawn message for item \"{itemName}\" (identifier: {itemIdentifier}, id: {itemId})");
|
||||
|
||||
Vector2 pos = Vector2.Zero;
|
||||
Submarine sub = null;
|
||||
@@ -1243,10 +1371,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
byte bodyType = msg.ReadByte();
|
||||
|
||||
byte teamID = msg.ReadByte();
|
||||
bool tagsChanged = msg.ReadBoolean();
|
||||
byte bodyType = msg.ReadByte();
|
||||
bool spawnedInOutpost = msg.ReadBoolean();
|
||||
byte teamID = msg.ReadByte();
|
||||
bool tagsChanged = msg.ReadBoolean();
|
||||
string tags = "";
|
||||
if (tagsChanged)
|
||||
{
|
||||
@@ -1289,6 +1417,7 @@ namespace Barotrauma
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
inventory = parentItem.GetComponent<ItemContainer>()?.Inventory;
|
||||
}
|
||||
else if (parentItem.components[itemContainerIndex] is ItemContainer container)
|
||||
{
|
||||
@@ -1307,7 +1436,8 @@ namespace Barotrauma
|
||||
|
||||
var item = new Item(itemPrefab, pos, sub)
|
||||
{
|
||||
ID = itemId
|
||||
ID = itemId,
|
||||
SpawnedInOutpost = spawnedInOutpost
|
||||
};
|
||||
|
||||
if (item.body != null)
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 placeSize = size;
|
||||
Vector2 placeSize = size * Scale;
|
||||
|
||||
if (placePosition == Vector2.Zero)
|
||||
{
|
||||
@@ -161,7 +161,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite?.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), size, color: SpriteColor);
|
||||
Vector2 placeSize = size * Scale;
|
||||
if (placePosition != Vector2.Zero)
|
||||
{
|
||||
if (ResizeHorizontal) { placeSize.X = Math.Max(position.X - placePosition.X, placeSize.X); }
|
||||
if (ResizeVertical) { placeSize.Y = Math.Max(placePosition.Y - position.Y, placeSize.Y); }
|
||||
position = placePosition;
|
||||
}
|
||||
sprite?.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), placeSize, color: SpriteColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +180,15 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sprite != null) sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), placeRect.Size.ToVector2(), null, SpriteColor * 0.8f);
|
||||
Vector2 position = Submarine.MouseToWorldGrid(Screen.Selected.Cam, Submarine.MainSub);
|
||||
Vector2 placeSize = size * Scale;
|
||||
if (placePosition != Vector2.Zero)
|
||||
{
|
||||
if (ResizeHorizontal) { placeSize.X = Math.Max(position.X - placePosition.X, placeSize.X); }
|
||||
if (ResizeVertical) { placeSize.Y = Math.Max(placePosition.Y - position.Y, placeSize.Y); }
|
||||
position = placePosition;
|
||||
}
|
||||
sprite?.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), placeSize, color: SpriteColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma
|
||||
{
|
||||
Vector2 dir = IsHorizontal ?
|
||||
new Vector2(Math.Sign(linkedTo[i].Rect.Center.X - rect.Center.X), 0.0f)
|
||||
: new Vector2(0.0f, Math.Sign((linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f) - (rect.Y - rect.Height / 2.0f)));
|
||||
: new Vector2(0.0f, Math.Sign((rect.Y - rect.Height / 2.0f) - (linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f)));
|
||||
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Barotrauma
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i]));
|
||||
if (maxDelta > Rand.Range(1.0f, 10.0f))
|
||||
if (maxDelta > 1.0f && maxDelta > Rand.Range(1.0f, 10.0f))
|
||||
{
|
||||
var particlePos = new Vector2(rect.X + WaveWidth * i, surface + waveY[i]);
|
||||
if (Submarine != null) particlePos += Submarine.Position;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma
|
||||
|
||||
HashSet<Texture2D> uniqueTextures = new HashSet<Texture2D>();
|
||||
HashSet<Sprite> uniqueSprites = new HashSet<Sprite>();
|
||||
var allLevelObjects = levelObjectManager.GetAllObjects();
|
||||
var allLevelObjects = LevelObjectManager.GetAllObjects();
|
||||
foreach (var levelObj in allLevelObjects)
|
||||
{
|
||||
foreach (Sprite sprite in levelObj.Prefab.Sprites)
|
||||
@@ -56,7 +56,7 @@ namespace Barotrauma
|
||||
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
{
|
||||
foreach (InterestingPosition pos in positionsOfInterest)
|
||||
foreach (InterestingPosition pos in PositionsOfInterest)
|
||||
{
|
||||
Color color = Color.Yellow;
|
||||
if (pos.PositionType == PositionType.Cave)
|
||||
@@ -71,7 +71,7 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(pos.Position.X - 15.0f, -pos.Position.Y - 15.0f), new Vector2(30.0f, 30.0f), color, true);
|
||||
}
|
||||
|
||||
foreach (RuinGeneration.Ruin ruin in ruins)
|
||||
foreach (RuinGeneration.Ruin ruin in Ruins)
|
||||
{
|
||||
Rectangle ruinArea = ruin.Area;
|
||||
ruinArea.Y = -ruinArea.Y - ruinArea.Height;
|
||||
@@ -113,7 +113,7 @@ namespace Barotrauma
|
||||
public void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float brightness = MathHelper.Clamp(1.1f + (cam.Position.Y - Size.Y) / 100000.0f, 0.1f, 1.0f);
|
||||
var lightColorHLS = generationParams.AmbientLightColor.RgbToHLS();
|
||||
var lightColorHLS = GenerationParams.AmbientLightColor.RgbToHLS();
|
||||
lightColorHLS.Y *= brightness;
|
||||
|
||||
GameMain.LightManager.AmbientLight = ToolBox.HLSToRGB(lightColorHLS);
|
||||
@@ -121,12 +121,12 @@ namespace Barotrauma
|
||||
graphics.Clear(BackgroundColor);
|
||||
|
||||
if (renderer == null) return;
|
||||
renderer.DrawBackground(spriteBatch, cam, levelObjectManager, backgroundCreatureManager);
|
||||
renderer.DrawBackground(spriteBatch, cam, LevelObjectManager, backgroundCreatureManager);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
foreach (LevelWall levelWall in extraWalls)
|
||||
foreach (LevelWall levelWall in ExtraWalls)
|
||||
{
|
||||
if (levelWall.Body.BodyType == BodyType.Static) continue;
|
||||
|
||||
|
||||
@@ -9,8 +9,12 @@ namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectManager
|
||||
{
|
||||
private List<LevelObject> visibleObjectsBack = new List<LevelObject>();
|
||||
private List<LevelObject> visibleObjectsFront = new List<LevelObject>();
|
||||
private readonly List<LevelObject> visibleObjectsBack = new List<LevelObject>();
|
||||
private readonly List<LevelObject> visibleObjectsFront = new List<LevelObject>();
|
||||
|
||||
//Maximum number of visible objects drawn at once. Should be large enough to not have an effect during normal gameplay,
|
||||
//but small enough to prevent wrecking performance when zooming out very far
|
||||
const int MaxVisibleObjects = 500;
|
||||
|
||||
private Rectangle currentGridIndices;
|
||||
|
||||
@@ -43,7 +47,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int y = currentIndices.Y; y <= currentIndices.Height; y++)
|
||||
{
|
||||
if (objectGrid[x, y] == null) continue;
|
||||
if (objectGrid[x, y] == null) { continue; }
|
||||
foreach (LevelObject obj in objectGrid[x, y])
|
||||
{
|
||||
var objectList = obj.Position.Z >= 0 ? visibleObjectsBack : visibleObjectsFront;
|
||||
@@ -69,6 +73,7 @@ namespace Barotrauma
|
||||
if (drawOrderIndex >= 0)
|
||||
{
|
||||
objectList.Insert(drawOrderIndex, obj);
|
||||
if (objectList.Count >= MaxVisibleObjects) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace Barotrauma
|
||||
level.GenerationParams.WaterParticles.DrawTiled(
|
||||
spriteBatch, origin + offsetS,
|
||||
new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y),
|
||||
rect: srcRect, color: Color.White * alpha, textureScale: new Vector2(texScale));
|
||||
color: Color.White * alpha, textureScale: new Vector2(texScale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,10 +170,12 @@ namespace Barotrauma.Lights
|
||||
isHorizontal = BoundingBox.Width > BoundingBox.Height;
|
||||
if (ParentEntity is Structure structure)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!structure.Removed);
|
||||
isHorizontal = structure.IsHorizontal;
|
||||
}
|
||||
else if (ParentEntity is Item item)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!item.Removed);
|
||||
var door = item.GetComponent<Door>();
|
||||
if (door != null) { isHorizontal = door.IsHorizontal; }
|
||||
}
|
||||
@@ -444,7 +446,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
CalculateDimensions();
|
||||
|
||||
if (ParentEntity == null) return;
|
||||
if (ParentEntity == null) { return; }
|
||||
|
||||
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
|
||||
if (chList != null)
|
||||
|
||||
@@ -55,7 +55,9 @@ namespace Barotrauma.Lights
|
||||
public bool ObstructVision;
|
||||
|
||||
private readonly Texture2D visionCircle;
|
||||
|
||||
|
||||
private Vector2 losOffset;
|
||||
|
||||
public IEnumerable<LightSource> Lights
|
||||
{
|
||||
get { return lights; }
|
||||
@@ -70,7 +72,7 @@ namespace Barotrauma.Lights
|
||||
visionCircle = Sprite.LoadTexture("Content/Lights/visioncircle.png");
|
||||
highlightRaster = Sprite.LoadTexture("Content/UI/HighlightRaster.png");
|
||||
|
||||
GameMain.Instance.OnResolutionChanged += () =>
|
||||
GameMain.Instance.ResolutionChanged += () =>
|
||||
{
|
||||
CreateRenderTargets(graphics);
|
||||
};
|
||||
@@ -279,7 +281,7 @@ namespace Barotrauma.Lights
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled) { continue; }
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
@@ -297,7 +299,7 @@ namespace Barotrauma.Lights
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled) { continue; }
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
@@ -335,20 +337,34 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
Vector2 haloDrawPos = Character.Controlled.DrawPosition;
|
||||
DrawHalo(Character.Controlled);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.Submarine == null || character.IsDead || !character.IsHuman) { continue; }
|
||||
DrawHalo(character);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawHalo(Character character)
|
||||
{
|
||||
Vector2 haloDrawPos = character.DrawPosition;
|
||||
haloDrawPos.Y = -haloDrawPos.Y;
|
||||
|
||||
//ambient light decreases the brightness of the halo (no need for a bright halo if the ambient light is bright enough)
|
||||
float ambientBrightness = (AmbientLight.R + AmbientLight.B + AmbientLight.G) / 255.0f / 3.0f;
|
||||
Color haloColor = Color.White.Multiply(0.3f - ambientBrightness);
|
||||
Color haloColor = Color.White.Multiply(0.3f - ambientBrightness);
|
||||
if (haloColor.A > 0)
|
||||
{
|
||||
float scale = 512.0f / LightSource.LightTexture.Width;
|
||||
spriteBatch.Draw(
|
||||
LightSource.LightTexture, haloDrawPos, null, haloColor, 0.0f,
|
||||
new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
//draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
|
||||
@@ -477,10 +493,11 @@ namespace Barotrauma.Lights
|
||||
graphics.Clear(Color.Black);
|
||||
Vector2 diff = lookAtPosition - ViewTarget.WorldPosition;
|
||||
diff.Y = -diff.Y;
|
||||
float rotation = MathUtils.VectorToAngle(diff);
|
||||
if (diff.LengthSquared() > 30.0f) { losOffset = diff; }
|
||||
float rotation = MathUtils.VectorToAngle(losOffset);
|
||||
|
||||
Vector2 scale = new Vector2(
|
||||
MathHelper.Clamp(diff.Length() / 256.0f, 2.0f, 5.0f), 2.0f);
|
||||
MathHelper.Clamp(losOffset.Length() / 256.0f, 2.0f, 5.0f), 2.0f);
|
||||
|
||||
spriteBatch.Draw(visionCircle, new Vector2(ViewTarget.WorldPosition.X, -ViewTarget.WorldPosition.Y), null, Color.White, rotation,
|
||||
new Vector2(visionCircle.Width * 0.2f, visionCircle.Height / 2), scale, SpriteEffects.None, 0.0f);
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Location
|
||||
{
|
||||
private HireManager hireManager;
|
||||
|
||||
public void RemoveHireableCharacter(CharacterInfo character)
|
||||
{
|
||||
if (!Type.HasHireableCharacters)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - the location has no hireable characters.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
if (hireManager == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - hire manager has not been instantiated.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
hireManager.RemoveCharacter(character);
|
||||
}
|
||||
|
||||
public IEnumerable<CharacterInfo> GetHireableCharacters()
|
||||
{
|
||||
if (!Type.HasHireableCharacters)
|
||||
{
|
||||
return Enumerable.Empty<CharacterInfo>();
|
||||
}
|
||||
|
||||
if (hireManager == null)
|
||||
{
|
||||
hireManager = new HireManager();
|
||||
}
|
||||
if (!hireManager.AvailableCharacters.Any())
|
||||
{
|
||||
hireManager.GenerateCharacters(location: this, amount: HireManager.MaxAvailableCharacters);
|
||||
}
|
||||
return hireManager.AvailableCharacters;
|
||||
}
|
||||
|
||||
partial void RemoveProjSpecific()
|
||||
{
|
||||
hireManager?.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,14 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract partial class MapEntityPrefab : IPrefab, IDisposable
|
||||
{
|
||||
public readonly Dictionary<string, List<DecorativeSprite>> UpgradeOverrideSprites = new Dictionary<string, List<DecorativeSprite>>();
|
||||
|
||||
public virtual void UpdatePlacing(Camera cam)
|
||||
{
|
||||
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||
|
||||
@@ -94,7 +94,23 @@ namespace Barotrauma
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null);
|
||||
var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont);
|
||||
|
||||
|
||||
if (Submarine.MainSub?.Info?.Type == SubmarineType.OutpostModule)
|
||||
{
|
||||
GUITickBox tickBox = new GUITickBox(new RectTransform(new Point(listBox.Content.Rect.Width, 10)), TextManager.Get("sp.structure.removeiflinkedoutpostdoorinuse.name"))
|
||||
{
|
||||
Font = GUI.SmallFont,
|
||||
Selected = RemoveIfLinkedOutpostDoorInUse,
|
||||
ToolTip = TextManager.Get("sp.structure.removeiflinkedoutpostdoorinuse.description"),
|
||||
OnSelected = (tickBox) =>
|
||||
{
|
||||
RemoveIfLinkedOutpostDoorInUse = tickBox.Selected;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
editor.AddCustomContent(tickBox, 1);
|
||||
}
|
||||
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, heightScaled)), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
@@ -261,7 +277,7 @@ namespace Barotrauma
|
||||
SpriteEffects oldEffects = Prefab.BackgroundSprite.effects;
|
||||
Prefab.BackgroundSprite.effects ^= SpriteEffects;
|
||||
|
||||
Point backGroundOffset = new Point(
|
||||
Vector2 backGroundOffset = new Vector2(
|
||||
MathUtils.PositiveModulo((int)-textureOffset.X, Prefab.BackgroundSprite.SourceRect.Width),
|
||||
MathUtils.PositiveModulo((int)-textureOffset.Y, Prefab.BackgroundSprite.SourceRect.Height));
|
||||
|
||||
@@ -299,7 +315,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (damageEffect != null)
|
||||
{
|
||||
float newCutoff = MathHelper.Lerp(0.0f, 0.65f, Sections[i].damage / Prefab.Health);
|
||||
float newCutoff = MathHelper.Lerp(0.0f, 0.65f, Sections[i].damage / MaxHealth);
|
||||
|
||||
if (Math.Abs(newCutoff - Submarine.DamageEffectCutoff) > 0.01f || color != Submarine.DamageEffectColor)
|
||||
{
|
||||
@@ -314,7 +330,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Point sectionOffset = new Point(
|
||||
Vector2 sectionOffset = new Vector2(
|
||||
Math.Abs(rect.Location.X - Sections[i].rect.Location.X),
|
||||
Math.Abs(rect.Location.Y - Sections[i].rect.Location.Y));
|
||||
|
||||
@@ -371,7 +387,7 @@ namespace Barotrauma
|
||||
{
|
||||
var textPos = SectionPosition(i, true);
|
||||
textPos.Y = -textPos.Y;
|
||||
GUI.DrawString(spriteBatch, textPos, "Damage: " + (int)((GetSection(i).damage / Health) * 100f) + "%", Color.Yellow);
|
||||
GUI.DrawString(spriteBatch, textPos, "Damage: " + (int)((GetSection(i).damage / MaxHealth) * 100f) + "%", Color.Yellow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,7 +464,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < sectionCount; i++)
|
||||
{
|
||||
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * Health;
|
||||
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * MaxHealth;
|
||||
if (i < Sections.Length)
|
||||
{
|
||||
SetDamage(i, damage);
|
||||
|
||||
@@ -5,6 +5,7 @@ using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
@@ -306,9 +307,9 @@ namespace Barotrauma
|
||||
|
||||
public static void DrawGrid(SpriteBatch spriteBatch, int gridCells, Vector2 gridCenter, Vector2 roundedGridCenter, float alpha = 1.0f)
|
||||
{
|
||||
var horizontalLine = GUI.Style.GetComponentStyle("HorizontalLine").Sprites[GUIComponent.ComponentState.None].First();
|
||||
var verticalLine = GUI.Style.GetComponentStyle("VerticalLine").Sprites[GUIComponent.ComponentState.None].First();
|
||||
|
||||
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;
|
||||
|
||||
@@ -324,19 +325,19 @@ namespace Barotrauma
|
||||
float expandY = MathHelper.Lerp(30.0f, 0.0f, normalizedDistY);
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
horizontalLine.Sprite,
|
||||
horizontalLine,
|
||||
new Vector2(topLeft.X - expandX, -bottomRight.Y + i * GridSize.Y),
|
||||
new Vector2(bottomRight.X + expandX, -bottomRight.Y + i * GridSize.Y),
|
||||
Color.White * (1.0f - normalizedDistY) * alpha, depth: 0.6f, width: 3);
|
||||
GUI.DrawLine(spriteBatch,
|
||||
verticalLine.Sprite,
|
||||
verticalLine,
|
||||
new Vector2(topLeft.X + i * GridSize.X, -topLeft.Y + expandY),
|
||||
new Vector2(topLeft.X + i * GridSize.X, -bottomRight.Y - expandY),
|
||||
Color.White * (1.0f - normalizedDistX) * alpha, depth: 0.6f, width: 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null)
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null, bool ignoreOutpost = false)
|
||||
{
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
worldBorders.Location += WorldPosition.ToPoint();
|
||||
@@ -354,7 +355,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine != this && !DockedTo.Contains(hull.Submarine)) continue;
|
||||
if (hull.Submarine != this && !(DockedTo.Contains(hull.Submarine))) continue;
|
||||
if (ignoreOutpost && !IsEntityFoundOnThisSub(hull, true)) { continue; }
|
||||
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
@@ -393,35 +395,61 @@ namespace Barotrauma
|
||||
errorMsgs.Add(TextManager.Get("NoHullsWarning"));
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
(Info.OutpostModuleInfo?.ModuleFlags.Any(f => !f.Equals("hallwayvertical", StringComparison.OrdinalIgnoreCase) && !f.Equals("hallwayhorizontal", StringComparison.OrdinalIgnoreCase)) ?? true))
|
||||
{
|
||||
if (item.GetComponent<Items.Components.Vent>() == null) continue;
|
||||
|
||||
if (!item.linkedTo.Any())
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("DisconnectedVentsWarning"));
|
||||
break;
|
||||
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
|
||||
if (Info.Type == SubmarineType.Player)
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.GetComponent<Items.Components.Vent>() == null) { continue; }
|
||||
if (!item.linkedTo.Any())
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("DisconnectedVentsWarning"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
|
||||
}
|
||||
if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null)
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoCargoSpawnpointWarning"));
|
||||
}
|
||||
if (!Item.ItemList.Any(it => it.GetComponent<Items.Components.Pump>() != null && it.HasTag("ballast")))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoBallastTagsWarning"));
|
||||
}
|
||||
}
|
||||
|
||||
if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null)
|
||||
else if (Info.Type == SubmarineType.OutpostModule)
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoCargoSpawnpointWarning"));
|
||||
}
|
||||
|
||||
if (!Item.ItemList.Any(it => it.GetComponent<Items.Components.Pump>() != null && it.HasTag("ballast")))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoBallastTagsWarning"));
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
var junctionBox = item.GetComponent<PowerTransfer>();
|
||||
if (junctionBox == null) { continue; }
|
||||
int doorLinks =
|
||||
item.linkedTo.Count(lt => lt is Gap || (lt is Item it2 && it2.GetComponent<Door>() != null)) +
|
||||
Item.ItemList.Count(it2 => it2.linkedTo.Contains(item) && !item.linkedTo.Contains(it2));
|
||||
for (int i = 0; i < item.Connections.Count; i++)
|
||||
{
|
||||
int wireCount = item.Connections[i].Wires.Count(w => w != null);
|
||||
if (doorLinks + wireCount > Connection.MaxLinked)
|
||||
{
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
new string[] { "[doorcount]", "[freeconnectioncount]" },
|
||||
new string[] { doorLinks.ToString(), (Connection.MaxLinked - wireCount).ToString() }));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Gap.GapList.Any(g => g.linkedTo.Count == 0))
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class SubmarineInfo : IDisposable
|
||||
{
|
||||
public Sprite PreviewImage;
|
||||
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
string previewImageData = SubmarineElement.GetAttributeString("previewimage", "");
|
||||
@@ -57,78 +53,10 @@ namespace Barotrauma
|
||||
ScrollBarVisible = true,
|
||||
Spacing = 5
|
||||
};
|
||||
|
||||
ScalableFont font = parent.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), descriptionBox.Content.RectTransform), style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("submarine.name." + Name, true) ?? Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false };
|
||||
|
||||
float leftPanelWidth = 0.6f;
|
||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||
|
||||
ScalableFont font = descriptionBox.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
if (realWorldDimensions != Vector2.Zero)
|
||||
{
|
||||
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
||||
|
||||
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RecommendedCrewSizeMax > 0)
|
||||
{
|
||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
|
||||
{
|
||||
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RequiredContentPackages.Any())
|
||||
{
|
||||
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
// show what game version the submarine was created on
|
||||
if (!IsVanillaSubmarine() && GameVersion != null)
|
||||
{
|
||||
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
|
||||
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
|
||||
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(descriptionBox.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>());
|
||||
CreateSpecsWindow(descriptionBox, font);
|
||||
|
||||
//space
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null);
|
||||
@@ -145,5 +73,84 @@ namespace Barotrauma
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
public void CreateSpecsWindow(GUIListBox parent, ScalableFont font)
|
||||
{
|
||||
float leftPanelWidth = 0.6f;
|
||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||
string className = !HasTag(SubmarineTag.Shuttle) ? TextManager.Get($"submarineclass.{SubmarineClass}") : TextManager.Get("shuttle");
|
||||
|
||||
int nameHeight = (int)GUI.LargeFont.MeasureString(DisplayName, true).Y;
|
||||
int classHeight = (int)GUI.SubHeadingFont.MeasureString(className).Y;
|
||||
int leftPanelWidthInt = (int)(parent.Rect.Width * leftPanelWidth);
|
||||
|
||||
var submarineNameText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, nameHeight + HUDLayoutSettings.Padding / 2), parent.Content.RectTransform), DisplayName, textAlignment: Alignment.CenterLeft, font: GUI.LargeFont) { CanBeFocused = false };
|
||||
submarineNameText.RectTransform.MinSize = new Point(0, (int)submarineNameText.TextSize.Y);
|
||||
var submarineClassText = new GUITextBlock(new RectTransform(new Point(leftPanelWidthInt, classHeight), parent.Content.RectTransform), className, textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont) { CanBeFocused = false };
|
||||
submarineClassText.RectTransform.MinSize = new Point(0, (int)submarineClassText.TextSize.Y);
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
if (realWorldDimensions != Vector2.Zero)
|
||||
{
|
||||
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
||||
|
||||
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RecommendedCrewSizeMax > 0)
|
||||
{
|
||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
|
||||
{
|
||||
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
if (RequiredContentPackages.Any())
|
||||
{
|
||||
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
// show what game version the submarine was created on
|
||||
if (!IsVanillaSubmarine() && GameVersion != null)
|
||||
{
|
||||
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||
{ CanBeFocused = false };
|
||||
|
||||
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
|
||||
}
|
||||
|
||||
submarineNameText.AutoScaleHorizontal = true;
|
||||
GUITextBlock.AutoScaleAndNormalize(parent.Content.Children.Where(c => c is GUITextBlock && c != submarineNameText).Cast<GUITextBlock>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -22,7 +23,6 @@ namespace Barotrauma
|
||||
get { return !IsHidden(); }
|
||||
}
|
||||
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) { return; }
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Vector2 drawPos)
|
||||
{
|
||||
Color clr = currentHull == null ? Color.CadetBlue : GUI.Style.Green;
|
||||
Color clr = CurrentHull == null ? Color.DodgerBlue : GUI.Style.Green;
|
||||
if (spawnType != SpawnType.Path) { clr = Color.Gray; }
|
||||
if (isObstructed)
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace Barotrauma
|
||||
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
|
||||
|
||||
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
|
||||
if (ConnectedGap != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path) { iconSize = (int)(iconSize * 1.5f); }
|
||||
if (ConnectedDoor != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path) { iconSize = (int)(iconSize * 1.5f); }
|
||||
|
||||
if (IsSelected || IsHighlighted)
|
||||
{
|
||||
@@ -83,6 +83,20 @@ namespace Barotrauma
|
||||
new Vector2(e.DrawPosition.X, -e.DrawPosition.Y),
|
||||
(isObstructed ? Color.Gray : GUI.Style.Green) * 0.7f, width: 5, depth: 0.002f);
|
||||
}
|
||||
if (ConnectedGap != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(ConnectedGap.WorldPosition.X, -ConnectedGap.WorldPosition.Y),
|
||||
GUI.Style.Green * 0.5f, width: 1);
|
||||
}
|
||||
if (Ladders != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(Ladders.Item.WorldPosition.X, -Ladders.Item.WorldPosition.Y),
|
||||
GUI.Style.Green * 0.5f, width: 1);
|
||||
}
|
||||
|
||||
GUI.SmallFont.DrawString(spriteBatch,
|
||||
ID.ToString(),
|
||||
@@ -117,7 +131,7 @@ namespace Barotrauma
|
||||
editingHUD = CreateEditingHUD();
|
||||
}
|
||||
|
||||
if (IsSelected && PlayerInput.PrimaryMouseButtonClicked())
|
||||
if (IsSelected && PlayerInput.PrimaryMouseButtonClicked() && GUI.MouseOn == null)
|
||||
{
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
|
||||
@@ -144,6 +158,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
FindHull();
|
||||
// Update gaps, ladders, and stairs
|
||||
UpdateLinkedEntity(position, Gap.GapList, gap => ConnectedGap = gap, gap =>
|
||||
{
|
||||
@@ -170,6 +185,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}, inflate: 5);
|
||||
FindStairs();
|
||||
// TODO: Cannot check the rectangle, since the rectangle is not rotated -> Need to use the collider.
|
||||
//var stairList = mapEntityList.Where(me => me is Structure s && s.StairDirection != Direction.None).Select(me => me as Structure);
|
||||
//UpdateLinkedEntity(position, stairList, s =>
|
||||
@@ -240,7 +256,16 @@ namespace Barotrauma
|
||||
textBox.Deselect();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private bool EnterTags(GUITextBox textBox, string text)
|
||||
{
|
||||
tags = text.Split(',').ToList();
|
||||
textBox.Text = string.Join(",", Tags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
textBox.Deselect();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TextBoxChanged(GUITextBox textBox, string text)
|
||||
{
|
||||
textBox.Color = GUI.Style.Red;
|
||||
@@ -298,7 +323,7 @@ namespace Barotrauma
|
||||
|
||||
var descText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardDescription"), font: GUI.SmallFont);
|
||||
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), descText.RectTransform, Anchor.CenterRight), idCardDesc)
|
||||
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), descText.RectTransform, Anchor.CenterRight), IdCardDesc)
|
||||
{
|
||||
MaxTextLength = 150,
|
||||
OnEnterPressed = EnterIDCardDesc,
|
||||
@@ -306,9 +331,9 @@ namespace Barotrauma
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
|
||||
var tagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
var idCardTagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardTags"), font: GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), tagsText.RectTransform, Anchor.CenterRight), string.Join(", ", idCardTags))
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), idCardTagsText.RectTransform, Anchor.CenterRight), string.Join(", ", idCardTags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
OnEnterPressed = EnterIDCardTags,
|
||||
@@ -327,7 +352,7 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("SpawnpointJobsTooltip"),
|
||||
OnSelected = (selected, userdata) =>
|
||||
{
|
||||
assignedJob = userdata as JobPrefab;
|
||||
AssignedJob = userdata as JobPrefab;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -336,7 +361,17 @@ namespace Barotrauma
|
||||
{
|
||||
jobDropDown.AddItem(jobPrefab.Name, jobPrefab);
|
||||
}
|
||||
jobDropDown.SelectItem(assignedJob);
|
||||
jobDropDown.SelectItem(AssignedJob);
|
||||
|
||||
var tagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("spawnpointtags"), font: GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), tagsText.RectTransform, Anchor.CenterRight), string.Join(", ", tags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
OnEnterPressed = EnterTags,
|
||||
ToolTip = TextManager.Get("spawnpointtagstooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
}
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Barotrauma.Networking
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadByte();
|
||||
PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
|
||||
string txt = "";
|
||||
string styleSetting = string.Empty;
|
||||
|
||||
if (type != ChatMessageType.Order)
|
||||
{
|
||||
@@ -38,59 +39,65 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ChatMessageType.ServerMessageBox)
|
||||
switch (type)
|
||||
{
|
||||
txt = TextManager.GetServerMessage(txt);
|
||||
}
|
||||
else if (type == ChatMessageType.Order)
|
||||
{
|
||||
int orderIndex = msg.ReadByte();
|
||||
UInt16 targetCharacterID = msg.ReadUInt16();
|
||||
Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character;
|
||||
Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16());
|
||||
int optionIndex = msg.ReadByte();
|
||||
case ChatMessageType.Default:
|
||||
break;
|
||||
case ChatMessageType.Order:
|
||||
int orderIndex = msg.ReadByte();
|
||||
UInt16 targetCharacterID = msg.ReadUInt16();
|
||||
Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character;
|
||||
Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16());
|
||||
int optionIndex = msg.ReadByte();
|
||||
|
||||
Order order = null;
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID)) LastID = ID;
|
||||
Order order = null;
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID)) LastID = ID;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = Order.PrefabList[orderIndex];
|
||||
}
|
||||
string orderOption = "";
|
||||
if (optionIndex >= 0 && optionIndex < order.Options.Length)
|
||||
{
|
||||
orderOption = order.Options[optionIndex];
|
||||
}
|
||||
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
order.Prefab.FadeOutTime);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.SetOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
orderOption, senderCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID))
|
||||
{
|
||||
GameMain.Client.AddChatMessage(
|
||||
new OrderChatMessage(order, orderOption, txt, targetEntity, targetCharacter, senderCharacter));
|
||||
LastID = ID;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = Order.PrefabList[orderIndex];
|
||||
}
|
||||
string orderOption = "";
|
||||
if (optionIndex >= 0 && optionIndex < order.Options.Length)
|
||||
{
|
||||
orderOption = order.Options[optionIndex];
|
||||
}
|
||||
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
order.Prefab.FadeOutTime);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.SetOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
orderOption, senderCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID))
|
||||
{
|
||||
GameMain.Client.AddChatMessage(
|
||||
new OrderChatMessage(order, orderOption, txt, targetEntity, targetCharacter, senderCharacter));
|
||||
LastID = ID;
|
||||
}
|
||||
return;
|
||||
case ChatMessageType.ServerMessageBox:
|
||||
txt = TextManager.GetServerMessage(txt);
|
||||
break;
|
||||
case ChatMessageType.ServerMessageBoxInGame:
|
||||
styleSetting = msg.ReadString();
|
||||
txt = TextManager.GetServerMessage(txt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID))
|
||||
@@ -105,6 +112,9 @@ namespace Barotrauma.Networking
|
||||
new GUIMessageBox("", txt);
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.ServerMessageBoxInGame:
|
||||
new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
|
||||
break;
|
||||
case ChatMessageType.Console:
|
||||
DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
|
||||
break;
|
||||
@@ -120,7 +130,7 @@ namespace Barotrauma.Networking
|
||||
break;
|
||||
}
|
||||
LastID = ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user